18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * QLogic Fibre Channel HBA Driver
48c2ecf20Sopenharmony_ci * Copyright (c)  2003-2014 QLogic Corporation
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include "qla_def.h"
78c2ecf20Sopenharmony_ci#include <linux/delay.h>
88c2ecf20Sopenharmony_ci#include <linux/ktime.h>
98c2ecf20Sopenharmony_ci#include <linux/pci.h>
108c2ecf20Sopenharmony_ci#include <linux/ratelimit.h>
118c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
128c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h>
138c2ecf20Sopenharmony_ci#include <linux/utsname.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/* QLAFX00 specific Mailbox implementation functions */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/*
198c2ecf20Sopenharmony_ci * qlafx00_mailbox_command
208c2ecf20Sopenharmony_ci *	Issue mailbox command and waits for completion.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * Input:
238c2ecf20Sopenharmony_ci *	ha = adapter block pointer.
248c2ecf20Sopenharmony_ci *	mcp = driver internal mbx struct pointer.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * Output:
278c2ecf20Sopenharmony_ci *	mb[MAX_MAILBOX_REGISTER_COUNT] = returned mailbox data.
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * Returns:
308c2ecf20Sopenharmony_ci *	0 : QLA_SUCCESS = cmd performed success
318c2ecf20Sopenharmony_ci *	1 : QLA_FUNCTION_FAILED   (error encountered)
328c2ecf20Sopenharmony_ci *	6 : QLA_FUNCTION_TIMEOUT (timeout condition encountered)
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci * Context:
358c2ecf20Sopenharmony_ci *	Kernel context.
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_cistatic int
388c2ecf20Sopenharmony_ciqlafx00_mailbox_command(scsi_qla_host_t *vha, struct mbx_cmd_32 *mcp)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	int		rval;
428c2ecf20Sopenharmony_ci	unsigned long    flags = 0;
438c2ecf20Sopenharmony_ci	device_reg_t *reg;
448c2ecf20Sopenharmony_ci	uint8_t		abort_active;
458c2ecf20Sopenharmony_ci	uint8_t		io_lock_on;
468c2ecf20Sopenharmony_ci	uint16_t	command = 0;
478c2ecf20Sopenharmony_ci	uint32_t	*iptr;
488c2ecf20Sopenharmony_ci	__le32 __iomem *optr;
498c2ecf20Sopenharmony_ci	uint32_t	cnt;
508c2ecf20Sopenharmony_ci	uint32_t	mboxes;
518c2ecf20Sopenharmony_ci	unsigned long	wait_time;
528c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
538c2ecf20Sopenharmony_ci	scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (ha->pdev->error_state == pci_channel_io_perm_failure) {
568c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x115c,
578c2ecf20Sopenharmony_ci		    "PCI channel failed permanently, exiting.\n");
588c2ecf20Sopenharmony_ci		return QLA_FUNCTION_TIMEOUT;
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	if (vha->device_flags & DFLG_DEV_FAILED) {
628c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x115f,
638c2ecf20Sopenharmony_ci		    "Device in failed state, exiting.\n");
648c2ecf20Sopenharmony_ci		return QLA_FUNCTION_TIMEOUT;
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	reg = ha->iobase;
688c2ecf20Sopenharmony_ci	io_lock_on = base_vha->flags.init_done;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	rval = QLA_SUCCESS;
718c2ecf20Sopenharmony_ci	abort_active = test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (ha->flags.pci_channel_io_perm_failure) {
748c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x1175,
758c2ecf20Sopenharmony_ci		    "Perm failure on EEH timeout MBX, exiting.\n");
768c2ecf20Sopenharmony_ci		return QLA_FUNCTION_TIMEOUT;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (ha->flags.isp82xx_fw_hung) {
808c2ecf20Sopenharmony_ci		/* Setting Link-Down error */
818c2ecf20Sopenharmony_ci		mcp->mb[0] = MBS_LINK_DOWN_ERROR;
828c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x1176,
838c2ecf20Sopenharmony_ci		    "FW hung = %d.\n", ha->flags.isp82xx_fw_hung);
848c2ecf20Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
858c2ecf20Sopenharmony_ci		goto premature_exit;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	/*
898c2ecf20Sopenharmony_ci	 * Wait for active mailbox commands to finish by waiting at most tov
908c2ecf20Sopenharmony_ci	 * seconds. This is to serialize actual issuing of mailbox cmds during
918c2ecf20Sopenharmony_ci	 * non ISP abort time.
928c2ecf20Sopenharmony_ci	 */
938c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&ha->mbx_cmd_comp, mcp->tov * HZ)) {
948c2ecf20Sopenharmony_ci		/* Timeout occurred. Return error. */
958c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x1177,
968c2ecf20Sopenharmony_ci		    "Cmd access timeout, cmd=0x%x, Exiting.\n",
978c2ecf20Sopenharmony_ci		    mcp->mb[0]);
988c2ecf20Sopenharmony_ci		return QLA_FUNCTION_TIMEOUT;
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	ha->flags.mbox_busy = 1;
1028c2ecf20Sopenharmony_ci	/* Save mailbox command for debug */
1038c2ecf20Sopenharmony_ci	ha->mcp32 = mcp;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_mbx, vha, 0x1178,
1068c2ecf20Sopenharmony_ci	    "Prepare to issue mbox cmd=0x%x.\n", mcp->mb[0]);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	/* Load mailbox registers. */
1118c2ecf20Sopenharmony_ci	optr = &reg->ispfx00.mailbox0;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	iptr = mcp->mb;
1148c2ecf20Sopenharmony_ci	command = mcp->mb[0];
1158c2ecf20Sopenharmony_ci	mboxes = mcp->out_mb;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	for (cnt = 0; cnt < ha->mbx_count; cnt++) {
1188c2ecf20Sopenharmony_ci		if (mboxes & BIT_0)
1198c2ecf20Sopenharmony_ci			wrt_reg_dword(optr, *iptr);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		mboxes >>= 1;
1228c2ecf20Sopenharmony_ci		optr++;
1238c2ecf20Sopenharmony_ci		iptr++;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* Issue set host interrupt command to send cmd out. */
1278c2ecf20Sopenharmony_ci	ha->flags.mbox_int = 0;
1288c2ecf20Sopenharmony_ci	clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1172,
1318c2ecf20Sopenharmony_ci	    (uint8_t *)mcp->mb, 16);
1328c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1173,
1338c2ecf20Sopenharmony_ci	    ((uint8_t *)mcp->mb + 0x10), 16);
1348c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1174,
1358c2ecf20Sopenharmony_ci	    ((uint8_t *)mcp->mb + 0x20), 8);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	/* Unlock mbx registers and wait for interrupt */
1388c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_mbx, vha, 0x1179,
1398c2ecf20Sopenharmony_ci	    "Going to unlock irq & waiting for interrupts. "
1408c2ecf20Sopenharmony_ci	    "jiffies=%lx.\n", jiffies);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/* Wait for mbx cmd completion until timeout */
1438c2ecf20Sopenharmony_ci	if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) {
1448c2ecf20Sopenharmony_ci		set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci		QLAFX00_SET_HST_INTR(ha, ha->mbx_intr_code);
1478c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci		WARN_ON_ONCE(wait_for_completion_timeout(&ha->mbx_intr_comp,
1508c2ecf20Sopenharmony_ci							 mcp->tov * HZ) != 0);
1518c2ecf20Sopenharmony_ci	} else {
1528c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x112c,
1538c2ecf20Sopenharmony_ci		    "Cmd=%x Polling Mode.\n", command);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci		QLAFX00_SET_HST_INTR(ha, ha->mbx_intr_code);
1568c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci		wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */
1598c2ecf20Sopenharmony_ci		while (!ha->flags.mbox_int) {
1608c2ecf20Sopenharmony_ci			if (time_after(jiffies, wait_time))
1618c2ecf20Sopenharmony_ci				break;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci			/* Check for pending interrupts. */
1648c2ecf20Sopenharmony_ci			qla2x00_poll(ha->rsp_q_map[0]);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci			if (!ha->flags.mbox_int &&
1678c2ecf20Sopenharmony_ci			    !(IS_QLA2200(ha) &&
1688c2ecf20Sopenharmony_ci			    command == MBC_LOAD_RISC_RAM_EXTENDED))
1698c2ecf20Sopenharmony_ci				usleep_range(10000, 11000);
1708c2ecf20Sopenharmony_ci		} /* while */
1718c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x112d,
1728c2ecf20Sopenharmony_ci		    "Waited %d sec.\n",
1738c2ecf20Sopenharmony_ci		    (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ));
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	/* Check whether we timed out */
1778c2ecf20Sopenharmony_ci	if (ha->flags.mbox_int) {
1788c2ecf20Sopenharmony_ci		uint32_t *iptr2;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x112e,
1818c2ecf20Sopenharmony_ci		    "Cmd=%x completed.\n", command);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		/* Got interrupt. Clear the flag. */
1848c2ecf20Sopenharmony_ci		ha->flags.mbox_int = 0;
1858c2ecf20Sopenharmony_ci		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		if (ha->mailbox_out32[0] != MBS_COMMAND_COMPLETE)
1888c2ecf20Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci		/* Load return mailbox registers. */
1918c2ecf20Sopenharmony_ci		iptr2 = mcp->mb;
1928c2ecf20Sopenharmony_ci		iptr = (uint32_t *)&ha->mailbox_out32[0];
1938c2ecf20Sopenharmony_ci		mboxes = mcp->in_mb;
1948c2ecf20Sopenharmony_ci		for (cnt = 0; cnt < ha->mbx_count; cnt++) {
1958c2ecf20Sopenharmony_ci			if (mboxes & BIT_0)
1968c2ecf20Sopenharmony_ci				*iptr2 = *iptr;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci			mboxes >>= 1;
1998c2ecf20Sopenharmony_ci			iptr2++;
2008c2ecf20Sopenharmony_ci			iptr++;
2018c2ecf20Sopenharmony_ci		}
2028c2ecf20Sopenharmony_ci	} else {
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		rval = QLA_FUNCTION_TIMEOUT;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	ha->flags.mbox_busy = 0;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/* Clean up */
2108c2ecf20Sopenharmony_ci	ha->mcp32 = NULL;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if ((abort_active || !io_lock_on) && !IS_NOPOLLING_TYPE(ha)) {
2138c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x113a,
2148c2ecf20Sopenharmony_ci		    "checking for additional resp interrupt.\n");
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci		/* polling mode for non isp_abort commands. */
2178c2ecf20Sopenharmony_ci		qla2x00_poll(ha->rsp_q_map[0]);
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (rval == QLA_FUNCTION_TIMEOUT &&
2218c2ecf20Sopenharmony_ci	    mcp->mb[0] != MBC_GEN_SYSTEM_ERROR) {
2228c2ecf20Sopenharmony_ci		if (!io_lock_on || (mcp->flags & IOCTL_CMD) ||
2238c2ecf20Sopenharmony_ci		    ha->flags.eeh_busy) {
2248c2ecf20Sopenharmony_ci			/* not in dpc. schedule it for dpc to take over. */
2258c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_mbx, vha, 0x115d,
2268c2ecf20Sopenharmony_ci			    "Timeout, schedule isp_abort_needed.\n");
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci			if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
2298c2ecf20Sopenharmony_ci			    !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
2308c2ecf20Sopenharmony_ci			    !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci				ql_log(ql_log_info, base_vha, 0x115e,
2338c2ecf20Sopenharmony_ci				    "Mailbox cmd timeout occurred, cmd=0x%x, "
2348c2ecf20Sopenharmony_ci				    "mb[0]=0x%x, eeh_busy=0x%x. Scheduling ISP "
2358c2ecf20Sopenharmony_ci				    "abort.\n", command, mcp->mb[0],
2368c2ecf20Sopenharmony_ci				    ha->flags.eeh_busy);
2378c2ecf20Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
2388c2ecf20Sopenharmony_ci				qla2xxx_wake_dpc(vha);
2398c2ecf20Sopenharmony_ci			}
2408c2ecf20Sopenharmony_ci		} else if (!abort_active) {
2418c2ecf20Sopenharmony_ci			/* call abort directly since we are in the DPC thread */
2428c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_mbx, vha, 0x1160,
2438c2ecf20Sopenharmony_ci			    "Timeout, calling abort_isp.\n");
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci			if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
2468c2ecf20Sopenharmony_ci			    !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
2478c2ecf20Sopenharmony_ci			    !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci				ql_log(ql_log_info, base_vha, 0x1161,
2508c2ecf20Sopenharmony_ci				    "Mailbox cmd timeout occurred, cmd=0x%x, "
2518c2ecf20Sopenharmony_ci				    "mb[0]=0x%x. Scheduling ISP abort ",
2528c2ecf20Sopenharmony_ci				    command, mcp->mb[0]);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci				set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
2558c2ecf20Sopenharmony_ci				clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
2568c2ecf20Sopenharmony_ci				if (ha->isp_ops->abort_isp(vha)) {
2578c2ecf20Sopenharmony_ci					/* Failed. retry later. */
2588c2ecf20Sopenharmony_ci					set_bit(ISP_ABORT_NEEDED,
2598c2ecf20Sopenharmony_ci					    &vha->dpc_flags);
2608c2ecf20Sopenharmony_ci				}
2618c2ecf20Sopenharmony_ci				clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
2628c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_mbx, vha, 0x1162,
2638c2ecf20Sopenharmony_ci				    "Finished abort_isp.\n");
2648c2ecf20Sopenharmony_ci			}
2658c2ecf20Sopenharmony_ci		}
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cipremature_exit:
2698c2ecf20Sopenharmony_ci	/* Allow next mbx cmd to come in. */
2708c2ecf20Sopenharmony_ci	complete(&ha->mbx_cmd_comp);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (rval) {
2738c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, base_vha, 0x1163,
2748c2ecf20Sopenharmony_ci		       "**** Failed=%x mbx[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x, cmd=%x ****.\n",
2758c2ecf20Sopenharmony_ci		       rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3],
2768c2ecf20Sopenharmony_ci		       command);
2778c2ecf20Sopenharmony_ci	} else {
2788c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx, base_vha, 0x1164, "Done %s.\n", __func__);
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	return rval;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci/*
2858c2ecf20Sopenharmony_ci * qlafx00_driver_shutdown
2868c2ecf20Sopenharmony_ci *	Indicate a driver shutdown to firmware.
2878c2ecf20Sopenharmony_ci *
2888c2ecf20Sopenharmony_ci * Input:
2898c2ecf20Sopenharmony_ci *	ha = adapter block pointer.
2908c2ecf20Sopenharmony_ci *
2918c2ecf20Sopenharmony_ci * Returns:
2928c2ecf20Sopenharmony_ci *	local function return status code.
2938c2ecf20Sopenharmony_ci *
2948c2ecf20Sopenharmony_ci * Context:
2958c2ecf20Sopenharmony_ci *	Kernel context.
2968c2ecf20Sopenharmony_ci */
2978c2ecf20Sopenharmony_ciint
2988c2ecf20Sopenharmony_ciqlafx00_driver_shutdown(scsi_qla_host_t *vha, int tmo)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	int rval;
3018c2ecf20Sopenharmony_ci	struct mbx_cmd_32 mc;
3028c2ecf20Sopenharmony_ci	struct mbx_cmd_32 *mcp = &mc;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1166,
3058c2ecf20Sopenharmony_ci	    "Entered %s.\n", __func__);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	mcp->mb[0] = MBC_MR_DRV_SHUTDOWN;
3088c2ecf20Sopenharmony_ci	mcp->out_mb = MBX_0;
3098c2ecf20Sopenharmony_ci	mcp->in_mb = MBX_0;
3108c2ecf20Sopenharmony_ci	if (tmo)
3118c2ecf20Sopenharmony_ci		mcp->tov = tmo;
3128c2ecf20Sopenharmony_ci	else
3138c2ecf20Sopenharmony_ci		mcp->tov = MBX_TOV_SECONDS;
3148c2ecf20Sopenharmony_ci	mcp->flags = 0;
3158c2ecf20Sopenharmony_ci	rval = qlafx00_mailbox_command(vha, mcp);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
3188c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x1167,
3198c2ecf20Sopenharmony_ci		    "Failed=%x.\n", rval);
3208c2ecf20Sopenharmony_ci	} else {
3218c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1168,
3228c2ecf20Sopenharmony_ci		    "Done %s.\n", __func__);
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	return rval;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci/*
3298c2ecf20Sopenharmony_ci * qlafx00_get_firmware_state
3308c2ecf20Sopenharmony_ci *	Get adapter firmware state.
3318c2ecf20Sopenharmony_ci *
3328c2ecf20Sopenharmony_ci * Input:
3338c2ecf20Sopenharmony_ci *	ha = adapter block pointer.
3348c2ecf20Sopenharmony_ci *	TARGET_QUEUE_LOCK must be released.
3358c2ecf20Sopenharmony_ci *	ADAPTER_STATE_LOCK must be released.
3368c2ecf20Sopenharmony_ci *
3378c2ecf20Sopenharmony_ci * Returns:
3388c2ecf20Sopenharmony_ci *	qla7xxx local function return status code.
3398c2ecf20Sopenharmony_ci *
3408c2ecf20Sopenharmony_ci * Context:
3418c2ecf20Sopenharmony_ci *	Kernel context.
3428c2ecf20Sopenharmony_ci */
3438c2ecf20Sopenharmony_cistatic int
3448c2ecf20Sopenharmony_ciqlafx00_get_firmware_state(scsi_qla_host_t *vha, uint32_t *states)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	int rval;
3478c2ecf20Sopenharmony_ci	struct mbx_cmd_32 mc;
3488c2ecf20Sopenharmony_ci	struct mbx_cmd_32 *mcp = &mc;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1169,
3518c2ecf20Sopenharmony_ci	    "Entered %s.\n", __func__);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
3548c2ecf20Sopenharmony_ci	mcp->out_mb = MBX_0;
3558c2ecf20Sopenharmony_ci	mcp->in_mb = MBX_1|MBX_0;
3568c2ecf20Sopenharmony_ci	mcp->tov = MBX_TOV_SECONDS;
3578c2ecf20Sopenharmony_ci	mcp->flags = 0;
3588c2ecf20Sopenharmony_ci	rval = qlafx00_mailbox_command(vha, mcp);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/* Return firmware states. */
3618c2ecf20Sopenharmony_ci	states[0] = mcp->mb[1];
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
3648c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x116a,
3658c2ecf20Sopenharmony_ci		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
3668c2ecf20Sopenharmony_ci	} else {
3678c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116b,
3688c2ecf20Sopenharmony_ci		    "Done %s.\n", __func__);
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci	return rval;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci/*
3748c2ecf20Sopenharmony_ci * qlafx00_init_firmware
3758c2ecf20Sopenharmony_ci *	Initialize adapter firmware.
3768c2ecf20Sopenharmony_ci *
3778c2ecf20Sopenharmony_ci * Input:
3788c2ecf20Sopenharmony_ci *	ha = adapter block pointer.
3798c2ecf20Sopenharmony_ci *	dptr = Initialization control block pointer.
3808c2ecf20Sopenharmony_ci *	size = size of initialization control block.
3818c2ecf20Sopenharmony_ci *	TARGET_QUEUE_LOCK must be released.
3828c2ecf20Sopenharmony_ci *	ADAPTER_STATE_LOCK must be released.
3838c2ecf20Sopenharmony_ci *
3848c2ecf20Sopenharmony_ci * Returns:
3858c2ecf20Sopenharmony_ci *	qlafx00 local function return status code.
3868c2ecf20Sopenharmony_ci *
3878c2ecf20Sopenharmony_ci * Context:
3888c2ecf20Sopenharmony_ci *	Kernel context.
3898c2ecf20Sopenharmony_ci */
3908c2ecf20Sopenharmony_ciint
3918c2ecf20Sopenharmony_ciqlafx00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	int rval;
3948c2ecf20Sopenharmony_ci	struct mbx_cmd_32 mc;
3958c2ecf20Sopenharmony_ci	struct mbx_cmd_32 *mcp = &mc;
3968c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116c,
3998c2ecf20Sopenharmony_ci	    "Entered %s.\n", __func__);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	mcp->mb[1] = 0;
4048c2ecf20Sopenharmony_ci	mcp->mb[2] = MSD(ha->init_cb_dma);
4058c2ecf20Sopenharmony_ci	mcp->mb[3] = LSD(ha->init_cb_dma);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
4088c2ecf20Sopenharmony_ci	mcp->in_mb = MBX_0;
4098c2ecf20Sopenharmony_ci	mcp->buf_size = size;
4108c2ecf20Sopenharmony_ci	mcp->flags = MBX_DMA_OUT;
4118c2ecf20Sopenharmony_ci	mcp->tov = MBX_TOV_SECONDS;
4128c2ecf20Sopenharmony_ci	rval = qlafx00_mailbox_command(vha, mcp);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
4158c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x116d,
4168c2ecf20Sopenharmony_ci		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
4178c2ecf20Sopenharmony_ci	} else {
4188c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116e,
4198c2ecf20Sopenharmony_ci		    "Done %s.\n", __func__);
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci	return rval;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci/*
4258c2ecf20Sopenharmony_ci * qlafx00_mbx_reg_test
4268c2ecf20Sopenharmony_ci */
4278c2ecf20Sopenharmony_cistatic int
4288c2ecf20Sopenharmony_ciqlafx00_mbx_reg_test(scsi_qla_host_t *vha)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	int rval;
4318c2ecf20Sopenharmony_ci	struct mbx_cmd_32 mc;
4328c2ecf20Sopenharmony_ci	struct mbx_cmd_32 *mcp = &mc;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116f,
4358c2ecf20Sopenharmony_ci	    "Entered %s.\n", __func__);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST;
4398c2ecf20Sopenharmony_ci	mcp->mb[1] = 0xAAAA;
4408c2ecf20Sopenharmony_ci	mcp->mb[2] = 0x5555;
4418c2ecf20Sopenharmony_ci	mcp->mb[3] = 0xAA55;
4428c2ecf20Sopenharmony_ci	mcp->mb[4] = 0x55AA;
4438c2ecf20Sopenharmony_ci	mcp->mb[5] = 0xA5A5;
4448c2ecf20Sopenharmony_ci	mcp->mb[6] = 0x5A5A;
4458c2ecf20Sopenharmony_ci	mcp->mb[7] = 0x2525;
4468c2ecf20Sopenharmony_ci	mcp->mb[8] = 0xBBBB;
4478c2ecf20Sopenharmony_ci	mcp->mb[9] = 0x6666;
4488c2ecf20Sopenharmony_ci	mcp->mb[10] = 0xBB66;
4498c2ecf20Sopenharmony_ci	mcp->mb[11] = 0x66BB;
4508c2ecf20Sopenharmony_ci	mcp->mb[12] = 0xB6B6;
4518c2ecf20Sopenharmony_ci	mcp->mb[13] = 0x6B6B;
4528c2ecf20Sopenharmony_ci	mcp->mb[14] = 0x3636;
4538c2ecf20Sopenharmony_ci	mcp->mb[15] = 0xCCCC;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	mcp->out_mb = MBX_15|MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|
4578c2ecf20Sopenharmony_ci			MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
4588c2ecf20Sopenharmony_ci	mcp->in_mb = MBX_15|MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|
4598c2ecf20Sopenharmony_ci			MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
4608c2ecf20Sopenharmony_ci	mcp->buf_size = 0;
4618c2ecf20Sopenharmony_ci	mcp->flags = MBX_DMA_OUT;
4628c2ecf20Sopenharmony_ci	mcp->tov = MBX_TOV_SECONDS;
4638c2ecf20Sopenharmony_ci	rval = qlafx00_mailbox_command(vha, mcp);
4648c2ecf20Sopenharmony_ci	if (rval == QLA_SUCCESS) {
4658c2ecf20Sopenharmony_ci		if (mcp->mb[17] != 0xAAAA || mcp->mb[18] != 0x5555 ||
4668c2ecf20Sopenharmony_ci		    mcp->mb[19] != 0xAA55 || mcp->mb[20] != 0x55AA)
4678c2ecf20Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
4688c2ecf20Sopenharmony_ci		if (mcp->mb[21] != 0xA5A5 || mcp->mb[22] != 0x5A5A ||
4698c2ecf20Sopenharmony_ci		    mcp->mb[23] != 0x2525 || mcp->mb[24] != 0xBBBB)
4708c2ecf20Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
4718c2ecf20Sopenharmony_ci		if (mcp->mb[25] != 0x6666 || mcp->mb[26] != 0xBB66 ||
4728c2ecf20Sopenharmony_ci		    mcp->mb[27] != 0x66BB || mcp->mb[28] != 0xB6B6)
4738c2ecf20Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
4748c2ecf20Sopenharmony_ci		if (mcp->mb[29] != 0x6B6B || mcp->mb[30] != 0x3636 ||
4758c2ecf20Sopenharmony_ci		    mcp->mb[31] != 0xCCCC)
4768c2ecf20Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
4808c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x1170,
4818c2ecf20Sopenharmony_ci		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
4828c2ecf20Sopenharmony_ci	} else {
4838c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1171,
4848c2ecf20Sopenharmony_ci		    "Done %s.\n", __func__);
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci	return rval;
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci/**
4908c2ecf20Sopenharmony_ci * qlafx00_pci_config() - Setup ISPFx00 PCI configuration registers.
4918c2ecf20Sopenharmony_ci * @vha: HA context
4928c2ecf20Sopenharmony_ci *
4938c2ecf20Sopenharmony_ci * Returns 0 on success.
4948c2ecf20Sopenharmony_ci */
4958c2ecf20Sopenharmony_ciint
4968c2ecf20Sopenharmony_ciqlafx00_pci_config(scsi_qla_host_t *vha)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	uint16_t w;
4998c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	pci_set_master(ha->pdev);
5028c2ecf20Sopenharmony_ci	pci_try_set_mwi(ha->pdev);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
5058c2ecf20Sopenharmony_ci	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
5068c2ecf20Sopenharmony_ci	w &= ~PCI_COMMAND_INTX_DISABLE;
5078c2ecf20Sopenharmony_ci	pci_write_config_word(ha->pdev, PCI_COMMAND, w);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	/* PCIe -- adjust Maximum Read Request Size (2048). */
5108c2ecf20Sopenharmony_ci	if (pci_is_pcie(ha->pdev))
5118c2ecf20Sopenharmony_ci		pcie_set_readrq(ha->pdev, 2048);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	ha->chip_revision = ha->pdev->revision;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci/**
5198c2ecf20Sopenharmony_ci * qlafx00_warm_reset() - Perform warm reset of iSA(CPUs being reset on SOC).
5208c2ecf20Sopenharmony_ci * @vha: HA context
5218c2ecf20Sopenharmony_ci *
5228c2ecf20Sopenharmony_ci */
5238c2ecf20Sopenharmony_cistatic inline void
5248c2ecf20Sopenharmony_ciqlafx00_soc_cpu_reset(scsi_qla_host_t *vha)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	unsigned long flags = 0;
5278c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
5288c2ecf20Sopenharmony_ci	int i, core;
5298c2ecf20Sopenharmony_ci	uint32_t cnt;
5308c2ecf20Sopenharmony_ci	uint32_t reg_val;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x80004, 0);
5358c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x82004, 0);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	/* stop the XOR DMA engines */
5388c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x60920, 0x02);
5398c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x60924, 0x02);
5408c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0xf0920, 0x02);
5418c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0xf0924, 0x02);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	/* stop the IDMA engines */
5448c2ecf20Sopenharmony_ci	reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x60840);
5458c2ecf20Sopenharmony_ci	reg_val &= ~(1<<12);
5468c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x60840, reg_val);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x60844);
5498c2ecf20Sopenharmony_ci	reg_val &= ~(1<<12);
5508c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x60844, reg_val);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x60848);
5538c2ecf20Sopenharmony_ci	reg_val &= ~(1<<12);
5548c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x60848, reg_val);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x6084C);
5578c2ecf20Sopenharmony_ci	reg_val &= ~(1<<12);
5588c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x6084C, reg_val);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	for (i = 0; i < 100000; i++) {
5618c2ecf20Sopenharmony_ci		if ((QLAFX00_GET_HBA_SOC_REG(ha, 0xd0000) & 0x10000000) == 0 &&
5628c2ecf20Sopenharmony_ci		    (QLAFX00_GET_HBA_SOC_REG(ha, 0x10600) & 0x1) == 0)
5638c2ecf20Sopenharmony_ci			break;
5648c2ecf20Sopenharmony_ci		udelay(100);
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	/* Set all 4 cores in reset */
5688c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
5698c2ecf20Sopenharmony_ci		QLAFX00_SET_HBA_SOC_REG(ha,
5708c2ecf20Sopenharmony_ci		    (SOC_SW_RST_CONTROL_REG_CORE0 + 8*i), (0xF01));
5718c2ecf20Sopenharmony_ci		QLAFX00_SET_HBA_SOC_REG(ha,
5728c2ecf20Sopenharmony_ci		    (SOC_SW_RST_CONTROL_REG_CORE0 + 4 + 8*i), (0x01010101));
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	/* Reset all units in Fabric */
5768c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_RST_CONTROL_REG, (0x011f0101));
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	/* */
5798c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x10610, 1);
5808c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x10600, 0);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/* Set all 4 core Memory Power Down Registers */
5838c2ecf20Sopenharmony_ci	for (i = 0; i < 5; i++) {
5848c2ecf20Sopenharmony_ci		QLAFX00_SET_HBA_SOC_REG(ha,
5858c2ecf20Sopenharmony_ci		    (SOC_PWR_MANAGEMENT_PWR_DOWN_REG + 4*i), (0x0));
5868c2ecf20Sopenharmony_ci	}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	/* Reset all interrupt control registers */
5898c2ecf20Sopenharmony_ci	for (i = 0; i < 115; i++) {
5908c2ecf20Sopenharmony_ci		QLAFX00_SET_HBA_SOC_REG(ha,
5918c2ecf20Sopenharmony_ci		    (SOC_INTERRUPT_SOURCE_I_CONTROL_REG + 4*i), (0x0));
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	/* Reset Timers control registers. per core */
5958c2ecf20Sopenharmony_ci	for (core = 0; core < 4; core++)
5968c2ecf20Sopenharmony_ci		for (i = 0; i < 8; i++)
5978c2ecf20Sopenharmony_ci			QLAFX00_SET_HBA_SOC_REG(ha,
5988c2ecf20Sopenharmony_ci			    (SOC_CORE_TIMER_REG + 0x100*core + 4*i), (0x0));
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	/* Reset per core IRQ ack register */
6018c2ecf20Sopenharmony_ci	for (core = 0; core < 4; core++)
6028c2ecf20Sopenharmony_ci		QLAFX00_SET_HBA_SOC_REG(ha,
6038c2ecf20Sopenharmony_ci		    (SOC_IRQ_ACK_REG + 0x100*core), (0x3FF));
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	/* Set Fabric control and config to defaults */
6068c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_CONTROL_REG, (0x2));
6078c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_CONFIG_REG, (0x3));
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	/* Kick in Fabric units */
6108c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_RST_CONTROL_REG, (0x0));
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/* Kick in Core0 to start boot process */
6138c2ecf20Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, SOC_SW_RST_CONTROL_REG_CORE0, (0xF00));
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	/* Wait 10secs for soft-reset to complete. */
6188c2ecf20Sopenharmony_ci	for (cnt = 10; cnt; cnt--) {
6198c2ecf20Sopenharmony_ci		msleep(1000);
6208c2ecf20Sopenharmony_ci		barrier();
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci/**
6258c2ecf20Sopenharmony_ci * qlafx00_soft_reset() - Soft Reset ISPFx00.
6268c2ecf20Sopenharmony_ci * @vha: HA context
6278c2ecf20Sopenharmony_ci *
6288c2ecf20Sopenharmony_ci * Returns 0 on success.
6298c2ecf20Sopenharmony_ci */
6308c2ecf20Sopenharmony_ciint
6318c2ecf20Sopenharmony_ciqlafx00_soft_reset(scsi_qla_host_t *vha)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
6348c2ecf20Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev) &&
6378c2ecf20Sopenharmony_ci	    ha->flags.pci_channel_io_perm_failure))
6388c2ecf20Sopenharmony_ci		return rval;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	ha->isp_ops->disable_intrs(ha);
6418c2ecf20Sopenharmony_ci	qlafx00_soc_cpu_reset(vha);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci/**
6478c2ecf20Sopenharmony_ci * qlafx00_chip_diag() - Test ISPFx00 for proper operation.
6488c2ecf20Sopenharmony_ci * @vha: HA context
6498c2ecf20Sopenharmony_ci *
6508c2ecf20Sopenharmony_ci * Returns 0 on success.
6518c2ecf20Sopenharmony_ci */
6528c2ecf20Sopenharmony_ciint
6538c2ecf20Sopenharmony_ciqlafx00_chip_diag(scsi_qla_host_t *vha)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	int rval = 0;
6568c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
6578c2ecf20Sopenharmony_ci	struct req_que *req = ha->req_q_map[0];
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	rval = qlafx00_mbx_reg_test(vha);
6628c2ecf20Sopenharmony_ci	if (rval) {
6638c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x1165,
6648c2ecf20Sopenharmony_ci		    "Failed mailbox send register test\n");
6658c2ecf20Sopenharmony_ci	} else {
6668c2ecf20Sopenharmony_ci		/* Flag a successful rval */
6678c2ecf20Sopenharmony_ci		rval = QLA_SUCCESS;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci	return rval;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_civoid
6738c2ecf20Sopenharmony_ciqlafx00_config_rings(struct scsi_qla_host *vha)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
6768c2ecf20Sopenharmony_ci	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	wrt_reg_dword(&reg->req_q_in, 0);
6798c2ecf20Sopenharmony_ci	wrt_reg_dword(&reg->req_q_out, 0);
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	wrt_reg_dword(&reg->rsp_q_in, 0);
6828c2ecf20Sopenharmony_ci	wrt_reg_dword(&reg->rsp_q_out, 0);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	/* PCI posting */
6858c2ecf20Sopenharmony_ci	rd_reg_dword(&reg->rsp_q_out);
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_cichar *
6898c2ecf20Sopenharmony_ciqlafx00_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len)
6908c2ecf20Sopenharmony_ci{
6918c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	if (pci_is_pcie(ha->pdev))
6948c2ecf20Sopenharmony_ci		strlcpy(str, "PCIe iSA", str_len);
6958c2ecf20Sopenharmony_ci	return str;
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_cichar *
6998c2ecf20Sopenharmony_ciqlafx00_fw_version_str(struct scsi_qla_host *vha, char *str, size_t size)
7008c2ecf20Sopenharmony_ci{
7018c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	snprintf(str, size, "%s", ha->mr.fw_version);
7048c2ecf20Sopenharmony_ci	return str;
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_civoid
7088c2ecf20Sopenharmony_ciqlafx00_enable_intrs(struct qla_hw_data *ha)
7098c2ecf20Sopenharmony_ci{
7108c2ecf20Sopenharmony_ci	unsigned long flags = 0;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
7138c2ecf20Sopenharmony_ci	ha->interrupts_on = 1;
7148c2ecf20Sopenharmony_ci	QLAFX00_ENABLE_ICNTRL_REG(ha);
7158c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_civoid
7198c2ecf20Sopenharmony_ciqlafx00_disable_intrs(struct qla_hw_data *ha)
7208c2ecf20Sopenharmony_ci{
7218c2ecf20Sopenharmony_ci	unsigned long flags = 0;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
7248c2ecf20Sopenharmony_ci	ha->interrupts_on = 0;
7258c2ecf20Sopenharmony_ci	QLAFX00_DISABLE_ICNTRL_REG(ha);
7268c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
7278c2ecf20Sopenharmony_ci}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ciint
7308c2ecf20Sopenharmony_ciqlafx00_abort_target(fc_port_t *fcport, uint64_t l, int tag)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	return qla2x00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
7338c2ecf20Sopenharmony_ci}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ciint
7368c2ecf20Sopenharmony_ciqlafx00_lun_reset(fc_port_t *fcport, uint64_t l, int tag)
7378c2ecf20Sopenharmony_ci{
7388c2ecf20Sopenharmony_ci	return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
7398c2ecf20Sopenharmony_ci}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ciint
7428c2ecf20Sopenharmony_ciqlafx00_iospace_config(struct qla_hw_data *ha)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	if (pci_request_selected_regions(ha->pdev, ha->bars,
7458c2ecf20Sopenharmony_ci	    QLA2XXX_DRIVER_NAME)) {
7468c2ecf20Sopenharmony_ci		ql_log_pci(ql_log_fatal, ha->pdev, 0x014e,
7478c2ecf20Sopenharmony_ci		    "Failed to reserve PIO/MMIO regions (%s), aborting.\n",
7488c2ecf20Sopenharmony_ci		    pci_name(ha->pdev));
7498c2ecf20Sopenharmony_ci		goto iospace_error_exit;
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	/* Use MMIO operations for all accesses. */
7538c2ecf20Sopenharmony_ci	if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) {
7548c2ecf20Sopenharmony_ci		ql_log_pci(ql_log_warn, ha->pdev, 0x014f,
7558c2ecf20Sopenharmony_ci		    "Invalid pci I/O region size (%s).\n",
7568c2ecf20Sopenharmony_ci		    pci_name(ha->pdev));
7578c2ecf20Sopenharmony_ci		goto iospace_error_exit;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci	if (pci_resource_len(ha->pdev, 0) < BAR0_LEN_FX00) {
7608c2ecf20Sopenharmony_ci		ql_log_pci(ql_log_warn, ha->pdev, 0x0127,
7618c2ecf20Sopenharmony_ci		    "Invalid PCI mem BAR0 region size (%s), aborting\n",
7628c2ecf20Sopenharmony_ci			pci_name(ha->pdev));
7638c2ecf20Sopenharmony_ci		goto iospace_error_exit;
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	ha->cregbase =
7678c2ecf20Sopenharmony_ci	    ioremap(pci_resource_start(ha->pdev, 0), BAR0_LEN_FX00);
7688c2ecf20Sopenharmony_ci	if (!ha->cregbase) {
7698c2ecf20Sopenharmony_ci		ql_log_pci(ql_log_fatal, ha->pdev, 0x0128,
7708c2ecf20Sopenharmony_ci		    "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
7718c2ecf20Sopenharmony_ci		goto iospace_error_exit;
7728c2ecf20Sopenharmony_ci	}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	if (!(pci_resource_flags(ha->pdev, 2) & IORESOURCE_MEM)) {
7758c2ecf20Sopenharmony_ci		ql_log_pci(ql_log_warn, ha->pdev, 0x0129,
7768c2ecf20Sopenharmony_ci		    "region #2 not an MMIO resource (%s), aborting\n",
7778c2ecf20Sopenharmony_ci		    pci_name(ha->pdev));
7788c2ecf20Sopenharmony_ci		goto iospace_error_exit;
7798c2ecf20Sopenharmony_ci	}
7808c2ecf20Sopenharmony_ci	if (pci_resource_len(ha->pdev, 2) < BAR2_LEN_FX00) {
7818c2ecf20Sopenharmony_ci		ql_log_pci(ql_log_warn, ha->pdev, 0x012a,
7828c2ecf20Sopenharmony_ci		    "Invalid PCI mem BAR2 region size (%s), aborting\n",
7838c2ecf20Sopenharmony_ci			pci_name(ha->pdev));
7848c2ecf20Sopenharmony_ci		goto iospace_error_exit;
7858c2ecf20Sopenharmony_ci	}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	ha->iobase =
7888c2ecf20Sopenharmony_ci	    ioremap(pci_resource_start(ha->pdev, 2), BAR2_LEN_FX00);
7898c2ecf20Sopenharmony_ci	if (!ha->iobase) {
7908c2ecf20Sopenharmony_ci		ql_log_pci(ql_log_fatal, ha->pdev, 0x012b,
7918c2ecf20Sopenharmony_ci		    "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
7928c2ecf20Sopenharmony_ci		goto iospace_error_exit;
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	/* Determine queue resources */
7968c2ecf20Sopenharmony_ci	ha->max_req_queues = ha->max_rsp_queues = 1;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	ql_log_pci(ql_log_info, ha->pdev, 0x012c,
7998c2ecf20Sopenharmony_ci	    "Bars 0x%x, iobase0 0x%p, iobase2 0x%p\n",
8008c2ecf20Sopenharmony_ci	    ha->bars, ha->cregbase, ha->iobase);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	return 0;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ciiospace_error_exit:
8058c2ecf20Sopenharmony_ci	return -ENOMEM;
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cistatic void
8098c2ecf20Sopenharmony_ciqlafx00_save_queue_ptrs(struct scsi_qla_host *vha)
8108c2ecf20Sopenharmony_ci{
8118c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
8128c2ecf20Sopenharmony_ci	struct req_que *req = ha->req_q_map[0];
8138c2ecf20Sopenharmony_ci	struct rsp_que *rsp = ha->rsp_q_map[0];
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	req->length_fx00 = req->length;
8168c2ecf20Sopenharmony_ci	req->ring_fx00 = req->ring;
8178c2ecf20Sopenharmony_ci	req->dma_fx00 = req->dma;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	rsp->length_fx00 = rsp->length;
8208c2ecf20Sopenharmony_ci	rsp->ring_fx00 = rsp->ring;
8218c2ecf20Sopenharmony_ci	rsp->dma_fx00 = rsp->dma;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x012d,
8248c2ecf20Sopenharmony_ci	    "req: %p, ring_fx00: %p, length_fx00: 0x%x,"
8258c2ecf20Sopenharmony_ci	    "req->dma_fx00: 0x%llx\n", req, req->ring_fx00,
8268c2ecf20Sopenharmony_ci	    req->length_fx00, (u64)req->dma_fx00);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x012e,
8298c2ecf20Sopenharmony_ci	    "rsp: %p, ring_fx00: %p, length_fx00: 0x%x,"
8308c2ecf20Sopenharmony_ci	    "rsp->dma_fx00: 0x%llx\n", rsp, rsp->ring_fx00,
8318c2ecf20Sopenharmony_ci	    rsp->length_fx00, (u64)rsp->dma_fx00);
8328c2ecf20Sopenharmony_ci}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistatic int
8358c2ecf20Sopenharmony_ciqlafx00_config_queues(struct scsi_qla_host *vha)
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
8388c2ecf20Sopenharmony_ci	struct req_que *req = ha->req_q_map[0];
8398c2ecf20Sopenharmony_ci	struct rsp_que *rsp = ha->rsp_q_map[0];
8408c2ecf20Sopenharmony_ci	dma_addr_t bar2_hdl = pci_resource_start(ha->pdev, 2);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	req->length = ha->req_que_len;
8438c2ecf20Sopenharmony_ci	req->ring = (void __force *)ha->iobase + ha->req_que_off;
8448c2ecf20Sopenharmony_ci	req->dma = bar2_hdl + ha->req_que_off;
8458c2ecf20Sopenharmony_ci	if ((!req->ring) || (req->length == 0)) {
8468c2ecf20Sopenharmony_ci		ql_log_pci(ql_log_info, ha->pdev, 0x012f,
8478c2ecf20Sopenharmony_ci		    "Unable to allocate memory for req_ring\n");
8488c2ecf20Sopenharmony_ci		return QLA_FUNCTION_FAILED;
8498c2ecf20Sopenharmony_ci	}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0130,
8528c2ecf20Sopenharmony_ci	    "req: %p req_ring pointer %p req len 0x%x "
8538c2ecf20Sopenharmony_ci	    "req off 0x%x\n, req->dma: 0x%llx",
8548c2ecf20Sopenharmony_ci	    req, req->ring, req->length,
8558c2ecf20Sopenharmony_ci	    ha->req_que_off, (u64)req->dma);
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	rsp->length = ha->rsp_que_len;
8588c2ecf20Sopenharmony_ci	rsp->ring = (void __force *)ha->iobase + ha->rsp_que_off;
8598c2ecf20Sopenharmony_ci	rsp->dma = bar2_hdl + ha->rsp_que_off;
8608c2ecf20Sopenharmony_ci	if ((!rsp->ring) || (rsp->length == 0)) {
8618c2ecf20Sopenharmony_ci		ql_log_pci(ql_log_info, ha->pdev, 0x0131,
8628c2ecf20Sopenharmony_ci		    "Unable to allocate memory for rsp_ring\n");
8638c2ecf20Sopenharmony_ci		return QLA_FUNCTION_FAILED;
8648c2ecf20Sopenharmony_ci	}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0132,
8678c2ecf20Sopenharmony_ci	    "rsp: %p rsp_ring pointer %p rsp len 0x%x "
8688c2ecf20Sopenharmony_ci	    "rsp off 0x%x, rsp->dma: 0x%llx\n",
8698c2ecf20Sopenharmony_ci	    rsp, rsp->ring, rsp->length,
8708c2ecf20Sopenharmony_ci	    ha->rsp_que_off, (u64)rsp->dma);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic int
8768c2ecf20Sopenharmony_ciqlafx00_init_fw_ready(scsi_qla_host_t *vha)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	int rval = 0;
8798c2ecf20Sopenharmony_ci	unsigned long wtime;
8808c2ecf20Sopenharmony_ci	uint16_t wait_time;	/* Wait time */
8818c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
8828c2ecf20Sopenharmony_ci	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
8838c2ecf20Sopenharmony_ci	uint32_t aenmbx, aenmbx7 = 0;
8848c2ecf20Sopenharmony_ci	uint32_t pseudo_aen;
8858c2ecf20Sopenharmony_ci	uint32_t state[5];
8868c2ecf20Sopenharmony_ci	bool done = false;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	/* 30 seconds wait - Adjust if required */
8898c2ecf20Sopenharmony_ci	wait_time = 30;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	pseudo_aen = rd_reg_dword(&reg->pseudoaen);
8928c2ecf20Sopenharmony_ci	if (pseudo_aen == 1) {
8938c2ecf20Sopenharmony_ci		aenmbx7 = rd_reg_dword(&reg->initval7);
8948c2ecf20Sopenharmony_ci		ha->mbx_intr_code = MSW(aenmbx7);
8958c2ecf20Sopenharmony_ci		ha->rqstq_intr_code = LSW(aenmbx7);
8968c2ecf20Sopenharmony_ci		rval = qlafx00_driver_shutdown(vha, 10);
8978c2ecf20Sopenharmony_ci		if (rval != QLA_SUCCESS)
8988c2ecf20Sopenharmony_ci			qlafx00_soft_reset(vha);
8998c2ecf20Sopenharmony_ci	}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	/* wait time before firmware ready */
9028c2ecf20Sopenharmony_ci	wtime = jiffies + (wait_time * HZ);
9038c2ecf20Sopenharmony_ci	do {
9048c2ecf20Sopenharmony_ci		aenmbx = rd_reg_dword(&reg->aenmailbox0);
9058c2ecf20Sopenharmony_ci		barrier();
9068c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x0133,
9078c2ecf20Sopenharmony_ci		    "aenmbx: 0x%x\n", aenmbx);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci		switch (aenmbx) {
9108c2ecf20Sopenharmony_ci		case MBA_FW_NOT_STARTED:
9118c2ecf20Sopenharmony_ci		case MBA_FW_STARTING:
9128c2ecf20Sopenharmony_ci			break;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci		case MBA_SYSTEM_ERR:
9158c2ecf20Sopenharmony_ci		case MBA_REQ_TRANSFER_ERR:
9168c2ecf20Sopenharmony_ci		case MBA_RSP_TRANSFER_ERR:
9178c2ecf20Sopenharmony_ci		case MBA_FW_INIT_FAILURE:
9188c2ecf20Sopenharmony_ci			qlafx00_soft_reset(vha);
9198c2ecf20Sopenharmony_ci			break;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci		case MBA_FW_RESTART_CMPLT:
9228c2ecf20Sopenharmony_ci			/* Set the mbx and rqstq intr code */
9238c2ecf20Sopenharmony_ci			aenmbx7 = rd_reg_dword(&reg->aenmailbox7);
9248c2ecf20Sopenharmony_ci			ha->mbx_intr_code = MSW(aenmbx7);
9258c2ecf20Sopenharmony_ci			ha->rqstq_intr_code = LSW(aenmbx7);
9268c2ecf20Sopenharmony_ci			ha->req_que_off = rd_reg_dword(&reg->aenmailbox1);
9278c2ecf20Sopenharmony_ci			ha->rsp_que_off = rd_reg_dword(&reg->aenmailbox3);
9288c2ecf20Sopenharmony_ci			ha->req_que_len = rd_reg_dword(&reg->aenmailbox5);
9298c2ecf20Sopenharmony_ci			ha->rsp_que_len = rd_reg_dword(&reg->aenmailbox6);
9308c2ecf20Sopenharmony_ci			wrt_reg_dword(&reg->aenmailbox0, 0);
9318c2ecf20Sopenharmony_ci			rd_reg_dword_relaxed(&reg->aenmailbox0);
9328c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x0134,
9338c2ecf20Sopenharmony_ci			    "f/w returned mbx_intr_code: 0x%x, "
9348c2ecf20Sopenharmony_ci			    "rqstq_intr_code: 0x%x\n",
9358c2ecf20Sopenharmony_ci			    ha->mbx_intr_code, ha->rqstq_intr_code);
9368c2ecf20Sopenharmony_ci			QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
9378c2ecf20Sopenharmony_ci			rval = QLA_SUCCESS;
9388c2ecf20Sopenharmony_ci			done = true;
9398c2ecf20Sopenharmony_ci			break;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci		default:
9428c2ecf20Sopenharmony_ci			if ((aenmbx & 0xFF00) == MBA_FW_INIT_INPROGRESS)
9438c2ecf20Sopenharmony_ci				break;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci			/* If fw is apparently not ready. In order to continue,
9468c2ecf20Sopenharmony_ci			 * we might need to issue Mbox cmd, but the problem is
9478c2ecf20Sopenharmony_ci			 * that the DoorBell vector values that come with the
9488c2ecf20Sopenharmony_ci			 * 8060 AEN are most likely gone by now (and thus no
9498c2ecf20Sopenharmony_ci			 * bell would be rung on the fw side when mbox cmd is
9508c2ecf20Sopenharmony_ci			 * issued). We have to therefore grab the 8060 AEN
9518c2ecf20Sopenharmony_ci			 * shadow regs (filled in by FW when the last 8060
9528c2ecf20Sopenharmony_ci			 * AEN was being posted).
9538c2ecf20Sopenharmony_ci			 * Do the following to determine what is needed in
9548c2ecf20Sopenharmony_ci			 * order to get the FW ready:
9558c2ecf20Sopenharmony_ci			 * 1. reload the 8060 AEN values from the shadow regs
9568c2ecf20Sopenharmony_ci			 * 2. clear int status to get rid of possible pending
9578c2ecf20Sopenharmony_ci			 *    interrupts
9588c2ecf20Sopenharmony_ci			 * 3. issue Get FW State Mbox cmd to determine fw state
9598c2ecf20Sopenharmony_ci			 * Set the mbx and rqstq intr code from Shadow Regs
9608c2ecf20Sopenharmony_ci			 */
9618c2ecf20Sopenharmony_ci			aenmbx7 = rd_reg_dword(&reg->initval7);
9628c2ecf20Sopenharmony_ci			ha->mbx_intr_code = MSW(aenmbx7);
9638c2ecf20Sopenharmony_ci			ha->rqstq_intr_code = LSW(aenmbx7);
9648c2ecf20Sopenharmony_ci			ha->req_que_off = rd_reg_dword(&reg->initval1);
9658c2ecf20Sopenharmony_ci			ha->rsp_que_off = rd_reg_dword(&reg->initval3);
9668c2ecf20Sopenharmony_ci			ha->req_que_len = rd_reg_dword(&reg->initval5);
9678c2ecf20Sopenharmony_ci			ha->rsp_que_len = rd_reg_dword(&reg->initval6);
9688c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x0135,
9698c2ecf20Sopenharmony_ci			    "f/w returned mbx_intr_code: 0x%x, "
9708c2ecf20Sopenharmony_ci			    "rqstq_intr_code: 0x%x\n",
9718c2ecf20Sopenharmony_ci			    ha->mbx_intr_code, ha->rqstq_intr_code);
9728c2ecf20Sopenharmony_ci			QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci			/* Get the FW state */
9758c2ecf20Sopenharmony_ci			rval = qlafx00_get_firmware_state(vha, state);
9768c2ecf20Sopenharmony_ci			if (rval != QLA_SUCCESS) {
9778c2ecf20Sopenharmony_ci				/* Retry if timer has not expired */
9788c2ecf20Sopenharmony_ci				break;
9798c2ecf20Sopenharmony_ci			}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci			if (state[0] == FSTATE_FX00_CONFIG_WAIT) {
9828c2ecf20Sopenharmony_ci				/* Firmware is waiting to be
9838c2ecf20Sopenharmony_ci				 * initialized by driver
9848c2ecf20Sopenharmony_ci				 */
9858c2ecf20Sopenharmony_ci				rval = QLA_SUCCESS;
9868c2ecf20Sopenharmony_ci				done = true;
9878c2ecf20Sopenharmony_ci				break;
9888c2ecf20Sopenharmony_ci			}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci			/* Issue driver shutdown and wait until f/w recovers.
9918c2ecf20Sopenharmony_ci			 * Driver should continue to poll until 8060 AEN is
9928c2ecf20Sopenharmony_ci			 * received indicating firmware recovery.
9938c2ecf20Sopenharmony_ci			 */
9948c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x0136,
9958c2ecf20Sopenharmony_ci			    "Sending Driver shutdown fw_state 0x%x\n",
9968c2ecf20Sopenharmony_ci			    state[0]);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci			rval = qlafx00_driver_shutdown(vha, 10);
9998c2ecf20Sopenharmony_ci			if (rval != QLA_SUCCESS) {
10008c2ecf20Sopenharmony_ci				rval = QLA_FUNCTION_FAILED;
10018c2ecf20Sopenharmony_ci				break;
10028c2ecf20Sopenharmony_ci			}
10038c2ecf20Sopenharmony_ci			msleep(500);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci			wtime = jiffies + (wait_time * HZ);
10068c2ecf20Sopenharmony_ci			break;
10078c2ecf20Sopenharmony_ci		}
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci		if (!done) {
10108c2ecf20Sopenharmony_ci			if (time_after_eq(jiffies, wtime)) {
10118c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_init, vha, 0x0137,
10128c2ecf20Sopenharmony_ci				    "Init f/w failed: aen[7]: 0x%x\n",
10138c2ecf20Sopenharmony_ci				    rd_reg_dword(&reg->aenmailbox7));
10148c2ecf20Sopenharmony_ci				rval = QLA_FUNCTION_FAILED;
10158c2ecf20Sopenharmony_ci				done = true;
10168c2ecf20Sopenharmony_ci				break;
10178c2ecf20Sopenharmony_ci			}
10188c2ecf20Sopenharmony_ci			/* Delay for a while */
10198c2ecf20Sopenharmony_ci			msleep(500);
10208c2ecf20Sopenharmony_ci		}
10218c2ecf20Sopenharmony_ci	} while (!done);
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	if (rval)
10248c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0138,
10258c2ecf20Sopenharmony_ci		    "%s **** FAILED ****.\n", __func__);
10268c2ecf20Sopenharmony_ci	else
10278c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0139,
10288c2ecf20Sopenharmony_ci		    "%s **** SUCCESS ****.\n", __func__);
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	return rval;
10318c2ecf20Sopenharmony_ci}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci/*
10348c2ecf20Sopenharmony_ci * qlafx00_fw_ready() - Waits for firmware ready.
10358c2ecf20Sopenharmony_ci * @ha: HA context
10368c2ecf20Sopenharmony_ci *
10378c2ecf20Sopenharmony_ci * Returns 0 on success.
10388c2ecf20Sopenharmony_ci */
10398c2ecf20Sopenharmony_ciint
10408c2ecf20Sopenharmony_ciqlafx00_fw_ready(scsi_qla_host_t *vha)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci	int		rval;
10438c2ecf20Sopenharmony_ci	unsigned long	wtime;
10448c2ecf20Sopenharmony_ci	uint16_t	wait_time;	/* Wait time if loop is coming ready */
10458c2ecf20Sopenharmony_ci	uint32_t	state[5];
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	rval = QLA_SUCCESS;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	wait_time = 10;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	/* wait time before firmware ready */
10528c2ecf20Sopenharmony_ci	wtime = jiffies + (wait_time * HZ);
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	/* Wait for ISP to finish init */
10558c2ecf20Sopenharmony_ci	if (!vha->flags.init_done)
10568c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x013a,
10578c2ecf20Sopenharmony_ci		    "Waiting for init to complete...\n");
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	do {
10608c2ecf20Sopenharmony_ci		rval = qlafx00_get_firmware_state(vha, state);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci		if (rval == QLA_SUCCESS) {
10638c2ecf20Sopenharmony_ci			if (state[0] == FSTATE_FX00_INITIALIZED) {
10648c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_init, vha, 0x013b,
10658c2ecf20Sopenharmony_ci				    "fw_state=%x\n", state[0]);
10668c2ecf20Sopenharmony_ci				rval = QLA_SUCCESS;
10678c2ecf20Sopenharmony_ci					break;
10688c2ecf20Sopenharmony_ci			}
10698c2ecf20Sopenharmony_ci		}
10708c2ecf20Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci		if (time_after_eq(jiffies, wtime))
10738c2ecf20Sopenharmony_ci			break;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci		/* Delay for a while */
10768c2ecf20Sopenharmony_ci		msleep(500);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x013c,
10798c2ecf20Sopenharmony_ci		    "fw_state=%x curr time=%lx.\n", state[0], jiffies);
10808c2ecf20Sopenharmony_ci	} while (1);
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	if (rval)
10848c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x013d,
10858c2ecf20Sopenharmony_ci		    "Firmware ready **** FAILED ****.\n");
10868c2ecf20Sopenharmony_ci	else
10878c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x013e,
10888c2ecf20Sopenharmony_ci		    "Firmware ready **** SUCCESS ****.\n");
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	return rval;
10918c2ecf20Sopenharmony_ci}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_cistatic int
10948c2ecf20Sopenharmony_ciqlafx00_find_all_targets(scsi_qla_host_t *vha,
10958c2ecf20Sopenharmony_ci	struct list_head *new_fcports)
10968c2ecf20Sopenharmony_ci{
10978c2ecf20Sopenharmony_ci	int		rval;
10988c2ecf20Sopenharmony_ci	uint16_t	tgt_id;
10998c2ecf20Sopenharmony_ci	fc_port_t	*fcport, *new_fcport;
11008c2ecf20Sopenharmony_ci	int		found;
11018c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	rval = QLA_SUCCESS;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	if (!test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))
11068c2ecf20Sopenharmony_ci		return QLA_FUNCTION_FAILED;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	if ((atomic_read(&vha->loop_down_timer) ||
11098c2ecf20Sopenharmony_ci	     STATE_TRANSITION(vha))) {
11108c2ecf20Sopenharmony_ci		atomic_set(&vha->loop_down_timer, 0);
11118c2ecf20Sopenharmony_ci		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
11128c2ecf20Sopenharmony_ci		return QLA_FUNCTION_FAILED;
11138c2ecf20Sopenharmony_ci	}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x2088,
11168c2ecf20Sopenharmony_ci	    "Listing Target bit map...\n");
11178c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_disc + ql_dbg_init, vha, 0x2089,
11188c2ecf20Sopenharmony_ci	    ha->gid_list, 32);
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	/* Allocate temporary rmtport for any new rmtports discovered. */
11218c2ecf20Sopenharmony_ci	new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
11228c2ecf20Sopenharmony_ci	if (new_fcport == NULL)
11238c2ecf20Sopenharmony_ci		return QLA_MEMORY_ALLOC_FAILED;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	for_each_set_bit(tgt_id, (void *)ha->gid_list,
11268c2ecf20Sopenharmony_ci	    QLAFX00_TGT_NODE_LIST_SIZE) {
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci		/* Send get target node info */
11298c2ecf20Sopenharmony_ci		new_fcport->tgt_id = tgt_id;
11308c2ecf20Sopenharmony_ci		rval = qlafx00_fx_disc(vha, new_fcport,
11318c2ecf20Sopenharmony_ci		    FXDISC_GET_TGT_NODE_INFO);
11328c2ecf20Sopenharmony_ci		if (rval != QLA_SUCCESS) {
11338c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x208a,
11348c2ecf20Sopenharmony_ci			    "Target info scan failed -- assuming zero-entry "
11358c2ecf20Sopenharmony_ci			    "result...\n");
11368c2ecf20Sopenharmony_ci			continue;
11378c2ecf20Sopenharmony_ci		}
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci		/* Locate matching device in database. */
11408c2ecf20Sopenharmony_ci		found = 0;
11418c2ecf20Sopenharmony_ci		list_for_each_entry(fcport, &vha->vp_fcports, list) {
11428c2ecf20Sopenharmony_ci			if (memcmp(new_fcport->port_name,
11438c2ecf20Sopenharmony_ci			    fcport->port_name, WWN_SIZE))
11448c2ecf20Sopenharmony_ci				continue;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci			found++;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci			/*
11498c2ecf20Sopenharmony_ci			 * If tgt_id is same and state FCS_ONLINE, nothing
11508c2ecf20Sopenharmony_ci			 * changed.
11518c2ecf20Sopenharmony_ci			 */
11528c2ecf20Sopenharmony_ci			if (fcport->tgt_id == new_fcport->tgt_id &&
11538c2ecf20Sopenharmony_ci			    atomic_read(&fcport->state) == FCS_ONLINE)
11548c2ecf20Sopenharmony_ci				break;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci			/*
11578c2ecf20Sopenharmony_ci			 * Tgt ID changed or device was marked to be updated.
11588c2ecf20Sopenharmony_ci			 */
11598c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x208b,
11608c2ecf20Sopenharmony_ci			    "TGT-ID Change(%s): Present tgt id: "
11618c2ecf20Sopenharmony_ci			    "0x%x state: 0x%x "
11628c2ecf20Sopenharmony_ci			    "wwnn = %llx wwpn = %llx.\n",
11638c2ecf20Sopenharmony_ci			    __func__, fcport->tgt_id,
11648c2ecf20Sopenharmony_ci			    atomic_read(&fcport->state),
11658c2ecf20Sopenharmony_ci			    (unsigned long long)wwn_to_u64(fcport->node_name),
11668c2ecf20Sopenharmony_ci			    (unsigned long long)wwn_to_u64(fcport->port_name));
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci			ql_log(ql_log_info, vha, 0x208c,
11698c2ecf20Sopenharmony_ci			    "TGT-ID Announce(%s): Discovered tgt "
11708c2ecf20Sopenharmony_ci			    "id 0x%x wwnn = %llx "
11718c2ecf20Sopenharmony_ci			    "wwpn = %llx.\n", __func__, new_fcport->tgt_id,
11728c2ecf20Sopenharmony_ci			    (unsigned long long)
11738c2ecf20Sopenharmony_ci			    wwn_to_u64(new_fcport->node_name),
11748c2ecf20Sopenharmony_ci			    (unsigned long long)
11758c2ecf20Sopenharmony_ci			    wwn_to_u64(new_fcport->port_name));
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci			if (atomic_read(&fcport->state) != FCS_ONLINE) {
11788c2ecf20Sopenharmony_ci				fcport->old_tgt_id = fcport->tgt_id;
11798c2ecf20Sopenharmony_ci				fcport->tgt_id = new_fcport->tgt_id;
11808c2ecf20Sopenharmony_ci				ql_log(ql_log_info, vha, 0x208d,
11818c2ecf20Sopenharmony_ci				   "TGT-ID: New fcport Added: %p\n", fcport);
11828c2ecf20Sopenharmony_ci				qla2x00_update_fcport(vha, fcport);
11838c2ecf20Sopenharmony_ci			} else {
11848c2ecf20Sopenharmony_ci				ql_log(ql_log_info, vha, 0x208e,
11858c2ecf20Sopenharmony_ci				    " Existing TGT-ID %x did not get "
11868c2ecf20Sopenharmony_ci				    " offline event from firmware.\n",
11878c2ecf20Sopenharmony_ci				    fcport->old_tgt_id);
11888c2ecf20Sopenharmony_ci				qla2x00_mark_device_lost(vha, fcport, 0);
11898c2ecf20Sopenharmony_ci				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
11908c2ecf20Sopenharmony_ci				qla2x00_free_fcport(new_fcport);
11918c2ecf20Sopenharmony_ci				return rval;
11928c2ecf20Sopenharmony_ci			}
11938c2ecf20Sopenharmony_ci			break;
11948c2ecf20Sopenharmony_ci		}
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci		if (found)
11978c2ecf20Sopenharmony_ci			continue;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci		/* If device was not in our fcports list, then add it. */
12008c2ecf20Sopenharmony_ci		list_add_tail(&new_fcport->list, new_fcports);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci		/* Allocate a new replacement fcport. */
12038c2ecf20Sopenharmony_ci		new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
12048c2ecf20Sopenharmony_ci		if (new_fcport == NULL)
12058c2ecf20Sopenharmony_ci			return QLA_MEMORY_ALLOC_FAILED;
12068c2ecf20Sopenharmony_ci	}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	qla2x00_free_fcport(new_fcport);
12098c2ecf20Sopenharmony_ci	return rval;
12108c2ecf20Sopenharmony_ci}
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci/*
12138c2ecf20Sopenharmony_ci * qlafx00_configure_all_targets
12148c2ecf20Sopenharmony_ci *      Setup target devices with node ID's.
12158c2ecf20Sopenharmony_ci *
12168c2ecf20Sopenharmony_ci * Input:
12178c2ecf20Sopenharmony_ci *      ha = adapter block pointer.
12188c2ecf20Sopenharmony_ci *
12198c2ecf20Sopenharmony_ci * Returns:
12208c2ecf20Sopenharmony_ci *      0 = success.
12218c2ecf20Sopenharmony_ci *      BIT_0 = error
12228c2ecf20Sopenharmony_ci */
12238c2ecf20Sopenharmony_cistatic int
12248c2ecf20Sopenharmony_ciqlafx00_configure_all_targets(scsi_qla_host_t *vha)
12258c2ecf20Sopenharmony_ci{
12268c2ecf20Sopenharmony_ci	int rval;
12278c2ecf20Sopenharmony_ci	fc_port_t *fcport, *rmptemp;
12288c2ecf20Sopenharmony_ci	LIST_HEAD(new_fcports);
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	rval = qlafx00_fx_disc(vha, &vha->hw->mr.fcport,
12318c2ecf20Sopenharmony_ci	    FXDISC_GET_TGT_NODE_LIST);
12328c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
12338c2ecf20Sopenharmony_ci		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
12348c2ecf20Sopenharmony_ci		return rval;
12358c2ecf20Sopenharmony_ci	}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	rval = qlafx00_find_all_targets(vha, &new_fcports);
12388c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
12398c2ecf20Sopenharmony_ci		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
12408c2ecf20Sopenharmony_ci		return rval;
12418c2ecf20Sopenharmony_ci	}
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	/*
12448c2ecf20Sopenharmony_ci	 * Delete all previous devices marked lost.
12458c2ecf20Sopenharmony_ci	 */
12468c2ecf20Sopenharmony_ci	list_for_each_entry(fcport, &vha->vp_fcports, list) {
12478c2ecf20Sopenharmony_ci		if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
12488c2ecf20Sopenharmony_ci			break;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci		if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
12518c2ecf20Sopenharmony_ci			if (fcport->port_type != FCT_INITIATOR)
12528c2ecf20Sopenharmony_ci				qla2x00_mark_device_lost(vha, fcport, 0);
12538c2ecf20Sopenharmony_ci		}
12548c2ecf20Sopenharmony_ci	}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	/*
12578c2ecf20Sopenharmony_ci	 * Add the new devices to our devices list.
12588c2ecf20Sopenharmony_ci	 */
12598c2ecf20Sopenharmony_ci	list_for_each_entry_safe(fcport, rmptemp, &new_fcports, list) {
12608c2ecf20Sopenharmony_ci		if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
12618c2ecf20Sopenharmony_ci			break;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci		qla2x00_update_fcport(vha, fcport);
12648c2ecf20Sopenharmony_ci		list_move_tail(&fcport->list, &vha->vp_fcports);
12658c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x208f,
12668c2ecf20Sopenharmony_ci		    "Attach new target id 0x%x wwnn = %llx "
12678c2ecf20Sopenharmony_ci		    "wwpn = %llx.\n",
12688c2ecf20Sopenharmony_ci		    fcport->tgt_id,
12698c2ecf20Sopenharmony_ci		    (unsigned long long)wwn_to_u64(fcport->node_name),
12708c2ecf20Sopenharmony_ci		    (unsigned long long)wwn_to_u64(fcport->port_name));
12718c2ecf20Sopenharmony_ci	}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	/* Free all new device structures not processed. */
12748c2ecf20Sopenharmony_ci	list_for_each_entry_safe(fcport, rmptemp, &new_fcports, list) {
12758c2ecf20Sopenharmony_ci		list_del(&fcport->list);
12768c2ecf20Sopenharmony_ci		qla2x00_free_fcport(fcport);
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	return rval;
12808c2ecf20Sopenharmony_ci}
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci/*
12838c2ecf20Sopenharmony_ci * qlafx00_configure_devices
12848c2ecf20Sopenharmony_ci *      Updates Fibre Channel Device Database with what is actually on loop.
12858c2ecf20Sopenharmony_ci *
12868c2ecf20Sopenharmony_ci * Input:
12878c2ecf20Sopenharmony_ci *      ha                = adapter block pointer.
12888c2ecf20Sopenharmony_ci *
12898c2ecf20Sopenharmony_ci * Returns:
12908c2ecf20Sopenharmony_ci *      0 = success.
12918c2ecf20Sopenharmony_ci *      1 = error.
12928c2ecf20Sopenharmony_ci *      2 = database was full and device was not configured.
12938c2ecf20Sopenharmony_ci */
12948c2ecf20Sopenharmony_ciint
12958c2ecf20Sopenharmony_ciqlafx00_configure_devices(scsi_qla_host_t *vha)
12968c2ecf20Sopenharmony_ci{
12978c2ecf20Sopenharmony_ci	int  rval;
12988c2ecf20Sopenharmony_ci	unsigned long flags;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	rval = QLA_SUCCESS;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	flags = vha->dpc_flags;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_disc, vha, 0x2090,
13058c2ecf20Sopenharmony_ci	    "Configure devices -- dpc flags =0x%lx\n", flags);
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	rval = qlafx00_configure_all_targets(vha);
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	if (rval == QLA_SUCCESS) {
13108c2ecf20Sopenharmony_ci		if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
13118c2ecf20Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
13128c2ecf20Sopenharmony_ci		} else {
13138c2ecf20Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_READY);
13148c2ecf20Sopenharmony_ci			ql_log(ql_log_info, vha, 0x2091,
13158c2ecf20Sopenharmony_ci			    "Device Ready\n");
13168c2ecf20Sopenharmony_ci		}
13178c2ecf20Sopenharmony_ci	}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	if (rval) {
13208c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_disc, vha, 0x2092,
13218c2ecf20Sopenharmony_ci		    "%s *** FAILED ***.\n", __func__);
13228c2ecf20Sopenharmony_ci	} else {
13238c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_disc, vha, 0x2093,
13248c2ecf20Sopenharmony_ci		    "%s: exiting normally.\n", __func__);
13258c2ecf20Sopenharmony_ci	}
13268c2ecf20Sopenharmony_ci	return rval;
13278c2ecf20Sopenharmony_ci}
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_cistatic void
13308c2ecf20Sopenharmony_ciqlafx00_abort_isp_cleanup(scsi_qla_host_t *vha, bool critemp)
13318c2ecf20Sopenharmony_ci{
13328c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
13338c2ecf20Sopenharmony_ci	fc_port_t *fcport;
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	vha->flags.online = 0;
13368c2ecf20Sopenharmony_ci	ha->mr.fw_hbt_en = 0;
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	if (!critemp) {
13398c2ecf20Sopenharmony_ci		ha->flags.chip_reset_done = 0;
13408c2ecf20Sopenharmony_ci		clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
13418c2ecf20Sopenharmony_ci		vha->qla_stats.total_isp_aborts++;
13428c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x013f,
13438c2ecf20Sopenharmony_ci		    "Performing ISP error recovery - ha = %p.\n", ha);
13448c2ecf20Sopenharmony_ci		ha->isp_ops->reset_chip(vha);
13458c2ecf20Sopenharmony_ci	}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
13488c2ecf20Sopenharmony_ci		atomic_set(&vha->loop_state, LOOP_DOWN);
13498c2ecf20Sopenharmony_ci		atomic_set(&vha->loop_down_timer,
13508c2ecf20Sopenharmony_ci		    QLAFX00_LOOP_DOWN_TIME);
13518c2ecf20Sopenharmony_ci	} else {
13528c2ecf20Sopenharmony_ci		if (!atomic_read(&vha->loop_down_timer))
13538c2ecf20Sopenharmony_ci			atomic_set(&vha->loop_down_timer,
13548c2ecf20Sopenharmony_ci			    QLAFX00_LOOP_DOWN_TIME);
13558c2ecf20Sopenharmony_ci	}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	/* Clear all async request states across all VPs. */
13588c2ecf20Sopenharmony_ci	list_for_each_entry(fcport, &vha->vp_fcports, list) {
13598c2ecf20Sopenharmony_ci		fcport->flags = 0;
13608c2ecf20Sopenharmony_ci		if (atomic_read(&fcport->state) == FCS_ONLINE)
13618c2ecf20Sopenharmony_ci			qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST);
13628c2ecf20Sopenharmony_ci	}
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	if (!ha->flags.eeh_busy) {
13658c2ecf20Sopenharmony_ci		if (critemp) {
13668c2ecf20Sopenharmony_ci			qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
13678c2ecf20Sopenharmony_ci		} else {
13688c2ecf20Sopenharmony_ci			/* Requeue all commands in outstanding command list. */
13698c2ecf20Sopenharmony_ci			qla2x00_abort_all_cmds(vha, DID_RESET << 16);
13708c2ecf20Sopenharmony_ci		}
13718c2ecf20Sopenharmony_ci	}
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	qla2x00_free_irqs(vha);
13748c2ecf20Sopenharmony_ci	if (critemp)
13758c2ecf20Sopenharmony_ci		set_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags);
13768c2ecf20Sopenharmony_ci	else
13778c2ecf20Sopenharmony_ci		set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	/* Clear the Interrupts */
13808c2ecf20Sopenharmony_ci	QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	ql_log(ql_log_info, vha, 0x0140,
13838c2ecf20Sopenharmony_ci	    "%s Done done - ha=%p.\n", __func__, ha);
13848c2ecf20Sopenharmony_ci}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci/**
13878c2ecf20Sopenharmony_ci * qlafx00_init_response_q_entries() - Initializes response queue entries.
13888c2ecf20Sopenharmony_ci * @rsp: response queue
13898c2ecf20Sopenharmony_ci *
13908c2ecf20Sopenharmony_ci * Beginning of request ring has initialization control block already built
13918c2ecf20Sopenharmony_ci * by nvram config routine.
13928c2ecf20Sopenharmony_ci *
13938c2ecf20Sopenharmony_ci * Returns 0 on success.
13948c2ecf20Sopenharmony_ci */
13958c2ecf20Sopenharmony_civoid
13968c2ecf20Sopenharmony_ciqlafx00_init_response_q_entries(struct rsp_que *rsp)
13978c2ecf20Sopenharmony_ci{
13988c2ecf20Sopenharmony_ci	uint16_t cnt;
13998c2ecf20Sopenharmony_ci	response_t *pkt;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	rsp->ring_ptr = rsp->ring;
14028c2ecf20Sopenharmony_ci	rsp->ring_index    = 0;
14038c2ecf20Sopenharmony_ci	rsp->status_srb = NULL;
14048c2ecf20Sopenharmony_ci	pkt = rsp->ring_ptr;
14058c2ecf20Sopenharmony_ci	for (cnt = 0; cnt < rsp->length; cnt++) {
14068c2ecf20Sopenharmony_ci		pkt->signature = RESPONSE_PROCESSED;
14078c2ecf20Sopenharmony_ci		wrt_reg_dword((void __force __iomem *)&pkt->signature,
14088c2ecf20Sopenharmony_ci		    RESPONSE_PROCESSED);
14098c2ecf20Sopenharmony_ci		pkt++;
14108c2ecf20Sopenharmony_ci	}
14118c2ecf20Sopenharmony_ci}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ciint
14148c2ecf20Sopenharmony_ciqlafx00_rescan_isp(scsi_qla_host_t *vha)
14158c2ecf20Sopenharmony_ci{
14168c2ecf20Sopenharmony_ci	uint32_t status = QLA_FUNCTION_FAILED;
14178c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
14188c2ecf20Sopenharmony_ci	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
14198c2ecf20Sopenharmony_ci	uint32_t aenmbx7;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	qla2x00_request_irqs(ha, ha->rsp_q_map[0]);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	aenmbx7 = rd_reg_dword(&reg->aenmailbox7);
14248c2ecf20Sopenharmony_ci	ha->mbx_intr_code = MSW(aenmbx7);
14258c2ecf20Sopenharmony_ci	ha->rqstq_intr_code = LSW(aenmbx7);
14268c2ecf20Sopenharmony_ci	ha->req_que_off = rd_reg_dword(&reg->aenmailbox1);
14278c2ecf20Sopenharmony_ci	ha->rsp_que_off = rd_reg_dword(&reg->aenmailbox3);
14288c2ecf20Sopenharmony_ci	ha->req_que_len = rd_reg_dword(&reg->aenmailbox5);
14298c2ecf20Sopenharmony_ci	ha->rsp_que_len = rd_reg_dword(&reg->aenmailbox6);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_disc, vha, 0x2094,
14328c2ecf20Sopenharmony_ci	    "fw returned mbx_intr_code: 0x%x, rqstq_intr_code: 0x%x "
14338c2ecf20Sopenharmony_ci	    " Req que offset 0x%x Rsp que offset 0x%x\n",
14348c2ecf20Sopenharmony_ci	    ha->mbx_intr_code, ha->rqstq_intr_code,
14358c2ecf20Sopenharmony_ci	    ha->req_que_off, ha->rsp_que_len);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	/* Clear the Interrupts */
14388c2ecf20Sopenharmony_ci	QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	status = qla2x00_init_rings(vha);
14418c2ecf20Sopenharmony_ci	if (!status) {
14428c2ecf20Sopenharmony_ci		vha->flags.online = 1;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci		/* if no cable then assume it's good */
14458c2ecf20Sopenharmony_ci		if ((vha->device_flags & DFLG_NO_CABLE))
14468c2ecf20Sopenharmony_ci			status = 0;
14478c2ecf20Sopenharmony_ci		/* Register system information */
14488c2ecf20Sopenharmony_ci		if (qlafx00_fx_disc(vha,
14498c2ecf20Sopenharmony_ci		    &vha->hw->mr.fcport, FXDISC_REG_HOST_INFO))
14508c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_disc, vha, 0x2095,
14518c2ecf20Sopenharmony_ci			    "failed to register host info\n");
14528c2ecf20Sopenharmony_ci	}
14538c2ecf20Sopenharmony_ci	scsi_unblock_requests(vha->host);
14548c2ecf20Sopenharmony_ci	return status;
14558c2ecf20Sopenharmony_ci}
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_civoid
14588c2ecf20Sopenharmony_ciqlafx00_timer_routine(scsi_qla_host_t *vha)
14598c2ecf20Sopenharmony_ci{
14608c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
14618c2ecf20Sopenharmony_ci	uint32_t fw_heart_beat;
14628c2ecf20Sopenharmony_ci	uint32_t aenmbx0;
14638c2ecf20Sopenharmony_ci	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
14648c2ecf20Sopenharmony_ci	uint32_t tempc;
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	/* Check firmware health */
14678c2ecf20Sopenharmony_ci	if (ha->mr.fw_hbt_cnt)
14688c2ecf20Sopenharmony_ci		ha->mr.fw_hbt_cnt--;
14698c2ecf20Sopenharmony_ci	else {
14708c2ecf20Sopenharmony_ci		if ((!ha->flags.mr_reset_hdlr_active) &&
14718c2ecf20Sopenharmony_ci		    (!test_bit(UNLOADING, &vha->dpc_flags)) &&
14728c2ecf20Sopenharmony_ci		    (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) &&
14738c2ecf20Sopenharmony_ci		    (ha->mr.fw_hbt_en)) {
14748c2ecf20Sopenharmony_ci			fw_heart_beat = rd_reg_dword(&reg->fwheartbeat);
14758c2ecf20Sopenharmony_ci			if (fw_heart_beat != ha->mr.old_fw_hbt_cnt) {
14768c2ecf20Sopenharmony_ci				ha->mr.old_fw_hbt_cnt = fw_heart_beat;
14778c2ecf20Sopenharmony_ci				ha->mr.fw_hbt_miss_cnt = 0;
14788c2ecf20Sopenharmony_ci			} else {
14798c2ecf20Sopenharmony_ci				ha->mr.fw_hbt_miss_cnt++;
14808c2ecf20Sopenharmony_ci				if (ha->mr.fw_hbt_miss_cnt ==
14818c2ecf20Sopenharmony_ci				    QLAFX00_HEARTBEAT_MISS_CNT) {
14828c2ecf20Sopenharmony_ci					set_bit(ISP_ABORT_NEEDED,
14838c2ecf20Sopenharmony_ci					    &vha->dpc_flags);
14848c2ecf20Sopenharmony_ci					qla2xxx_wake_dpc(vha);
14858c2ecf20Sopenharmony_ci					ha->mr.fw_hbt_miss_cnt = 0;
14868c2ecf20Sopenharmony_ci				}
14878c2ecf20Sopenharmony_ci			}
14888c2ecf20Sopenharmony_ci		}
14898c2ecf20Sopenharmony_ci		ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL;
14908c2ecf20Sopenharmony_ci	}
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	if (test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags)) {
14938c2ecf20Sopenharmony_ci		/* Reset recovery to be performed in timer routine */
14948c2ecf20Sopenharmony_ci		aenmbx0 = rd_reg_dword(&reg->aenmailbox0);
14958c2ecf20Sopenharmony_ci		if (ha->mr.fw_reset_timer_exp) {
14968c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
14978c2ecf20Sopenharmony_ci			qla2xxx_wake_dpc(vha);
14988c2ecf20Sopenharmony_ci			ha->mr.fw_reset_timer_exp = 0;
14998c2ecf20Sopenharmony_ci		} else if (aenmbx0 == MBA_FW_RESTART_CMPLT) {
15008c2ecf20Sopenharmony_ci			/* Wake up DPC to rescan the targets */
15018c2ecf20Sopenharmony_ci			set_bit(FX00_TARGET_SCAN, &vha->dpc_flags);
15028c2ecf20Sopenharmony_ci			clear_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
15038c2ecf20Sopenharmony_ci			qla2xxx_wake_dpc(vha);
15048c2ecf20Sopenharmony_ci			ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
15058c2ecf20Sopenharmony_ci		} else if ((aenmbx0 == MBA_FW_STARTING) &&
15068c2ecf20Sopenharmony_ci		    (!ha->mr.fw_hbt_en)) {
15078c2ecf20Sopenharmony_ci			ha->mr.fw_hbt_en = 1;
15088c2ecf20Sopenharmony_ci		} else if (!ha->mr.fw_reset_timer_tick) {
15098c2ecf20Sopenharmony_ci			if (aenmbx0 == ha->mr.old_aenmbx0_state)
15108c2ecf20Sopenharmony_ci				ha->mr.fw_reset_timer_exp = 1;
15118c2ecf20Sopenharmony_ci			ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
15128c2ecf20Sopenharmony_ci		} else if (aenmbx0 == 0xFFFFFFFF) {
15138c2ecf20Sopenharmony_ci			uint32_t data0, data1;
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci			data0 = QLAFX00_RD_REG(ha,
15168c2ecf20Sopenharmony_ci			    QLAFX00_BAR1_BASE_ADDR_REG);
15178c2ecf20Sopenharmony_ci			data1 = QLAFX00_RD_REG(ha,
15188c2ecf20Sopenharmony_ci			    QLAFX00_PEX0_WIN0_BASE_ADDR_REG);
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci			data0 &= 0xffff0000;
15218c2ecf20Sopenharmony_ci			data1 &= 0x0000ffff;
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci			QLAFX00_WR_REG(ha,
15248c2ecf20Sopenharmony_ci			    QLAFX00_PEX0_WIN0_BASE_ADDR_REG,
15258c2ecf20Sopenharmony_ci			    (data0 | data1));
15268c2ecf20Sopenharmony_ci		} else if ((aenmbx0 & 0xFF00) == MBA_FW_POLL_STATE) {
15278c2ecf20Sopenharmony_ci			ha->mr.fw_reset_timer_tick =
15288c2ecf20Sopenharmony_ci			    QLAFX00_MAX_RESET_INTERVAL;
15298c2ecf20Sopenharmony_ci		} else if (aenmbx0 == MBA_FW_RESET_FCT) {
15308c2ecf20Sopenharmony_ci			ha->mr.fw_reset_timer_tick =
15318c2ecf20Sopenharmony_ci			    QLAFX00_MAX_RESET_INTERVAL;
15328c2ecf20Sopenharmony_ci		}
15338c2ecf20Sopenharmony_ci		if (ha->mr.old_aenmbx0_state != aenmbx0) {
15348c2ecf20Sopenharmony_ci			ha->mr.old_aenmbx0_state = aenmbx0;
15358c2ecf20Sopenharmony_ci			ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
15368c2ecf20Sopenharmony_ci		}
15378c2ecf20Sopenharmony_ci		ha->mr.fw_reset_timer_tick--;
15388c2ecf20Sopenharmony_ci	}
15398c2ecf20Sopenharmony_ci	if (test_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags)) {
15408c2ecf20Sopenharmony_ci		/*
15418c2ecf20Sopenharmony_ci		 * Critical temperature recovery to be
15428c2ecf20Sopenharmony_ci		 * performed in timer routine
15438c2ecf20Sopenharmony_ci		 */
15448c2ecf20Sopenharmony_ci		if (ha->mr.fw_critemp_timer_tick == 0) {
15458c2ecf20Sopenharmony_ci			tempc = QLAFX00_GET_TEMPERATURE(ha);
15468c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_timer, vha, 0x6012,
15478c2ecf20Sopenharmony_ci			    "ISPFx00(%s): Critical temp timer, "
15488c2ecf20Sopenharmony_ci			    "current SOC temperature: %d\n",
15498c2ecf20Sopenharmony_ci			    __func__, tempc);
15508c2ecf20Sopenharmony_ci			if (tempc < ha->mr.critical_temperature) {
15518c2ecf20Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
15528c2ecf20Sopenharmony_ci				clear_bit(FX00_CRITEMP_RECOVERY,
15538c2ecf20Sopenharmony_ci				    &vha->dpc_flags);
15548c2ecf20Sopenharmony_ci				qla2xxx_wake_dpc(vha);
15558c2ecf20Sopenharmony_ci			}
15568c2ecf20Sopenharmony_ci			ha->mr.fw_critemp_timer_tick =
15578c2ecf20Sopenharmony_ci			    QLAFX00_CRITEMP_INTERVAL;
15588c2ecf20Sopenharmony_ci		} else {
15598c2ecf20Sopenharmony_ci			ha->mr.fw_critemp_timer_tick--;
15608c2ecf20Sopenharmony_ci		}
15618c2ecf20Sopenharmony_ci	}
15628c2ecf20Sopenharmony_ci	if (ha->mr.host_info_resend) {
15638c2ecf20Sopenharmony_ci		/*
15648c2ecf20Sopenharmony_ci		 * Incomplete host info might be sent to firmware
15658c2ecf20Sopenharmony_ci		 * durinng system boot - info should be resend
15668c2ecf20Sopenharmony_ci		 */
15678c2ecf20Sopenharmony_ci		if (ha->mr.hinfo_resend_timer_tick == 0) {
15688c2ecf20Sopenharmony_ci			ha->mr.host_info_resend = false;
15698c2ecf20Sopenharmony_ci			set_bit(FX00_HOST_INFO_RESEND, &vha->dpc_flags);
15708c2ecf20Sopenharmony_ci			ha->mr.hinfo_resend_timer_tick =
15718c2ecf20Sopenharmony_ci			    QLAFX00_HINFO_RESEND_INTERVAL;
15728c2ecf20Sopenharmony_ci			qla2xxx_wake_dpc(vha);
15738c2ecf20Sopenharmony_ci		} else {
15748c2ecf20Sopenharmony_ci			ha->mr.hinfo_resend_timer_tick--;
15758c2ecf20Sopenharmony_ci		}
15768c2ecf20Sopenharmony_ci	}
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci/*
15818c2ecf20Sopenharmony_ci *  qlfx00a_reset_initialize
15828c2ecf20Sopenharmony_ci *      Re-initialize after a iSA device reset.
15838c2ecf20Sopenharmony_ci *
15848c2ecf20Sopenharmony_ci * Input:
15858c2ecf20Sopenharmony_ci *      ha  = adapter block pointer.
15868c2ecf20Sopenharmony_ci *
15878c2ecf20Sopenharmony_ci * Returns:
15888c2ecf20Sopenharmony_ci *      0 = success
15898c2ecf20Sopenharmony_ci */
15908c2ecf20Sopenharmony_ciint
15918c2ecf20Sopenharmony_ciqlafx00_reset_initialize(scsi_qla_host_t *vha)
15928c2ecf20Sopenharmony_ci{
15938c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	if (vha->device_flags & DFLG_DEV_FAILED) {
15968c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0142,
15978c2ecf20Sopenharmony_ci		    "Device in failed state\n");
15988c2ecf20Sopenharmony_ci		return QLA_SUCCESS;
15998c2ecf20Sopenharmony_ci	}
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	ha->flags.mr_reset_hdlr_active = 1;
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	if (vha->flags.online) {
16048c2ecf20Sopenharmony_ci		scsi_block_requests(vha->host);
16058c2ecf20Sopenharmony_ci		qlafx00_abort_isp_cleanup(vha, false);
16068c2ecf20Sopenharmony_ci	}
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	ql_log(ql_log_info, vha, 0x0143,
16098c2ecf20Sopenharmony_ci	    "(%s): succeeded.\n", __func__);
16108c2ecf20Sopenharmony_ci	ha->flags.mr_reset_hdlr_active = 0;
16118c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
16128c2ecf20Sopenharmony_ci}
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci/*
16158c2ecf20Sopenharmony_ci *  qlafx00_abort_isp
16168c2ecf20Sopenharmony_ci *      Resets ISP and aborts all outstanding commands.
16178c2ecf20Sopenharmony_ci *
16188c2ecf20Sopenharmony_ci * Input:
16198c2ecf20Sopenharmony_ci *      ha  = adapter block pointer.
16208c2ecf20Sopenharmony_ci *
16218c2ecf20Sopenharmony_ci * Returns:
16228c2ecf20Sopenharmony_ci *      0 = success
16238c2ecf20Sopenharmony_ci */
16248c2ecf20Sopenharmony_ciint
16258c2ecf20Sopenharmony_ciqlafx00_abort_isp(scsi_qla_host_t *vha)
16268c2ecf20Sopenharmony_ci{
16278c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	if (vha->flags.online) {
16308c2ecf20Sopenharmony_ci		if (unlikely(pci_channel_offline(ha->pdev) &&
16318c2ecf20Sopenharmony_ci		    ha->flags.pci_channel_io_perm_failure)) {
16328c2ecf20Sopenharmony_ci			clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
16338c2ecf20Sopenharmony_ci			return QLA_SUCCESS;
16348c2ecf20Sopenharmony_ci		}
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci		scsi_block_requests(vha->host);
16378c2ecf20Sopenharmony_ci		qlafx00_abort_isp_cleanup(vha, false);
16388c2ecf20Sopenharmony_ci	} else {
16398c2ecf20Sopenharmony_ci		scsi_block_requests(vha->host);
16408c2ecf20Sopenharmony_ci		clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
16418c2ecf20Sopenharmony_ci		vha->qla_stats.total_isp_aborts++;
16428c2ecf20Sopenharmony_ci		ha->isp_ops->reset_chip(vha);
16438c2ecf20Sopenharmony_ci		set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
16448c2ecf20Sopenharmony_ci		/* Clear the Interrupts */
16458c2ecf20Sopenharmony_ci		QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
16468c2ecf20Sopenharmony_ci	}
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	ql_log(ql_log_info, vha, 0x0145,
16498c2ecf20Sopenharmony_ci	    "(%s): succeeded.\n", __func__);
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
16528c2ecf20Sopenharmony_ci}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_cistatic inline fc_port_t*
16558c2ecf20Sopenharmony_ciqlafx00_get_fcport(struct scsi_qla_host *vha, int tgt_id)
16568c2ecf20Sopenharmony_ci{
16578c2ecf20Sopenharmony_ci	fc_port_t	*fcport;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	/* Check for matching device in remote port list. */
16608c2ecf20Sopenharmony_ci	list_for_each_entry(fcport, &vha->vp_fcports, list) {
16618c2ecf20Sopenharmony_ci		if (fcport->tgt_id == tgt_id) {
16628c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5072,
16638c2ecf20Sopenharmony_ci			    "Matching fcport(%p) found with TGT-ID: 0x%x "
16648c2ecf20Sopenharmony_ci			    "and Remote TGT_ID: 0x%x\n",
16658c2ecf20Sopenharmony_ci			    fcport, fcport->tgt_id, tgt_id);
16668c2ecf20Sopenharmony_ci			return fcport;
16678c2ecf20Sopenharmony_ci		}
16688c2ecf20Sopenharmony_ci	}
16698c2ecf20Sopenharmony_ci	return NULL;
16708c2ecf20Sopenharmony_ci}
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_cistatic void
16738c2ecf20Sopenharmony_ciqlafx00_tgt_detach(struct scsi_qla_host *vha, int tgt_id)
16748c2ecf20Sopenharmony_ci{
16758c2ecf20Sopenharmony_ci	fc_port_t	*fcport;
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	ql_log(ql_log_info, vha, 0x5073,
16788c2ecf20Sopenharmony_ci	    "Detach TGT-ID: 0x%x\n", tgt_id);
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	fcport = qlafx00_get_fcport(vha, tgt_id);
16818c2ecf20Sopenharmony_ci	if (!fcport)
16828c2ecf20Sopenharmony_ci		return;
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci	qla2x00_mark_device_lost(vha, fcport, 0);
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	return;
16878c2ecf20Sopenharmony_ci}
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_civoid
16908c2ecf20Sopenharmony_ciqlafx00_process_aen(struct scsi_qla_host *vha, struct qla_work_evt *evt)
16918c2ecf20Sopenharmony_ci{
16928c2ecf20Sopenharmony_ci	uint32_t aen_code, aen_data;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	aen_code = FCH_EVT_VENDOR_UNIQUE;
16958c2ecf20Sopenharmony_ci	aen_data = evt->u.aenfx.evtcode;
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	switch (evt->u.aenfx.evtcode) {
16988c2ecf20Sopenharmony_ci	case QLAFX00_MBA_PORT_UPDATE:		/* Port database update */
16998c2ecf20Sopenharmony_ci		if (evt->u.aenfx.mbx[1] == 0) {
17008c2ecf20Sopenharmony_ci			if (evt->u.aenfx.mbx[2] == 1) {
17018c2ecf20Sopenharmony_ci				if (!vha->flags.fw_tgt_reported)
17028c2ecf20Sopenharmony_ci					vha->flags.fw_tgt_reported = 1;
17038c2ecf20Sopenharmony_ci				atomic_set(&vha->loop_down_timer, 0);
17048c2ecf20Sopenharmony_ci				atomic_set(&vha->loop_state, LOOP_UP);
17058c2ecf20Sopenharmony_ci				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
17068c2ecf20Sopenharmony_ci				qla2xxx_wake_dpc(vha);
17078c2ecf20Sopenharmony_ci			} else if (evt->u.aenfx.mbx[2] == 2) {
17088c2ecf20Sopenharmony_ci				qlafx00_tgt_detach(vha, evt->u.aenfx.mbx[3]);
17098c2ecf20Sopenharmony_ci			}
17108c2ecf20Sopenharmony_ci		} else if (evt->u.aenfx.mbx[1] == 0xffff) {
17118c2ecf20Sopenharmony_ci			if (evt->u.aenfx.mbx[2] == 1) {
17128c2ecf20Sopenharmony_ci				if (!vha->flags.fw_tgt_reported)
17138c2ecf20Sopenharmony_ci					vha->flags.fw_tgt_reported = 1;
17148c2ecf20Sopenharmony_ci				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
17158c2ecf20Sopenharmony_ci			} else if (evt->u.aenfx.mbx[2] == 2) {
17168c2ecf20Sopenharmony_ci				vha->device_flags |= DFLG_NO_CABLE;
17178c2ecf20Sopenharmony_ci				qla2x00_mark_all_devices_lost(vha);
17188c2ecf20Sopenharmony_ci			}
17198c2ecf20Sopenharmony_ci		}
17208c2ecf20Sopenharmony_ci		break;
17218c2ecf20Sopenharmony_ci	case QLAFX00_MBA_LINK_UP:
17228c2ecf20Sopenharmony_ci		aen_code = FCH_EVT_LINKUP;
17238c2ecf20Sopenharmony_ci		aen_data = 0;
17248c2ecf20Sopenharmony_ci		break;
17258c2ecf20Sopenharmony_ci	case QLAFX00_MBA_LINK_DOWN:
17268c2ecf20Sopenharmony_ci		aen_code = FCH_EVT_LINKDOWN;
17278c2ecf20Sopenharmony_ci		aen_data = 0;
17288c2ecf20Sopenharmony_ci		break;
17298c2ecf20Sopenharmony_ci	case QLAFX00_MBA_TEMP_CRIT:	/* Critical temperature event */
17308c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x5082,
17318c2ecf20Sopenharmony_ci		    "Process critical temperature event "
17328c2ecf20Sopenharmony_ci		    "aenmb[0]: %x\n",
17338c2ecf20Sopenharmony_ci		    evt->u.aenfx.evtcode);
17348c2ecf20Sopenharmony_ci		scsi_block_requests(vha->host);
17358c2ecf20Sopenharmony_ci		qlafx00_abort_isp_cleanup(vha, true);
17368c2ecf20Sopenharmony_ci		scsi_unblock_requests(vha->host);
17378c2ecf20Sopenharmony_ci		break;
17388c2ecf20Sopenharmony_ci	}
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	fc_host_post_event(vha->host, fc_get_event_number(),
17418c2ecf20Sopenharmony_ci	    aen_code, aen_data);
17428c2ecf20Sopenharmony_ci}
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_cistatic void
17458c2ecf20Sopenharmony_ciqlafx00_update_host_attr(scsi_qla_host_t *vha, struct port_info_data *pinfo)
17468c2ecf20Sopenharmony_ci{
17478c2ecf20Sopenharmony_ci	u64 port_name = 0, node_name = 0;
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	port_name = (unsigned long long)wwn_to_u64(pinfo->port_name);
17508c2ecf20Sopenharmony_ci	node_name = (unsigned long long)wwn_to_u64(pinfo->node_name);
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	fc_host_node_name(vha->host) = node_name;
17538c2ecf20Sopenharmony_ci	fc_host_port_name(vha->host) = port_name;
17548c2ecf20Sopenharmony_ci	if (!pinfo->port_type)
17558c2ecf20Sopenharmony_ci		vha->hw->current_topology = ISP_CFG_F;
17568c2ecf20Sopenharmony_ci	if (pinfo->link_status == QLAFX00_LINK_STATUS_UP)
17578c2ecf20Sopenharmony_ci		atomic_set(&vha->loop_state, LOOP_READY);
17588c2ecf20Sopenharmony_ci	else if (pinfo->link_status == QLAFX00_LINK_STATUS_DOWN)
17598c2ecf20Sopenharmony_ci		atomic_set(&vha->loop_state, LOOP_DOWN);
17608c2ecf20Sopenharmony_ci	vha->hw->link_data_rate = (uint16_t)pinfo->link_config;
17618c2ecf20Sopenharmony_ci}
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_cistatic void
17648c2ecf20Sopenharmony_ciqla2x00_fxdisc_iocb_timeout(void *data)
17658c2ecf20Sopenharmony_ci{
17668c2ecf20Sopenharmony_ci	srb_t *sp = data;
17678c2ecf20Sopenharmony_ci	struct srb_iocb *lio = &sp->u.iocb_cmd;
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci	complete(&lio->u.fxiocb.fxiocb_comp);
17708c2ecf20Sopenharmony_ci}
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_cistatic void qla2x00_fxdisc_sp_done(srb_t *sp, int res)
17738c2ecf20Sopenharmony_ci{
17748c2ecf20Sopenharmony_ci	struct srb_iocb *lio = &sp->u.iocb_cmd;
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	complete(&lio->u.fxiocb.fxiocb_comp);
17778c2ecf20Sopenharmony_ci}
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ciint
17808c2ecf20Sopenharmony_ciqlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
17818c2ecf20Sopenharmony_ci{
17828c2ecf20Sopenharmony_ci	srb_t *sp;
17838c2ecf20Sopenharmony_ci	struct srb_iocb *fdisc;
17848c2ecf20Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
17858c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
17868c2ecf20Sopenharmony_ci	struct host_system_info *phost_info;
17878c2ecf20Sopenharmony_ci	struct register_host_info *preg_hsi;
17888c2ecf20Sopenharmony_ci	struct new_utsname *p_sysid = NULL;
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
17918c2ecf20Sopenharmony_ci	if (!sp)
17928c2ecf20Sopenharmony_ci		goto done;
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	sp->type = SRB_FXIOCB_DCMD;
17958c2ecf20Sopenharmony_ci	sp->name = "fxdisc";
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	fdisc = &sp->u.iocb_cmd;
17988c2ecf20Sopenharmony_ci	fdisc->timeout = qla2x00_fxdisc_iocb_timeout;
17998c2ecf20Sopenharmony_ci	qla2x00_init_timer(sp, FXDISC_TIMEOUT);
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	switch (fx_type) {
18028c2ecf20Sopenharmony_ci	case FXDISC_GET_CONFIG_INFO:
18038c2ecf20Sopenharmony_ci	fdisc->u.fxiocb.flags =
18048c2ecf20Sopenharmony_ci		    SRB_FXDISC_RESP_DMA_VALID;
18058c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.rsp_len = sizeof(struct config_info_data);
18068c2ecf20Sopenharmony_ci		break;
18078c2ecf20Sopenharmony_ci	case FXDISC_GET_PORT_INFO:
18088c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.flags =
18098c2ecf20Sopenharmony_ci		    SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
18108c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.rsp_len = QLAFX00_PORT_DATA_INFO;
18118c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.req_data = cpu_to_le32(fcport->port_id);
18128c2ecf20Sopenharmony_ci		break;
18138c2ecf20Sopenharmony_ci	case FXDISC_GET_TGT_NODE_INFO:
18148c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.flags =
18158c2ecf20Sopenharmony_ci		    SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
18168c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_INFO;
18178c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.req_data = cpu_to_le32(fcport->tgt_id);
18188c2ecf20Sopenharmony_ci		break;
18198c2ecf20Sopenharmony_ci	case FXDISC_GET_TGT_NODE_LIST:
18208c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.flags =
18218c2ecf20Sopenharmony_ci		    SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
18228c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_LIST_SIZE;
18238c2ecf20Sopenharmony_ci		break;
18248c2ecf20Sopenharmony_ci	case FXDISC_REG_HOST_INFO:
18258c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.flags = SRB_FXDISC_REQ_DMA_VALID;
18268c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.req_len = sizeof(struct register_host_info);
18278c2ecf20Sopenharmony_ci		p_sysid = utsname();
18288c2ecf20Sopenharmony_ci		if (!p_sysid) {
18298c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x303c,
18308c2ecf20Sopenharmony_ci			    "Not able to get the system information\n");
18318c2ecf20Sopenharmony_ci			goto done_free_sp;
18328c2ecf20Sopenharmony_ci		}
18338c2ecf20Sopenharmony_ci		break;
18348c2ecf20Sopenharmony_ci	case FXDISC_ABORT_IOCTL:
18358c2ecf20Sopenharmony_ci	default:
18368c2ecf20Sopenharmony_ci		break;
18378c2ecf20Sopenharmony_ci	}
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	if (fdisc->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) {
18408c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.req_addr = dma_alloc_coherent(&ha->pdev->dev,
18418c2ecf20Sopenharmony_ci		    fdisc->u.fxiocb.req_len,
18428c2ecf20Sopenharmony_ci		    &fdisc->u.fxiocb.req_dma_handle, GFP_KERNEL);
18438c2ecf20Sopenharmony_ci		if (!fdisc->u.fxiocb.req_addr)
18448c2ecf20Sopenharmony_ci			goto done_free_sp;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci		if (fx_type == FXDISC_REG_HOST_INFO) {
18478c2ecf20Sopenharmony_ci			preg_hsi = (struct register_host_info *)
18488c2ecf20Sopenharmony_ci				fdisc->u.fxiocb.req_addr;
18498c2ecf20Sopenharmony_ci			phost_info = &preg_hsi->hsi;
18508c2ecf20Sopenharmony_ci			memset(preg_hsi, 0, sizeof(struct register_host_info));
18518c2ecf20Sopenharmony_ci			phost_info->os_type = OS_TYPE_LINUX;
18528c2ecf20Sopenharmony_ci			strlcpy(phost_info->sysname, p_sysid->sysname,
18538c2ecf20Sopenharmony_ci				sizeof(phost_info->sysname));
18548c2ecf20Sopenharmony_ci			strlcpy(phost_info->nodename, p_sysid->nodename,
18558c2ecf20Sopenharmony_ci				sizeof(phost_info->nodename));
18568c2ecf20Sopenharmony_ci			if (!strcmp(phost_info->nodename, "(none)"))
18578c2ecf20Sopenharmony_ci				ha->mr.host_info_resend = true;
18588c2ecf20Sopenharmony_ci			strlcpy(phost_info->release, p_sysid->release,
18598c2ecf20Sopenharmony_ci				sizeof(phost_info->release));
18608c2ecf20Sopenharmony_ci			strlcpy(phost_info->version, p_sysid->version,
18618c2ecf20Sopenharmony_ci				sizeof(phost_info->version));
18628c2ecf20Sopenharmony_ci			strlcpy(phost_info->machine, p_sysid->machine,
18638c2ecf20Sopenharmony_ci				sizeof(phost_info->machine));
18648c2ecf20Sopenharmony_ci			strlcpy(phost_info->domainname, p_sysid->domainname,
18658c2ecf20Sopenharmony_ci				sizeof(phost_info->domainname));
18668c2ecf20Sopenharmony_ci			strlcpy(phost_info->hostdriver, QLA2XXX_VERSION,
18678c2ecf20Sopenharmony_ci				sizeof(phost_info->hostdriver));
18688c2ecf20Sopenharmony_ci			preg_hsi->utc = (uint64_t)ktime_get_real_seconds();
18698c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x0149,
18708c2ecf20Sopenharmony_ci			    "ISP%04X: Host registration with firmware\n",
18718c2ecf20Sopenharmony_ci			    ha->pdev->device);
18728c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x014a,
18738c2ecf20Sopenharmony_ci			    "os_type = '%d', sysname = '%s', nodname = '%s'\n",
18748c2ecf20Sopenharmony_ci			    phost_info->os_type,
18758c2ecf20Sopenharmony_ci			    phost_info->sysname,
18768c2ecf20Sopenharmony_ci			    phost_info->nodename);
18778c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x014b,
18788c2ecf20Sopenharmony_ci			    "release = '%s', version = '%s'\n",
18798c2ecf20Sopenharmony_ci			    phost_info->release,
18808c2ecf20Sopenharmony_ci			    phost_info->version);
18818c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x014c,
18828c2ecf20Sopenharmony_ci			    "machine = '%s' "
18838c2ecf20Sopenharmony_ci			    "domainname = '%s', hostdriver = '%s'\n",
18848c2ecf20Sopenharmony_ci			    phost_info->machine,
18858c2ecf20Sopenharmony_ci			    phost_info->domainname,
18868c2ecf20Sopenharmony_ci			    phost_info->hostdriver);
18878c2ecf20Sopenharmony_ci			ql_dump_buffer(ql_dbg_init + ql_dbg_disc, vha, 0x014d,
18888c2ecf20Sopenharmony_ci			    phost_info, sizeof(*phost_info));
18898c2ecf20Sopenharmony_ci		}
18908c2ecf20Sopenharmony_ci	}
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	if (fdisc->u.fxiocb.flags & SRB_FXDISC_RESP_DMA_VALID) {
18938c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.rsp_addr = dma_alloc_coherent(&ha->pdev->dev,
18948c2ecf20Sopenharmony_ci		    fdisc->u.fxiocb.rsp_len,
18958c2ecf20Sopenharmony_ci		    &fdisc->u.fxiocb.rsp_dma_handle, GFP_KERNEL);
18968c2ecf20Sopenharmony_ci		if (!fdisc->u.fxiocb.rsp_addr)
18978c2ecf20Sopenharmony_ci			goto done_unmap_req;
18988c2ecf20Sopenharmony_ci	}
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	fdisc->u.fxiocb.req_func_type = cpu_to_le16(fx_type);
19018c2ecf20Sopenharmony_ci	sp->done = qla2x00_fxdisc_sp_done;
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	rval = qla2x00_start_sp(sp);
19048c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS)
19058c2ecf20Sopenharmony_ci		goto done_unmap_dma;
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	wait_for_completion(&fdisc->u.fxiocb.fxiocb_comp);
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	if (fx_type == FXDISC_GET_CONFIG_INFO) {
19108c2ecf20Sopenharmony_ci		struct config_info_data *pinfo =
19118c2ecf20Sopenharmony_ci		    (struct config_info_data *) fdisc->u.fxiocb.rsp_addr;
19128c2ecf20Sopenharmony_ci		strlcpy(vha->hw->model_number, pinfo->model_num,
19138c2ecf20Sopenharmony_ci			ARRAY_SIZE(vha->hw->model_number));
19148c2ecf20Sopenharmony_ci		strlcpy(vha->hw->model_desc, pinfo->model_description,
19158c2ecf20Sopenharmony_ci			ARRAY_SIZE(vha->hw->model_desc));
19168c2ecf20Sopenharmony_ci		memcpy(&vha->hw->mr.symbolic_name, pinfo->symbolic_name,
19178c2ecf20Sopenharmony_ci		    sizeof(vha->hw->mr.symbolic_name));
19188c2ecf20Sopenharmony_ci		memcpy(&vha->hw->mr.serial_num, pinfo->serial_num,
19198c2ecf20Sopenharmony_ci		    sizeof(vha->hw->mr.serial_num));
19208c2ecf20Sopenharmony_ci		memcpy(&vha->hw->mr.hw_version, pinfo->hw_version,
19218c2ecf20Sopenharmony_ci		    sizeof(vha->hw->mr.hw_version));
19228c2ecf20Sopenharmony_ci		memcpy(&vha->hw->mr.fw_version, pinfo->fw_version,
19238c2ecf20Sopenharmony_ci		    sizeof(vha->hw->mr.fw_version));
19248c2ecf20Sopenharmony_ci		strim(vha->hw->mr.fw_version);
19258c2ecf20Sopenharmony_ci		memcpy(&vha->hw->mr.uboot_version, pinfo->uboot_version,
19268c2ecf20Sopenharmony_ci		    sizeof(vha->hw->mr.uboot_version));
19278c2ecf20Sopenharmony_ci		memcpy(&vha->hw->mr.fru_serial_num, pinfo->fru_serial_num,
19288c2ecf20Sopenharmony_ci		    sizeof(vha->hw->mr.fru_serial_num));
19298c2ecf20Sopenharmony_ci		vha->hw->mr.critical_temperature =
19308c2ecf20Sopenharmony_ci		    (pinfo->nominal_temp_value) ?
19318c2ecf20Sopenharmony_ci		    pinfo->nominal_temp_value : QLAFX00_CRITEMP_THRSHLD;
19328c2ecf20Sopenharmony_ci		ha->mr.extended_io_enabled = (pinfo->enabled_capabilities &
19338c2ecf20Sopenharmony_ci		    QLAFX00_EXTENDED_IO_EN_MASK) != 0;
19348c2ecf20Sopenharmony_ci	} else if (fx_type == FXDISC_GET_PORT_INFO) {
19358c2ecf20Sopenharmony_ci		struct port_info_data *pinfo =
19368c2ecf20Sopenharmony_ci		    (struct port_info_data *) fdisc->u.fxiocb.rsp_addr;
19378c2ecf20Sopenharmony_ci		memcpy(vha->node_name, pinfo->node_name, WWN_SIZE);
19388c2ecf20Sopenharmony_ci		memcpy(vha->port_name, pinfo->port_name, WWN_SIZE);
19398c2ecf20Sopenharmony_ci		vha->d_id.b.domain = pinfo->port_id[0];
19408c2ecf20Sopenharmony_ci		vha->d_id.b.area = pinfo->port_id[1];
19418c2ecf20Sopenharmony_ci		vha->d_id.b.al_pa = pinfo->port_id[2];
19428c2ecf20Sopenharmony_ci		qlafx00_update_host_attr(vha, pinfo);
19438c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0141,
19448c2ecf20Sopenharmony_ci		    pinfo, 16);
19458c2ecf20Sopenharmony_ci	} else if (fx_type == FXDISC_GET_TGT_NODE_INFO) {
19468c2ecf20Sopenharmony_ci		struct qlafx00_tgt_node_info *pinfo =
19478c2ecf20Sopenharmony_ci		    (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr;
19488c2ecf20Sopenharmony_ci		memcpy(fcport->node_name, pinfo->tgt_node_wwnn, WWN_SIZE);
19498c2ecf20Sopenharmony_ci		memcpy(fcport->port_name, pinfo->tgt_node_wwpn, WWN_SIZE);
19508c2ecf20Sopenharmony_ci		fcport->port_type = FCT_TARGET;
19518c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0144,
19528c2ecf20Sopenharmony_ci		    pinfo, 16);
19538c2ecf20Sopenharmony_ci	} else if (fx_type == FXDISC_GET_TGT_NODE_LIST) {
19548c2ecf20Sopenharmony_ci		struct qlafx00_tgt_node_info *pinfo =
19558c2ecf20Sopenharmony_ci		    (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr;
19568c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0146,
19578c2ecf20Sopenharmony_ci		    pinfo, 16);
19588c2ecf20Sopenharmony_ci		memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE);
19598c2ecf20Sopenharmony_ci	} else if (fx_type == FXDISC_ABORT_IOCTL)
19608c2ecf20Sopenharmony_ci		fdisc->u.fxiocb.result =
19618c2ecf20Sopenharmony_ci		    (fdisc->u.fxiocb.result ==
19628c2ecf20Sopenharmony_ci			cpu_to_le32(QLAFX00_IOCTL_ICOB_ABORT_SUCCESS)) ?
19638c2ecf20Sopenharmony_ci		    cpu_to_le32(QLA_SUCCESS) : cpu_to_le32(QLA_FUNCTION_FAILED);
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	rval = le32_to_cpu(fdisc->u.fxiocb.result);
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_cidone_unmap_dma:
19688c2ecf20Sopenharmony_ci	if (fdisc->u.fxiocb.rsp_addr)
19698c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.rsp_len,
19708c2ecf20Sopenharmony_ci		    fdisc->u.fxiocb.rsp_addr, fdisc->u.fxiocb.rsp_dma_handle);
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_cidone_unmap_req:
19738c2ecf20Sopenharmony_ci	if (fdisc->u.fxiocb.req_addr)
19748c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.req_len,
19758c2ecf20Sopenharmony_ci		    fdisc->u.fxiocb.req_addr, fdisc->u.fxiocb.req_dma_handle);
19768c2ecf20Sopenharmony_cidone_free_sp:
19778c2ecf20Sopenharmony_ci	sp->free(sp);
19788c2ecf20Sopenharmony_cidone:
19798c2ecf20Sopenharmony_ci	return rval;
19808c2ecf20Sopenharmony_ci}
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci/*
19838c2ecf20Sopenharmony_ci * qlafx00_initialize_adapter
19848c2ecf20Sopenharmony_ci *      Initialize board.
19858c2ecf20Sopenharmony_ci *
19868c2ecf20Sopenharmony_ci * Input:
19878c2ecf20Sopenharmony_ci *      ha = adapter block pointer.
19888c2ecf20Sopenharmony_ci *
19898c2ecf20Sopenharmony_ci * Returns:
19908c2ecf20Sopenharmony_ci *      0 = success
19918c2ecf20Sopenharmony_ci */
19928c2ecf20Sopenharmony_ciint
19938c2ecf20Sopenharmony_ciqlafx00_initialize_adapter(scsi_qla_host_t *vha)
19948c2ecf20Sopenharmony_ci{
19958c2ecf20Sopenharmony_ci	int	rval;
19968c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
19978c2ecf20Sopenharmony_ci	uint32_t tempc;
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_ci	/* Clear adapter flags. */
20008c2ecf20Sopenharmony_ci	vha->flags.online = 0;
20018c2ecf20Sopenharmony_ci	ha->flags.chip_reset_done = 0;
20028c2ecf20Sopenharmony_ci	vha->flags.reset_active = 0;
20038c2ecf20Sopenharmony_ci	ha->flags.pci_channel_io_perm_failure = 0;
20048c2ecf20Sopenharmony_ci	ha->flags.eeh_busy = 0;
20058c2ecf20Sopenharmony_ci	atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
20068c2ecf20Sopenharmony_ci	atomic_set(&vha->loop_state, LOOP_DOWN);
20078c2ecf20Sopenharmony_ci	vha->device_flags = DFLG_NO_CABLE;
20088c2ecf20Sopenharmony_ci	vha->dpc_flags = 0;
20098c2ecf20Sopenharmony_ci	vha->flags.management_server_logged_in = 0;
20108c2ecf20Sopenharmony_ci	ha->isp_abort_cnt = 0;
20118c2ecf20Sopenharmony_ci	ha->beacon_blink_led = 0;
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	set_bit(0, ha->req_qid_map);
20148c2ecf20Sopenharmony_ci	set_bit(0, ha->rsp_qid_map);
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0147,
20178c2ecf20Sopenharmony_ci	    "Configuring PCI space...\n");
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	rval = ha->isp_ops->pci_config(vha);
20208c2ecf20Sopenharmony_ci	if (rval) {
20218c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0148,
20228c2ecf20Sopenharmony_ci		    "Unable to configure PCI space.\n");
20238c2ecf20Sopenharmony_ci		return rval;
20248c2ecf20Sopenharmony_ci	}
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci	rval = qlafx00_init_fw_ready(vha);
20278c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS)
20288c2ecf20Sopenharmony_ci		return rval;
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci	qlafx00_save_queue_ptrs(vha);
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	rval = qlafx00_config_queues(vha);
20338c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS)
20348c2ecf20Sopenharmony_ci		return rval;
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	/*
20378c2ecf20Sopenharmony_ci	 * Allocate the array of outstanding commands
20388c2ecf20Sopenharmony_ci	 * now that we know the firmware resources.
20398c2ecf20Sopenharmony_ci	 */
20408c2ecf20Sopenharmony_ci	rval = qla2x00_alloc_outstanding_cmds(ha, vha->req);
20418c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS)
20428c2ecf20Sopenharmony_ci		return rval;
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci	rval = qla2x00_init_rings(vha);
20458c2ecf20Sopenharmony_ci	ha->flags.chip_reset_done = 1;
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci	tempc = QLAFX00_GET_TEMPERATURE(ha);
20488c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0152,
20498c2ecf20Sopenharmony_ci	    "ISPFx00(%s): Critical temp timer, current SOC temperature: 0x%x\n",
20508c2ecf20Sopenharmony_ci	    __func__, tempc);
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	return rval;
20538c2ecf20Sopenharmony_ci}
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ciuint32_t
20568c2ecf20Sopenharmony_ciqlafx00_fw_state_show(struct device *dev, struct device_attribute *attr,
20578c2ecf20Sopenharmony_ci		      char *buf)
20588c2ecf20Sopenharmony_ci{
20598c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
20608c2ecf20Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
20618c2ecf20Sopenharmony_ci	uint32_t state[1];
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	if (qla2x00_reset_active(vha))
20648c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70ce,
20658c2ecf20Sopenharmony_ci		    "ISP reset active.\n");
20668c2ecf20Sopenharmony_ci	else if (!vha->hw->flags.eeh_busy) {
20678c2ecf20Sopenharmony_ci		rval = qlafx00_get_firmware_state(vha, state);
20688c2ecf20Sopenharmony_ci	}
20698c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS)
20708c2ecf20Sopenharmony_ci		memset(state, -1, sizeof(state));
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	return state[0];
20738c2ecf20Sopenharmony_ci}
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_civoid
20768c2ecf20Sopenharmony_ciqlafx00_get_host_speed(struct Scsi_Host *shost)
20778c2ecf20Sopenharmony_ci{
20788c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = ((struct scsi_qla_host *)
20798c2ecf20Sopenharmony_ci					(shost_priv(shost)))->hw;
20808c2ecf20Sopenharmony_ci	u32 speed = FC_PORTSPEED_UNKNOWN;
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	switch (ha->link_data_rate) {
20838c2ecf20Sopenharmony_ci	case QLAFX00_PORT_SPEED_2G:
20848c2ecf20Sopenharmony_ci		speed = FC_PORTSPEED_2GBIT;
20858c2ecf20Sopenharmony_ci		break;
20868c2ecf20Sopenharmony_ci	case QLAFX00_PORT_SPEED_4G:
20878c2ecf20Sopenharmony_ci		speed = FC_PORTSPEED_4GBIT;
20888c2ecf20Sopenharmony_ci		break;
20898c2ecf20Sopenharmony_ci	case QLAFX00_PORT_SPEED_8G:
20908c2ecf20Sopenharmony_ci		speed = FC_PORTSPEED_8GBIT;
20918c2ecf20Sopenharmony_ci		break;
20928c2ecf20Sopenharmony_ci	case QLAFX00_PORT_SPEED_10G:
20938c2ecf20Sopenharmony_ci		speed = FC_PORTSPEED_10GBIT;
20948c2ecf20Sopenharmony_ci		break;
20958c2ecf20Sopenharmony_ci	}
20968c2ecf20Sopenharmony_ci	fc_host_speed(shost) = speed;
20978c2ecf20Sopenharmony_ci}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci/** QLAFX00 specific ISR implementation functions */
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_cistatic inline void
21028c2ecf20Sopenharmony_ciqlafx00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
21038c2ecf20Sopenharmony_ci		     uint32_t sense_len, struct rsp_que *rsp, int res)
21048c2ecf20Sopenharmony_ci{
21058c2ecf20Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
21068c2ecf20Sopenharmony_ci	struct scsi_cmnd *cp = GET_CMD_SP(sp);
21078c2ecf20Sopenharmony_ci	uint32_t track_sense_len;
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci	SET_FW_SENSE_LEN(sp, sense_len);
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
21128c2ecf20Sopenharmony_ci		sense_len = SCSI_SENSE_BUFFERSIZE;
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	SET_CMD_SENSE_LEN(sp, sense_len);
21158c2ecf20Sopenharmony_ci	SET_CMD_SENSE_PTR(sp, cp->sense_buffer);
21168c2ecf20Sopenharmony_ci	track_sense_len = sense_len;
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci	if (sense_len > par_sense_len)
21198c2ecf20Sopenharmony_ci		sense_len = par_sense_len;
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	memcpy(cp->sense_buffer, sense_data, sense_len);
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_ci	SET_FW_SENSE_LEN(sp, GET_FW_SENSE_LEN(sp) - sense_len);
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len);
21268c2ecf20Sopenharmony_ci	track_sense_len -= sense_len;
21278c2ecf20Sopenharmony_ci	SET_CMD_SENSE_LEN(sp, track_sense_len);
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x304d,
21308c2ecf20Sopenharmony_ci	    "sense_len=0x%x par_sense_len=0x%x track_sense_len=0x%x.\n",
21318c2ecf20Sopenharmony_ci	    sense_len, par_sense_len, track_sense_len);
21328c2ecf20Sopenharmony_ci	if (GET_FW_SENSE_LEN(sp) > 0) {
21338c2ecf20Sopenharmony_ci		rsp->status_srb = sp;
21348c2ecf20Sopenharmony_ci		cp->result = res;
21358c2ecf20Sopenharmony_ci	}
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	if (sense_len) {
21388c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3039,
21398c2ecf20Sopenharmony_ci		    "Check condition Sense data, nexus%ld:%d:%llu cmd=%p.\n",
21408c2ecf20Sopenharmony_ci		    sp->vha->host_no, cp->device->id, cp->device->lun,
21418c2ecf20Sopenharmony_ci		    cp);
21428c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3049,
21438c2ecf20Sopenharmony_ci		    cp->sense_buffer, sense_len);
21448c2ecf20Sopenharmony_ci	}
21458c2ecf20Sopenharmony_ci}
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_cistatic void
21488c2ecf20Sopenharmony_ciqlafx00_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
21498c2ecf20Sopenharmony_ci		      struct tsk_mgmt_entry_fx00 *pkt, srb_t *sp,
21508c2ecf20Sopenharmony_ci		      __le16 sstatus, __le16 cpstatus)
21518c2ecf20Sopenharmony_ci{
21528c2ecf20Sopenharmony_ci	struct srb_iocb *tmf;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	tmf = &sp->u.iocb_cmd;
21558c2ecf20Sopenharmony_ci	if (cpstatus != cpu_to_le16((uint16_t)CS_COMPLETE) ||
21568c2ecf20Sopenharmony_ci	    (sstatus & cpu_to_le16((uint16_t)SS_RESPONSE_INFO_LEN_VALID)))
21578c2ecf20Sopenharmony_ci		cpstatus = cpu_to_le16((uint16_t)CS_INCOMPLETE);
21588c2ecf20Sopenharmony_ci	tmf->u.tmf.comp_status = cpstatus;
21598c2ecf20Sopenharmony_ci	sp->done(sp, 0);
21608c2ecf20Sopenharmony_ci}
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_cistatic void
21638c2ecf20Sopenharmony_ciqlafx00_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
21648c2ecf20Sopenharmony_ci			 struct abort_iocb_entry_fx00 *pkt)
21658c2ecf20Sopenharmony_ci{
21668c2ecf20Sopenharmony_ci	const char func[] = "ABT_IOCB";
21678c2ecf20Sopenharmony_ci	srb_t *sp;
21688c2ecf20Sopenharmony_ci	struct srb_iocb *abt;
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
21718c2ecf20Sopenharmony_ci	if (!sp)
21728c2ecf20Sopenharmony_ci		return;
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	abt = &sp->u.iocb_cmd;
21758c2ecf20Sopenharmony_ci	abt->u.abt.comp_status = pkt->tgt_id_sts;
21768c2ecf20Sopenharmony_ci	sp->done(sp, 0);
21778c2ecf20Sopenharmony_ci}
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_cistatic void
21808c2ecf20Sopenharmony_ciqlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
21818c2ecf20Sopenharmony_ci			 struct ioctl_iocb_entry_fx00 *pkt)
21828c2ecf20Sopenharmony_ci{
21838c2ecf20Sopenharmony_ci	const char func[] = "IOSB_IOCB";
21848c2ecf20Sopenharmony_ci	srb_t *sp;
21858c2ecf20Sopenharmony_ci	struct bsg_job *bsg_job;
21868c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
21878c2ecf20Sopenharmony_ci	struct srb_iocb *iocb_job;
21888c2ecf20Sopenharmony_ci	int res = 0;
21898c2ecf20Sopenharmony_ci	struct qla_mt_iocb_rsp_fx00 fstatus;
21908c2ecf20Sopenharmony_ci	uint8_t	*fw_sts_ptr;
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
21938c2ecf20Sopenharmony_ci	if (!sp)
21948c2ecf20Sopenharmony_ci		return;
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	if (sp->type == SRB_FXIOCB_DCMD) {
21978c2ecf20Sopenharmony_ci		iocb_job = &sp->u.iocb_cmd;
21988c2ecf20Sopenharmony_ci		iocb_job->u.fxiocb.seq_number = pkt->seq_no;
21998c2ecf20Sopenharmony_ci		iocb_job->u.fxiocb.fw_flags = pkt->fw_iotcl_flags;
22008c2ecf20Sopenharmony_ci		iocb_job->u.fxiocb.result = pkt->status;
22018c2ecf20Sopenharmony_ci		if (iocb_job->u.fxiocb.flags & SRB_FXDISC_RSP_DWRD_VALID)
22028c2ecf20Sopenharmony_ci			iocb_job->u.fxiocb.req_data =
22038c2ecf20Sopenharmony_ci			    pkt->dataword_r;
22048c2ecf20Sopenharmony_ci	} else {
22058c2ecf20Sopenharmony_ci		bsg_job = sp->u.bsg_job;
22068c2ecf20Sopenharmony_ci		bsg_reply = bsg_job->reply;
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci		memset(&fstatus, 0, sizeof(struct qla_mt_iocb_rsp_fx00));
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci		fstatus.reserved_1 = pkt->reserved_0;
22118c2ecf20Sopenharmony_ci		fstatus.func_type = pkt->comp_func_num;
22128c2ecf20Sopenharmony_ci		fstatus.ioctl_flags = pkt->fw_iotcl_flags;
22138c2ecf20Sopenharmony_ci		fstatus.ioctl_data = pkt->dataword_r;
22148c2ecf20Sopenharmony_ci		fstatus.adapid = pkt->adapid;
22158c2ecf20Sopenharmony_ci		fstatus.reserved_2 = pkt->dataword_r_extra;
22168c2ecf20Sopenharmony_ci		fstatus.res_count = pkt->residuallen;
22178c2ecf20Sopenharmony_ci		fstatus.status = pkt->status;
22188c2ecf20Sopenharmony_ci		fstatus.seq_number = pkt->seq_no;
22198c2ecf20Sopenharmony_ci		memcpy(fstatus.reserved_3,
22208c2ecf20Sopenharmony_ci		    pkt->reserved_2, 20 * sizeof(uint8_t));
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci		fw_sts_ptr = bsg_job->reply + sizeof(struct fc_bsg_reply);
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci		memcpy(fw_sts_ptr, &fstatus, sizeof(fstatus));
22258c2ecf20Sopenharmony_ci		bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
22268c2ecf20Sopenharmony_ci			sizeof(struct qla_mt_iocb_rsp_fx00) + sizeof(uint8_t);
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
22298c2ecf20Sopenharmony_ci		    sp->vha, 0x5080, pkt, sizeof(*pkt));
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
22328c2ecf20Sopenharmony_ci		    sp->vha, 0x5074,
22338c2ecf20Sopenharmony_ci		    fw_sts_ptr, sizeof(fstatus));
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci		res = bsg_reply->result = DID_OK << 16;
22368c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len =
22378c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.payload_len;
22388c2ecf20Sopenharmony_ci	}
22398c2ecf20Sopenharmony_ci	sp->done(sp, res);
22408c2ecf20Sopenharmony_ci}
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci/**
22438c2ecf20Sopenharmony_ci * qlafx00_status_entry() - Process a Status IOCB entry.
22448c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
22458c2ecf20Sopenharmony_ci * @rsp: response queue
22468c2ecf20Sopenharmony_ci * @pkt: Entry pointer
22478c2ecf20Sopenharmony_ci */
22488c2ecf20Sopenharmony_cistatic void
22498c2ecf20Sopenharmony_ciqlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
22508c2ecf20Sopenharmony_ci{
22518c2ecf20Sopenharmony_ci	srb_t		*sp;
22528c2ecf20Sopenharmony_ci	fc_port_t	*fcport;
22538c2ecf20Sopenharmony_ci	struct scsi_cmnd *cp;
22548c2ecf20Sopenharmony_ci	struct sts_entry_fx00 *sts;
22558c2ecf20Sopenharmony_ci	__le16		comp_status;
22568c2ecf20Sopenharmony_ci	__le16		scsi_status;
22578c2ecf20Sopenharmony_ci	__le16		lscsi_status;
22588c2ecf20Sopenharmony_ci	int32_t		resid;
22598c2ecf20Sopenharmony_ci	uint32_t	sense_len, par_sense_len, rsp_info_len, resid_len,
22608c2ecf20Sopenharmony_ci	    fw_resid_len;
22618c2ecf20Sopenharmony_ci	uint8_t		*rsp_info = NULL, *sense_data = NULL;
22628c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
22638c2ecf20Sopenharmony_ci	uint32_t hindex, handle;
22648c2ecf20Sopenharmony_ci	uint16_t que;
22658c2ecf20Sopenharmony_ci	struct req_que *req;
22668c2ecf20Sopenharmony_ci	int logit = 1;
22678c2ecf20Sopenharmony_ci	int res = 0;
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci	sts = (struct sts_entry_fx00 *) pkt;
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	comp_status = sts->comp_status;
22728c2ecf20Sopenharmony_ci	scsi_status = sts->scsi_status & cpu_to_le16((uint16_t)SS_MASK);
22738c2ecf20Sopenharmony_ci	hindex = sts->handle;
22748c2ecf20Sopenharmony_ci	handle = LSW(hindex);
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	que = MSW(hindex);
22778c2ecf20Sopenharmony_ci	req = ha->req_q_map[que];
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_ci	/* Validate handle. */
22808c2ecf20Sopenharmony_ci	if (handle < req->num_outstanding_cmds)
22818c2ecf20Sopenharmony_ci		sp = req->outstanding_cmds[handle];
22828c2ecf20Sopenharmony_ci	else
22838c2ecf20Sopenharmony_ci		sp = NULL;
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci	if (sp == NULL) {
22868c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3034,
22878c2ecf20Sopenharmony_ci		    "Invalid status handle (0x%x).\n", handle);
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
22908c2ecf20Sopenharmony_ci		qla2xxx_wake_dpc(vha);
22918c2ecf20Sopenharmony_ci		return;
22928c2ecf20Sopenharmony_ci	}
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	if (sp->type == SRB_TM_CMD) {
22958c2ecf20Sopenharmony_ci		req->outstanding_cmds[handle] = NULL;
22968c2ecf20Sopenharmony_ci		qlafx00_tm_iocb_entry(vha, req, pkt, sp,
22978c2ecf20Sopenharmony_ci		    scsi_status, comp_status);
22988c2ecf20Sopenharmony_ci		return;
22998c2ecf20Sopenharmony_ci	}
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	/* Fast path completion. */
23028c2ecf20Sopenharmony_ci	if (comp_status == CS_COMPLETE && scsi_status == 0) {
23038c2ecf20Sopenharmony_ci		qla2x00_process_completed_request(vha, req, handle);
23048c2ecf20Sopenharmony_ci		return;
23058c2ecf20Sopenharmony_ci	}
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci	req->outstanding_cmds[handle] = NULL;
23088c2ecf20Sopenharmony_ci	cp = GET_CMD_SP(sp);
23098c2ecf20Sopenharmony_ci	if (cp == NULL) {
23108c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3048,
23118c2ecf20Sopenharmony_ci		    "Command already returned (0x%x/%p).\n",
23128c2ecf20Sopenharmony_ci		    handle, sp);
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci		return;
23158c2ecf20Sopenharmony_ci	}
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci	lscsi_status = scsi_status & cpu_to_le16((uint16_t)STATUS_MASK);
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci	fcport = sp->fcport;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	sense_len = par_sense_len = rsp_info_len = resid_len =
23228c2ecf20Sopenharmony_ci		fw_resid_len = 0;
23238c2ecf20Sopenharmony_ci	if (scsi_status & cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID))
23248c2ecf20Sopenharmony_ci		sense_len = sts->sense_len;
23258c2ecf20Sopenharmony_ci	if (scsi_status & cpu_to_le16(((uint16_t)SS_RESIDUAL_UNDER
23268c2ecf20Sopenharmony_ci	    | (uint16_t)SS_RESIDUAL_OVER)))
23278c2ecf20Sopenharmony_ci		resid_len = le32_to_cpu(sts->residual_len);
23288c2ecf20Sopenharmony_ci	if (comp_status == cpu_to_le16((uint16_t)CS_DATA_UNDERRUN))
23298c2ecf20Sopenharmony_ci		fw_resid_len = le32_to_cpu(sts->residual_len);
23308c2ecf20Sopenharmony_ci	rsp_info = sense_data = sts->data;
23318c2ecf20Sopenharmony_ci	par_sense_len = sizeof(sts->data);
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	/* Check for overrun. */
23348c2ecf20Sopenharmony_ci	if (comp_status == CS_COMPLETE &&
23358c2ecf20Sopenharmony_ci	    scsi_status & cpu_to_le16((uint16_t)SS_RESIDUAL_OVER))
23368c2ecf20Sopenharmony_ci		comp_status = cpu_to_le16((uint16_t)CS_DATA_OVERRUN);
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci	/*
23398c2ecf20Sopenharmony_ci	 * Based on Host and scsi status generate status code for Linux
23408c2ecf20Sopenharmony_ci	 */
23418c2ecf20Sopenharmony_ci	switch (le16_to_cpu(comp_status)) {
23428c2ecf20Sopenharmony_ci	case CS_COMPLETE:
23438c2ecf20Sopenharmony_ci	case CS_QUEUE_FULL:
23448c2ecf20Sopenharmony_ci		if (scsi_status == 0) {
23458c2ecf20Sopenharmony_ci			res = DID_OK << 16;
23468c2ecf20Sopenharmony_ci			break;
23478c2ecf20Sopenharmony_ci		}
23488c2ecf20Sopenharmony_ci		if (scsi_status & cpu_to_le16(((uint16_t)SS_RESIDUAL_UNDER
23498c2ecf20Sopenharmony_ci		    | (uint16_t)SS_RESIDUAL_OVER))) {
23508c2ecf20Sopenharmony_ci			resid = resid_len;
23518c2ecf20Sopenharmony_ci			scsi_set_resid(cp, resid);
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci			if (!lscsi_status &&
23548c2ecf20Sopenharmony_ci			    ((unsigned)(scsi_bufflen(cp) - resid) <
23558c2ecf20Sopenharmony_ci			     cp->underflow)) {
23568c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x3050,
23578c2ecf20Sopenharmony_ci				    "Mid-layer underflow "
23588c2ecf20Sopenharmony_ci				    "detected (0x%x of 0x%x bytes).\n",
23598c2ecf20Sopenharmony_ci				    resid, scsi_bufflen(cp));
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci				res = DID_ERROR << 16;
23628c2ecf20Sopenharmony_ci				break;
23638c2ecf20Sopenharmony_ci			}
23648c2ecf20Sopenharmony_ci		}
23658c2ecf20Sopenharmony_ci		res = DID_OK << 16 | le16_to_cpu(lscsi_status);
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci		if (lscsi_status ==
23688c2ecf20Sopenharmony_ci		    cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL)) {
23698c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x3051,
23708c2ecf20Sopenharmony_ci			    "QUEUE FULL detected.\n");
23718c2ecf20Sopenharmony_ci			break;
23728c2ecf20Sopenharmony_ci		}
23738c2ecf20Sopenharmony_ci		logit = 0;
23748c2ecf20Sopenharmony_ci		if (lscsi_status != cpu_to_le16((uint16_t)SS_CHECK_CONDITION))
23758c2ecf20Sopenharmony_ci			break;
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
23788c2ecf20Sopenharmony_ci		if (!(scsi_status & cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID)))
23798c2ecf20Sopenharmony_ci			break;
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci		qlafx00_handle_sense(sp, sense_data, par_sense_len, sense_len,
23828c2ecf20Sopenharmony_ci		    rsp, res);
23838c2ecf20Sopenharmony_ci		break;
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci	case CS_DATA_UNDERRUN:
23868c2ecf20Sopenharmony_ci		/* Use F/W calculated residual length. */
23878c2ecf20Sopenharmony_ci		if (IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
23888c2ecf20Sopenharmony_ci			resid = fw_resid_len;
23898c2ecf20Sopenharmony_ci		else
23908c2ecf20Sopenharmony_ci			resid = resid_len;
23918c2ecf20Sopenharmony_ci		scsi_set_resid(cp, resid);
23928c2ecf20Sopenharmony_ci		if (scsi_status & cpu_to_le16((uint16_t)SS_RESIDUAL_UNDER)) {
23938c2ecf20Sopenharmony_ci			if ((IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
23948c2ecf20Sopenharmony_ci			    && fw_resid_len != resid_len) {
23958c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x3052,
23968c2ecf20Sopenharmony_ci				    "Dropped frame(s) detected "
23978c2ecf20Sopenharmony_ci				    "(0x%x of 0x%x bytes).\n",
23988c2ecf20Sopenharmony_ci				    resid, scsi_bufflen(cp));
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci				res = DID_ERROR << 16 |
24018c2ecf20Sopenharmony_ci				    le16_to_cpu(lscsi_status);
24028c2ecf20Sopenharmony_ci				goto check_scsi_status;
24038c2ecf20Sopenharmony_ci			}
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci			if (!lscsi_status &&
24068c2ecf20Sopenharmony_ci			    ((unsigned)(scsi_bufflen(cp) - resid) <
24078c2ecf20Sopenharmony_ci			    cp->underflow)) {
24088c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x3053,
24098c2ecf20Sopenharmony_ci				    "Mid-layer underflow "
24108c2ecf20Sopenharmony_ci				    "detected (0x%x of 0x%x bytes, "
24118c2ecf20Sopenharmony_ci				    "cp->underflow: 0x%x).\n",
24128c2ecf20Sopenharmony_ci				    resid, scsi_bufflen(cp), cp->underflow);
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci				res = DID_ERROR << 16;
24158c2ecf20Sopenharmony_ci				break;
24168c2ecf20Sopenharmony_ci			}
24178c2ecf20Sopenharmony_ci		} else if (lscsi_status !=
24188c2ecf20Sopenharmony_ci		    cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL) &&
24198c2ecf20Sopenharmony_ci		    lscsi_status != cpu_to_le16((uint16_t)SAM_STAT_BUSY)) {
24208c2ecf20Sopenharmony_ci			/*
24218c2ecf20Sopenharmony_ci			 * scsi status of task set and busy are considered
24228c2ecf20Sopenharmony_ci			 * to be task not completed.
24238c2ecf20Sopenharmony_ci			 */
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x3054,
24268c2ecf20Sopenharmony_ci			    "Dropped frame(s) detected (0x%x "
24278c2ecf20Sopenharmony_ci			    "of 0x%x bytes).\n", resid,
24288c2ecf20Sopenharmony_ci			    scsi_bufflen(cp));
24298c2ecf20Sopenharmony_ci
24308c2ecf20Sopenharmony_ci			res = DID_ERROR << 16 | le16_to_cpu(lscsi_status);
24318c2ecf20Sopenharmony_ci			goto check_scsi_status;
24328c2ecf20Sopenharmony_ci		} else {
24338c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x3055,
24348c2ecf20Sopenharmony_ci			    "scsi_status: 0x%x, lscsi_status: 0x%x\n",
24358c2ecf20Sopenharmony_ci			    scsi_status, lscsi_status);
24368c2ecf20Sopenharmony_ci		}
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci		res = DID_OK << 16 | le16_to_cpu(lscsi_status);
24398c2ecf20Sopenharmony_ci		logit = 0;
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_cicheck_scsi_status:
24428c2ecf20Sopenharmony_ci		/*
24438c2ecf20Sopenharmony_ci		 * Check to see if SCSI Status is non zero. If so report SCSI
24448c2ecf20Sopenharmony_ci		 * Status.
24458c2ecf20Sopenharmony_ci		 */
24468c2ecf20Sopenharmony_ci		if (lscsi_status != 0) {
24478c2ecf20Sopenharmony_ci			if (lscsi_status ==
24488c2ecf20Sopenharmony_ci			    cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL)) {
24498c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x3056,
24508c2ecf20Sopenharmony_ci				    "QUEUE FULL detected.\n");
24518c2ecf20Sopenharmony_ci				logit = 1;
24528c2ecf20Sopenharmony_ci				break;
24538c2ecf20Sopenharmony_ci			}
24548c2ecf20Sopenharmony_ci			if (lscsi_status !=
24558c2ecf20Sopenharmony_ci			    cpu_to_le16((uint16_t)SS_CHECK_CONDITION))
24568c2ecf20Sopenharmony_ci				break;
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
24598c2ecf20Sopenharmony_ci			if (!(scsi_status &
24608c2ecf20Sopenharmony_ci			    cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID)))
24618c2ecf20Sopenharmony_ci				break;
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_ci			qlafx00_handle_sense(sp, sense_data, par_sense_len,
24648c2ecf20Sopenharmony_ci			    sense_len, rsp, res);
24658c2ecf20Sopenharmony_ci		}
24668c2ecf20Sopenharmony_ci		break;
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci	case CS_PORT_LOGGED_OUT:
24698c2ecf20Sopenharmony_ci	case CS_PORT_CONFIG_CHG:
24708c2ecf20Sopenharmony_ci	case CS_PORT_BUSY:
24718c2ecf20Sopenharmony_ci	case CS_INCOMPLETE:
24728c2ecf20Sopenharmony_ci	case CS_PORT_UNAVAILABLE:
24738c2ecf20Sopenharmony_ci	case CS_TIMEOUT:
24748c2ecf20Sopenharmony_ci	case CS_RESET:
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci		/*
24778c2ecf20Sopenharmony_ci		 * We are going to have the fc class block the rport
24788c2ecf20Sopenharmony_ci		 * while we try to recover so instruct the mid layer
24798c2ecf20Sopenharmony_ci		 * to requeue until the class decides how to handle this.
24808c2ecf20Sopenharmony_ci		 */
24818c2ecf20Sopenharmony_ci		res = DID_TRANSPORT_DISRUPTED << 16;
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, fcport->vha, 0x3057,
24848c2ecf20Sopenharmony_ci		    "Port down status: port-state=0x%x.\n",
24858c2ecf20Sopenharmony_ci		    atomic_read(&fcport->state));
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci		if (atomic_read(&fcport->state) == FCS_ONLINE)
24888c2ecf20Sopenharmony_ci			qla2x00_mark_device_lost(fcport->vha, fcport, 1);
24898c2ecf20Sopenharmony_ci		break;
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci	case CS_ABORTED:
24928c2ecf20Sopenharmony_ci		res = DID_RESET << 16;
24938c2ecf20Sopenharmony_ci		break;
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ci	default:
24968c2ecf20Sopenharmony_ci		res = DID_ERROR << 16;
24978c2ecf20Sopenharmony_ci		break;
24988c2ecf20Sopenharmony_ci	}
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	if (logit)
25018c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, fcport->vha, 0x3058,
25028c2ecf20Sopenharmony_ci		    "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu "
25038c2ecf20Sopenharmony_ci		    "tgt_id: 0x%x lscsi_status: 0x%x cdb=%10phN len=0x%x "
25048c2ecf20Sopenharmony_ci		    "rsp_info=%p resid=0x%x fw_resid=0x%x sense_len=0x%x, "
25058c2ecf20Sopenharmony_ci		    "par_sense_len=0x%x, rsp_info_len=0x%x\n",
25068c2ecf20Sopenharmony_ci		    comp_status, scsi_status, res, vha->host_no,
25078c2ecf20Sopenharmony_ci		    cp->device->id, cp->device->lun, fcport->tgt_id,
25088c2ecf20Sopenharmony_ci		    lscsi_status, cp->cmnd, scsi_bufflen(cp),
25098c2ecf20Sopenharmony_ci		    rsp_info, resid_len, fw_resid_len, sense_len,
25108c2ecf20Sopenharmony_ci		    par_sense_len, rsp_info_len);
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci	if (rsp->status_srb == NULL)
25138c2ecf20Sopenharmony_ci		sp->done(sp, res);
25148c2ecf20Sopenharmony_ci	else
25158c2ecf20Sopenharmony_ci		WARN_ON_ONCE(true);
25168c2ecf20Sopenharmony_ci}
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci/**
25198c2ecf20Sopenharmony_ci * qlafx00_status_cont_entry() - Process a Status Continuations entry.
25208c2ecf20Sopenharmony_ci * @rsp: response queue
25218c2ecf20Sopenharmony_ci * @pkt: Entry pointer
25228c2ecf20Sopenharmony_ci *
25238c2ecf20Sopenharmony_ci * Extended sense data.
25248c2ecf20Sopenharmony_ci */
25258c2ecf20Sopenharmony_cistatic void
25268c2ecf20Sopenharmony_ciqlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
25278c2ecf20Sopenharmony_ci{
25288c2ecf20Sopenharmony_ci	uint8_t	sense_sz = 0;
25298c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = rsp->hw;
25308c2ecf20Sopenharmony_ci	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
25318c2ecf20Sopenharmony_ci	srb_t *sp = rsp->status_srb;
25328c2ecf20Sopenharmony_ci	struct scsi_cmnd *cp;
25338c2ecf20Sopenharmony_ci	uint32_t sense_len;
25348c2ecf20Sopenharmony_ci	uint8_t *sense_ptr;
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci	if (!sp) {
25378c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3037,
25388c2ecf20Sopenharmony_ci		    "no SP, sp = %p\n", sp);
25398c2ecf20Sopenharmony_ci		return;
25408c2ecf20Sopenharmony_ci	}
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_ci	if (!GET_FW_SENSE_LEN(sp)) {
25438c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x304b,
25448c2ecf20Sopenharmony_ci		    "no fw sense data, sp = %p\n", sp);
25458c2ecf20Sopenharmony_ci		return;
25468c2ecf20Sopenharmony_ci	}
25478c2ecf20Sopenharmony_ci	cp = GET_CMD_SP(sp);
25488c2ecf20Sopenharmony_ci	if (cp == NULL) {
25498c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x303b,
25508c2ecf20Sopenharmony_ci		    "cmd is NULL: already returned to OS (sp=%p).\n", sp);
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci		rsp->status_srb = NULL;
25538c2ecf20Sopenharmony_ci		return;
25548c2ecf20Sopenharmony_ci	}
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_ci	if (!GET_CMD_SENSE_LEN(sp)) {
25578c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x304c,
25588c2ecf20Sopenharmony_ci		    "no sense data, sp = %p\n", sp);
25598c2ecf20Sopenharmony_ci	} else {
25608c2ecf20Sopenharmony_ci		sense_len = GET_CMD_SENSE_LEN(sp);
25618c2ecf20Sopenharmony_ci		sense_ptr = GET_CMD_SENSE_PTR(sp);
25628c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x304f,
25638c2ecf20Sopenharmony_ci		    "sp=%p sense_len=0x%x sense_ptr=%p.\n",
25648c2ecf20Sopenharmony_ci		    sp, sense_len, sense_ptr);
25658c2ecf20Sopenharmony_ci
25668c2ecf20Sopenharmony_ci		if (sense_len > sizeof(pkt->data))
25678c2ecf20Sopenharmony_ci			sense_sz = sizeof(pkt->data);
25688c2ecf20Sopenharmony_ci		else
25698c2ecf20Sopenharmony_ci			sense_sz = sense_len;
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci		/* Move sense data. */
25728c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304e,
25738c2ecf20Sopenharmony_ci		    pkt, sizeof(*pkt));
25748c2ecf20Sopenharmony_ci		memcpy(sense_ptr, pkt->data, sense_sz);
25758c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304a,
25768c2ecf20Sopenharmony_ci		    sense_ptr, sense_sz);
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci		sense_len -= sense_sz;
25798c2ecf20Sopenharmony_ci		sense_ptr += sense_sz;
25808c2ecf20Sopenharmony_ci
25818c2ecf20Sopenharmony_ci		SET_CMD_SENSE_PTR(sp, sense_ptr);
25828c2ecf20Sopenharmony_ci		SET_CMD_SENSE_LEN(sp, sense_len);
25838c2ecf20Sopenharmony_ci	}
25848c2ecf20Sopenharmony_ci	sense_len = GET_FW_SENSE_LEN(sp);
25858c2ecf20Sopenharmony_ci	sense_len = (sense_len > sizeof(pkt->data)) ?
25868c2ecf20Sopenharmony_ci	    (sense_len - sizeof(pkt->data)) : 0;
25878c2ecf20Sopenharmony_ci	SET_FW_SENSE_LEN(sp, sense_len);
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ci	/* Place command on done queue. */
25908c2ecf20Sopenharmony_ci	if (sense_len == 0) {
25918c2ecf20Sopenharmony_ci		rsp->status_srb = NULL;
25928c2ecf20Sopenharmony_ci		sp->done(sp, cp->result);
25938c2ecf20Sopenharmony_ci	} else {
25948c2ecf20Sopenharmony_ci		WARN_ON_ONCE(true);
25958c2ecf20Sopenharmony_ci	}
25968c2ecf20Sopenharmony_ci}
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci/**
25998c2ecf20Sopenharmony_ci * qlafx00_multistatus_entry() - Process Multi response queue entries.
26008c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
26018c2ecf20Sopenharmony_ci * @rsp: response queue
26028c2ecf20Sopenharmony_ci * @pkt: received packet
26038c2ecf20Sopenharmony_ci */
26048c2ecf20Sopenharmony_cistatic void
26058c2ecf20Sopenharmony_ciqlafx00_multistatus_entry(struct scsi_qla_host *vha,
26068c2ecf20Sopenharmony_ci	struct rsp_que *rsp, void *pkt)
26078c2ecf20Sopenharmony_ci{
26088c2ecf20Sopenharmony_ci	srb_t		*sp;
26098c2ecf20Sopenharmony_ci	struct multi_sts_entry_fx00 *stsmfx;
26108c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
26118c2ecf20Sopenharmony_ci	uint32_t handle, hindex, handle_count, i;
26128c2ecf20Sopenharmony_ci	uint16_t que;
26138c2ecf20Sopenharmony_ci	struct req_que *req;
26148c2ecf20Sopenharmony_ci	__le32 *handle_ptr;
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_ci	stsmfx = (struct multi_sts_entry_fx00 *) pkt;
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci	handle_count = stsmfx->handle_count;
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	if (handle_count > MAX_HANDLE_COUNT) {
26218c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3035,
26228c2ecf20Sopenharmony_ci		    "Invalid handle count (0x%x).\n", handle_count);
26238c2ecf20Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
26248c2ecf20Sopenharmony_ci		qla2xxx_wake_dpc(vha);
26258c2ecf20Sopenharmony_ci		return;
26268c2ecf20Sopenharmony_ci	}
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_ci	handle_ptr =  &stsmfx->handles[0];
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	for (i = 0; i < handle_count; i++) {
26318c2ecf20Sopenharmony_ci		hindex = le32_to_cpu(*handle_ptr);
26328c2ecf20Sopenharmony_ci		handle = LSW(hindex);
26338c2ecf20Sopenharmony_ci		que = MSW(hindex);
26348c2ecf20Sopenharmony_ci		req = ha->req_q_map[que];
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci		/* Validate handle. */
26378c2ecf20Sopenharmony_ci		if (handle < req->num_outstanding_cmds)
26388c2ecf20Sopenharmony_ci			sp = req->outstanding_cmds[handle];
26398c2ecf20Sopenharmony_ci		else
26408c2ecf20Sopenharmony_ci			sp = NULL;
26418c2ecf20Sopenharmony_ci
26428c2ecf20Sopenharmony_ci		if (sp == NULL) {
26438c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_io, vha, 0x3044,
26448c2ecf20Sopenharmony_ci			    "Invalid status handle (0x%x).\n", handle);
26458c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
26468c2ecf20Sopenharmony_ci			qla2xxx_wake_dpc(vha);
26478c2ecf20Sopenharmony_ci			return;
26488c2ecf20Sopenharmony_ci		}
26498c2ecf20Sopenharmony_ci		qla2x00_process_completed_request(vha, req, handle);
26508c2ecf20Sopenharmony_ci		handle_ptr++;
26518c2ecf20Sopenharmony_ci	}
26528c2ecf20Sopenharmony_ci}
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ci/**
26558c2ecf20Sopenharmony_ci * qlafx00_error_entry() - Process an error entry.
26568c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
26578c2ecf20Sopenharmony_ci * @rsp: response queue
26588c2ecf20Sopenharmony_ci * @pkt: Entry pointer
26598c2ecf20Sopenharmony_ci */
26608c2ecf20Sopenharmony_cistatic void
26618c2ecf20Sopenharmony_ciqlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp,
26628c2ecf20Sopenharmony_ci		    struct sts_entry_fx00 *pkt)
26638c2ecf20Sopenharmony_ci{
26648c2ecf20Sopenharmony_ci	srb_t *sp;
26658c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
26668c2ecf20Sopenharmony_ci	const char func[] = "ERROR-IOCB";
26678c2ecf20Sopenharmony_ci	uint16_t que = 0;
26688c2ecf20Sopenharmony_ci	struct req_que *req = NULL;
26698c2ecf20Sopenharmony_ci	int res = DID_ERROR << 16;
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_ci	req = ha->req_q_map[que];
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
26748c2ecf20Sopenharmony_ci	if (sp) {
26758c2ecf20Sopenharmony_ci		sp->done(sp, res);
26768c2ecf20Sopenharmony_ci		return;
26778c2ecf20Sopenharmony_ci	}
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_ci	set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
26808c2ecf20Sopenharmony_ci	qla2xxx_wake_dpc(vha);
26818c2ecf20Sopenharmony_ci}
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci/**
26848c2ecf20Sopenharmony_ci * qlafx00_process_response_queue() - Process response queue entries.
26858c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
26868c2ecf20Sopenharmony_ci * @rsp: response queue
26878c2ecf20Sopenharmony_ci */
26888c2ecf20Sopenharmony_cistatic void
26898c2ecf20Sopenharmony_ciqlafx00_process_response_queue(struct scsi_qla_host *vha,
26908c2ecf20Sopenharmony_ci	struct rsp_que *rsp)
26918c2ecf20Sopenharmony_ci{
26928c2ecf20Sopenharmony_ci	struct sts_entry_fx00 *pkt;
26938c2ecf20Sopenharmony_ci	response_t *lptr;
26948c2ecf20Sopenharmony_ci	uint16_t lreq_q_in = 0;
26958c2ecf20Sopenharmony_ci	uint16_t lreq_q_out = 0;
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	lreq_q_in = rd_reg_dword(rsp->rsp_q_in);
26988c2ecf20Sopenharmony_ci	lreq_q_out = rsp->ring_index;
26998c2ecf20Sopenharmony_ci
27008c2ecf20Sopenharmony_ci	while (lreq_q_in != lreq_q_out) {
27018c2ecf20Sopenharmony_ci		lptr = rsp->ring_ptr;
27028c2ecf20Sopenharmony_ci		memcpy_fromio(rsp->rsp_pkt, (void __iomem *)lptr,
27038c2ecf20Sopenharmony_ci		    sizeof(rsp->rsp_pkt));
27048c2ecf20Sopenharmony_ci		pkt = (struct sts_entry_fx00 *)rsp->rsp_pkt;
27058c2ecf20Sopenharmony_ci
27068c2ecf20Sopenharmony_ci		rsp->ring_index++;
27078c2ecf20Sopenharmony_ci		lreq_q_out++;
27088c2ecf20Sopenharmony_ci		if (rsp->ring_index == rsp->length) {
27098c2ecf20Sopenharmony_ci			lreq_q_out = 0;
27108c2ecf20Sopenharmony_ci			rsp->ring_index = 0;
27118c2ecf20Sopenharmony_ci			rsp->ring_ptr = rsp->ring;
27128c2ecf20Sopenharmony_ci		} else {
27138c2ecf20Sopenharmony_ci			rsp->ring_ptr++;
27148c2ecf20Sopenharmony_ci		}
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_ci		if (pkt->entry_status != 0 &&
27178c2ecf20Sopenharmony_ci		    pkt->entry_type != IOCTL_IOSB_TYPE_FX00) {
27188c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x507f,
27198c2ecf20Sopenharmony_ci			       "type of error status in response: 0x%x\n",
27208c2ecf20Sopenharmony_ci			       pkt->entry_status);
27218c2ecf20Sopenharmony_ci			qlafx00_error_entry(vha, rsp,
27228c2ecf20Sopenharmony_ci					    (struct sts_entry_fx00 *)pkt);
27238c2ecf20Sopenharmony_ci			continue;
27248c2ecf20Sopenharmony_ci		}
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci		switch (pkt->entry_type) {
27278c2ecf20Sopenharmony_ci		case STATUS_TYPE_FX00:
27288c2ecf20Sopenharmony_ci			qlafx00_status_entry(vha, rsp, pkt);
27298c2ecf20Sopenharmony_ci			break;
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci		case STATUS_CONT_TYPE_FX00:
27328c2ecf20Sopenharmony_ci			qlafx00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
27338c2ecf20Sopenharmony_ci			break;
27348c2ecf20Sopenharmony_ci
27358c2ecf20Sopenharmony_ci		case MULTI_STATUS_TYPE_FX00:
27368c2ecf20Sopenharmony_ci			qlafx00_multistatus_entry(vha, rsp, pkt);
27378c2ecf20Sopenharmony_ci			break;
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_ci		case ABORT_IOCB_TYPE_FX00:
27408c2ecf20Sopenharmony_ci			qlafx00_abort_iocb_entry(vha, rsp->req,
27418c2ecf20Sopenharmony_ci			   (struct abort_iocb_entry_fx00 *)pkt);
27428c2ecf20Sopenharmony_ci			break;
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci		case IOCTL_IOSB_TYPE_FX00:
27458c2ecf20Sopenharmony_ci			qlafx00_ioctl_iosb_entry(vha, rsp->req,
27468c2ecf20Sopenharmony_ci			    (struct ioctl_iocb_entry_fx00 *)pkt);
27478c2ecf20Sopenharmony_ci			break;
27488c2ecf20Sopenharmony_ci		default:
27498c2ecf20Sopenharmony_ci			/* Type Not Supported. */
27508c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5081,
27518c2ecf20Sopenharmony_ci			    "Received unknown response pkt type %x "
27528c2ecf20Sopenharmony_ci			    "entry status=%x.\n",
27538c2ecf20Sopenharmony_ci			    pkt->entry_type, pkt->entry_status);
27548c2ecf20Sopenharmony_ci			break;
27558c2ecf20Sopenharmony_ci		}
27568c2ecf20Sopenharmony_ci	}
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci	/* Adjust ring index */
27598c2ecf20Sopenharmony_ci	wrt_reg_dword(rsp->rsp_q_out, rsp->ring_index);
27608c2ecf20Sopenharmony_ci}
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci/**
27638c2ecf20Sopenharmony_ci * qlafx00_async_event() - Process aynchronous events.
27648c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
27658c2ecf20Sopenharmony_ci */
27668c2ecf20Sopenharmony_cistatic void
27678c2ecf20Sopenharmony_ciqlafx00_async_event(scsi_qla_host_t *vha)
27688c2ecf20Sopenharmony_ci{
27698c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
27708c2ecf20Sopenharmony_ci	struct device_reg_fx00 __iomem *reg;
27718c2ecf20Sopenharmony_ci	int data_size = 1;
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	reg = &ha->iobase->ispfx00;
27748c2ecf20Sopenharmony_ci	/* Setup to process RIO completion. */
27758c2ecf20Sopenharmony_ci	switch (ha->aenmb[0]) {
27768c2ecf20Sopenharmony_ci	case QLAFX00_MBA_SYSTEM_ERR:		/* System Error */
27778c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5079,
27788c2ecf20Sopenharmony_ci		    "ISP System Error - mbx1=%x\n", ha->aenmb[0]);
27798c2ecf20Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
27808c2ecf20Sopenharmony_ci		break;
27818c2ecf20Sopenharmony_ci
27828c2ecf20Sopenharmony_ci	case QLAFX00_MBA_SHUTDOWN_RQSTD:	/* Shutdown requested */
27838c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5076,
27848c2ecf20Sopenharmony_ci		    "Asynchronous FW shutdown requested.\n");
27858c2ecf20Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
27868c2ecf20Sopenharmony_ci		qla2xxx_wake_dpc(vha);
27878c2ecf20Sopenharmony_ci		break;
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci	case QLAFX00_MBA_PORT_UPDATE:		/* Port database update */
27908c2ecf20Sopenharmony_ci		ha->aenmb[1] = rd_reg_dword(&reg->aenmailbox1);
27918c2ecf20Sopenharmony_ci		ha->aenmb[2] = rd_reg_dword(&reg->aenmailbox2);
27928c2ecf20Sopenharmony_ci		ha->aenmb[3] = rd_reg_dword(&reg->aenmailbox3);
27938c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5077,
27948c2ecf20Sopenharmony_ci		    "Asynchronous port Update received "
27958c2ecf20Sopenharmony_ci		    "aenmb[0]: %x, aenmb[1]: %x, aenmb[2]: %x, aenmb[3]: %x\n",
27968c2ecf20Sopenharmony_ci		    ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3]);
27978c2ecf20Sopenharmony_ci		data_size = 4;
27988c2ecf20Sopenharmony_ci		break;
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_ci	case QLAFX00_MBA_TEMP_OVER:	/* Over temperature event */
28018c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x5085,
28028c2ecf20Sopenharmony_ci		    "Asynchronous over temperature event received "
28038c2ecf20Sopenharmony_ci		    "aenmb[0]: %x\n",
28048c2ecf20Sopenharmony_ci		    ha->aenmb[0]);
28058c2ecf20Sopenharmony_ci		break;
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_ci	case QLAFX00_MBA_TEMP_NORM:	/* Normal temperature event */
28088c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x5086,
28098c2ecf20Sopenharmony_ci		    "Asynchronous normal temperature event received "
28108c2ecf20Sopenharmony_ci		    "aenmb[0]: %x\n",
28118c2ecf20Sopenharmony_ci		    ha->aenmb[0]);
28128c2ecf20Sopenharmony_ci		break;
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci	case QLAFX00_MBA_TEMP_CRIT:	/* Critical temperature event */
28158c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x5083,
28168c2ecf20Sopenharmony_ci		    "Asynchronous critical temperature event received "
28178c2ecf20Sopenharmony_ci		    "aenmb[0]: %x\n",
28188c2ecf20Sopenharmony_ci		ha->aenmb[0]);
28198c2ecf20Sopenharmony_ci		break;
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_ci	default:
28228c2ecf20Sopenharmony_ci		ha->aenmb[1] = rd_reg_dword(&reg->aenmailbox1);
28238c2ecf20Sopenharmony_ci		ha->aenmb[2] = rd_reg_dword(&reg->aenmailbox2);
28248c2ecf20Sopenharmony_ci		ha->aenmb[3] = rd_reg_dword(&reg->aenmailbox3);
28258c2ecf20Sopenharmony_ci		ha->aenmb[4] = rd_reg_dword(&reg->aenmailbox4);
28268c2ecf20Sopenharmony_ci		ha->aenmb[5] = rd_reg_dword(&reg->aenmailbox5);
28278c2ecf20Sopenharmony_ci		ha->aenmb[6] = rd_reg_dword(&reg->aenmailbox6);
28288c2ecf20Sopenharmony_ci		ha->aenmb[7] = rd_reg_dword(&reg->aenmailbox7);
28298c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5078,
28308c2ecf20Sopenharmony_ci		    "AEN:%04x %04x %04x %04x :%04x %04x %04x %04x\n",
28318c2ecf20Sopenharmony_ci		    ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3],
28328c2ecf20Sopenharmony_ci		    ha->aenmb[4], ha->aenmb[5], ha->aenmb[6], ha->aenmb[7]);
28338c2ecf20Sopenharmony_ci		break;
28348c2ecf20Sopenharmony_ci	}
28358c2ecf20Sopenharmony_ci	qlafx00_post_aenfx_work(vha, ha->aenmb[0],
28368c2ecf20Sopenharmony_ci	    (uint32_t *)ha->aenmb, data_size);
28378c2ecf20Sopenharmony_ci}
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_ci/**
28408c2ecf20Sopenharmony_ci * qlafx00x_mbx_completion() - Process mailbox command completions.
28418c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
28428c2ecf20Sopenharmony_ci * @mb0: value to be written into mailbox register 0
28438c2ecf20Sopenharmony_ci */
28448c2ecf20Sopenharmony_cistatic void
28458c2ecf20Sopenharmony_ciqlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0)
28468c2ecf20Sopenharmony_ci{
28478c2ecf20Sopenharmony_ci	uint16_t	cnt;
28488c2ecf20Sopenharmony_ci	__le32 __iomem *wptr;
28498c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
28508c2ecf20Sopenharmony_ci	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
28518c2ecf20Sopenharmony_ci
28528c2ecf20Sopenharmony_ci	if (!ha->mcp32)
28538c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x507e, "MBX pointer ERROR.\n");
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_ci	/* Load return mailbox registers. */
28568c2ecf20Sopenharmony_ci	ha->flags.mbox_int = 1;
28578c2ecf20Sopenharmony_ci	ha->mailbox_out32[0] = mb0;
28588c2ecf20Sopenharmony_ci	wptr = &reg->mailbox17;
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
28618c2ecf20Sopenharmony_ci		ha->mailbox_out32[cnt] = rd_reg_dword(wptr);
28628c2ecf20Sopenharmony_ci		wptr++;
28638c2ecf20Sopenharmony_ci	}
28648c2ecf20Sopenharmony_ci}
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci/**
28678c2ecf20Sopenharmony_ci * qlafx00_intr_handler() - Process interrupts for the ISPFX00.
28688c2ecf20Sopenharmony_ci * @irq: interrupt number
28698c2ecf20Sopenharmony_ci * @dev_id: SCSI driver HA context
28708c2ecf20Sopenharmony_ci *
28718c2ecf20Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt.
28728c2ecf20Sopenharmony_ci *
28738c2ecf20Sopenharmony_ci * Returns handled flag.
28748c2ecf20Sopenharmony_ci */
28758c2ecf20Sopenharmony_ciirqreturn_t
28768c2ecf20Sopenharmony_ciqlafx00_intr_handler(int irq, void *dev_id)
28778c2ecf20Sopenharmony_ci{
28788c2ecf20Sopenharmony_ci	scsi_qla_host_t	*vha;
28798c2ecf20Sopenharmony_ci	struct qla_hw_data *ha;
28808c2ecf20Sopenharmony_ci	struct device_reg_fx00 __iomem *reg;
28818c2ecf20Sopenharmony_ci	int		status;
28828c2ecf20Sopenharmony_ci	unsigned long	iter;
28838c2ecf20Sopenharmony_ci	uint32_t	stat;
28848c2ecf20Sopenharmony_ci	uint32_t	mb[8];
28858c2ecf20Sopenharmony_ci	struct rsp_que *rsp;
28868c2ecf20Sopenharmony_ci	unsigned long	flags;
28878c2ecf20Sopenharmony_ci	uint32_t clr_intr = 0;
28888c2ecf20Sopenharmony_ci	uint32_t intr_stat = 0;
28898c2ecf20Sopenharmony_ci
28908c2ecf20Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
28918c2ecf20Sopenharmony_ci	if (!rsp) {
28928c2ecf20Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x507d,
28938c2ecf20Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
28948c2ecf20Sopenharmony_ci		return IRQ_NONE;
28958c2ecf20Sopenharmony_ci	}
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_ci	ha = rsp->hw;
28988c2ecf20Sopenharmony_ci	reg = &ha->iobase->ispfx00;
28998c2ecf20Sopenharmony_ci	status = 0;
29008c2ecf20Sopenharmony_ci
29018c2ecf20Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
29028c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
29038c2ecf20Sopenharmony_ci
29048c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
29058c2ecf20Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
29068c2ecf20Sopenharmony_ci	for (iter = 50; iter--; clr_intr = 0) {
29078c2ecf20Sopenharmony_ci		stat = QLAFX00_RD_INTR_REG(ha);
29088c2ecf20Sopenharmony_ci		if (qla2x00_check_reg32_for_disconnect(vha, stat))
29098c2ecf20Sopenharmony_ci			break;
29108c2ecf20Sopenharmony_ci		intr_stat = stat & QLAFX00_HST_INT_STS_BITS;
29118c2ecf20Sopenharmony_ci		if (!intr_stat)
29128c2ecf20Sopenharmony_ci			break;
29138c2ecf20Sopenharmony_ci
29148c2ecf20Sopenharmony_ci		if (stat & QLAFX00_INTR_MB_CMPLT) {
29158c2ecf20Sopenharmony_ci			mb[0] = rd_reg_dword(&reg->mailbox16);
29168c2ecf20Sopenharmony_ci			qlafx00_mbx_completion(vha, mb[0]);
29178c2ecf20Sopenharmony_ci			status |= MBX_INTERRUPT;
29188c2ecf20Sopenharmony_ci			clr_intr |= QLAFX00_INTR_MB_CMPLT;
29198c2ecf20Sopenharmony_ci		}
29208c2ecf20Sopenharmony_ci		if (intr_stat & QLAFX00_INTR_ASYNC_CMPLT) {
29218c2ecf20Sopenharmony_ci			ha->aenmb[0] = rd_reg_dword(&reg->aenmailbox0);
29228c2ecf20Sopenharmony_ci			qlafx00_async_event(vha);
29238c2ecf20Sopenharmony_ci			clr_intr |= QLAFX00_INTR_ASYNC_CMPLT;
29248c2ecf20Sopenharmony_ci		}
29258c2ecf20Sopenharmony_ci		if (intr_stat & QLAFX00_INTR_RSP_CMPLT) {
29268c2ecf20Sopenharmony_ci			qlafx00_process_response_queue(vha, rsp);
29278c2ecf20Sopenharmony_ci			clr_intr |= QLAFX00_INTR_RSP_CMPLT;
29288c2ecf20Sopenharmony_ci		}
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ci		QLAFX00_CLR_INTR_REG(ha, clr_intr);
29318c2ecf20Sopenharmony_ci		QLAFX00_RD_INTR_REG(ha);
29328c2ecf20Sopenharmony_ci	}
29338c2ecf20Sopenharmony_ci
29348c2ecf20Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
29358c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
29368c2ecf20Sopenharmony_ci
29378c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
29388c2ecf20Sopenharmony_ci}
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_ci/** QLAFX00 specific IOCB implementation functions */
29418c2ecf20Sopenharmony_ci
29428c2ecf20Sopenharmony_cistatic inline cont_a64_entry_t *
29438c2ecf20Sopenharmony_ciqlafx00_prep_cont_type1_iocb(struct req_que *req,
29448c2ecf20Sopenharmony_ci			     cont_a64_entry_t *lcont_pkt)
29458c2ecf20Sopenharmony_ci{
29468c2ecf20Sopenharmony_ci	cont_a64_entry_t *cont_pkt;
29478c2ecf20Sopenharmony_ci
29488c2ecf20Sopenharmony_ci	/* Adjust ring index. */
29498c2ecf20Sopenharmony_ci	req->ring_index++;
29508c2ecf20Sopenharmony_ci	if (req->ring_index == req->length) {
29518c2ecf20Sopenharmony_ci		req->ring_index = 0;
29528c2ecf20Sopenharmony_ci		req->ring_ptr = req->ring;
29538c2ecf20Sopenharmony_ci	} else {
29548c2ecf20Sopenharmony_ci		req->ring_ptr++;
29558c2ecf20Sopenharmony_ci	}
29568c2ecf20Sopenharmony_ci
29578c2ecf20Sopenharmony_ci	cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
29588c2ecf20Sopenharmony_ci
29598c2ecf20Sopenharmony_ci	/* Load packet defaults. */
29608c2ecf20Sopenharmony_ci	lcont_pkt->entry_type = CONTINUE_A64_TYPE_FX00;
29618c2ecf20Sopenharmony_ci
29628c2ecf20Sopenharmony_ci	return cont_pkt;
29638c2ecf20Sopenharmony_ci}
29648c2ecf20Sopenharmony_ci
29658c2ecf20Sopenharmony_cistatic inline void
29668c2ecf20Sopenharmony_ciqlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
29678c2ecf20Sopenharmony_ci			 uint16_t tot_dsds, struct cmd_type_7_fx00 *lcmd_pkt)
29688c2ecf20Sopenharmony_ci{
29698c2ecf20Sopenharmony_ci	uint16_t	avail_dsds;
29708c2ecf20Sopenharmony_ci	struct dsd64	*cur_dsd;
29718c2ecf20Sopenharmony_ci	scsi_qla_host_t	*vha;
29728c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd;
29738c2ecf20Sopenharmony_ci	struct scatterlist *sg;
29748c2ecf20Sopenharmony_ci	int i, cont;
29758c2ecf20Sopenharmony_ci	struct req_que *req;
29768c2ecf20Sopenharmony_ci	cont_a64_entry_t lcont_pkt;
29778c2ecf20Sopenharmony_ci	cont_a64_entry_t *cont_pkt;
29788c2ecf20Sopenharmony_ci
29798c2ecf20Sopenharmony_ci	vha = sp->vha;
29808c2ecf20Sopenharmony_ci	req = vha->req;
29818c2ecf20Sopenharmony_ci
29828c2ecf20Sopenharmony_ci	cmd = GET_CMD_SP(sp);
29838c2ecf20Sopenharmony_ci	cont = 0;
29848c2ecf20Sopenharmony_ci	cont_pkt = NULL;
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci	/* Update entry type to indicate Command Type 3 IOCB */
29878c2ecf20Sopenharmony_ci	lcmd_pkt->entry_type = FX00_COMMAND_TYPE_7;
29888c2ecf20Sopenharmony_ci
29898c2ecf20Sopenharmony_ci	/* No data transfer */
29908c2ecf20Sopenharmony_ci	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
29918c2ecf20Sopenharmony_ci		lcmd_pkt->byte_count = cpu_to_le32(0);
29928c2ecf20Sopenharmony_ci		return;
29938c2ecf20Sopenharmony_ci	}
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_ci	/* Set transfer direction */
29968c2ecf20Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
29978c2ecf20Sopenharmony_ci		lcmd_pkt->cntrl_flags = TMF_WRITE_DATA;
29988c2ecf20Sopenharmony_ci		vha->qla_stats.output_bytes += scsi_bufflen(cmd);
29998c2ecf20Sopenharmony_ci	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
30008c2ecf20Sopenharmony_ci		lcmd_pkt->cntrl_flags = TMF_READ_DATA;
30018c2ecf20Sopenharmony_ci		vha->qla_stats.input_bytes += scsi_bufflen(cmd);
30028c2ecf20Sopenharmony_ci	}
30038c2ecf20Sopenharmony_ci
30048c2ecf20Sopenharmony_ci	/* One DSD is available in the Command Type 3 IOCB */
30058c2ecf20Sopenharmony_ci	avail_dsds = 1;
30068c2ecf20Sopenharmony_ci	cur_dsd = &lcmd_pkt->dsd;
30078c2ecf20Sopenharmony_ci
30088c2ecf20Sopenharmony_ci	/* Load data segments */
30098c2ecf20Sopenharmony_ci	scsi_for_each_sg(cmd, sg, tot_dsds, i) {
30108c2ecf20Sopenharmony_ci		/* Allocate additional continuation packets? */
30118c2ecf20Sopenharmony_ci		if (avail_dsds == 0) {
30128c2ecf20Sopenharmony_ci			/*
30138c2ecf20Sopenharmony_ci			 * Five DSDs are available in the Continuation
30148c2ecf20Sopenharmony_ci			 * Type 1 IOCB.
30158c2ecf20Sopenharmony_ci			 */
30168c2ecf20Sopenharmony_ci			memset(&lcont_pkt, 0, REQUEST_ENTRY_SIZE);
30178c2ecf20Sopenharmony_ci			cont_pkt =
30188c2ecf20Sopenharmony_ci			    qlafx00_prep_cont_type1_iocb(req, &lcont_pkt);
30198c2ecf20Sopenharmony_ci			cur_dsd = lcont_pkt.dsd;
30208c2ecf20Sopenharmony_ci			avail_dsds = 5;
30218c2ecf20Sopenharmony_ci			cont = 1;
30228c2ecf20Sopenharmony_ci		}
30238c2ecf20Sopenharmony_ci
30248c2ecf20Sopenharmony_ci		append_dsd64(&cur_dsd, sg);
30258c2ecf20Sopenharmony_ci		avail_dsds--;
30268c2ecf20Sopenharmony_ci		if (avail_dsds == 0 && cont == 1) {
30278c2ecf20Sopenharmony_ci			cont = 0;
30288c2ecf20Sopenharmony_ci			memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt,
30298c2ecf20Sopenharmony_ci			    sizeof(lcont_pkt));
30308c2ecf20Sopenharmony_ci		}
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_ci	}
30338c2ecf20Sopenharmony_ci	if (avail_dsds != 0 && cont == 1) {
30348c2ecf20Sopenharmony_ci		memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt,
30358c2ecf20Sopenharmony_ci		    sizeof(lcont_pkt));
30368c2ecf20Sopenharmony_ci	}
30378c2ecf20Sopenharmony_ci}
30388c2ecf20Sopenharmony_ci
30398c2ecf20Sopenharmony_ci/**
30408c2ecf20Sopenharmony_ci * qlafx00_start_scsi() - Send a SCSI command to the ISP
30418c2ecf20Sopenharmony_ci * @sp: command to send to the ISP
30428c2ecf20Sopenharmony_ci *
30438c2ecf20Sopenharmony_ci * Returns non-zero if a failure occurred, else zero.
30448c2ecf20Sopenharmony_ci */
30458c2ecf20Sopenharmony_ciint
30468c2ecf20Sopenharmony_ciqlafx00_start_scsi(srb_t *sp)
30478c2ecf20Sopenharmony_ci{
30488c2ecf20Sopenharmony_ci	int		nseg;
30498c2ecf20Sopenharmony_ci	unsigned long   flags;
30508c2ecf20Sopenharmony_ci	uint32_t	handle;
30518c2ecf20Sopenharmony_ci	uint16_t	cnt;
30528c2ecf20Sopenharmony_ci	uint16_t	req_cnt;
30538c2ecf20Sopenharmony_ci	uint16_t	tot_dsds;
30548c2ecf20Sopenharmony_ci	struct req_que *req = NULL;
30558c2ecf20Sopenharmony_ci	struct rsp_que *rsp = NULL;
30568c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
30578c2ecf20Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
30588c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
30598c2ecf20Sopenharmony_ci	struct cmd_type_7_fx00 *cmd_pkt;
30608c2ecf20Sopenharmony_ci	struct cmd_type_7_fx00 lcmd_pkt;
30618c2ecf20Sopenharmony_ci	struct scsi_lun llun;
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_ci	/* Setup device pointers. */
30648c2ecf20Sopenharmony_ci	rsp = ha->rsp_q_map[0];
30658c2ecf20Sopenharmony_ci	req = vha->req;
30668c2ecf20Sopenharmony_ci
30678c2ecf20Sopenharmony_ci	/* So we know we haven't pci_map'ed anything yet */
30688c2ecf20Sopenharmony_ci	tot_dsds = 0;
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci	/* Acquire ring specific lock */
30718c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci	handle = qla2xxx_get_next_handle(req);
30748c2ecf20Sopenharmony_ci	if (handle == 0)
30758c2ecf20Sopenharmony_ci		goto queuing_error;
30768c2ecf20Sopenharmony_ci
30778c2ecf20Sopenharmony_ci	/* Map the sg table so we have an accurate count of sg entries needed */
30788c2ecf20Sopenharmony_ci	if (scsi_sg_count(cmd)) {
30798c2ecf20Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
30808c2ecf20Sopenharmony_ci		    scsi_sg_count(cmd), cmd->sc_data_direction);
30818c2ecf20Sopenharmony_ci		if (unlikely(!nseg))
30828c2ecf20Sopenharmony_ci			goto queuing_error;
30838c2ecf20Sopenharmony_ci	} else
30848c2ecf20Sopenharmony_ci		nseg = 0;
30858c2ecf20Sopenharmony_ci
30868c2ecf20Sopenharmony_ci	tot_dsds = nseg;
30878c2ecf20Sopenharmony_ci	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
30888c2ecf20Sopenharmony_ci	if (req->cnt < (req_cnt + 2)) {
30898c2ecf20Sopenharmony_ci		cnt = rd_reg_dword_relaxed(req->req_q_out);
30908c2ecf20Sopenharmony_ci
30918c2ecf20Sopenharmony_ci		if (req->ring_index < cnt)
30928c2ecf20Sopenharmony_ci			req->cnt = cnt - req->ring_index;
30938c2ecf20Sopenharmony_ci		else
30948c2ecf20Sopenharmony_ci			req->cnt = req->length -
30958c2ecf20Sopenharmony_ci				(req->ring_index - cnt);
30968c2ecf20Sopenharmony_ci		if (req->cnt < (req_cnt + 2))
30978c2ecf20Sopenharmony_ci			goto queuing_error;
30988c2ecf20Sopenharmony_ci	}
30998c2ecf20Sopenharmony_ci
31008c2ecf20Sopenharmony_ci	/* Build command packet. */
31018c2ecf20Sopenharmony_ci	req->current_outstanding_cmd = handle;
31028c2ecf20Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
31038c2ecf20Sopenharmony_ci	sp->handle = handle;
31048c2ecf20Sopenharmony_ci	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
31058c2ecf20Sopenharmony_ci	req->cnt -= req_cnt;
31068c2ecf20Sopenharmony_ci
31078c2ecf20Sopenharmony_ci	cmd_pkt = (struct cmd_type_7_fx00 *)req->ring_ptr;
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci	memset(&lcmd_pkt, 0, REQUEST_ENTRY_SIZE);
31108c2ecf20Sopenharmony_ci
31118c2ecf20Sopenharmony_ci	lcmd_pkt.handle = make_handle(req->id, sp->handle);
31128c2ecf20Sopenharmony_ci	lcmd_pkt.reserved_0 = 0;
31138c2ecf20Sopenharmony_ci	lcmd_pkt.port_path_ctrl = 0;
31148c2ecf20Sopenharmony_ci	lcmd_pkt.reserved_1 = 0;
31158c2ecf20Sopenharmony_ci	lcmd_pkt.dseg_count = cpu_to_le16(tot_dsds);
31168c2ecf20Sopenharmony_ci	lcmd_pkt.tgt_idx = cpu_to_le16(sp->fcport->tgt_id);
31178c2ecf20Sopenharmony_ci
31188c2ecf20Sopenharmony_ci	int_to_scsilun(cmd->device->lun, &llun);
31198c2ecf20Sopenharmony_ci	host_to_adap((uint8_t *)&llun, (uint8_t *)&lcmd_pkt.lun,
31208c2ecf20Sopenharmony_ci	    sizeof(lcmd_pkt.lun));
31218c2ecf20Sopenharmony_ci
31228c2ecf20Sopenharmony_ci	/* Load SCSI command packet. */
31238c2ecf20Sopenharmony_ci	host_to_adap(cmd->cmnd, lcmd_pkt.fcp_cdb, sizeof(lcmd_pkt.fcp_cdb));
31248c2ecf20Sopenharmony_ci	lcmd_pkt.byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_ci	/* Build IOCB segments */
31278c2ecf20Sopenharmony_ci	qlafx00_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, &lcmd_pkt);
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	/* Set total data segment count. */
31308c2ecf20Sopenharmony_ci	lcmd_pkt.entry_count = (uint8_t)req_cnt;
31318c2ecf20Sopenharmony_ci
31328c2ecf20Sopenharmony_ci	/* Specify response queue number where completion should happen */
31338c2ecf20Sopenharmony_ci	lcmd_pkt.entry_status = (uint8_t) rsp->id;
31348c2ecf20Sopenharmony_ci
31358c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302e,
31368c2ecf20Sopenharmony_ci	    cmd->cmnd, cmd->cmd_len);
31378c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3032,
31388c2ecf20Sopenharmony_ci	    &lcmd_pkt, sizeof(lcmd_pkt));
31398c2ecf20Sopenharmony_ci
31408c2ecf20Sopenharmony_ci	memcpy_toio((void __iomem *)cmd_pkt, &lcmd_pkt, REQUEST_ENTRY_SIZE);
31418c2ecf20Sopenharmony_ci	wmb();
31428c2ecf20Sopenharmony_ci
31438c2ecf20Sopenharmony_ci	/* Adjust ring index. */
31448c2ecf20Sopenharmony_ci	req->ring_index++;
31458c2ecf20Sopenharmony_ci	if (req->ring_index == req->length) {
31468c2ecf20Sopenharmony_ci		req->ring_index = 0;
31478c2ecf20Sopenharmony_ci		req->ring_ptr = req->ring;
31488c2ecf20Sopenharmony_ci	} else
31498c2ecf20Sopenharmony_ci		req->ring_ptr++;
31508c2ecf20Sopenharmony_ci
31518c2ecf20Sopenharmony_ci	sp->flags |= SRB_DMA_VALID;
31528c2ecf20Sopenharmony_ci
31538c2ecf20Sopenharmony_ci	/* Set chip new ring index. */
31548c2ecf20Sopenharmony_ci	wrt_reg_dword(req->req_q_in, req->ring_index);
31558c2ecf20Sopenharmony_ci	QLAFX00_SET_HST_INTR(ha, ha->rqstq_intr_code);
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
31588c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
31598c2ecf20Sopenharmony_ci
31608c2ecf20Sopenharmony_ciqueuing_error:
31618c2ecf20Sopenharmony_ci	if (tot_dsds)
31628c2ecf20Sopenharmony_ci		scsi_dma_unmap(cmd);
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
31658c2ecf20Sopenharmony_ci
31668c2ecf20Sopenharmony_ci	return QLA_FUNCTION_FAILED;
31678c2ecf20Sopenharmony_ci}
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_civoid
31708c2ecf20Sopenharmony_ciqlafx00_tm_iocb(srb_t *sp, struct tsk_mgmt_entry_fx00 *ptm_iocb)
31718c2ecf20Sopenharmony_ci{
31728c2ecf20Sopenharmony_ci	struct srb_iocb *fxio = &sp->u.iocb_cmd;
31738c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = sp->vha;
31748c2ecf20Sopenharmony_ci	struct req_que *req = vha->req;
31758c2ecf20Sopenharmony_ci	struct tsk_mgmt_entry_fx00 tm_iocb;
31768c2ecf20Sopenharmony_ci	struct scsi_lun llun;
31778c2ecf20Sopenharmony_ci
31788c2ecf20Sopenharmony_ci	memset(&tm_iocb, 0, sizeof(struct tsk_mgmt_entry_fx00));
31798c2ecf20Sopenharmony_ci	tm_iocb.entry_type = TSK_MGMT_IOCB_TYPE_FX00;
31808c2ecf20Sopenharmony_ci	tm_iocb.entry_count = 1;
31818c2ecf20Sopenharmony_ci	tm_iocb.handle = make_handle(req->id, sp->handle);
31828c2ecf20Sopenharmony_ci	tm_iocb.reserved_0 = 0;
31838c2ecf20Sopenharmony_ci	tm_iocb.tgt_id = cpu_to_le16(sp->fcport->tgt_id);
31848c2ecf20Sopenharmony_ci	tm_iocb.control_flags = cpu_to_le32(fxio->u.tmf.flags);
31858c2ecf20Sopenharmony_ci	if (tm_iocb.control_flags == cpu_to_le32((uint32_t)TCF_LUN_RESET)) {
31868c2ecf20Sopenharmony_ci		int_to_scsilun(fxio->u.tmf.lun, &llun);
31878c2ecf20Sopenharmony_ci		host_to_adap((uint8_t *)&llun, (uint8_t *)&tm_iocb.lun,
31888c2ecf20Sopenharmony_ci		    sizeof(struct scsi_lun));
31898c2ecf20Sopenharmony_ci	}
31908c2ecf20Sopenharmony_ci
31918c2ecf20Sopenharmony_ci	memcpy(ptm_iocb, &tm_iocb,
31928c2ecf20Sopenharmony_ci	    sizeof(struct tsk_mgmt_entry_fx00));
31938c2ecf20Sopenharmony_ci	wmb();
31948c2ecf20Sopenharmony_ci}
31958c2ecf20Sopenharmony_ci
31968c2ecf20Sopenharmony_civoid
31978c2ecf20Sopenharmony_ciqlafx00_abort_iocb(srb_t *sp, struct abort_iocb_entry_fx00 *pabt_iocb)
31988c2ecf20Sopenharmony_ci{
31998c2ecf20Sopenharmony_ci	struct srb_iocb *fxio = &sp->u.iocb_cmd;
32008c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = sp->vha;
32018c2ecf20Sopenharmony_ci	struct req_que *req = vha->req;
32028c2ecf20Sopenharmony_ci	struct abort_iocb_entry_fx00 abt_iocb;
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci	memset(&abt_iocb, 0, sizeof(struct abort_iocb_entry_fx00));
32058c2ecf20Sopenharmony_ci	abt_iocb.entry_type = ABORT_IOCB_TYPE_FX00;
32068c2ecf20Sopenharmony_ci	abt_iocb.entry_count = 1;
32078c2ecf20Sopenharmony_ci	abt_iocb.handle = make_handle(req->id, sp->handle);
32088c2ecf20Sopenharmony_ci	abt_iocb.abort_handle = make_handle(req->id, fxio->u.abt.cmd_hndl);
32098c2ecf20Sopenharmony_ci	abt_iocb.tgt_id_sts = cpu_to_le16(sp->fcport->tgt_id);
32108c2ecf20Sopenharmony_ci	abt_iocb.req_que_no = cpu_to_le16(req->id);
32118c2ecf20Sopenharmony_ci
32128c2ecf20Sopenharmony_ci	memcpy(pabt_iocb, &abt_iocb,
32138c2ecf20Sopenharmony_ci	    sizeof(struct abort_iocb_entry_fx00));
32148c2ecf20Sopenharmony_ci	wmb();
32158c2ecf20Sopenharmony_ci}
32168c2ecf20Sopenharmony_ci
32178c2ecf20Sopenharmony_civoid
32188c2ecf20Sopenharmony_ciqlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
32198c2ecf20Sopenharmony_ci{
32208c2ecf20Sopenharmony_ci	struct srb_iocb *fxio = &sp->u.iocb_cmd;
32218c2ecf20Sopenharmony_ci	struct qla_mt_iocb_rqst_fx00 *piocb_rqst;
32228c2ecf20Sopenharmony_ci	struct bsg_job *bsg_job;
32238c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request;
32248c2ecf20Sopenharmony_ci	struct fxdisc_entry_fx00 fx_iocb;
32258c2ecf20Sopenharmony_ci	uint8_t entry_cnt = 1;
32268c2ecf20Sopenharmony_ci
32278c2ecf20Sopenharmony_ci	memset(&fx_iocb, 0, sizeof(struct fxdisc_entry_fx00));
32288c2ecf20Sopenharmony_ci	fx_iocb.entry_type = FX00_IOCB_TYPE;
32298c2ecf20Sopenharmony_ci	fx_iocb.handle = sp->handle;
32308c2ecf20Sopenharmony_ci	fx_iocb.entry_count = entry_cnt;
32318c2ecf20Sopenharmony_ci
32328c2ecf20Sopenharmony_ci	if (sp->type == SRB_FXIOCB_DCMD) {
32338c2ecf20Sopenharmony_ci		fx_iocb.func_num =
32348c2ecf20Sopenharmony_ci		    sp->u.iocb_cmd.u.fxiocb.req_func_type;
32358c2ecf20Sopenharmony_ci		fx_iocb.adapid = fxio->u.fxiocb.adapter_id;
32368c2ecf20Sopenharmony_ci		fx_iocb.adapid_hi = fxio->u.fxiocb.adapter_id_hi;
32378c2ecf20Sopenharmony_ci		fx_iocb.reserved_0 = fxio->u.fxiocb.reserved_0;
32388c2ecf20Sopenharmony_ci		fx_iocb.reserved_1 = fxio->u.fxiocb.reserved_1;
32398c2ecf20Sopenharmony_ci		fx_iocb.dataword_extra = fxio->u.fxiocb.req_data_extra;
32408c2ecf20Sopenharmony_ci
32418c2ecf20Sopenharmony_ci		if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) {
32428c2ecf20Sopenharmony_ci			fx_iocb.req_dsdcnt = cpu_to_le16(1);
32438c2ecf20Sopenharmony_ci			fx_iocb.req_xfrcnt =
32448c2ecf20Sopenharmony_ci			    cpu_to_le16(fxio->u.fxiocb.req_len);
32458c2ecf20Sopenharmony_ci			put_unaligned_le64(fxio->u.fxiocb.req_dma_handle,
32468c2ecf20Sopenharmony_ci					   &fx_iocb.dseg_rq.address);
32478c2ecf20Sopenharmony_ci			fx_iocb.dseg_rq.length =
32488c2ecf20Sopenharmony_ci			    cpu_to_le32(fxio->u.fxiocb.req_len);
32498c2ecf20Sopenharmony_ci		}
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_ci		if (fxio->u.fxiocb.flags & SRB_FXDISC_RESP_DMA_VALID) {
32528c2ecf20Sopenharmony_ci			fx_iocb.rsp_dsdcnt = cpu_to_le16(1);
32538c2ecf20Sopenharmony_ci			fx_iocb.rsp_xfrcnt =
32548c2ecf20Sopenharmony_ci			    cpu_to_le16(fxio->u.fxiocb.rsp_len);
32558c2ecf20Sopenharmony_ci			put_unaligned_le64(fxio->u.fxiocb.rsp_dma_handle,
32568c2ecf20Sopenharmony_ci					   &fx_iocb.dseg_rsp.address);
32578c2ecf20Sopenharmony_ci			fx_iocb.dseg_rsp.length =
32588c2ecf20Sopenharmony_ci			    cpu_to_le32(fxio->u.fxiocb.rsp_len);
32598c2ecf20Sopenharmony_ci		}
32608c2ecf20Sopenharmony_ci
32618c2ecf20Sopenharmony_ci		if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DWRD_VALID) {
32628c2ecf20Sopenharmony_ci			fx_iocb.dataword = fxio->u.fxiocb.req_data;
32638c2ecf20Sopenharmony_ci		}
32648c2ecf20Sopenharmony_ci		fx_iocb.flags = fxio->u.fxiocb.flags;
32658c2ecf20Sopenharmony_ci	} else {
32668c2ecf20Sopenharmony_ci		struct scatterlist *sg;
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci		bsg_job = sp->u.bsg_job;
32698c2ecf20Sopenharmony_ci		bsg_request = bsg_job->request;
32708c2ecf20Sopenharmony_ci		piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
32718c2ecf20Sopenharmony_ci			&bsg_request->rqst_data.h_vendor.vendor_cmd[1];
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci		fx_iocb.func_num = piocb_rqst->func_type;
32748c2ecf20Sopenharmony_ci		fx_iocb.adapid = piocb_rqst->adapid;
32758c2ecf20Sopenharmony_ci		fx_iocb.adapid_hi = piocb_rqst->adapid_hi;
32768c2ecf20Sopenharmony_ci		fx_iocb.reserved_0 = piocb_rqst->reserved_0;
32778c2ecf20Sopenharmony_ci		fx_iocb.reserved_1 = piocb_rqst->reserved_1;
32788c2ecf20Sopenharmony_ci		fx_iocb.dataword_extra = piocb_rqst->dataword_extra;
32798c2ecf20Sopenharmony_ci		fx_iocb.dataword = piocb_rqst->dataword;
32808c2ecf20Sopenharmony_ci		fx_iocb.req_xfrcnt = piocb_rqst->req_len;
32818c2ecf20Sopenharmony_ci		fx_iocb.rsp_xfrcnt = piocb_rqst->rsp_len;
32828c2ecf20Sopenharmony_ci
32838c2ecf20Sopenharmony_ci		if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) {
32848c2ecf20Sopenharmony_ci			int avail_dsds, tot_dsds;
32858c2ecf20Sopenharmony_ci			cont_a64_entry_t lcont_pkt;
32868c2ecf20Sopenharmony_ci			cont_a64_entry_t *cont_pkt = NULL;
32878c2ecf20Sopenharmony_ci			struct dsd64 *cur_dsd;
32888c2ecf20Sopenharmony_ci			int index = 0, cont = 0;
32898c2ecf20Sopenharmony_ci
32908c2ecf20Sopenharmony_ci			fx_iocb.req_dsdcnt =
32918c2ecf20Sopenharmony_ci			    cpu_to_le16(bsg_job->request_payload.sg_cnt);
32928c2ecf20Sopenharmony_ci			tot_dsds =
32938c2ecf20Sopenharmony_ci			    bsg_job->request_payload.sg_cnt;
32948c2ecf20Sopenharmony_ci			cur_dsd = &fx_iocb.dseg_rq;
32958c2ecf20Sopenharmony_ci			avail_dsds = 1;
32968c2ecf20Sopenharmony_ci			for_each_sg(bsg_job->request_payload.sg_list, sg,
32978c2ecf20Sopenharmony_ci			    tot_dsds, index) {
32988c2ecf20Sopenharmony_ci				/* Allocate additional continuation packets? */
32998c2ecf20Sopenharmony_ci				if (avail_dsds == 0) {
33008c2ecf20Sopenharmony_ci					/*
33018c2ecf20Sopenharmony_ci					 * Five DSDs are available in the Cont.
33028c2ecf20Sopenharmony_ci					 * Type 1 IOCB.
33038c2ecf20Sopenharmony_ci					 */
33048c2ecf20Sopenharmony_ci					memset(&lcont_pkt, 0,
33058c2ecf20Sopenharmony_ci					    REQUEST_ENTRY_SIZE);
33068c2ecf20Sopenharmony_ci					cont_pkt =
33078c2ecf20Sopenharmony_ci					    qlafx00_prep_cont_type1_iocb(
33088c2ecf20Sopenharmony_ci						sp->vha->req, &lcont_pkt);
33098c2ecf20Sopenharmony_ci					cur_dsd = lcont_pkt.dsd;
33108c2ecf20Sopenharmony_ci					avail_dsds = 5;
33118c2ecf20Sopenharmony_ci					cont = 1;
33128c2ecf20Sopenharmony_ci					entry_cnt++;
33138c2ecf20Sopenharmony_ci				}
33148c2ecf20Sopenharmony_ci
33158c2ecf20Sopenharmony_ci				append_dsd64(&cur_dsd, sg);
33168c2ecf20Sopenharmony_ci				avail_dsds--;
33178c2ecf20Sopenharmony_ci
33188c2ecf20Sopenharmony_ci				if (avail_dsds == 0 && cont == 1) {
33198c2ecf20Sopenharmony_ci					cont = 0;
33208c2ecf20Sopenharmony_ci					memcpy_toio(
33218c2ecf20Sopenharmony_ci					    (void __iomem *)cont_pkt,
33228c2ecf20Sopenharmony_ci					    &lcont_pkt, REQUEST_ENTRY_SIZE);
33238c2ecf20Sopenharmony_ci					ql_dump_buffer(
33248c2ecf20Sopenharmony_ci					    ql_dbg_user + ql_dbg_verbose,
33258c2ecf20Sopenharmony_ci					    sp->vha, 0x3042,
33268c2ecf20Sopenharmony_ci					    (uint8_t *)&lcont_pkt,
33278c2ecf20Sopenharmony_ci					     REQUEST_ENTRY_SIZE);
33288c2ecf20Sopenharmony_ci				}
33298c2ecf20Sopenharmony_ci			}
33308c2ecf20Sopenharmony_ci			if (avail_dsds != 0 && cont == 1) {
33318c2ecf20Sopenharmony_ci				memcpy_toio((void __iomem *)cont_pkt,
33328c2ecf20Sopenharmony_ci				    &lcont_pkt, REQUEST_ENTRY_SIZE);
33338c2ecf20Sopenharmony_ci				ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
33348c2ecf20Sopenharmony_ci				    sp->vha, 0x3043,
33358c2ecf20Sopenharmony_ci				    (uint8_t *)&lcont_pkt, REQUEST_ENTRY_SIZE);
33368c2ecf20Sopenharmony_ci			}
33378c2ecf20Sopenharmony_ci		}
33388c2ecf20Sopenharmony_ci
33398c2ecf20Sopenharmony_ci		if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) {
33408c2ecf20Sopenharmony_ci			int avail_dsds, tot_dsds;
33418c2ecf20Sopenharmony_ci			cont_a64_entry_t lcont_pkt;
33428c2ecf20Sopenharmony_ci			cont_a64_entry_t *cont_pkt = NULL;
33438c2ecf20Sopenharmony_ci			struct dsd64 *cur_dsd;
33448c2ecf20Sopenharmony_ci			int index = 0, cont = 0;
33458c2ecf20Sopenharmony_ci
33468c2ecf20Sopenharmony_ci			fx_iocb.rsp_dsdcnt =
33478c2ecf20Sopenharmony_ci			   cpu_to_le16(bsg_job->reply_payload.sg_cnt);
33488c2ecf20Sopenharmony_ci			tot_dsds = bsg_job->reply_payload.sg_cnt;
33498c2ecf20Sopenharmony_ci			cur_dsd = &fx_iocb.dseg_rsp;
33508c2ecf20Sopenharmony_ci			avail_dsds = 1;
33518c2ecf20Sopenharmony_ci
33528c2ecf20Sopenharmony_ci			for_each_sg(bsg_job->reply_payload.sg_list, sg,
33538c2ecf20Sopenharmony_ci			    tot_dsds, index) {
33548c2ecf20Sopenharmony_ci				/* Allocate additional continuation packets? */
33558c2ecf20Sopenharmony_ci				if (avail_dsds == 0) {
33568c2ecf20Sopenharmony_ci					/*
33578c2ecf20Sopenharmony_ci					* Five DSDs are available in the Cont.
33588c2ecf20Sopenharmony_ci					* Type 1 IOCB.
33598c2ecf20Sopenharmony_ci					*/
33608c2ecf20Sopenharmony_ci					memset(&lcont_pkt, 0,
33618c2ecf20Sopenharmony_ci					    REQUEST_ENTRY_SIZE);
33628c2ecf20Sopenharmony_ci					cont_pkt =
33638c2ecf20Sopenharmony_ci					    qlafx00_prep_cont_type1_iocb(
33648c2ecf20Sopenharmony_ci						sp->vha->req, &lcont_pkt);
33658c2ecf20Sopenharmony_ci					cur_dsd = lcont_pkt.dsd;
33668c2ecf20Sopenharmony_ci					avail_dsds = 5;
33678c2ecf20Sopenharmony_ci					cont = 1;
33688c2ecf20Sopenharmony_ci					entry_cnt++;
33698c2ecf20Sopenharmony_ci				}
33708c2ecf20Sopenharmony_ci
33718c2ecf20Sopenharmony_ci				append_dsd64(&cur_dsd, sg);
33728c2ecf20Sopenharmony_ci				avail_dsds--;
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ci				if (avail_dsds == 0 && cont == 1) {
33758c2ecf20Sopenharmony_ci					cont = 0;
33768c2ecf20Sopenharmony_ci					memcpy_toio((void __iomem *)cont_pkt,
33778c2ecf20Sopenharmony_ci					    &lcont_pkt,
33788c2ecf20Sopenharmony_ci					    REQUEST_ENTRY_SIZE);
33798c2ecf20Sopenharmony_ci					ql_dump_buffer(
33808c2ecf20Sopenharmony_ci					    ql_dbg_user + ql_dbg_verbose,
33818c2ecf20Sopenharmony_ci					    sp->vha, 0x3045,
33828c2ecf20Sopenharmony_ci					    (uint8_t *)&lcont_pkt,
33838c2ecf20Sopenharmony_ci					    REQUEST_ENTRY_SIZE);
33848c2ecf20Sopenharmony_ci				}
33858c2ecf20Sopenharmony_ci			}
33868c2ecf20Sopenharmony_ci			if (avail_dsds != 0 && cont == 1) {
33878c2ecf20Sopenharmony_ci				memcpy_toio((void __iomem *)cont_pkt,
33888c2ecf20Sopenharmony_ci				    &lcont_pkt, REQUEST_ENTRY_SIZE);
33898c2ecf20Sopenharmony_ci				ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
33908c2ecf20Sopenharmony_ci				    sp->vha, 0x3046,
33918c2ecf20Sopenharmony_ci				    (uint8_t *)&lcont_pkt, REQUEST_ENTRY_SIZE);
33928c2ecf20Sopenharmony_ci			}
33938c2ecf20Sopenharmony_ci		}
33948c2ecf20Sopenharmony_ci
33958c2ecf20Sopenharmony_ci		if (piocb_rqst->flags & SRB_FXDISC_REQ_DWRD_VALID)
33968c2ecf20Sopenharmony_ci			fx_iocb.dataword = piocb_rqst->dataword;
33978c2ecf20Sopenharmony_ci		fx_iocb.flags = piocb_rqst->flags;
33988c2ecf20Sopenharmony_ci		fx_iocb.entry_count = entry_cnt;
33998c2ecf20Sopenharmony_ci	}
34008c2ecf20Sopenharmony_ci
34018c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
34028c2ecf20Sopenharmony_ci	    sp->vha, 0x3047, &fx_iocb, sizeof(fx_iocb));
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_ci	memcpy_toio((void __iomem *)pfxiocb, &fx_iocb, sizeof(fx_iocb));
34058c2ecf20Sopenharmony_ci	wmb();
34068c2ecf20Sopenharmony_ci}
3407