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
88c2ecf20Sopenharmony_ci#include <linux/kthread.h>
98c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci#include <linux/bsg-lib.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic void qla2xxx_free_fcport_work(struct work_struct *work)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	struct fc_port *fcport = container_of(work, typeof(*fcport),
168c2ecf20Sopenharmony_ci	    free_work);
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	qla2x00_free_fcport(fcport);
198c2ecf20Sopenharmony_ci}
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* BSG support for ELS/CT pass through */
228c2ecf20Sopenharmony_civoid qla2x00_bsg_job_done(srb_t *sp, int res)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	struct bsg_job *bsg_job = sp->u.bsg_job;
258c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	sp->free(sp);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	bsg_reply->result = res;
308c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
318c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_civoid qla2x00_bsg_sp_free(srb_t *sp)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = sp->vha->hw;
378c2ecf20Sopenharmony_ci	struct bsg_job *bsg_job = sp->u.bsg_job;
388c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
398c2ecf20Sopenharmony_ci	struct qla_mt_iocb_rqst_fx00 *piocb_rqst;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (sp->type == SRB_FXIOCB_BCMD) {
428c2ecf20Sopenharmony_ci		piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
438c2ecf20Sopenharmony_ci		    &bsg_request->rqst_data.h_vendor.vendor_cmd[1];
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci		if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID)
468c2ecf20Sopenharmony_ci			dma_unmap_sg(&ha->pdev->dev,
478c2ecf20Sopenharmony_ci			    bsg_job->request_payload.sg_list,
488c2ecf20Sopenharmony_ci			    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci		if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID)
518c2ecf20Sopenharmony_ci			dma_unmap_sg(&ha->pdev->dev,
528c2ecf20Sopenharmony_ci			    bsg_job->reply_payload.sg_list,
538c2ecf20Sopenharmony_ci			    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
548c2ecf20Sopenharmony_ci	} else {
558c2ecf20Sopenharmony_ci		dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
568c2ecf20Sopenharmony_ci		    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci		dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
598c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (sp->type == SRB_CT_CMD ||
638c2ecf20Sopenharmony_ci	    sp->type == SRB_FXIOCB_BCMD ||
648c2ecf20Sopenharmony_ci	    sp->type == SRB_ELS_CMD_HST) {
658c2ecf20Sopenharmony_ci		INIT_WORK(&sp->fcport->free_work, qla2xxx_free_fcport_work);
668c2ecf20Sopenharmony_ci		queue_work(ha->wq, &sp->fcport->free_work);
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	qla2x00_rel_sp(sp);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ciint
738c2ecf20Sopenharmony_ciqla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *vha,
748c2ecf20Sopenharmony_ci	struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	int i, ret, num_valid;
778c2ecf20Sopenharmony_ci	uint8_t *bcode;
788c2ecf20Sopenharmony_ci	struct qla_fcp_prio_entry *pri_entry;
798c2ecf20Sopenharmony_ci	uint32_t *bcode_val_ptr, bcode_val;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	ret = 1;
828c2ecf20Sopenharmony_ci	num_valid = 0;
838c2ecf20Sopenharmony_ci	bcode = (uint8_t *)pri_cfg;
848c2ecf20Sopenharmony_ci	bcode_val_ptr = (uint32_t *)pri_cfg;
858c2ecf20Sopenharmony_ci	bcode_val = (uint32_t)(*bcode_val_ptr);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if (bcode_val == 0xFFFFFFFF) {
888c2ecf20Sopenharmony_ci		/* No FCP Priority config data in flash */
898c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7051,
908c2ecf20Sopenharmony_ci		    "No FCP Priority config data.\n");
918c2ecf20Sopenharmony_ci		return 0;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (memcmp(bcode, "HQOS", 4)) {
958c2ecf20Sopenharmony_ci		/* Invalid FCP priority data header*/
968c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7052,
978c2ecf20Sopenharmony_ci		    "Invalid FCP Priority data header. bcode=0x%x.\n",
988c2ecf20Sopenharmony_ci		    bcode_val);
998c2ecf20Sopenharmony_ci		return 0;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci	if (flag != 1)
1028c2ecf20Sopenharmony_ci		return ret;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	pri_entry = &pri_cfg->entry[0];
1058c2ecf20Sopenharmony_ci	for (i = 0; i < pri_cfg->num_entries; i++) {
1068c2ecf20Sopenharmony_ci		if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID)
1078c2ecf20Sopenharmony_ci			num_valid++;
1088c2ecf20Sopenharmony_ci		pri_entry++;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (num_valid == 0) {
1128c2ecf20Sopenharmony_ci		/* No valid FCP priority data entries */
1138c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7053,
1148c2ecf20Sopenharmony_ci		    "No valid FCP Priority data entries.\n");
1158c2ecf20Sopenharmony_ci		ret = 0;
1168c2ecf20Sopenharmony_ci	} else {
1178c2ecf20Sopenharmony_ci		/* FCP priority data is valid */
1188c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7054,
1198c2ecf20Sopenharmony_ci		    "Valid FCP priority data. num entries = %d.\n",
1208c2ecf20Sopenharmony_ci		    num_valid);
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	return ret;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic int
1278c2ecf20Sopenharmony_ciqla24xx_proc_fcp_prio_cfg_cmd(struct bsg_job *bsg_job)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
1308c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
1318c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
1328c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
1338c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
1348c2ecf20Sopenharmony_ci	int ret = 0;
1358c2ecf20Sopenharmony_ci	uint32_t len;
1368c2ecf20Sopenharmony_ci	uint32_t oper;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_P3P_TYPE(ha))) {
1398c2ecf20Sopenharmony_ci		ret = -EINVAL;
1408c2ecf20Sopenharmony_ci		goto exit_fcp_prio_cfg;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	/* Get the sub command */
1448c2ecf20Sopenharmony_ci	oper = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* Only set config is allowed if config memory is not allocated */
1478c2ecf20Sopenharmony_ci	if (!ha->fcp_prio_cfg && (oper != QLFC_FCP_PRIO_SET_CONFIG)) {
1488c2ecf20Sopenharmony_ci		ret = -EINVAL;
1498c2ecf20Sopenharmony_ci		goto exit_fcp_prio_cfg;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci	switch (oper) {
1528c2ecf20Sopenharmony_ci	case QLFC_FCP_PRIO_DISABLE:
1538c2ecf20Sopenharmony_ci		if (ha->flags.fcp_prio_enabled) {
1548c2ecf20Sopenharmony_ci			ha->flags.fcp_prio_enabled = 0;
1558c2ecf20Sopenharmony_ci			ha->fcp_prio_cfg->attributes &=
1568c2ecf20Sopenharmony_ci				~FCP_PRIO_ATTR_ENABLE;
1578c2ecf20Sopenharmony_ci			qla24xx_update_all_fcp_prio(vha);
1588c2ecf20Sopenharmony_ci			bsg_reply->result = DID_OK;
1598c2ecf20Sopenharmony_ci		} else {
1608c2ecf20Sopenharmony_ci			ret = -EINVAL;
1618c2ecf20Sopenharmony_ci			bsg_reply->result = (DID_ERROR << 16);
1628c2ecf20Sopenharmony_ci			goto exit_fcp_prio_cfg;
1638c2ecf20Sopenharmony_ci		}
1648c2ecf20Sopenharmony_ci		break;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	case QLFC_FCP_PRIO_ENABLE:
1678c2ecf20Sopenharmony_ci		if (!ha->flags.fcp_prio_enabled) {
1688c2ecf20Sopenharmony_ci			if (ha->fcp_prio_cfg) {
1698c2ecf20Sopenharmony_ci				ha->flags.fcp_prio_enabled = 1;
1708c2ecf20Sopenharmony_ci				ha->fcp_prio_cfg->attributes |=
1718c2ecf20Sopenharmony_ci				    FCP_PRIO_ATTR_ENABLE;
1728c2ecf20Sopenharmony_ci				qla24xx_update_all_fcp_prio(vha);
1738c2ecf20Sopenharmony_ci				bsg_reply->result = DID_OK;
1748c2ecf20Sopenharmony_ci			} else {
1758c2ecf20Sopenharmony_ci				ret = -EINVAL;
1768c2ecf20Sopenharmony_ci				bsg_reply->result = (DID_ERROR << 16);
1778c2ecf20Sopenharmony_ci				goto exit_fcp_prio_cfg;
1788c2ecf20Sopenharmony_ci			}
1798c2ecf20Sopenharmony_ci		}
1808c2ecf20Sopenharmony_ci		break;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	case QLFC_FCP_PRIO_GET_CONFIG:
1838c2ecf20Sopenharmony_ci		len = bsg_job->reply_payload.payload_len;
1848c2ecf20Sopenharmony_ci		if (!len || len > FCP_PRIO_CFG_SIZE) {
1858c2ecf20Sopenharmony_ci			ret = -EINVAL;
1868c2ecf20Sopenharmony_ci			bsg_reply->result = (DID_ERROR << 16);
1878c2ecf20Sopenharmony_ci			goto exit_fcp_prio_cfg;
1888c2ecf20Sopenharmony_ci		}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci		bsg_reply->result = DID_OK;
1918c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len =
1928c2ecf20Sopenharmony_ci			sg_copy_from_buffer(
1938c2ecf20Sopenharmony_ci			bsg_job->reply_payload.sg_list,
1948c2ecf20Sopenharmony_ci			bsg_job->reply_payload.sg_cnt, ha->fcp_prio_cfg,
1958c2ecf20Sopenharmony_ci			len);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		break;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	case QLFC_FCP_PRIO_SET_CONFIG:
2008c2ecf20Sopenharmony_ci		len = bsg_job->request_payload.payload_len;
2018c2ecf20Sopenharmony_ci		if (!len || len > FCP_PRIO_CFG_SIZE) {
2028c2ecf20Sopenharmony_ci			bsg_reply->result = (DID_ERROR << 16);
2038c2ecf20Sopenharmony_ci			ret = -EINVAL;
2048c2ecf20Sopenharmony_ci			goto exit_fcp_prio_cfg;
2058c2ecf20Sopenharmony_ci		}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		if (!ha->fcp_prio_cfg) {
2088c2ecf20Sopenharmony_ci			ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE);
2098c2ecf20Sopenharmony_ci			if (!ha->fcp_prio_cfg) {
2108c2ecf20Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x7050,
2118c2ecf20Sopenharmony_ci				    "Unable to allocate memory for fcp prio "
2128c2ecf20Sopenharmony_ci				    "config data (%x).\n", FCP_PRIO_CFG_SIZE);
2138c2ecf20Sopenharmony_ci				bsg_reply->result = (DID_ERROR << 16);
2148c2ecf20Sopenharmony_ci				ret = -ENOMEM;
2158c2ecf20Sopenharmony_ci				goto exit_fcp_prio_cfg;
2168c2ecf20Sopenharmony_ci			}
2178c2ecf20Sopenharmony_ci		}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE);
2208c2ecf20Sopenharmony_ci		sg_copy_to_buffer(bsg_job->request_payload.sg_list,
2218c2ecf20Sopenharmony_ci		bsg_job->request_payload.sg_cnt, ha->fcp_prio_cfg,
2228c2ecf20Sopenharmony_ci			FCP_PRIO_CFG_SIZE);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci		/* validate fcp priority data */
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci		if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 1)) {
2278c2ecf20Sopenharmony_ci			bsg_reply->result = (DID_ERROR << 16);
2288c2ecf20Sopenharmony_ci			ret = -EINVAL;
2298c2ecf20Sopenharmony_ci			/* If buffer was invalidatic int
2308c2ecf20Sopenharmony_ci			 * fcp_prio_cfg is of no use
2318c2ecf20Sopenharmony_ci			 */
2328c2ecf20Sopenharmony_ci			vfree(ha->fcp_prio_cfg);
2338c2ecf20Sopenharmony_ci			ha->fcp_prio_cfg = NULL;
2348c2ecf20Sopenharmony_ci			goto exit_fcp_prio_cfg;
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		ha->flags.fcp_prio_enabled = 0;
2388c2ecf20Sopenharmony_ci		if (ha->fcp_prio_cfg->attributes & FCP_PRIO_ATTR_ENABLE)
2398c2ecf20Sopenharmony_ci			ha->flags.fcp_prio_enabled = 1;
2408c2ecf20Sopenharmony_ci		qla24xx_update_all_fcp_prio(vha);
2418c2ecf20Sopenharmony_ci		bsg_reply->result = DID_OK;
2428c2ecf20Sopenharmony_ci		break;
2438c2ecf20Sopenharmony_ci	default:
2448c2ecf20Sopenharmony_ci		ret = -EINVAL;
2458c2ecf20Sopenharmony_ci		break;
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ciexit_fcp_prio_cfg:
2488c2ecf20Sopenharmony_ci	if (!ret)
2498c2ecf20Sopenharmony_ci		bsg_job_done(bsg_job, bsg_reply->result,
2508c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
2518c2ecf20Sopenharmony_ci	return ret;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int
2558c2ecf20Sopenharmony_ciqla2x00_process_els(struct bsg_job *bsg_job)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
2588c2ecf20Sopenharmony_ci	struct fc_rport *rport;
2598c2ecf20Sopenharmony_ci	fc_port_t *fcport = NULL;
2608c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
2618c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha;
2628c2ecf20Sopenharmony_ci	struct qla_hw_data *ha;
2638c2ecf20Sopenharmony_ci	srb_t *sp;
2648c2ecf20Sopenharmony_ci	const char *type;
2658c2ecf20Sopenharmony_ci	int req_sg_cnt, rsp_sg_cnt;
2668c2ecf20Sopenharmony_ci	int rval =  (DID_ERROR << 16);
2678c2ecf20Sopenharmony_ci	uint16_t nextlid = 0;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (bsg_request->msgcode == FC_BSG_RPT_ELS) {
2708c2ecf20Sopenharmony_ci		rport = fc_bsg_to_rport(bsg_job);
2718c2ecf20Sopenharmony_ci		if (!rport) {
2728c2ecf20Sopenharmony_ci			rval = -ENOMEM;
2738c2ecf20Sopenharmony_ci			goto done;
2748c2ecf20Sopenharmony_ci		}
2758c2ecf20Sopenharmony_ci		fcport = *(fc_port_t **) rport->dd_data;
2768c2ecf20Sopenharmony_ci		host = rport_to_shost(rport);
2778c2ecf20Sopenharmony_ci		vha = shost_priv(host);
2788c2ecf20Sopenharmony_ci		ha = vha->hw;
2798c2ecf20Sopenharmony_ci		type = "FC_BSG_RPT_ELS";
2808c2ecf20Sopenharmony_ci	} else {
2818c2ecf20Sopenharmony_ci		host = fc_bsg_to_shost(bsg_job);
2828c2ecf20Sopenharmony_ci		vha = shost_priv(host);
2838c2ecf20Sopenharmony_ci		ha = vha->hw;
2848c2ecf20Sopenharmony_ci		type = "FC_BSG_HST_ELS_NOLOGIN";
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (!vha->flags.online) {
2888c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n");
2898c2ecf20Sopenharmony_ci		rval = -EIO;
2908c2ecf20Sopenharmony_ci		goto done;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	/* pass through is supported only for ISP 4Gb or higher */
2948c2ecf20Sopenharmony_ci	if (!IS_FWI2_CAPABLE(ha)) {
2958c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7001,
2968c2ecf20Sopenharmony_ci		    "ELS passthru not supported for ISP23xx based adapters.\n");
2978c2ecf20Sopenharmony_ci		rval = -EPERM;
2988c2ecf20Sopenharmony_ci		goto done;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/*  Multiple SG's are not supported for ELS requests */
3028c2ecf20Sopenharmony_ci	if (bsg_job->request_payload.sg_cnt > 1 ||
3038c2ecf20Sopenharmony_ci		bsg_job->reply_payload.sg_cnt > 1) {
3048c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7002,
3058c2ecf20Sopenharmony_ci		    "Multiple SG's are not supported for ELS requests, "
3068c2ecf20Sopenharmony_ci		    "request_sg_cnt=%x reply_sg_cnt=%x.\n",
3078c2ecf20Sopenharmony_ci		    bsg_job->request_payload.sg_cnt,
3088c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_cnt);
3098c2ecf20Sopenharmony_ci		rval = -EPERM;
3108c2ecf20Sopenharmony_ci		goto done;
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* ELS request for rport */
3148c2ecf20Sopenharmony_ci	if (bsg_request->msgcode == FC_BSG_RPT_ELS) {
3158c2ecf20Sopenharmony_ci		/* make sure the rport is logged in,
3168c2ecf20Sopenharmony_ci		 * if not perform fabric login
3178c2ecf20Sopenharmony_ci		 */
3188c2ecf20Sopenharmony_ci		if (qla2x00_fabric_login(vha, fcport, &nextlid)) {
3198c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x7003,
3208c2ecf20Sopenharmony_ci			    "Failed to login port %06X for ELS passthru.\n",
3218c2ecf20Sopenharmony_ci			    fcport->d_id.b24);
3228c2ecf20Sopenharmony_ci			rval = -EIO;
3238c2ecf20Sopenharmony_ci			goto done;
3248c2ecf20Sopenharmony_ci		}
3258c2ecf20Sopenharmony_ci	} else {
3268c2ecf20Sopenharmony_ci		/* Allocate a dummy fcport structure, since functions
3278c2ecf20Sopenharmony_ci		 * preparing the IOCB and mailbox command retrieves port
3288c2ecf20Sopenharmony_ci		 * specific information from fcport structure. For Host based
3298c2ecf20Sopenharmony_ci		 * ELS commands there will be no fcport structure allocated
3308c2ecf20Sopenharmony_ci		 */
3318c2ecf20Sopenharmony_ci		fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
3328c2ecf20Sopenharmony_ci		if (!fcport) {
3338c2ecf20Sopenharmony_ci			rval = -ENOMEM;
3348c2ecf20Sopenharmony_ci			goto done;
3358c2ecf20Sopenharmony_ci		}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		/* Initialize all required  fields of fcport */
3388c2ecf20Sopenharmony_ci		fcport->vha = vha;
3398c2ecf20Sopenharmony_ci		fcport->d_id.b.al_pa =
3408c2ecf20Sopenharmony_ci			bsg_request->rqst_data.h_els.port_id[0];
3418c2ecf20Sopenharmony_ci		fcport->d_id.b.area =
3428c2ecf20Sopenharmony_ci			bsg_request->rqst_data.h_els.port_id[1];
3438c2ecf20Sopenharmony_ci		fcport->d_id.b.domain =
3448c2ecf20Sopenharmony_ci			bsg_request->rqst_data.h_els.port_id[2];
3458c2ecf20Sopenharmony_ci		fcport->loop_id =
3468c2ecf20Sopenharmony_ci			(fcport->d_id.b.al_pa == 0xFD) ?
3478c2ecf20Sopenharmony_ci			NPH_FABRIC_CONTROLLER : NPH_F_PORT;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	req_sg_cnt =
3518c2ecf20Sopenharmony_ci		dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
3528c2ecf20Sopenharmony_ci		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
3538c2ecf20Sopenharmony_ci	if (!req_sg_cnt) {
3548c2ecf20Sopenharmony_ci		dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
3558c2ecf20Sopenharmony_ci		    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
3568c2ecf20Sopenharmony_ci		rval = -ENOMEM;
3578c2ecf20Sopenharmony_ci		goto done_free_fcport;
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
3618c2ecf20Sopenharmony_ci		bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
3628c2ecf20Sopenharmony_ci        if (!rsp_sg_cnt) {
3638c2ecf20Sopenharmony_ci		dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
3648c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
3658c2ecf20Sopenharmony_ci		rval = -ENOMEM;
3668c2ecf20Sopenharmony_ci		goto done_free_fcport;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
3708c2ecf20Sopenharmony_ci		(rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
3718c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7008,
3728c2ecf20Sopenharmony_ci		    "dma mapping resulted in different sg counts, "
3738c2ecf20Sopenharmony_ci		    "request_sg_cnt: %x dma_request_sg_cnt:%x reply_sg_cnt:%x "
3748c2ecf20Sopenharmony_ci		    "dma_reply_sg_cnt:%x.\n", bsg_job->request_payload.sg_cnt,
3758c2ecf20Sopenharmony_ci		    req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);
3768c2ecf20Sopenharmony_ci		rval = -EAGAIN;
3778c2ecf20Sopenharmony_ci		goto done_unmap_sg;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	/* Alloc SRB structure */
3818c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
3828c2ecf20Sopenharmony_ci	if (!sp) {
3838c2ecf20Sopenharmony_ci		rval = -ENOMEM;
3848c2ecf20Sopenharmony_ci		goto done_unmap_sg;
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	sp->type =
3888c2ecf20Sopenharmony_ci		(bsg_request->msgcode == FC_BSG_RPT_ELS ?
3898c2ecf20Sopenharmony_ci		 SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST);
3908c2ecf20Sopenharmony_ci	sp->name =
3918c2ecf20Sopenharmony_ci		(bsg_request->msgcode == FC_BSG_RPT_ELS ?
3928c2ecf20Sopenharmony_ci		 "bsg_els_rpt" : "bsg_els_hst");
3938c2ecf20Sopenharmony_ci	sp->u.bsg_job = bsg_job;
3948c2ecf20Sopenharmony_ci	sp->free = qla2x00_bsg_sp_free;
3958c2ecf20Sopenharmony_ci	sp->done = qla2x00_bsg_job_done;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_user, vha, 0x700a,
3988c2ecf20Sopenharmony_ci	    "bsg rqst type: %s els type: %x - loop-id=%x "
3998c2ecf20Sopenharmony_ci	    "portid=%-2x%02x%02x.\n", type,
4008c2ecf20Sopenharmony_ci	    bsg_request->rqst_data.h_els.command_code, fcport->loop_id,
4018c2ecf20Sopenharmony_ci	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	rval = qla2x00_start_sp(sp);
4048c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
4058c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x700e,
4068c2ecf20Sopenharmony_ci		    "qla2x00_start_sp failed = %d\n", rval);
4078c2ecf20Sopenharmony_ci		qla2x00_rel_sp(sp);
4088c2ecf20Sopenharmony_ci		rval = -EIO;
4098c2ecf20Sopenharmony_ci		goto done_unmap_sg;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci	return rval;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cidone_unmap_sg:
4148c2ecf20Sopenharmony_ci	dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
4158c2ecf20Sopenharmony_ci		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
4168c2ecf20Sopenharmony_ci	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
4178c2ecf20Sopenharmony_ci		bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
4188c2ecf20Sopenharmony_ci	goto done_free_fcport;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cidone_free_fcport:
4218c2ecf20Sopenharmony_ci	if (bsg_request->msgcode != FC_BSG_RPT_ELS)
4228c2ecf20Sopenharmony_ci		qla2x00_free_fcport(fcport);
4238c2ecf20Sopenharmony_cidone:
4248c2ecf20Sopenharmony_ci	return rval;
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic inline uint16_t
4288c2ecf20Sopenharmony_ciqla24xx_calc_ct_iocbs(uint16_t dsds)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	uint16_t iocbs;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	iocbs = 1;
4338c2ecf20Sopenharmony_ci	if (dsds > 2) {
4348c2ecf20Sopenharmony_ci		iocbs += (dsds - 2) / 5;
4358c2ecf20Sopenharmony_ci		if ((dsds - 2) % 5)
4368c2ecf20Sopenharmony_ci			iocbs++;
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci	return iocbs;
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cistatic int
4428c2ecf20Sopenharmony_ciqla2x00_process_ct(struct bsg_job *bsg_job)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	srb_t *sp;
4458c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
4468c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
4478c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
4488c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
4498c2ecf20Sopenharmony_ci	int rval = (DID_ERROR << 16);
4508c2ecf20Sopenharmony_ci	int req_sg_cnt, rsp_sg_cnt;
4518c2ecf20Sopenharmony_ci	uint16_t loop_id;
4528c2ecf20Sopenharmony_ci	struct fc_port *fcport;
4538c2ecf20Sopenharmony_ci	char  *type = "FC_BSG_HST_CT";
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	req_sg_cnt =
4568c2ecf20Sopenharmony_ci		dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
4578c2ecf20Sopenharmony_ci			bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
4588c2ecf20Sopenharmony_ci	if (!req_sg_cnt) {
4598c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x700f,
4608c2ecf20Sopenharmony_ci		    "dma_map_sg return %d for request\n", req_sg_cnt);
4618c2ecf20Sopenharmony_ci		rval = -ENOMEM;
4628c2ecf20Sopenharmony_ci		goto done;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
4668c2ecf20Sopenharmony_ci		bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
4678c2ecf20Sopenharmony_ci	if (!rsp_sg_cnt) {
4688c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7010,
4698c2ecf20Sopenharmony_ci		    "dma_map_sg return %d for reply\n", rsp_sg_cnt);
4708c2ecf20Sopenharmony_ci		rval = -ENOMEM;
4718c2ecf20Sopenharmony_ci		goto done;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
4758c2ecf20Sopenharmony_ci	    (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
4768c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7011,
4778c2ecf20Sopenharmony_ci		    "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x "
4788c2ecf20Sopenharmony_ci		    "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt,
4798c2ecf20Sopenharmony_ci		    req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);
4808c2ecf20Sopenharmony_ci		rval = -EAGAIN;
4818c2ecf20Sopenharmony_ci		goto done_unmap_sg;
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	if (!vha->flags.online) {
4858c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7012,
4868c2ecf20Sopenharmony_ci		    "Host is not online.\n");
4878c2ecf20Sopenharmony_ci		rval = -EIO;
4888c2ecf20Sopenharmony_ci		goto done_unmap_sg;
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	loop_id =
4928c2ecf20Sopenharmony_ci		(bsg_request->rqst_data.h_ct.preamble_word1 & 0xFF000000)
4938c2ecf20Sopenharmony_ci			>> 24;
4948c2ecf20Sopenharmony_ci	switch (loop_id) {
4958c2ecf20Sopenharmony_ci	case 0xFC:
4968c2ecf20Sopenharmony_ci		loop_id = NPH_SNS;
4978c2ecf20Sopenharmony_ci		break;
4988c2ecf20Sopenharmony_ci	case 0xFA:
4998c2ecf20Sopenharmony_ci		loop_id = vha->mgmt_svr_loop_id;
5008c2ecf20Sopenharmony_ci		break;
5018c2ecf20Sopenharmony_ci	default:
5028c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7013,
5038c2ecf20Sopenharmony_ci		    "Unknown loop id: %x.\n", loop_id);
5048c2ecf20Sopenharmony_ci		rval = -EINVAL;
5058c2ecf20Sopenharmony_ci		goto done_unmap_sg;
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	/* Allocate a dummy fcport structure, since functions preparing the
5098c2ecf20Sopenharmony_ci	 * IOCB and mailbox command retrieves port specific information
5108c2ecf20Sopenharmony_ci	 * from fcport structure. For Host based ELS commands there will be
5118c2ecf20Sopenharmony_ci	 * no fcport structure allocated
5128c2ecf20Sopenharmony_ci	 */
5138c2ecf20Sopenharmony_ci	fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
5148c2ecf20Sopenharmony_ci	if (!fcport) {
5158c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7014,
5168c2ecf20Sopenharmony_ci		    "Failed to allocate fcport.\n");
5178c2ecf20Sopenharmony_ci		rval = -ENOMEM;
5188c2ecf20Sopenharmony_ci		goto done_unmap_sg;
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	/* Initialize all required  fields of fcport */
5228c2ecf20Sopenharmony_ci	fcport->vha = vha;
5238c2ecf20Sopenharmony_ci	fcport->d_id.b.al_pa = bsg_request->rqst_data.h_ct.port_id[0];
5248c2ecf20Sopenharmony_ci	fcport->d_id.b.area = bsg_request->rqst_data.h_ct.port_id[1];
5258c2ecf20Sopenharmony_ci	fcport->d_id.b.domain = bsg_request->rqst_data.h_ct.port_id[2];
5268c2ecf20Sopenharmony_ci	fcport->loop_id = loop_id;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	/* Alloc SRB structure */
5298c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
5308c2ecf20Sopenharmony_ci	if (!sp) {
5318c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7015,
5328c2ecf20Sopenharmony_ci		    "qla2x00_get_sp failed.\n");
5338c2ecf20Sopenharmony_ci		rval = -ENOMEM;
5348c2ecf20Sopenharmony_ci		goto done_free_fcport;
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	sp->type = SRB_CT_CMD;
5388c2ecf20Sopenharmony_ci	sp->name = "bsg_ct";
5398c2ecf20Sopenharmony_ci	sp->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt);
5408c2ecf20Sopenharmony_ci	sp->u.bsg_job = bsg_job;
5418c2ecf20Sopenharmony_ci	sp->free = qla2x00_bsg_sp_free;
5428c2ecf20Sopenharmony_ci	sp->done = qla2x00_bsg_job_done;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_user, vha, 0x7016,
5458c2ecf20Sopenharmony_ci	    "bsg rqst type: %s else type: %x - "
5468c2ecf20Sopenharmony_ci	    "loop-id=%x portid=%02x%02x%02x.\n", type,
5478c2ecf20Sopenharmony_ci	    (bsg_request->rqst_data.h_ct.preamble_word2 >> 16),
5488c2ecf20Sopenharmony_ci	    fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
5498c2ecf20Sopenharmony_ci	    fcport->d_id.b.al_pa);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	rval = qla2x00_start_sp(sp);
5528c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
5538c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7017,
5548c2ecf20Sopenharmony_ci		    "qla2x00_start_sp failed=%d.\n", rval);
5558c2ecf20Sopenharmony_ci		qla2x00_rel_sp(sp);
5568c2ecf20Sopenharmony_ci		rval = -EIO;
5578c2ecf20Sopenharmony_ci		goto done_free_fcport;
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci	return rval;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cidone_free_fcport:
5628c2ecf20Sopenharmony_ci	qla2x00_free_fcport(fcport);
5638c2ecf20Sopenharmony_cidone_unmap_sg:
5648c2ecf20Sopenharmony_ci	dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
5658c2ecf20Sopenharmony_ci		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
5668c2ecf20Sopenharmony_ci	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
5678c2ecf20Sopenharmony_ci		bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
5688c2ecf20Sopenharmony_cidone:
5698c2ecf20Sopenharmony_ci	return rval;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci/* Disable loopback mode */
5738c2ecf20Sopenharmony_cistatic inline int
5748c2ecf20Sopenharmony_ciqla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
5758c2ecf20Sopenharmony_ci			    int wait, int wait2)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	int ret = 0;
5788c2ecf20Sopenharmony_ci	int rval = 0;
5798c2ecf20Sopenharmony_ci	uint16_t new_config[4];
5808c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
5838c2ecf20Sopenharmony_ci		goto done_reset_internal;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	memset(new_config, 0 , sizeof(new_config));
5868c2ecf20Sopenharmony_ci	if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
5878c2ecf20Sopenharmony_ci	    ENABLE_INTERNAL_LOOPBACK ||
5888c2ecf20Sopenharmony_ci	    (config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
5898c2ecf20Sopenharmony_ci	    ENABLE_EXTERNAL_LOOPBACK) {
5908c2ecf20Sopenharmony_ci		new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK;
5918c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70bf, "new_config[0]=%02x\n",
5928c2ecf20Sopenharmony_ci		    (new_config[0] & INTERNAL_LOOPBACK_MASK));
5938c2ecf20Sopenharmony_ci		memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		ha->notify_dcbx_comp = wait;
5968c2ecf20Sopenharmony_ci		ha->notify_lb_portup_comp = wait2;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci		ret = qla81xx_set_port_config(vha, new_config);
5998c2ecf20Sopenharmony_ci		if (ret != QLA_SUCCESS) {
6008c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7025,
6018c2ecf20Sopenharmony_ci			    "Set port config failed.\n");
6028c2ecf20Sopenharmony_ci			ha->notify_dcbx_comp = 0;
6038c2ecf20Sopenharmony_ci			ha->notify_lb_portup_comp = 0;
6048c2ecf20Sopenharmony_ci			rval = -EINVAL;
6058c2ecf20Sopenharmony_ci			goto done_reset_internal;
6068c2ecf20Sopenharmony_ci		}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci		/* Wait for DCBX complete event */
6098c2ecf20Sopenharmony_ci		if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
6108c2ecf20Sopenharmony_ci			(DCBX_COMP_TIMEOUT * HZ))) {
6118c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x7026,
6128c2ecf20Sopenharmony_ci			    "DCBX completion not received.\n");
6138c2ecf20Sopenharmony_ci			ha->notify_dcbx_comp = 0;
6148c2ecf20Sopenharmony_ci			ha->notify_lb_portup_comp = 0;
6158c2ecf20Sopenharmony_ci			rval = -EINVAL;
6168c2ecf20Sopenharmony_ci			goto done_reset_internal;
6178c2ecf20Sopenharmony_ci		} else
6188c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x7027,
6198c2ecf20Sopenharmony_ci			    "DCBX completion received.\n");
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci		if (wait2 &&
6228c2ecf20Sopenharmony_ci		    !wait_for_completion_timeout(&ha->lb_portup_comp,
6238c2ecf20Sopenharmony_ci		    (LB_PORTUP_COMP_TIMEOUT * HZ))) {
6248c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x70c5,
6258c2ecf20Sopenharmony_ci			    "Port up completion not received.\n");
6268c2ecf20Sopenharmony_ci			ha->notify_lb_portup_comp = 0;
6278c2ecf20Sopenharmony_ci			rval = -EINVAL;
6288c2ecf20Sopenharmony_ci			goto done_reset_internal;
6298c2ecf20Sopenharmony_ci		} else
6308c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x70c6,
6318c2ecf20Sopenharmony_ci			    "Port up completion received.\n");
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci		ha->notify_dcbx_comp = 0;
6348c2ecf20Sopenharmony_ci		ha->notify_lb_portup_comp = 0;
6358c2ecf20Sopenharmony_ci	}
6368c2ecf20Sopenharmony_cidone_reset_internal:
6378c2ecf20Sopenharmony_ci	return rval;
6388c2ecf20Sopenharmony_ci}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci/*
6418c2ecf20Sopenharmony_ci * Set the port configuration to enable the internal or external loopback
6428c2ecf20Sopenharmony_ci * depending on the loopback mode.
6438c2ecf20Sopenharmony_ci */
6448c2ecf20Sopenharmony_cistatic inline int
6458c2ecf20Sopenharmony_ciqla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
6468c2ecf20Sopenharmony_ci	uint16_t *new_config, uint16_t mode)
6478c2ecf20Sopenharmony_ci{
6488c2ecf20Sopenharmony_ci	int ret = 0;
6498c2ecf20Sopenharmony_ci	int rval = 0;
6508c2ecf20Sopenharmony_ci	unsigned long rem_tmo = 0, current_tmo = 0;
6518c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
6548c2ecf20Sopenharmony_ci		goto done_set_internal;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (mode == INTERNAL_LOOPBACK)
6578c2ecf20Sopenharmony_ci		new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);
6588c2ecf20Sopenharmony_ci	else if (mode == EXTERNAL_LOOPBACK)
6598c2ecf20Sopenharmony_ci		new_config[0] = config[0] | (ENABLE_EXTERNAL_LOOPBACK << 1);
6608c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_user, vha, 0x70be,
6618c2ecf20Sopenharmony_ci	     "new_config[0]=%02x\n", (new_config[0] & INTERNAL_LOOPBACK_MASK));
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	ha->notify_dcbx_comp = 1;
6668c2ecf20Sopenharmony_ci	ret = qla81xx_set_port_config(vha, new_config);
6678c2ecf20Sopenharmony_ci	if (ret != QLA_SUCCESS) {
6688c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7021,
6698c2ecf20Sopenharmony_ci		    "set port config failed.\n");
6708c2ecf20Sopenharmony_ci		ha->notify_dcbx_comp = 0;
6718c2ecf20Sopenharmony_ci		rval = -EINVAL;
6728c2ecf20Sopenharmony_ci		goto done_set_internal;
6738c2ecf20Sopenharmony_ci	}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	/* Wait for DCBX complete event */
6768c2ecf20Sopenharmony_ci	current_tmo = DCBX_COMP_TIMEOUT * HZ;
6778c2ecf20Sopenharmony_ci	while (1) {
6788c2ecf20Sopenharmony_ci		rem_tmo = wait_for_completion_timeout(&ha->dcbx_comp,
6798c2ecf20Sopenharmony_ci		    current_tmo);
6808c2ecf20Sopenharmony_ci		if (!ha->idc_extend_tmo || rem_tmo) {
6818c2ecf20Sopenharmony_ci			ha->idc_extend_tmo = 0;
6828c2ecf20Sopenharmony_ci			break;
6838c2ecf20Sopenharmony_ci		}
6848c2ecf20Sopenharmony_ci		current_tmo = ha->idc_extend_tmo * HZ;
6858c2ecf20Sopenharmony_ci		ha->idc_extend_tmo = 0;
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	if (!rem_tmo) {
6898c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7022,
6908c2ecf20Sopenharmony_ci		    "DCBX completion not received.\n");
6918c2ecf20Sopenharmony_ci		ret = qla81xx_reset_loopback_mode(vha, new_config, 0, 0);
6928c2ecf20Sopenharmony_ci		/*
6938c2ecf20Sopenharmony_ci		 * If the reset of the loopback mode doesn't work take a FCoE
6948c2ecf20Sopenharmony_ci		 * dump and reset the chip.
6958c2ecf20Sopenharmony_ci		 */
6968c2ecf20Sopenharmony_ci		if (ret) {
6978c2ecf20Sopenharmony_ci			qla2xxx_dump_fw(vha);
6988c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
6998c2ecf20Sopenharmony_ci		}
7008c2ecf20Sopenharmony_ci		rval = -EINVAL;
7018c2ecf20Sopenharmony_ci	} else {
7028c2ecf20Sopenharmony_ci		if (ha->flags.idc_compl_status) {
7038c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x70c3,
7048c2ecf20Sopenharmony_ci			    "Bad status in IDC Completion AEN\n");
7058c2ecf20Sopenharmony_ci			rval = -EINVAL;
7068c2ecf20Sopenharmony_ci			ha->flags.idc_compl_status = 0;
7078c2ecf20Sopenharmony_ci		} else
7088c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x7023,
7098c2ecf20Sopenharmony_ci			    "DCBX completion received.\n");
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	ha->notify_dcbx_comp = 0;
7138c2ecf20Sopenharmony_ci	ha->idc_extend_tmo = 0;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_cidone_set_internal:
7168c2ecf20Sopenharmony_ci	return rval;
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_cistatic int
7208c2ecf20Sopenharmony_ciqla2x00_process_loopback(struct bsg_job *bsg_job)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
7238c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
7248c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
7258c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
7268c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
7278c2ecf20Sopenharmony_ci	int rval;
7288c2ecf20Sopenharmony_ci	uint8_t command_sent;
7298c2ecf20Sopenharmony_ci	char *type;
7308c2ecf20Sopenharmony_ci	struct msg_echo_lb elreq;
7318c2ecf20Sopenharmony_ci	uint16_t response[MAILBOX_REGISTER_COUNT];
7328c2ecf20Sopenharmony_ci	uint16_t config[4], new_config[4];
7338c2ecf20Sopenharmony_ci	uint8_t *fw_sts_ptr;
7348c2ecf20Sopenharmony_ci	void *req_data = NULL;
7358c2ecf20Sopenharmony_ci	dma_addr_t req_data_dma;
7368c2ecf20Sopenharmony_ci	uint32_t req_data_len;
7378c2ecf20Sopenharmony_ci	uint8_t *rsp_data = NULL;
7388c2ecf20Sopenharmony_ci	dma_addr_t rsp_data_dma;
7398c2ecf20Sopenharmony_ci	uint32_t rsp_data_len;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	if (!vha->flags.online) {
7428c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7019, "Host is not online.\n");
7438c2ecf20Sopenharmony_ci		return -EIO;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	memset(&elreq, 0, sizeof(elreq));
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	elreq.req_sg_cnt = dma_map_sg(&ha->pdev->dev,
7498c2ecf20Sopenharmony_ci		bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt,
7508c2ecf20Sopenharmony_ci		DMA_TO_DEVICE);
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	if (!elreq.req_sg_cnt) {
7538c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x701a,
7548c2ecf20Sopenharmony_ci		    "dma_map_sg returned %d for request.\n", elreq.req_sg_cnt);
7558c2ecf20Sopenharmony_ci		return -ENOMEM;
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	elreq.rsp_sg_cnt = dma_map_sg(&ha->pdev->dev,
7598c2ecf20Sopenharmony_ci		bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt,
7608c2ecf20Sopenharmony_ci		DMA_FROM_DEVICE);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	if (!elreq.rsp_sg_cnt) {
7638c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x701b,
7648c2ecf20Sopenharmony_ci		    "dma_map_sg returned %d for reply.\n", elreq.rsp_sg_cnt);
7658c2ecf20Sopenharmony_ci		rval = -ENOMEM;
7668c2ecf20Sopenharmony_ci		goto done_unmap_req_sg;
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	if ((elreq.req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
7708c2ecf20Sopenharmony_ci		(elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
7718c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x701c,
7728c2ecf20Sopenharmony_ci		    "dma mapping resulted in different sg counts, "
7738c2ecf20Sopenharmony_ci		    "request_sg_cnt: %x dma_request_sg_cnt: %x "
7748c2ecf20Sopenharmony_ci		    "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n",
7758c2ecf20Sopenharmony_ci		    bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt,
7768c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt);
7778c2ecf20Sopenharmony_ci		rval = -EAGAIN;
7788c2ecf20Sopenharmony_ci		goto done_unmap_sg;
7798c2ecf20Sopenharmony_ci	}
7808c2ecf20Sopenharmony_ci	req_data_len = rsp_data_len = bsg_job->request_payload.payload_len;
7818c2ecf20Sopenharmony_ci	req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len,
7828c2ecf20Sopenharmony_ci		&req_data_dma, GFP_KERNEL);
7838c2ecf20Sopenharmony_ci	if (!req_data) {
7848c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x701d,
7858c2ecf20Sopenharmony_ci		    "dma alloc failed for req_data.\n");
7868c2ecf20Sopenharmony_ci		rval = -ENOMEM;
7878c2ecf20Sopenharmony_ci		goto done_unmap_sg;
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len,
7918c2ecf20Sopenharmony_ci		&rsp_data_dma, GFP_KERNEL);
7928c2ecf20Sopenharmony_ci	if (!rsp_data) {
7938c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7004,
7948c2ecf20Sopenharmony_ci		    "dma alloc failed for rsp_data.\n");
7958c2ecf20Sopenharmony_ci		rval = -ENOMEM;
7968c2ecf20Sopenharmony_ci		goto done_free_dma_req;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	/* Copy the request buffer in req_data now */
8008c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
8018c2ecf20Sopenharmony_ci		bsg_job->request_payload.sg_cnt, req_data, req_data_len);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	elreq.send_dma = req_data_dma;
8048c2ecf20Sopenharmony_ci	elreq.rcv_dma = rsp_data_dma;
8058c2ecf20Sopenharmony_ci	elreq.transfer_size = req_data_len;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	elreq.options = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
8088c2ecf20Sopenharmony_ci	elreq.iteration_count =
8098c2ecf20Sopenharmony_ci	    bsg_request->rqst_data.h_vendor.vendor_cmd[2];
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	if (atomic_read(&vha->loop_state) == LOOP_READY &&
8128c2ecf20Sopenharmony_ci	    ((ha->current_topology == ISP_CFG_F && (elreq.options & 7) >= 2) ||
8138c2ecf20Sopenharmony_ci	    ((IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) &&
8148c2ecf20Sopenharmony_ci	    get_unaligned_le32(req_data) == ELS_OPCODE_BYTE &&
8158c2ecf20Sopenharmony_ci	    req_data_len == MAX_ELS_FRAME_PAYLOAD &&
8168c2ecf20Sopenharmony_ci	    elreq.options == EXTERNAL_LOOPBACK))) {
8178c2ecf20Sopenharmony_ci		type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
8188c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x701e,
8198c2ecf20Sopenharmony_ci		    "BSG request type: %s.\n", type);
8208c2ecf20Sopenharmony_ci		command_sent = INT_DEF_LB_ECHO_CMD;
8218c2ecf20Sopenharmony_ci		rval = qla2x00_echo_test(vha, &elreq, response);
8228c2ecf20Sopenharmony_ci	} else {
8238c2ecf20Sopenharmony_ci		if (IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) {
8248c2ecf20Sopenharmony_ci			memset(config, 0, sizeof(config));
8258c2ecf20Sopenharmony_ci			memset(new_config, 0, sizeof(new_config));
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci			if (qla81xx_get_port_config(vha, config)) {
8288c2ecf20Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x701f,
8298c2ecf20Sopenharmony_ci				    "Get port config failed.\n");
8308c2ecf20Sopenharmony_ci				rval = -EPERM;
8318c2ecf20Sopenharmony_ci				goto done_free_dma_rsp;
8328c2ecf20Sopenharmony_ci			}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci			if ((config[0] & INTERNAL_LOOPBACK_MASK) != 0) {
8358c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_user, vha, 0x70c4,
8368c2ecf20Sopenharmony_ci				    "Loopback operation already in "
8378c2ecf20Sopenharmony_ci				    "progress.\n");
8388c2ecf20Sopenharmony_ci				rval = -EAGAIN;
8398c2ecf20Sopenharmony_ci				goto done_free_dma_rsp;
8408c2ecf20Sopenharmony_ci			}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x70c0,
8438c2ecf20Sopenharmony_ci			    "elreq.options=%04x\n", elreq.options);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci			if (elreq.options == EXTERNAL_LOOPBACK)
8468c2ecf20Sopenharmony_ci				if (IS_QLA8031(ha) || IS_QLA8044(ha))
8478c2ecf20Sopenharmony_ci					rval = qla81xx_set_loopback_mode(vha,
8488c2ecf20Sopenharmony_ci					    config, new_config, elreq.options);
8498c2ecf20Sopenharmony_ci				else
8508c2ecf20Sopenharmony_ci					rval = qla81xx_reset_loopback_mode(vha,
8518c2ecf20Sopenharmony_ci					    config, 1, 0);
8528c2ecf20Sopenharmony_ci			else
8538c2ecf20Sopenharmony_ci				rval = qla81xx_set_loopback_mode(vha, config,
8548c2ecf20Sopenharmony_ci				    new_config, elreq.options);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci			if (rval) {
8578c2ecf20Sopenharmony_ci				rval = -EPERM;
8588c2ecf20Sopenharmony_ci				goto done_free_dma_rsp;
8598c2ecf20Sopenharmony_ci			}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci			type = "FC_BSG_HST_VENDOR_LOOPBACK";
8628c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x7028,
8638c2ecf20Sopenharmony_ci			    "BSG request type: %s.\n", type);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci			command_sent = INT_DEF_LB_LOOPBACK_CMD;
8668c2ecf20Sopenharmony_ci			rval = qla2x00_loopback_test(vha, &elreq, response);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci			if (response[0] == MBS_COMMAND_ERROR &&
8698c2ecf20Sopenharmony_ci					response[1] == MBS_LB_RESET) {
8708c2ecf20Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x7029,
8718c2ecf20Sopenharmony_ci				    "MBX command error, Aborting ISP.\n");
8728c2ecf20Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
8738c2ecf20Sopenharmony_ci				qla2xxx_wake_dpc(vha);
8748c2ecf20Sopenharmony_ci				qla2x00_wait_for_chip_reset(vha);
8758c2ecf20Sopenharmony_ci				/* Also reset the MPI */
8768c2ecf20Sopenharmony_ci				if (IS_QLA81XX(ha)) {
8778c2ecf20Sopenharmony_ci					if (qla81xx_restart_mpi_firmware(vha) !=
8788c2ecf20Sopenharmony_ci					    QLA_SUCCESS) {
8798c2ecf20Sopenharmony_ci						ql_log(ql_log_warn, vha, 0x702a,
8808c2ecf20Sopenharmony_ci						    "MPI reset failed.\n");
8818c2ecf20Sopenharmony_ci					}
8828c2ecf20Sopenharmony_ci				}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci				rval = -EIO;
8858c2ecf20Sopenharmony_ci				goto done_free_dma_rsp;
8868c2ecf20Sopenharmony_ci			}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci			if (new_config[0]) {
8898c2ecf20Sopenharmony_ci				int ret;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci				/* Revert back to original port config
8928c2ecf20Sopenharmony_ci				 * Also clear internal loopback
8938c2ecf20Sopenharmony_ci				 */
8948c2ecf20Sopenharmony_ci				ret = qla81xx_reset_loopback_mode(vha,
8958c2ecf20Sopenharmony_ci				    new_config, 0, 1);
8968c2ecf20Sopenharmony_ci				if (ret) {
8978c2ecf20Sopenharmony_ci					/*
8988c2ecf20Sopenharmony_ci					 * If the reset of the loopback mode
8998c2ecf20Sopenharmony_ci					 * doesn't work take FCoE dump and then
9008c2ecf20Sopenharmony_ci					 * reset the chip.
9018c2ecf20Sopenharmony_ci					 */
9028c2ecf20Sopenharmony_ci					qla2xxx_dump_fw(vha);
9038c2ecf20Sopenharmony_ci					set_bit(ISP_ABORT_NEEDED,
9048c2ecf20Sopenharmony_ci					    &vha->dpc_flags);
9058c2ecf20Sopenharmony_ci				}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci			}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci		} else {
9108c2ecf20Sopenharmony_ci			type = "FC_BSG_HST_VENDOR_LOOPBACK";
9118c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x702b,
9128c2ecf20Sopenharmony_ci			    "BSG request type: %s.\n", type);
9138c2ecf20Sopenharmony_ci			command_sent = INT_DEF_LB_LOOPBACK_CMD;
9148c2ecf20Sopenharmony_ci			rval = qla2x00_loopback_test(vha, &elreq, response);
9158c2ecf20Sopenharmony_ci		}
9168c2ecf20Sopenharmony_ci	}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	if (rval) {
9198c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x702c,
9208c2ecf20Sopenharmony_ci		    "Vendor request %s failed.\n", type);
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci		rval = 0;
9238c2ecf20Sopenharmony_ci		bsg_reply->result = (DID_ERROR << 16);
9248c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len = 0;
9258c2ecf20Sopenharmony_ci	} else {
9268c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x702d,
9278c2ecf20Sopenharmony_ci		    "Vendor request %s completed.\n", type);
9288c2ecf20Sopenharmony_ci		bsg_reply->result = (DID_OK << 16);
9298c2ecf20Sopenharmony_ci		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
9308c2ecf20Sopenharmony_ci			bsg_job->reply_payload.sg_cnt, rsp_data,
9318c2ecf20Sopenharmony_ci			rsp_data_len);
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
9358c2ecf20Sopenharmony_ci	    sizeof(response) + sizeof(uint8_t);
9368c2ecf20Sopenharmony_ci	fw_sts_ptr = bsg_job->reply + sizeof(struct fc_bsg_reply);
9378c2ecf20Sopenharmony_ci	memcpy(bsg_job->reply + sizeof(struct fc_bsg_reply), response,
9388c2ecf20Sopenharmony_ci			sizeof(response));
9398c2ecf20Sopenharmony_ci	fw_sts_ptr += sizeof(response);
9408c2ecf20Sopenharmony_ci	*fw_sts_ptr = command_sent;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cidone_free_dma_rsp:
9438c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, rsp_data_len,
9448c2ecf20Sopenharmony_ci		rsp_data, rsp_data_dma);
9458c2ecf20Sopenharmony_cidone_free_dma_req:
9468c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, req_data_len,
9478c2ecf20Sopenharmony_ci		req_data, req_data_dma);
9488c2ecf20Sopenharmony_cidone_unmap_sg:
9498c2ecf20Sopenharmony_ci	dma_unmap_sg(&ha->pdev->dev,
9508c2ecf20Sopenharmony_ci	    bsg_job->reply_payload.sg_list,
9518c2ecf20Sopenharmony_ci	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
9528c2ecf20Sopenharmony_cidone_unmap_req_sg:
9538c2ecf20Sopenharmony_ci	dma_unmap_sg(&ha->pdev->dev,
9548c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_list,
9558c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
9568c2ecf20Sopenharmony_ci	if (!rval)
9578c2ecf20Sopenharmony_ci		bsg_job_done(bsg_job, bsg_reply->result,
9588c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
9598c2ecf20Sopenharmony_ci	return rval;
9608c2ecf20Sopenharmony_ci}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_cistatic int
9638c2ecf20Sopenharmony_ciqla84xx_reset(struct bsg_job *bsg_job)
9648c2ecf20Sopenharmony_ci{
9658c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
9668c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
9678c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
9688c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
9698c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
9708c2ecf20Sopenharmony_ci	int rval = 0;
9718c2ecf20Sopenharmony_ci	uint32_t flag;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	if (!IS_QLA84XX(ha)) {
9748c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x702f, "Not 84xx, exiting.\n");
9758c2ecf20Sopenharmony_ci		return -EINVAL;
9768c2ecf20Sopenharmony_ci	}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	flag = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	rval = qla84xx_reset_chip(vha, flag == A84_ISSUE_RESET_DIAG_FW);
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	if (rval) {
9838c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7030,
9848c2ecf20Sopenharmony_ci		    "Vendor request 84xx reset failed.\n");
9858c2ecf20Sopenharmony_ci		rval = (DID_ERROR << 16);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	} else {
9888c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7031,
9898c2ecf20Sopenharmony_ci		    "Vendor request 84xx reset completed.\n");
9908c2ecf20Sopenharmony_ci		bsg_reply->result = DID_OK;
9918c2ecf20Sopenharmony_ci		bsg_job_done(bsg_job, bsg_reply->result,
9928c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
9938c2ecf20Sopenharmony_ci	}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	return rval;
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic int
9998c2ecf20Sopenharmony_ciqla84xx_updatefw(struct bsg_job *bsg_job)
10008c2ecf20Sopenharmony_ci{
10018c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
10028c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
10038c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
10048c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
10058c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
10068c2ecf20Sopenharmony_ci	struct verify_chip_entry_84xx *mn = NULL;
10078c2ecf20Sopenharmony_ci	dma_addr_t mn_dma, fw_dma;
10088c2ecf20Sopenharmony_ci	void *fw_buf = NULL;
10098c2ecf20Sopenharmony_ci	int rval = 0;
10108c2ecf20Sopenharmony_ci	uint32_t sg_cnt;
10118c2ecf20Sopenharmony_ci	uint32_t data_len;
10128c2ecf20Sopenharmony_ci	uint16_t options;
10138c2ecf20Sopenharmony_ci	uint32_t flag;
10148c2ecf20Sopenharmony_ci	uint32_t fw_ver;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	if (!IS_QLA84XX(ha)) {
10178c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7032,
10188c2ecf20Sopenharmony_ci		    "Not 84xx, exiting.\n");
10198c2ecf20Sopenharmony_ci		return -EINVAL;
10208c2ecf20Sopenharmony_ci	}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
10238c2ecf20Sopenharmony_ci		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
10248c2ecf20Sopenharmony_ci	if (!sg_cnt) {
10258c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7033,
10268c2ecf20Sopenharmony_ci		    "dma_map_sg returned %d for request.\n", sg_cnt);
10278c2ecf20Sopenharmony_ci		return -ENOMEM;
10288c2ecf20Sopenharmony_ci	}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (sg_cnt != bsg_job->request_payload.sg_cnt) {
10318c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7034,
10328c2ecf20Sopenharmony_ci		    "DMA mapping resulted in different sg counts, "
10338c2ecf20Sopenharmony_ci		    "request_sg_cnt: %x dma_request_sg_cnt: %x.\n",
10348c2ecf20Sopenharmony_ci		    bsg_job->request_payload.sg_cnt, sg_cnt);
10358c2ecf20Sopenharmony_ci		rval = -EAGAIN;
10368c2ecf20Sopenharmony_ci		goto done_unmap_sg;
10378c2ecf20Sopenharmony_ci	}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	data_len = bsg_job->request_payload.payload_len;
10408c2ecf20Sopenharmony_ci	fw_buf = dma_alloc_coherent(&ha->pdev->dev, data_len,
10418c2ecf20Sopenharmony_ci		&fw_dma, GFP_KERNEL);
10428c2ecf20Sopenharmony_ci	if (!fw_buf) {
10438c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7035,
10448c2ecf20Sopenharmony_ci		    "DMA alloc failed for fw_buf.\n");
10458c2ecf20Sopenharmony_ci		rval = -ENOMEM;
10468c2ecf20Sopenharmony_ci		goto done_unmap_sg;
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
10508c2ecf20Sopenharmony_ci		bsg_job->request_payload.sg_cnt, fw_buf, data_len);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	mn = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
10538c2ecf20Sopenharmony_ci	if (!mn) {
10548c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7036,
10558c2ecf20Sopenharmony_ci		    "DMA alloc failed for fw buffer.\n");
10568c2ecf20Sopenharmony_ci		rval = -ENOMEM;
10578c2ecf20Sopenharmony_ci		goto done_free_fw_buf;
10588c2ecf20Sopenharmony_ci	}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	flag = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
10618c2ecf20Sopenharmony_ci	fw_ver = get_unaligned_le32((uint32_t *)fw_buf + 2);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	mn->entry_type = VERIFY_CHIP_IOCB_TYPE;
10648c2ecf20Sopenharmony_ci	mn->entry_count = 1;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	options = VCO_FORCE_UPDATE | VCO_END_OF_DATA;
10678c2ecf20Sopenharmony_ci	if (flag == A84_ISSUE_UPDATE_DIAGFW_CMD)
10688c2ecf20Sopenharmony_ci		options |= VCO_DIAG_FW;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	mn->options = cpu_to_le16(options);
10718c2ecf20Sopenharmony_ci	mn->fw_ver =  cpu_to_le32(fw_ver);
10728c2ecf20Sopenharmony_ci	mn->fw_size =  cpu_to_le32(data_len);
10738c2ecf20Sopenharmony_ci	mn->fw_seq_size =  cpu_to_le32(data_len);
10748c2ecf20Sopenharmony_ci	put_unaligned_le64(fw_dma, &mn->dsd.address);
10758c2ecf20Sopenharmony_ci	mn->dsd.length = cpu_to_le32(data_len);
10768c2ecf20Sopenharmony_ci	mn->data_seg_cnt = cpu_to_le16(1);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	if (rval) {
10818c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7037,
10828c2ecf20Sopenharmony_ci		    "Vendor request 84xx updatefw failed.\n");
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci		rval = (DID_ERROR << 16);
10858c2ecf20Sopenharmony_ci	} else {
10868c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7038,
10878c2ecf20Sopenharmony_ci		    "Vendor request 84xx updatefw completed.\n");
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci		bsg_job->reply_len = sizeof(struct fc_bsg_reply);
10908c2ecf20Sopenharmony_ci		bsg_reply->result = DID_OK;
10918c2ecf20Sopenharmony_ci	}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	dma_pool_free(ha->s_dma_pool, mn, mn_dma);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_cidone_free_fw_buf:
10968c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, data_len, fw_buf, fw_dma);
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_cidone_unmap_sg:
10998c2ecf20Sopenharmony_ci	dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
11008c2ecf20Sopenharmony_ci		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	if (!rval)
11038c2ecf20Sopenharmony_ci		bsg_job_done(bsg_job, bsg_reply->result,
11048c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
11058c2ecf20Sopenharmony_ci	return rval;
11068c2ecf20Sopenharmony_ci}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_cistatic int
11098c2ecf20Sopenharmony_ciqla84xx_mgmt_cmd(struct bsg_job *bsg_job)
11108c2ecf20Sopenharmony_ci{
11118c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
11128c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
11138c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
11148c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
11158c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
11168c2ecf20Sopenharmony_ci	struct access_chip_84xx *mn = NULL;
11178c2ecf20Sopenharmony_ci	dma_addr_t mn_dma, mgmt_dma;
11188c2ecf20Sopenharmony_ci	void *mgmt_b = NULL;
11198c2ecf20Sopenharmony_ci	int rval = 0;
11208c2ecf20Sopenharmony_ci	struct qla_bsg_a84_mgmt *ql84_mgmt;
11218c2ecf20Sopenharmony_ci	uint32_t sg_cnt;
11228c2ecf20Sopenharmony_ci	uint32_t data_len = 0;
11238c2ecf20Sopenharmony_ci	uint32_t dma_direction = DMA_NONE;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	if (!IS_QLA84XX(ha)) {
11268c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x703a,
11278c2ecf20Sopenharmony_ci		    "Not 84xx, exiting.\n");
11288c2ecf20Sopenharmony_ci		return -EINVAL;
11298c2ecf20Sopenharmony_ci	}
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	mn = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
11328c2ecf20Sopenharmony_ci	if (!mn) {
11338c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x703c,
11348c2ecf20Sopenharmony_ci		    "DMA alloc failed for fw buffer.\n");
11358c2ecf20Sopenharmony_ci		return -ENOMEM;
11368c2ecf20Sopenharmony_ci	}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	mn->entry_type = ACCESS_CHIP_IOCB_TYPE;
11398c2ecf20Sopenharmony_ci	mn->entry_count = 1;
11408c2ecf20Sopenharmony_ci	ql84_mgmt = (void *)bsg_request + sizeof(struct fc_bsg_request);
11418c2ecf20Sopenharmony_ci	switch (ql84_mgmt->mgmt.cmd) {
11428c2ecf20Sopenharmony_ci	case QLA84_MGMT_READ_MEM:
11438c2ecf20Sopenharmony_ci	case QLA84_MGMT_GET_INFO:
11448c2ecf20Sopenharmony_ci		sg_cnt = dma_map_sg(&ha->pdev->dev,
11458c2ecf20Sopenharmony_ci			bsg_job->reply_payload.sg_list,
11468c2ecf20Sopenharmony_ci			bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
11478c2ecf20Sopenharmony_ci		if (!sg_cnt) {
11488c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x703d,
11498c2ecf20Sopenharmony_ci			    "dma_map_sg returned %d for reply.\n", sg_cnt);
11508c2ecf20Sopenharmony_ci			rval = -ENOMEM;
11518c2ecf20Sopenharmony_ci			goto exit_mgmt;
11528c2ecf20Sopenharmony_ci		}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci		dma_direction = DMA_FROM_DEVICE;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci		if (sg_cnt != bsg_job->reply_payload.sg_cnt) {
11578c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x703e,
11588c2ecf20Sopenharmony_ci			    "DMA mapping resulted in different sg counts, "
11598c2ecf20Sopenharmony_ci			    "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n",
11608c2ecf20Sopenharmony_ci			    bsg_job->reply_payload.sg_cnt, sg_cnt);
11618c2ecf20Sopenharmony_ci			rval = -EAGAIN;
11628c2ecf20Sopenharmony_ci			goto done_unmap_sg;
11638c2ecf20Sopenharmony_ci		}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci		data_len = bsg_job->reply_payload.payload_len;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci		mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len,
11688c2ecf20Sopenharmony_ci		    &mgmt_dma, GFP_KERNEL);
11698c2ecf20Sopenharmony_ci		if (!mgmt_b) {
11708c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x703f,
11718c2ecf20Sopenharmony_ci			    "DMA alloc failed for mgmt_b.\n");
11728c2ecf20Sopenharmony_ci			rval = -ENOMEM;
11738c2ecf20Sopenharmony_ci			goto done_unmap_sg;
11748c2ecf20Sopenharmony_ci		}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci		if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) {
11778c2ecf20Sopenharmony_ci			mn->options = cpu_to_le16(ACO_DUMP_MEMORY);
11788c2ecf20Sopenharmony_ci			mn->parameter1 =
11798c2ecf20Sopenharmony_ci				cpu_to_le32(
11808c2ecf20Sopenharmony_ci				ql84_mgmt->mgmt.mgmtp.u.mem.start_addr);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci		} else if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO) {
11838c2ecf20Sopenharmony_ci			mn->options = cpu_to_le16(ACO_REQUEST_INFO);
11848c2ecf20Sopenharmony_ci			mn->parameter1 =
11858c2ecf20Sopenharmony_ci				cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.info.type);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci			mn->parameter2 =
11888c2ecf20Sopenharmony_ci				cpu_to_le32(
11898c2ecf20Sopenharmony_ci				ql84_mgmt->mgmt.mgmtp.u.info.context);
11908c2ecf20Sopenharmony_ci		}
11918c2ecf20Sopenharmony_ci		break;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	case QLA84_MGMT_WRITE_MEM:
11948c2ecf20Sopenharmony_ci		sg_cnt = dma_map_sg(&ha->pdev->dev,
11958c2ecf20Sopenharmony_ci			bsg_job->request_payload.sg_list,
11968c2ecf20Sopenharmony_ci			bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci		if (!sg_cnt) {
11998c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7040,
12008c2ecf20Sopenharmony_ci			    "dma_map_sg returned %d.\n", sg_cnt);
12018c2ecf20Sopenharmony_ci			rval = -ENOMEM;
12028c2ecf20Sopenharmony_ci			goto exit_mgmt;
12038c2ecf20Sopenharmony_ci		}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci		dma_direction = DMA_TO_DEVICE;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci		if (sg_cnt != bsg_job->request_payload.sg_cnt) {
12088c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7041,
12098c2ecf20Sopenharmony_ci			    "DMA mapping resulted in different sg counts, "
12108c2ecf20Sopenharmony_ci			    "request_sg_cnt: %x dma_request_sg_cnt: %x.\n",
12118c2ecf20Sopenharmony_ci			    bsg_job->request_payload.sg_cnt, sg_cnt);
12128c2ecf20Sopenharmony_ci			rval = -EAGAIN;
12138c2ecf20Sopenharmony_ci			goto done_unmap_sg;
12148c2ecf20Sopenharmony_ci		}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci		data_len = bsg_job->request_payload.payload_len;
12178c2ecf20Sopenharmony_ci		mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len,
12188c2ecf20Sopenharmony_ci			&mgmt_dma, GFP_KERNEL);
12198c2ecf20Sopenharmony_ci		if (!mgmt_b) {
12208c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7042,
12218c2ecf20Sopenharmony_ci			    "DMA alloc failed for mgmt_b.\n");
12228c2ecf20Sopenharmony_ci			rval = -ENOMEM;
12238c2ecf20Sopenharmony_ci			goto done_unmap_sg;
12248c2ecf20Sopenharmony_ci		}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci		sg_copy_to_buffer(bsg_job->request_payload.sg_list,
12278c2ecf20Sopenharmony_ci			bsg_job->request_payload.sg_cnt, mgmt_b, data_len);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci		mn->options = cpu_to_le16(ACO_LOAD_MEMORY);
12308c2ecf20Sopenharmony_ci		mn->parameter1 =
12318c2ecf20Sopenharmony_ci			cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.mem.start_addr);
12328c2ecf20Sopenharmony_ci		break;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	case QLA84_MGMT_CHNG_CONFIG:
12358c2ecf20Sopenharmony_ci		mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM);
12368c2ecf20Sopenharmony_ci		mn->parameter1 =
12378c2ecf20Sopenharmony_ci			cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.id);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci		mn->parameter2 =
12408c2ecf20Sopenharmony_ci			cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param0);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci		mn->parameter3 =
12438c2ecf20Sopenharmony_ci			cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param1);
12448c2ecf20Sopenharmony_ci		break;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	default:
12478c2ecf20Sopenharmony_ci		rval = -EIO;
12488c2ecf20Sopenharmony_ci		goto exit_mgmt;
12498c2ecf20Sopenharmony_ci	}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	if (ql84_mgmt->mgmt.cmd != QLA84_MGMT_CHNG_CONFIG) {
12528c2ecf20Sopenharmony_ci		mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->mgmt.len);
12538c2ecf20Sopenharmony_ci		mn->dseg_count = cpu_to_le16(1);
12548c2ecf20Sopenharmony_ci		put_unaligned_le64(mgmt_dma, &mn->dsd.address);
12558c2ecf20Sopenharmony_ci		mn->dsd.length = cpu_to_le32(ql84_mgmt->mgmt.len);
12568c2ecf20Sopenharmony_ci	}
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	rval = qla2x00_issue_iocb(vha, mn, mn_dma, 0);
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	if (rval) {
12618c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7043,
12628c2ecf20Sopenharmony_ci		    "Vendor request 84xx mgmt failed.\n");
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci		rval = (DID_ERROR << 16);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	} else {
12678c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7044,
12688c2ecf20Sopenharmony_ci		    "Vendor request 84xx mgmt completed.\n");
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		bsg_job->reply_len = sizeof(struct fc_bsg_reply);
12718c2ecf20Sopenharmony_ci		bsg_reply->result = DID_OK;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci		if ((ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) ||
12748c2ecf20Sopenharmony_ci			(ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO)) {
12758c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len =
12768c2ecf20Sopenharmony_ci				bsg_job->reply_payload.payload_len;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci			sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
12798c2ecf20Sopenharmony_ci				bsg_job->reply_payload.sg_cnt, mgmt_b,
12808c2ecf20Sopenharmony_ci				data_len);
12818c2ecf20Sopenharmony_ci		}
12828c2ecf20Sopenharmony_ci	}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_cidone_unmap_sg:
12858c2ecf20Sopenharmony_ci	if (mgmt_b)
12868c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, data_len, mgmt_b, mgmt_dma);
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	if (dma_direction == DMA_TO_DEVICE)
12898c2ecf20Sopenharmony_ci		dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
12908c2ecf20Sopenharmony_ci			bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
12918c2ecf20Sopenharmony_ci	else if (dma_direction == DMA_FROM_DEVICE)
12928c2ecf20Sopenharmony_ci		dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
12938c2ecf20Sopenharmony_ci			bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ciexit_mgmt:
12968c2ecf20Sopenharmony_ci	dma_pool_free(ha->s_dma_pool, mn, mn_dma);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	if (!rval)
12998c2ecf20Sopenharmony_ci		bsg_job_done(bsg_job, bsg_reply->result,
13008c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
13018c2ecf20Sopenharmony_ci	return rval;
13028c2ecf20Sopenharmony_ci}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_cistatic int
13058c2ecf20Sopenharmony_ciqla24xx_iidma(struct bsg_job *bsg_job)
13068c2ecf20Sopenharmony_ci{
13078c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
13088c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
13098c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
13108c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
13118c2ecf20Sopenharmony_ci	int rval = 0;
13128c2ecf20Sopenharmony_ci	struct qla_port_param *port_param = NULL;
13138c2ecf20Sopenharmony_ci	fc_port_t *fcport = NULL;
13148c2ecf20Sopenharmony_ci	int found = 0;
13158c2ecf20Sopenharmony_ci	uint16_t mb[MAILBOX_REGISTER_COUNT];
13168c2ecf20Sopenharmony_ci	uint8_t *rsp_ptr = NULL;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	if (!IS_IIDMA_CAPABLE(vha->hw)) {
13198c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x7046, "iiDMA not supported.\n");
13208c2ecf20Sopenharmony_ci		return -EINVAL;
13218c2ecf20Sopenharmony_ci	}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	port_param = (void *)bsg_request + sizeof(struct fc_bsg_request);
13248c2ecf20Sopenharmony_ci	if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) {
13258c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7048,
13268c2ecf20Sopenharmony_ci		    "Invalid destination type.\n");
13278c2ecf20Sopenharmony_ci		return -EINVAL;
13288c2ecf20Sopenharmony_ci	}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	list_for_each_entry(fcport, &vha->vp_fcports, list) {
13318c2ecf20Sopenharmony_ci		if (fcport->port_type != FCT_TARGET)
13328c2ecf20Sopenharmony_ci			continue;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci		if (memcmp(port_param->fc_scsi_addr.dest_addr.wwpn,
13358c2ecf20Sopenharmony_ci			fcport->port_name, sizeof(fcport->port_name)))
13368c2ecf20Sopenharmony_ci			continue;
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci		found = 1;
13398c2ecf20Sopenharmony_ci		break;
13408c2ecf20Sopenharmony_ci	}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	if (!found) {
13438c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7049,
13448c2ecf20Sopenharmony_ci		    "Failed to find port.\n");
13458c2ecf20Sopenharmony_ci		return -EINVAL;
13468c2ecf20Sopenharmony_ci	}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	if (atomic_read(&fcport->state) != FCS_ONLINE) {
13498c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x704a,
13508c2ecf20Sopenharmony_ci		    "Port is not online.\n");
13518c2ecf20Sopenharmony_ci		return -EINVAL;
13528c2ecf20Sopenharmony_ci	}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	if (fcport->flags & FCF_LOGIN_NEEDED) {
13558c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x704b,
13568c2ecf20Sopenharmony_ci		    "Remote port not logged in flags = 0x%x.\n", fcport->flags);
13578c2ecf20Sopenharmony_ci		return -EINVAL;
13588c2ecf20Sopenharmony_ci	}
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	if (port_param->mode)
13618c2ecf20Sopenharmony_ci		rval = qla2x00_set_idma_speed(vha, fcport->loop_id,
13628c2ecf20Sopenharmony_ci			port_param->speed, mb);
13638c2ecf20Sopenharmony_ci	else
13648c2ecf20Sopenharmony_ci		rval = qla2x00_get_idma_speed(vha, fcport->loop_id,
13658c2ecf20Sopenharmony_ci			&port_param->speed, mb);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	if (rval) {
13688c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x704c,
13698c2ecf20Sopenharmony_ci		    "iiDMA cmd failed for %8phN -- "
13708c2ecf20Sopenharmony_ci		    "%04x %x %04x %04x.\n", fcport->port_name,
13718c2ecf20Sopenharmony_ci		    rval, fcport->fp_speed, mb[0], mb[1]);
13728c2ecf20Sopenharmony_ci		rval = (DID_ERROR << 16);
13738c2ecf20Sopenharmony_ci	} else {
13748c2ecf20Sopenharmony_ci		if (!port_param->mode) {
13758c2ecf20Sopenharmony_ci			bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
13768c2ecf20Sopenharmony_ci				sizeof(struct qla_port_param);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci			rsp_ptr = ((uint8_t *)bsg_reply) +
13798c2ecf20Sopenharmony_ci				sizeof(struct fc_bsg_reply);
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci			memcpy(rsp_ptr, port_param,
13828c2ecf20Sopenharmony_ci				sizeof(struct qla_port_param));
13838c2ecf20Sopenharmony_ci		}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci		bsg_reply->result = DID_OK;
13868c2ecf20Sopenharmony_ci		bsg_job_done(bsg_job, bsg_reply->result,
13878c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
13888c2ecf20Sopenharmony_ci	}
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci	return rval;
13918c2ecf20Sopenharmony_ci}
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_cistatic int
13948c2ecf20Sopenharmony_ciqla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
13958c2ecf20Sopenharmony_ci	uint8_t is_update)
13968c2ecf20Sopenharmony_ci{
13978c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
13988c2ecf20Sopenharmony_ci	uint32_t start = 0;
13998c2ecf20Sopenharmony_ci	int valid = 0;
14008c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
14038c2ecf20Sopenharmony_ci		return -EINVAL;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
14068c2ecf20Sopenharmony_ci	if (start > ha->optrom_size) {
14078c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7055,
14088c2ecf20Sopenharmony_ci		    "start %d > optrom_size %d.\n", start, ha->optrom_size);
14098c2ecf20Sopenharmony_ci		return -EINVAL;
14108c2ecf20Sopenharmony_ci	}
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	if (ha->optrom_state != QLA_SWAITING) {
14138c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x7056,
14148c2ecf20Sopenharmony_ci		    "optrom_state %d.\n", ha->optrom_state);
14158c2ecf20Sopenharmony_ci		return -EBUSY;
14168c2ecf20Sopenharmony_ci	}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	ha->optrom_region_start = start;
14198c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_user, vha, 0x7057, "is_update=%d.\n", is_update);
14208c2ecf20Sopenharmony_ci	if (is_update) {
14218c2ecf20Sopenharmony_ci		if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
14228c2ecf20Sopenharmony_ci			valid = 1;
14238c2ecf20Sopenharmony_ci		else if (start == (ha->flt_region_boot * 4) ||
14248c2ecf20Sopenharmony_ci		    start == (ha->flt_region_fw * 4))
14258c2ecf20Sopenharmony_ci			valid = 1;
14268c2ecf20Sopenharmony_ci		else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
14278c2ecf20Sopenharmony_ci		    IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
14288c2ecf20Sopenharmony_ci		    IS_QLA28XX(ha))
14298c2ecf20Sopenharmony_ci			valid = 1;
14308c2ecf20Sopenharmony_ci		if (!valid) {
14318c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7058,
14328c2ecf20Sopenharmony_ci			    "Invalid start region 0x%x/0x%x.\n", start,
14338c2ecf20Sopenharmony_ci			    bsg_job->request_payload.payload_len);
14348c2ecf20Sopenharmony_ci			return -EINVAL;
14358c2ecf20Sopenharmony_ci		}
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci		ha->optrom_region_size = start +
14388c2ecf20Sopenharmony_ci		    bsg_job->request_payload.payload_len > ha->optrom_size ?
14398c2ecf20Sopenharmony_ci		    ha->optrom_size - start :
14408c2ecf20Sopenharmony_ci		    bsg_job->request_payload.payload_len;
14418c2ecf20Sopenharmony_ci		ha->optrom_state = QLA_SWRITING;
14428c2ecf20Sopenharmony_ci	} else {
14438c2ecf20Sopenharmony_ci		ha->optrom_region_size = start +
14448c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.payload_len > ha->optrom_size ?
14458c2ecf20Sopenharmony_ci		    ha->optrom_size - start :
14468c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.payload_len;
14478c2ecf20Sopenharmony_ci		ha->optrom_state = QLA_SREADING;
14488c2ecf20Sopenharmony_ci	}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	ha->optrom_buffer = vzalloc(ha->optrom_region_size);
14518c2ecf20Sopenharmony_ci	if (!ha->optrom_buffer) {
14528c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7059,
14538c2ecf20Sopenharmony_ci		    "Read: Unable to allocate memory for optrom retrieval "
14548c2ecf20Sopenharmony_ci		    "(%x)\n", ha->optrom_region_size);
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci		ha->optrom_state = QLA_SWAITING;
14578c2ecf20Sopenharmony_ci		return -ENOMEM;
14588c2ecf20Sopenharmony_ci	}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	return 0;
14618c2ecf20Sopenharmony_ci}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_cistatic int
14648c2ecf20Sopenharmony_ciqla2x00_read_optrom(struct bsg_job *bsg_job)
14658c2ecf20Sopenharmony_ci{
14668c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
14678c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
14688c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
14698c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
14708c2ecf20Sopenharmony_ci	int rval = 0;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	if (ha->flags.nic_core_reset_hdlr_active)
14738c2ecf20Sopenharmony_ci		return -EBUSY;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	mutex_lock(&ha->optrom_mutex);
14768c2ecf20Sopenharmony_ci	rval = qla2x00_optrom_setup(bsg_job, vha, 0);
14778c2ecf20Sopenharmony_ci	if (rval) {
14788c2ecf20Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
14798c2ecf20Sopenharmony_ci		return rval;
14808c2ecf20Sopenharmony_ci	}
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
14838c2ecf20Sopenharmony_ci	    ha->optrom_region_start, ha->optrom_region_size);
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
14868c2ecf20Sopenharmony_ci	    bsg_job->reply_payload.sg_cnt, ha->optrom_buffer,
14878c2ecf20Sopenharmony_ci	    ha->optrom_region_size);
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = ha->optrom_region_size;
14908c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK;
14918c2ecf20Sopenharmony_ci	vfree(ha->optrom_buffer);
14928c2ecf20Sopenharmony_ci	ha->optrom_buffer = NULL;
14938c2ecf20Sopenharmony_ci	ha->optrom_state = QLA_SWAITING;
14948c2ecf20Sopenharmony_ci	mutex_unlock(&ha->optrom_mutex);
14958c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
14968c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
14978c2ecf20Sopenharmony_ci	return rval;
14988c2ecf20Sopenharmony_ci}
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_cistatic int
15018c2ecf20Sopenharmony_ciqla2x00_update_optrom(struct bsg_job *bsg_job)
15028c2ecf20Sopenharmony_ci{
15038c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
15048c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
15058c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
15068c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
15078c2ecf20Sopenharmony_ci	int rval = 0;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	mutex_lock(&ha->optrom_mutex);
15108c2ecf20Sopenharmony_ci	rval = qla2x00_optrom_setup(bsg_job, vha, 1);
15118c2ecf20Sopenharmony_ci	if (rval) {
15128c2ecf20Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
15138c2ecf20Sopenharmony_ci		return rval;
15148c2ecf20Sopenharmony_ci	}
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	/* Set the isp82xx_no_md_cap not to capture minidump */
15178c2ecf20Sopenharmony_ci	ha->flags.isp82xx_no_md_cap = 1;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
15208c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
15218c2ecf20Sopenharmony_ci	    ha->optrom_region_size);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	rval = ha->isp_ops->write_optrom(vha, ha->optrom_buffer,
15248c2ecf20Sopenharmony_ci	    ha->optrom_region_start, ha->optrom_region_size);
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	if (rval) {
15278c2ecf20Sopenharmony_ci		bsg_reply->result = -EINVAL;
15288c2ecf20Sopenharmony_ci		rval = -EINVAL;
15298c2ecf20Sopenharmony_ci	} else {
15308c2ecf20Sopenharmony_ci		bsg_reply->result = DID_OK;
15318c2ecf20Sopenharmony_ci	}
15328c2ecf20Sopenharmony_ci	vfree(ha->optrom_buffer);
15338c2ecf20Sopenharmony_ci	ha->optrom_buffer = NULL;
15348c2ecf20Sopenharmony_ci	ha->optrom_state = QLA_SWAITING;
15358c2ecf20Sopenharmony_ci	mutex_unlock(&ha->optrom_mutex);
15368c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
15378c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
15388c2ecf20Sopenharmony_ci	return rval;
15398c2ecf20Sopenharmony_ci}
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_cistatic int
15428c2ecf20Sopenharmony_ciqla2x00_update_fru_versions(struct bsg_job *bsg_job)
15438c2ecf20Sopenharmony_ci{
15448c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
15458c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
15468c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
15478c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
15488c2ecf20Sopenharmony_ci	int rval = 0;
15498c2ecf20Sopenharmony_ci	uint8_t bsg[DMA_POOL_SIZE];
15508c2ecf20Sopenharmony_ci	struct qla_image_version_list *list = (void *)bsg;
15518c2ecf20Sopenharmony_ci	struct qla_image_version *image;
15528c2ecf20Sopenharmony_ci	uint32_t count;
15538c2ecf20Sopenharmony_ci	dma_addr_t sfp_dma;
15548c2ecf20Sopenharmony_ci	void *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	if (!sfp) {
15578c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
15588c2ecf20Sopenharmony_ci		    EXT_STATUS_NO_MEMORY;
15598c2ecf20Sopenharmony_ci		goto done;
15608c2ecf20Sopenharmony_ci	}
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
15638c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, list, sizeof(bsg));
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	image = list->version;
15668c2ecf20Sopenharmony_ci	count = list->count;
15678c2ecf20Sopenharmony_ci	while (count--) {
15688c2ecf20Sopenharmony_ci		memcpy(sfp, &image->field_info, sizeof(image->field_info));
15698c2ecf20Sopenharmony_ci		rval = qla2x00_write_sfp(vha, sfp_dma, sfp,
15708c2ecf20Sopenharmony_ci		    image->field_address.device, image->field_address.offset,
15718c2ecf20Sopenharmony_ci		    sizeof(image->field_info), image->field_address.option);
15728c2ecf20Sopenharmony_ci		if (rval) {
15738c2ecf20Sopenharmony_ci			bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
15748c2ecf20Sopenharmony_ci			    EXT_STATUS_MAILBOX;
15758c2ecf20Sopenharmony_ci			goto dealloc;
15768c2ecf20Sopenharmony_ci		}
15778c2ecf20Sopenharmony_ci		image++;
15788c2ecf20Sopenharmony_ci	}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0;
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_cidealloc:
15838c2ecf20Sopenharmony_ci	dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_cidone:
15868c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
15878c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
15888c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
15898c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	return 0;
15928c2ecf20Sopenharmony_ci}
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_cistatic int
15958c2ecf20Sopenharmony_ciqla2x00_read_fru_status(struct bsg_job *bsg_job)
15968c2ecf20Sopenharmony_ci{
15978c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
15988c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
15998c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
16008c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
16018c2ecf20Sopenharmony_ci	int rval = 0;
16028c2ecf20Sopenharmony_ci	uint8_t bsg[DMA_POOL_SIZE];
16038c2ecf20Sopenharmony_ci	struct qla_status_reg *sr = (void *)bsg;
16048c2ecf20Sopenharmony_ci	dma_addr_t sfp_dma;
16058c2ecf20Sopenharmony_ci	uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	if (!sfp) {
16088c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
16098c2ecf20Sopenharmony_ci		    EXT_STATUS_NO_MEMORY;
16108c2ecf20Sopenharmony_ci		goto done;
16118c2ecf20Sopenharmony_ci	}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
16148c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, sr, sizeof(*sr));
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	rval = qla2x00_read_sfp(vha, sfp_dma, sfp,
16178c2ecf20Sopenharmony_ci	    sr->field_address.device, sr->field_address.offset,
16188c2ecf20Sopenharmony_ci	    sizeof(sr->status_reg), sr->field_address.option);
16198c2ecf20Sopenharmony_ci	sr->status_reg = *sfp;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	if (rval) {
16228c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
16238c2ecf20Sopenharmony_ci		    EXT_STATUS_MAILBOX;
16248c2ecf20Sopenharmony_ci		goto dealloc;
16258c2ecf20Sopenharmony_ci	}
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
16288c2ecf20Sopenharmony_ci	    bsg_job->reply_payload.sg_cnt, sr, sizeof(*sr));
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0;
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_cidealloc:
16338c2ecf20Sopenharmony_ci	dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_cidone:
16368c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
16378c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = sizeof(*sr);
16388c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
16398c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
16408c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	return 0;
16438c2ecf20Sopenharmony_ci}
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_cistatic int
16468c2ecf20Sopenharmony_ciqla2x00_write_fru_status(struct bsg_job *bsg_job)
16478c2ecf20Sopenharmony_ci{
16488c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
16498c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
16508c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
16518c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
16528c2ecf20Sopenharmony_ci	int rval = 0;
16538c2ecf20Sopenharmony_ci	uint8_t bsg[DMA_POOL_SIZE];
16548c2ecf20Sopenharmony_ci	struct qla_status_reg *sr = (void *)bsg;
16558c2ecf20Sopenharmony_ci	dma_addr_t sfp_dma;
16568c2ecf20Sopenharmony_ci	uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	if (!sfp) {
16598c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
16608c2ecf20Sopenharmony_ci		    EXT_STATUS_NO_MEMORY;
16618c2ecf20Sopenharmony_ci		goto done;
16628c2ecf20Sopenharmony_ci	}
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
16658c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, sr, sizeof(*sr));
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	*sfp = sr->status_reg;
16688c2ecf20Sopenharmony_ci	rval = qla2x00_write_sfp(vha, sfp_dma, sfp,
16698c2ecf20Sopenharmony_ci	    sr->field_address.device, sr->field_address.offset,
16708c2ecf20Sopenharmony_ci	    sizeof(sr->status_reg), sr->field_address.option);
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	if (rval) {
16738c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
16748c2ecf20Sopenharmony_ci		    EXT_STATUS_MAILBOX;
16758c2ecf20Sopenharmony_ci		goto dealloc;
16768c2ecf20Sopenharmony_ci	}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0;
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_cidealloc:
16818c2ecf20Sopenharmony_ci	dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_cidone:
16848c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
16858c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
16868c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
16878c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	return 0;
16908c2ecf20Sopenharmony_ci}
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_cistatic int
16938c2ecf20Sopenharmony_ciqla2x00_write_i2c(struct bsg_job *bsg_job)
16948c2ecf20Sopenharmony_ci{
16958c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
16968c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
16978c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
16988c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
16998c2ecf20Sopenharmony_ci	int rval = 0;
17008c2ecf20Sopenharmony_ci	uint8_t bsg[DMA_POOL_SIZE];
17018c2ecf20Sopenharmony_ci	struct qla_i2c_access *i2c = (void *)bsg;
17028c2ecf20Sopenharmony_ci	dma_addr_t sfp_dma;
17038c2ecf20Sopenharmony_ci	uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	if (!sfp) {
17068c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
17078c2ecf20Sopenharmony_ci		    EXT_STATUS_NO_MEMORY;
17088c2ecf20Sopenharmony_ci		goto done;
17098c2ecf20Sopenharmony_ci	}
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
17128c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c));
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	memcpy(sfp, i2c->buffer, i2c->length);
17158c2ecf20Sopenharmony_ci	rval = qla2x00_write_sfp(vha, sfp_dma, sfp,
17168c2ecf20Sopenharmony_ci	    i2c->device, i2c->offset, i2c->length, i2c->option);
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	if (rval) {
17198c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
17208c2ecf20Sopenharmony_ci		    EXT_STATUS_MAILBOX;
17218c2ecf20Sopenharmony_ci		goto dealloc;
17228c2ecf20Sopenharmony_ci	}
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0;
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_cidealloc:
17278c2ecf20Sopenharmony_ci	dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_cidone:
17308c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
17318c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
17328c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
17338c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	return 0;
17368c2ecf20Sopenharmony_ci}
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_cistatic int
17398c2ecf20Sopenharmony_ciqla2x00_read_i2c(struct bsg_job *bsg_job)
17408c2ecf20Sopenharmony_ci{
17418c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
17428c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
17438c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
17448c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
17458c2ecf20Sopenharmony_ci	int rval = 0;
17468c2ecf20Sopenharmony_ci	uint8_t bsg[DMA_POOL_SIZE];
17478c2ecf20Sopenharmony_ci	struct qla_i2c_access *i2c = (void *)bsg;
17488c2ecf20Sopenharmony_ci	dma_addr_t sfp_dma;
17498c2ecf20Sopenharmony_ci	uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	if (!sfp) {
17528c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
17538c2ecf20Sopenharmony_ci		    EXT_STATUS_NO_MEMORY;
17548c2ecf20Sopenharmony_ci		goto done;
17558c2ecf20Sopenharmony_ci	}
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
17588c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c));
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	rval = qla2x00_read_sfp(vha, sfp_dma, sfp,
17618c2ecf20Sopenharmony_ci		i2c->device, i2c->offset, i2c->length, i2c->option);
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	if (rval) {
17648c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
17658c2ecf20Sopenharmony_ci		    EXT_STATUS_MAILBOX;
17668c2ecf20Sopenharmony_ci		goto dealloc;
17678c2ecf20Sopenharmony_ci	}
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci	memcpy(i2c->buffer, sfp, i2c->length);
17708c2ecf20Sopenharmony_ci	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
17718c2ecf20Sopenharmony_ci	    bsg_job->reply_payload.sg_cnt, i2c, sizeof(*i2c));
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0;
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_cidealloc:
17768c2ecf20Sopenharmony_ci	dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_cidone:
17798c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
17808c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = sizeof(*i2c);
17818c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
17828c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
17838c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	return 0;
17868c2ecf20Sopenharmony_ci}
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_cistatic int
17898c2ecf20Sopenharmony_ciqla24xx_process_bidir_cmd(struct bsg_job *bsg_job)
17908c2ecf20Sopenharmony_ci{
17918c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
17928c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
17938c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
17948c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
17958c2ecf20Sopenharmony_ci	uint32_t rval = EXT_STATUS_OK;
17968c2ecf20Sopenharmony_ci	uint16_t req_sg_cnt = 0;
17978c2ecf20Sopenharmony_ci	uint16_t rsp_sg_cnt = 0;
17988c2ecf20Sopenharmony_ci	uint16_t nextlid = 0;
17998c2ecf20Sopenharmony_ci	uint32_t tot_dsds;
18008c2ecf20Sopenharmony_ci	srb_t *sp = NULL;
18018c2ecf20Sopenharmony_ci	uint32_t req_data_len;
18028c2ecf20Sopenharmony_ci	uint32_t rsp_data_len;
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	/* Check the type of the adapter */
18058c2ecf20Sopenharmony_ci	if (!IS_BIDI_CAPABLE(ha)) {
18068c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70a0,
18078c2ecf20Sopenharmony_ci			"This adapter is not supported\n");
18088c2ecf20Sopenharmony_ci		rval = EXT_STATUS_NOT_SUPPORTED;
18098c2ecf20Sopenharmony_ci		goto done;
18108c2ecf20Sopenharmony_ci	}
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
18138c2ecf20Sopenharmony_ci		test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
18148c2ecf20Sopenharmony_ci		test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
18158c2ecf20Sopenharmony_ci		rval =  EXT_STATUS_BUSY;
18168c2ecf20Sopenharmony_ci		goto done;
18178c2ecf20Sopenharmony_ci	}
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	/* Check if host is online */
18208c2ecf20Sopenharmony_ci	if (!vha->flags.online) {
18218c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70a1,
18228c2ecf20Sopenharmony_ci			"Host is not online\n");
18238c2ecf20Sopenharmony_ci		rval = EXT_STATUS_DEVICE_OFFLINE;
18248c2ecf20Sopenharmony_ci		goto done;
18258c2ecf20Sopenharmony_ci	}
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	/* Check if cable is plugged in or not */
18288c2ecf20Sopenharmony_ci	if (vha->device_flags & DFLG_NO_CABLE) {
18298c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70a2,
18308c2ecf20Sopenharmony_ci			"Cable is unplugged...\n");
18318c2ecf20Sopenharmony_ci		rval = EXT_STATUS_INVALID_CFG;
18328c2ecf20Sopenharmony_ci		goto done;
18338c2ecf20Sopenharmony_ci	}
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	/* Check if the switch is connected or not */
18368c2ecf20Sopenharmony_ci	if (ha->current_topology != ISP_CFG_F) {
18378c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70a3,
18388c2ecf20Sopenharmony_ci			"Host is not connected to the switch\n");
18398c2ecf20Sopenharmony_ci		rval = EXT_STATUS_INVALID_CFG;
18408c2ecf20Sopenharmony_ci		goto done;
18418c2ecf20Sopenharmony_ci	}
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	/* Check if operating mode is P2P */
18448c2ecf20Sopenharmony_ci	if (ha->operating_mode != P2P) {
18458c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70a4,
18468c2ecf20Sopenharmony_ci		    "Host operating mode is not P2p\n");
18478c2ecf20Sopenharmony_ci		rval = EXT_STATUS_INVALID_CFG;
18488c2ecf20Sopenharmony_ci		goto done;
18498c2ecf20Sopenharmony_ci	}
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	mutex_lock(&ha->selflogin_lock);
18528c2ecf20Sopenharmony_ci	if (vha->self_login_loop_id == 0) {
18538c2ecf20Sopenharmony_ci		/* Initialize all required  fields of fcport */
18548c2ecf20Sopenharmony_ci		vha->bidir_fcport.vha = vha;
18558c2ecf20Sopenharmony_ci		vha->bidir_fcport.d_id.b.al_pa = vha->d_id.b.al_pa;
18568c2ecf20Sopenharmony_ci		vha->bidir_fcport.d_id.b.area = vha->d_id.b.area;
18578c2ecf20Sopenharmony_ci		vha->bidir_fcport.d_id.b.domain = vha->d_id.b.domain;
18588c2ecf20Sopenharmony_ci		vha->bidir_fcport.loop_id = vha->loop_id;
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci		if (qla2x00_fabric_login(vha, &(vha->bidir_fcport), &nextlid)) {
18618c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x70a7,
18628c2ecf20Sopenharmony_ci			    "Failed to login port %06X for bidirectional IOCB\n",
18638c2ecf20Sopenharmony_ci			    vha->bidir_fcport.d_id.b24);
18648c2ecf20Sopenharmony_ci			mutex_unlock(&ha->selflogin_lock);
18658c2ecf20Sopenharmony_ci			rval = EXT_STATUS_MAILBOX;
18668c2ecf20Sopenharmony_ci			goto done;
18678c2ecf20Sopenharmony_ci		}
18688c2ecf20Sopenharmony_ci		vha->self_login_loop_id = nextlid - 1;
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	}
18718c2ecf20Sopenharmony_ci	/* Assign the self login loop id to fcport */
18728c2ecf20Sopenharmony_ci	mutex_unlock(&ha->selflogin_lock);
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	vha->bidir_fcport.loop_id = vha->self_login_loop_id;
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci	req_sg_cnt = dma_map_sg(&ha->pdev->dev,
18778c2ecf20Sopenharmony_ci		bsg_job->request_payload.sg_list,
18788c2ecf20Sopenharmony_ci		bsg_job->request_payload.sg_cnt,
18798c2ecf20Sopenharmony_ci		DMA_TO_DEVICE);
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	if (!req_sg_cnt) {
18828c2ecf20Sopenharmony_ci		rval = EXT_STATUS_NO_MEMORY;
18838c2ecf20Sopenharmony_ci		goto done;
18848c2ecf20Sopenharmony_ci	}
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci	rsp_sg_cnt = dma_map_sg(&ha->pdev->dev,
18878c2ecf20Sopenharmony_ci		bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt,
18888c2ecf20Sopenharmony_ci		DMA_FROM_DEVICE);
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	if (!rsp_sg_cnt) {
18918c2ecf20Sopenharmony_ci		rval = EXT_STATUS_NO_MEMORY;
18928c2ecf20Sopenharmony_ci		goto done_unmap_req_sg;
18938c2ecf20Sopenharmony_ci	}
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
18968c2ecf20Sopenharmony_ci		(rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
18978c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70a9,
18988c2ecf20Sopenharmony_ci		    "Dma mapping resulted in different sg counts "
18998c2ecf20Sopenharmony_ci		    "[request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt: "
19008c2ecf20Sopenharmony_ci		    "%x dma_reply_sg_cnt: %x]\n",
19018c2ecf20Sopenharmony_ci		    bsg_job->request_payload.sg_cnt, req_sg_cnt,
19028c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);
19038c2ecf20Sopenharmony_ci		rval = EXT_STATUS_NO_MEMORY;
19048c2ecf20Sopenharmony_ci		goto done_unmap_sg;
19058c2ecf20Sopenharmony_ci	}
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	req_data_len = bsg_job->request_payload.payload_len;
19088c2ecf20Sopenharmony_ci	rsp_data_len = bsg_job->reply_payload.payload_len;
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	if (req_data_len != rsp_data_len) {
19118c2ecf20Sopenharmony_ci		rval = EXT_STATUS_BUSY;
19128c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70aa,
19138c2ecf20Sopenharmony_ci		    "req_data_len != rsp_data_len\n");
19148c2ecf20Sopenharmony_ci		goto done_unmap_sg;
19158c2ecf20Sopenharmony_ci	}
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	/* Alloc SRB structure */
19188c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp(vha, &(vha->bidir_fcport), GFP_KERNEL);
19198c2ecf20Sopenharmony_ci	if (!sp) {
19208c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70ac,
19218c2ecf20Sopenharmony_ci		    "Alloc SRB structure failed\n");
19228c2ecf20Sopenharmony_ci		rval = EXT_STATUS_NO_MEMORY;
19238c2ecf20Sopenharmony_ci		goto done_unmap_sg;
19248c2ecf20Sopenharmony_ci	}
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	/*Populate srb->ctx with bidir ctx*/
19278c2ecf20Sopenharmony_ci	sp->u.bsg_job = bsg_job;
19288c2ecf20Sopenharmony_ci	sp->free = qla2x00_bsg_sp_free;
19298c2ecf20Sopenharmony_ci	sp->type = SRB_BIDI_CMD;
19308c2ecf20Sopenharmony_ci	sp->done = qla2x00_bsg_job_done;
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	/* Add the read and write sg count */
19338c2ecf20Sopenharmony_ci	tot_dsds = rsp_sg_cnt + req_sg_cnt;
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	rval = qla2x00_start_bidir(sp, vha, tot_dsds);
19368c2ecf20Sopenharmony_ci	if (rval != EXT_STATUS_OK)
19378c2ecf20Sopenharmony_ci		goto done_free_srb;
19388c2ecf20Sopenharmony_ci	/* the bsg request  will be completed in the interrupt handler */
19398c2ecf20Sopenharmony_ci	return rval;
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_cidone_free_srb:
19428c2ecf20Sopenharmony_ci	mempool_free(sp, ha->srb_mempool);
19438c2ecf20Sopenharmony_cidone_unmap_sg:
19448c2ecf20Sopenharmony_ci	dma_unmap_sg(&ha->pdev->dev,
19458c2ecf20Sopenharmony_ci	    bsg_job->reply_payload.sg_list,
19468c2ecf20Sopenharmony_ci	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
19478c2ecf20Sopenharmony_cidone_unmap_req_sg:
19488c2ecf20Sopenharmony_ci	dma_unmap_sg(&ha->pdev->dev,
19498c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_list,
19508c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
19518c2ecf20Sopenharmony_cidone:
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	/* Return an error vendor specific response
19548c2ecf20Sopenharmony_ci	 * and complete the bsg request
19558c2ecf20Sopenharmony_ci	 */
19568c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;
19578c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
19588c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
19598c2ecf20Sopenharmony_ci	bsg_reply->result = (DID_OK) << 16;
19608c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
19618c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
19628c2ecf20Sopenharmony_ci	/* Always return success, vendor rsp carries correct status */
19638c2ecf20Sopenharmony_ci	return 0;
19648c2ecf20Sopenharmony_ci}
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_cistatic int
19678c2ecf20Sopenharmony_ciqlafx00_mgmt_cmd(struct bsg_job *bsg_job)
19688c2ecf20Sopenharmony_ci{
19698c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
19708c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
19718c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
19728c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
19738c2ecf20Sopenharmony_ci	int rval = (DID_ERROR << 16);
19748c2ecf20Sopenharmony_ci	struct qla_mt_iocb_rqst_fx00 *piocb_rqst;
19758c2ecf20Sopenharmony_ci	srb_t *sp;
19768c2ecf20Sopenharmony_ci	int req_sg_cnt = 0, rsp_sg_cnt = 0;
19778c2ecf20Sopenharmony_ci	struct fc_port *fcport;
19788c2ecf20Sopenharmony_ci	char  *type = "FC_BSG_HST_FX_MGMT";
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	/* Copy the IOCB specific information */
19818c2ecf20Sopenharmony_ci	piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
19828c2ecf20Sopenharmony_ci	    &bsg_request->rqst_data.h_vendor.vendor_cmd[1];
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	/* Dump the vendor information */
19858c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_user + ql_dbg_verbose , vha, 0x70cf,
19868c2ecf20Sopenharmony_ci	    piocb_rqst, sizeof(*piocb_rqst));
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci	if (!vha->flags.online) {
19898c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70d0,
19908c2ecf20Sopenharmony_ci		    "Host is not online.\n");
19918c2ecf20Sopenharmony_ci		rval = -EIO;
19928c2ecf20Sopenharmony_ci		goto done;
19938c2ecf20Sopenharmony_ci	}
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) {
19968c2ecf20Sopenharmony_ci		req_sg_cnt = dma_map_sg(&ha->pdev->dev,
19978c2ecf20Sopenharmony_ci		    bsg_job->request_payload.sg_list,
19988c2ecf20Sopenharmony_ci		    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
19998c2ecf20Sopenharmony_ci		if (!req_sg_cnt) {
20008c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x70c7,
20018c2ecf20Sopenharmony_ci			    "dma_map_sg return %d for request\n", req_sg_cnt);
20028c2ecf20Sopenharmony_ci			rval = -ENOMEM;
20038c2ecf20Sopenharmony_ci			goto done;
20048c2ecf20Sopenharmony_ci		}
20058c2ecf20Sopenharmony_ci	}
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci	if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) {
20088c2ecf20Sopenharmony_ci		rsp_sg_cnt = dma_map_sg(&ha->pdev->dev,
20098c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_list,
20108c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
20118c2ecf20Sopenharmony_ci		if (!rsp_sg_cnt) {
20128c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x70c8,
20138c2ecf20Sopenharmony_ci			    "dma_map_sg return %d for reply\n", rsp_sg_cnt);
20148c2ecf20Sopenharmony_ci			rval = -ENOMEM;
20158c2ecf20Sopenharmony_ci			goto done_unmap_req_sg;
20168c2ecf20Sopenharmony_ci		}
20178c2ecf20Sopenharmony_ci	}
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_user, vha, 0x70c9,
20208c2ecf20Sopenharmony_ci	    "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x "
20218c2ecf20Sopenharmony_ci	    "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt,
20228c2ecf20Sopenharmony_ci	    req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	/* Allocate a dummy fcport structure, since functions preparing the
20258c2ecf20Sopenharmony_ci	 * IOCB and mailbox command retrieves port specific information
20268c2ecf20Sopenharmony_ci	 * from fcport structure. For Host based ELS commands there will be
20278c2ecf20Sopenharmony_ci	 * no fcport structure allocated
20288c2ecf20Sopenharmony_ci	 */
20298c2ecf20Sopenharmony_ci	fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
20308c2ecf20Sopenharmony_ci	if (!fcport) {
20318c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70ca,
20328c2ecf20Sopenharmony_ci		    "Failed to allocate fcport.\n");
20338c2ecf20Sopenharmony_ci		rval = -ENOMEM;
20348c2ecf20Sopenharmony_ci		goto done_unmap_rsp_sg;
20358c2ecf20Sopenharmony_ci	}
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci	/* Alloc SRB structure */
20388c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
20398c2ecf20Sopenharmony_ci	if (!sp) {
20408c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70cb,
20418c2ecf20Sopenharmony_ci		    "qla2x00_get_sp failed.\n");
20428c2ecf20Sopenharmony_ci		rval = -ENOMEM;
20438c2ecf20Sopenharmony_ci		goto done_free_fcport;
20448c2ecf20Sopenharmony_ci	}
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	/* Initialize all required  fields of fcport */
20478c2ecf20Sopenharmony_ci	fcport->vha = vha;
20488c2ecf20Sopenharmony_ci	fcport->loop_id = le32_to_cpu(piocb_rqst->dataword);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	sp->type = SRB_FXIOCB_BCMD;
20518c2ecf20Sopenharmony_ci	sp->name = "bsg_fx_mgmt";
20528c2ecf20Sopenharmony_ci	sp->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt);
20538c2ecf20Sopenharmony_ci	sp->u.bsg_job = bsg_job;
20548c2ecf20Sopenharmony_ci	sp->free = qla2x00_bsg_sp_free;
20558c2ecf20Sopenharmony_ci	sp->done = qla2x00_bsg_job_done;
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_user, vha, 0x70cc,
20588c2ecf20Sopenharmony_ci	    "bsg rqst type: %s fx_mgmt_type: %x id=%x\n",
20598c2ecf20Sopenharmony_ci	    type, piocb_rqst->func_type, fcport->loop_id);
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	rval = qla2x00_start_sp(sp);
20628c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
20638c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70cd,
20648c2ecf20Sopenharmony_ci		    "qla2x00_start_sp failed=%d.\n", rval);
20658c2ecf20Sopenharmony_ci		mempool_free(sp, ha->srb_mempool);
20668c2ecf20Sopenharmony_ci		rval = -EIO;
20678c2ecf20Sopenharmony_ci		goto done_free_fcport;
20688c2ecf20Sopenharmony_ci	}
20698c2ecf20Sopenharmony_ci	return rval;
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_cidone_free_fcport:
20728c2ecf20Sopenharmony_ci	qla2x00_free_fcport(fcport);
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_cidone_unmap_rsp_sg:
20758c2ecf20Sopenharmony_ci	if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID)
20768c2ecf20Sopenharmony_ci		dma_unmap_sg(&ha->pdev->dev,
20778c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_list,
20788c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
20798c2ecf20Sopenharmony_cidone_unmap_req_sg:
20808c2ecf20Sopenharmony_ci	if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID)
20818c2ecf20Sopenharmony_ci		dma_unmap_sg(&ha->pdev->dev,
20828c2ecf20Sopenharmony_ci		    bsg_job->request_payload.sg_list,
20838c2ecf20Sopenharmony_ci		    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_cidone:
20868c2ecf20Sopenharmony_ci	return rval;
20878c2ecf20Sopenharmony_ci}
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_cistatic int
20908c2ecf20Sopenharmony_ciqla26xx_serdes_op(struct bsg_job *bsg_job)
20918c2ecf20Sopenharmony_ci{
20928c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
20938c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
20948c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
20958c2ecf20Sopenharmony_ci	int rval = 0;
20968c2ecf20Sopenharmony_ci	struct qla_serdes_reg sr;
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci	memset(&sr, 0, sizeof(sr));
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
21018c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, &sr, sizeof(sr));
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci	switch (sr.cmd) {
21048c2ecf20Sopenharmony_ci	case INT_SC_SERDES_WRITE_REG:
21058c2ecf20Sopenharmony_ci		rval = qla2x00_write_serdes_word(vha, sr.addr, sr.val);
21068c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len = 0;
21078c2ecf20Sopenharmony_ci		break;
21088c2ecf20Sopenharmony_ci	case INT_SC_SERDES_READ_REG:
21098c2ecf20Sopenharmony_ci		rval = qla2x00_read_serdes_word(vha, sr.addr, &sr.val);
21108c2ecf20Sopenharmony_ci		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
21118c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_cnt, &sr, sizeof(sr));
21128c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len = sizeof(sr);
21138c2ecf20Sopenharmony_ci		break;
21148c2ecf20Sopenharmony_ci	default:
21158c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x708c,
21168c2ecf20Sopenharmony_ci		    "Unknown serdes cmd %x.\n", sr.cmd);
21178c2ecf20Sopenharmony_ci		rval = -EINVAL;
21188c2ecf20Sopenharmony_ci		break;
21198c2ecf20Sopenharmony_ci	}
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
21228c2ecf20Sopenharmony_ci	    rval ? EXT_STATUS_MAILBOX : 0;
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
21258c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
21268c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
21278c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
21288c2ecf20Sopenharmony_ci	return 0;
21298c2ecf20Sopenharmony_ci}
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_cistatic int
21328c2ecf20Sopenharmony_ciqla8044_serdes_op(struct bsg_job *bsg_job)
21338c2ecf20Sopenharmony_ci{
21348c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
21358c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
21368c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
21378c2ecf20Sopenharmony_ci	int rval = 0;
21388c2ecf20Sopenharmony_ci	struct qla_serdes_reg_ex sr;
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	memset(&sr, 0, sizeof(sr));
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
21438c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, &sr, sizeof(sr));
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci	switch (sr.cmd) {
21468c2ecf20Sopenharmony_ci	case INT_SC_SERDES_WRITE_REG:
21478c2ecf20Sopenharmony_ci		rval = qla8044_write_serdes_word(vha, sr.addr, sr.val);
21488c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len = 0;
21498c2ecf20Sopenharmony_ci		break;
21508c2ecf20Sopenharmony_ci	case INT_SC_SERDES_READ_REG:
21518c2ecf20Sopenharmony_ci		rval = qla8044_read_serdes_word(vha, sr.addr, &sr.val);
21528c2ecf20Sopenharmony_ci		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
21538c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_cnt, &sr, sizeof(sr));
21548c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len = sizeof(sr);
21558c2ecf20Sopenharmony_ci		break;
21568c2ecf20Sopenharmony_ci	default:
21578c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7020,
21588c2ecf20Sopenharmony_ci		    "Unknown serdes cmd %x.\n", sr.cmd);
21598c2ecf20Sopenharmony_ci		rval = -EINVAL;
21608c2ecf20Sopenharmony_ci		break;
21618c2ecf20Sopenharmony_ci	}
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
21648c2ecf20Sopenharmony_ci	    rval ? EXT_STATUS_MAILBOX : 0;
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
21678c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
21688c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
21698c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
21708c2ecf20Sopenharmony_ci	return 0;
21718c2ecf20Sopenharmony_ci}
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_cistatic int
21748c2ecf20Sopenharmony_ciqla27xx_get_flash_upd_cap(struct bsg_job *bsg_job)
21758c2ecf20Sopenharmony_ci{
21768c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
21778c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
21788c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
21798c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
21808c2ecf20Sopenharmony_ci	struct qla_flash_update_caps cap;
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	if (!(IS_QLA27XX(ha)) && !IS_QLA28XX(ha))
21838c2ecf20Sopenharmony_ci		return -EPERM;
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	memset(&cap, 0, sizeof(cap));
21868c2ecf20Sopenharmony_ci	cap.capabilities = (uint64_t)ha->fw_attributes_ext[1] << 48 |
21878c2ecf20Sopenharmony_ci			   (uint64_t)ha->fw_attributes_ext[0] << 32 |
21888c2ecf20Sopenharmony_ci			   (uint64_t)ha->fw_attributes_h << 16 |
21898c2ecf20Sopenharmony_ci			   (uint64_t)ha->fw_attributes;
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
21928c2ecf20Sopenharmony_ci	    bsg_job->reply_payload.sg_cnt, &cap, sizeof(cap));
21938c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = sizeof(cap);
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
21968c2ecf20Sopenharmony_ci	    EXT_STATUS_OK;
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
21998c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
22008c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
22018c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
22028c2ecf20Sopenharmony_ci	return 0;
22038c2ecf20Sopenharmony_ci}
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_cistatic int
22068c2ecf20Sopenharmony_ciqla27xx_set_flash_upd_cap(struct bsg_job *bsg_job)
22078c2ecf20Sopenharmony_ci{
22088c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
22098c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
22108c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
22118c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
22128c2ecf20Sopenharmony_ci	uint64_t online_fw_attr = 0;
22138c2ecf20Sopenharmony_ci	struct qla_flash_update_caps cap;
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
22168c2ecf20Sopenharmony_ci		return -EPERM;
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci	memset(&cap, 0, sizeof(cap));
22198c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
22208c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, &cap, sizeof(cap));
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci	online_fw_attr = (uint64_t)ha->fw_attributes_ext[1] << 48 |
22238c2ecf20Sopenharmony_ci			 (uint64_t)ha->fw_attributes_ext[0] << 32 |
22248c2ecf20Sopenharmony_ci			 (uint64_t)ha->fw_attributes_h << 16 |
22258c2ecf20Sopenharmony_ci			 (uint64_t)ha->fw_attributes;
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	if (online_fw_attr != cap.capabilities) {
22288c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
22298c2ecf20Sopenharmony_ci		    EXT_STATUS_INVALID_PARAM;
22308c2ecf20Sopenharmony_ci		return -EINVAL;
22318c2ecf20Sopenharmony_ci	}
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	if (cap.outage_duration < MAX_LOOP_TIMEOUT)  {
22348c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
22358c2ecf20Sopenharmony_ci		    EXT_STATUS_INVALID_PARAM;
22368c2ecf20Sopenharmony_ci		return -EINVAL;
22378c2ecf20Sopenharmony_ci	}
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
22428c2ecf20Sopenharmony_ci	    EXT_STATUS_OK;
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
22458c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
22468c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
22478c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
22488c2ecf20Sopenharmony_ci	return 0;
22498c2ecf20Sopenharmony_ci}
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_cistatic int
22528c2ecf20Sopenharmony_ciqla27xx_get_bbcr_data(struct bsg_job *bsg_job)
22538c2ecf20Sopenharmony_ci{
22548c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
22558c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
22568c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
22578c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
22588c2ecf20Sopenharmony_ci	struct qla_bbcr_data bbcr;
22598c2ecf20Sopenharmony_ci	uint16_t loop_id, topo, sw_cap;
22608c2ecf20Sopenharmony_ci	uint8_t domain, area, al_pa, state;
22618c2ecf20Sopenharmony_ci	int rval;
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
22648c2ecf20Sopenharmony_ci		return -EPERM;
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci	memset(&bbcr, 0, sizeof(bbcr));
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci	if (vha->flags.bbcr_enable)
22698c2ecf20Sopenharmony_ci		bbcr.status = QLA_BBCR_STATUS_ENABLED;
22708c2ecf20Sopenharmony_ci	else
22718c2ecf20Sopenharmony_ci		bbcr.status = QLA_BBCR_STATUS_DISABLED;
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	if (bbcr.status == QLA_BBCR_STATUS_ENABLED) {
22748c2ecf20Sopenharmony_ci		rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa,
22758c2ecf20Sopenharmony_ci			&area, &domain, &topo, &sw_cap);
22768c2ecf20Sopenharmony_ci		if (rval != QLA_SUCCESS) {
22778c2ecf20Sopenharmony_ci			bbcr.status = QLA_BBCR_STATUS_UNKNOWN;
22788c2ecf20Sopenharmony_ci			bbcr.state = QLA_BBCR_STATE_OFFLINE;
22798c2ecf20Sopenharmony_ci			bbcr.mbx1 = loop_id;
22808c2ecf20Sopenharmony_ci			goto done;
22818c2ecf20Sopenharmony_ci		}
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci		state = (vha->bbcr >> 12) & 0x1;
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci		if (state) {
22868c2ecf20Sopenharmony_ci			bbcr.state = QLA_BBCR_STATE_OFFLINE;
22878c2ecf20Sopenharmony_ci			bbcr.offline_reason_code = QLA_BBCR_REASON_LOGIN_REJECT;
22888c2ecf20Sopenharmony_ci		} else {
22898c2ecf20Sopenharmony_ci			bbcr.state = QLA_BBCR_STATE_ONLINE;
22908c2ecf20Sopenharmony_ci			bbcr.negotiated_bbscn = (vha->bbcr >> 8) & 0xf;
22918c2ecf20Sopenharmony_ci		}
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci		bbcr.configured_bbscn = vha->bbcr & 0xf;
22948c2ecf20Sopenharmony_ci	}
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_cidone:
22978c2ecf20Sopenharmony_ci	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
22988c2ecf20Sopenharmony_ci		bsg_job->reply_payload.sg_cnt, &bbcr, sizeof(bbcr));
22998c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = sizeof(bbcr);
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
23028c2ecf20Sopenharmony_ci
23038c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
23048c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
23058c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
23068c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
23078c2ecf20Sopenharmony_ci	return 0;
23088c2ecf20Sopenharmony_ci}
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_cistatic int
23118c2ecf20Sopenharmony_ciqla2x00_get_priv_stats(struct bsg_job *bsg_job)
23128c2ecf20Sopenharmony_ci{
23138c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
23148c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
23158c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
23168c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
23178c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
23188c2ecf20Sopenharmony_ci	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
23198c2ecf20Sopenharmony_ci	struct link_statistics *stats = NULL;
23208c2ecf20Sopenharmony_ci	dma_addr_t stats_dma;
23218c2ecf20Sopenharmony_ci	int rval;
23228c2ecf20Sopenharmony_ci	uint32_t *cmd = bsg_request->rqst_data.h_vendor.vendor_cmd;
23238c2ecf20Sopenharmony_ci	uint options = cmd[0] == QL_VND_GET_PRIV_STATS_EX ? cmd[1] : 0;
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	if (test_bit(UNLOADING, &vha->dpc_flags))
23268c2ecf20Sopenharmony_ci		return -ENODEV;
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
23298c2ecf20Sopenharmony_ci		return -ENODEV;
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_ci	if (qla2x00_reset_active(vha))
23328c2ecf20Sopenharmony_ci		return -EBUSY;
23338c2ecf20Sopenharmony_ci
23348c2ecf20Sopenharmony_ci	if (!IS_FWI2_CAPABLE(ha))
23358c2ecf20Sopenharmony_ci		return -EPERM;
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	stats = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stats), &stats_dma,
23388c2ecf20Sopenharmony_ci				   GFP_KERNEL);
23398c2ecf20Sopenharmony_ci	if (!stats) {
23408c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70e2,
23418c2ecf20Sopenharmony_ci		    "Failed to allocate memory for stats.\n");
23428c2ecf20Sopenharmony_ci		return -ENOMEM;
23438c2ecf20Sopenharmony_ci	}
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, options);
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ci	if (rval == QLA_SUCCESS) {
23488c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e5,
23498c2ecf20Sopenharmony_ci			stats, sizeof(*stats));
23508c2ecf20Sopenharmony_ci		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
23518c2ecf20Sopenharmony_ci			bsg_job->reply_payload.sg_cnt, stats, sizeof(*stats));
23528c2ecf20Sopenharmony_ci	}
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = sizeof(*stats);
23558c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
23568c2ecf20Sopenharmony_ci	    rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK;
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(*bsg_reply);
23598c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
23608c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
23618c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(*stats),
23648c2ecf20Sopenharmony_ci		stats, stats_dma);
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci	return 0;
23678c2ecf20Sopenharmony_ci}
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_cistatic int
23708c2ecf20Sopenharmony_ciqla2x00_do_dport_diagnostics(struct bsg_job *bsg_job)
23718c2ecf20Sopenharmony_ci{
23728c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
23738c2ecf20Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
23748c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
23758c2ecf20Sopenharmony_ci	int rval;
23768c2ecf20Sopenharmony_ci	struct qla_dport_diag *dd;
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci	if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
23798c2ecf20Sopenharmony_ci	    !IS_QLA28XX(vha->hw))
23808c2ecf20Sopenharmony_ci		return -EPERM;
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci	dd = kmalloc(sizeof(*dd), GFP_KERNEL);
23838c2ecf20Sopenharmony_ci	if (!dd) {
23848c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70db,
23858c2ecf20Sopenharmony_ci		    "Failed to allocate memory for dport.\n");
23868c2ecf20Sopenharmony_ci		return -ENOMEM;
23878c2ecf20Sopenharmony_ci	}
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
23908c2ecf20Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, dd, sizeof(*dd));
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci	rval = qla26xx_dport_diagnostics(
23938c2ecf20Sopenharmony_ci	    vha, dd->buf, sizeof(dd->buf), dd->options);
23948c2ecf20Sopenharmony_ci	if (rval == QLA_SUCCESS) {
23958c2ecf20Sopenharmony_ci		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
23968c2ecf20Sopenharmony_ci		    bsg_job->reply_payload.sg_cnt, dd, sizeof(*dd));
23978c2ecf20Sopenharmony_ci	}
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = sizeof(*dd);
24008c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
24018c2ecf20Sopenharmony_ci	    rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK;
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(*bsg_reply);
24048c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
24058c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
24068c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci	kfree(dd);
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci	return 0;
24118c2ecf20Sopenharmony_ci}
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_cistatic int
24148c2ecf20Sopenharmony_ciqla2x00_get_flash_image_status(struct bsg_job *bsg_job)
24158c2ecf20Sopenharmony_ci{
24168c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
24178c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
24188c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
24198c2ecf20Sopenharmony_ci	struct qla_active_regions regions = { };
24208c2ecf20Sopenharmony_ci	struct active_regions active_regions = { };
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci	qla27xx_get_active_image(vha, &active_regions);
24238c2ecf20Sopenharmony_ci	regions.global_image = active_regions.global;
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	if (IS_QLA28XX(ha)) {
24268c2ecf20Sopenharmony_ci		qla28xx_get_aux_images(vha, &active_regions);
24278c2ecf20Sopenharmony_ci		regions.board_config = active_regions.aux.board_config;
24288c2ecf20Sopenharmony_ci		regions.vpd_nvram = active_regions.aux.vpd_nvram;
24298c2ecf20Sopenharmony_ci		regions.npiv_config_0_1 = active_regions.aux.npiv_config_0_1;
24308c2ecf20Sopenharmony_ci		regions.npiv_config_2_3 = active_regions.aux.npiv_config_2_3;
24318c2ecf20Sopenharmony_ci	}
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_user, vha, 0x70e1,
24348c2ecf20Sopenharmony_ci	    "%s(%lu): FW=%u BCFG=%u VPDNVR=%u NPIV01=%u NPIV02=%u\n",
24358c2ecf20Sopenharmony_ci	    __func__, vha->host_no, regions.global_image,
24368c2ecf20Sopenharmony_ci	    regions.board_config, regions.vpd_nvram,
24378c2ecf20Sopenharmony_ci	    regions.npiv_config_0_1, regions.npiv_config_2_3);
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
24408c2ecf20Sopenharmony_ci	    bsg_job->reply_payload.sg_cnt, &regions, sizeof(regions));
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
24438c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = sizeof(regions);
24448c2ecf20Sopenharmony_ci	bsg_reply->result = DID_OK << 16;
24458c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
24468c2ecf20Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
24478c2ecf20Sopenharmony_ci	    bsg_reply->reply_payload_rcv_len);
24488c2ecf20Sopenharmony_ci
24498c2ecf20Sopenharmony_ci	return 0;
24508c2ecf20Sopenharmony_ci}
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_cistatic int
24538c2ecf20Sopenharmony_ciqla2x00_process_vendor_specific(struct bsg_job *bsg_job)
24548c2ecf20Sopenharmony_ci{
24558c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci	switch (bsg_request->rqst_data.h_vendor.vendor_cmd[0]) {
24588c2ecf20Sopenharmony_ci	case QL_VND_LOOPBACK:
24598c2ecf20Sopenharmony_ci		return qla2x00_process_loopback(bsg_job);
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	case QL_VND_A84_RESET:
24628c2ecf20Sopenharmony_ci		return qla84xx_reset(bsg_job);
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_ci	case QL_VND_A84_UPDATE_FW:
24658c2ecf20Sopenharmony_ci		return qla84xx_updatefw(bsg_job);
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	case QL_VND_A84_MGMT_CMD:
24688c2ecf20Sopenharmony_ci		return qla84xx_mgmt_cmd(bsg_job);
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_ci	case QL_VND_IIDMA:
24718c2ecf20Sopenharmony_ci		return qla24xx_iidma(bsg_job);
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_ci	case QL_VND_FCP_PRIO_CFG_CMD:
24748c2ecf20Sopenharmony_ci		return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job);
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci	case QL_VND_READ_FLASH:
24778c2ecf20Sopenharmony_ci		return qla2x00_read_optrom(bsg_job);
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci	case QL_VND_UPDATE_FLASH:
24808c2ecf20Sopenharmony_ci		return qla2x00_update_optrom(bsg_job);
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci	case QL_VND_SET_FRU_VERSION:
24838c2ecf20Sopenharmony_ci		return qla2x00_update_fru_versions(bsg_job);
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci	case QL_VND_READ_FRU_STATUS:
24868c2ecf20Sopenharmony_ci		return qla2x00_read_fru_status(bsg_job);
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	case QL_VND_WRITE_FRU_STATUS:
24898c2ecf20Sopenharmony_ci		return qla2x00_write_fru_status(bsg_job);
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci	case QL_VND_WRITE_I2C:
24928c2ecf20Sopenharmony_ci		return qla2x00_write_i2c(bsg_job);
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	case QL_VND_READ_I2C:
24958c2ecf20Sopenharmony_ci		return qla2x00_read_i2c(bsg_job);
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci	case QL_VND_DIAG_IO_CMD:
24988c2ecf20Sopenharmony_ci		return qla24xx_process_bidir_cmd(bsg_job);
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	case QL_VND_FX00_MGMT_CMD:
25018c2ecf20Sopenharmony_ci		return qlafx00_mgmt_cmd(bsg_job);
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_ci	case QL_VND_SERDES_OP:
25048c2ecf20Sopenharmony_ci		return qla26xx_serdes_op(bsg_job);
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_ci	case QL_VND_SERDES_OP_EX:
25078c2ecf20Sopenharmony_ci		return qla8044_serdes_op(bsg_job);
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci	case QL_VND_GET_FLASH_UPDATE_CAPS:
25108c2ecf20Sopenharmony_ci		return qla27xx_get_flash_upd_cap(bsg_job);
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci	case QL_VND_SET_FLASH_UPDATE_CAPS:
25138c2ecf20Sopenharmony_ci		return qla27xx_set_flash_upd_cap(bsg_job);
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	case QL_VND_GET_BBCR_DATA:
25168c2ecf20Sopenharmony_ci		return qla27xx_get_bbcr_data(bsg_job);
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	case QL_VND_GET_PRIV_STATS:
25198c2ecf20Sopenharmony_ci	case QL_VND_GET_PRIV_STATS_EX:
25208c2ecf20Sopenharmony_ci		return qla2x00_get_priv_stats(bsg_job);
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	case QL_VND_DPORT_DIAGNOSTICS:
25238c2ecf20Sopenharmony_ci		return qla2x00_do_dport_diagnostics(bsg_job);
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci	case QL_VND_SS_GET_FLASH_IMAGE_STATUS:
25268c2ecf20Sopenharmony_ci		return qla2x00_get_flash_image_status(bsg_job);
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	default:
25298c2ecf20Sopenharmony_ci		return -ENOSYS;
25308c2ecf20Sopenharmony_ci	}
25318c2ecf20Sopenharmony_ci}
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ciint
25348c2ecf20Sopenharmony_ciqla24xx_bsg_request(struct bsg_job *bsg_job)
25358c2ecf20Sopenharmony_ci{
25368c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
25378c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
25388c2ecf20Sopenharmony_ci	int ret = -EINVAL;
25398c2ecf20Sopenharmony_ci	struct fc_rport *rport;
25408c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
25418c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha;
25428c2ecf20Sopenharmony_ci
25438c2ecf20Sopenharmony_ci	/* In case no data transferred. */
25448c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	if (bsg_request->msgcode == FC_BSG_RPT_ELS) {
25478c2ecf20Sopenharmony_ci		rport = fc_bsg_to_rport(bsg_job);
25488c2ecf20Sopenharmony_ci		if (!rport)
25498c2ecf20Sopenharmony_ci			return ret;
25508c2ecf20Sopenharmony_ci		host = rport_to_shost(rport);
25518c2ecf20Sopenharmony_ci		vha = shost_priv(host);
25528c2ecf20Sopenharmony_ci	} else {
25538c2ecf20Sopenharmony_ci		host = fc_bsg_to_shost(bsg_job);
25548c2ecf20Sopenharmony_ci		vha = shost_priv(host);
25558c2ecf20Sopenharmony_ci	}
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
25588c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x709f,
25598c2ecf20Sopenharmony_ci		    "BSG: ISP abort active/needed -- cmd=%d.\n",
25608c2ecf20Sopenharmony_ci		    bsg_request->msgcode);
25618c2ecf20Sopenharmony_ci		return -EBUSY;
25628c2ecf20Sopenharmony_ci	}
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_user, vha, 0x7000,
25658c2ecf20Sopenharmony_ci	    "Entered %s msgcode=0x%x.\n", __func__, bsg_request->msgcode);
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci	switch (bsg_request->msgcode) {
25688c2ecf20Sopenharmony_ci	case FC_BSG_RPT_ELS:
25698c2ecf20Sopenharmony_ci	case FC_BSG_HST_ELS_NOLOGIN:
25708c2ecf20Sopenharmony_ci		ret = qla2x00_process_els(bsg_job);
25718c2ecf20Sopenharmony_ci		break;
25728c2ecf20Sopenharmony_ci	case FC_BSG_HST_CT:
25738c2ecf20Sopenharmony_ci		ret = qla2x00_process_ct(bsg_job);
25748c2ecf20Sopenharmony_ci		break;
25758c2ecf20Sopenharmony_ci	case FC_BSG_HST_VENDOR:
25768c2ecf20Sopenharmony_ci		ret = qla2x00_process_vendor_specific(bsg_job);
25778c2ecf20Sopenharmony_ci		break;
25788c2ecf20Sopenharmony_ci	case FC_BSG_HST_ADD_RPORT:
25798c2ecf20Sopenharmony_ci	case FC_BSG_HST_DEL_RPORT:
25808c2ecf20Sopenharmony_ci	case FC_BSG_RPT_CT:
25818c2ecf20Sopenharmony_ci	default:
25828c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x705a, "Unsupported BSG request.\n");
25838c2ecf20Sopenharmony_ci		break;
25848c2ecf20Sopenharmony_ci	}
25858c2ecf20Sopenharmony_ci	return ret;
25868c2ecf20Sopenharmony_ci}
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ciint
25898c2ecf20Sopenharmony_ciqla24xx_bsg_timeout(struct bsg_job *bsg_job)
25908c2ecf20Sopenharmony_ci{
25918c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
25928c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
25938c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
25948c2ecf20Sopenharmony_ci	srb_t *sp;
25958c2ecf20Sopenharmony_ci	int cnt, que;
25968c2ecf20Sopenharmony_ci	unsigned long flags;
25978c2ecf20Sopenharmony_ci	struct req_que *req;
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci	/* find the bsg job from the active list of commands */
26008c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
26018c2ecf20Sopenharmony_ci	for (que = 0; que < ha->max_req_queues; que++) {
26028c2ecf20Sopenharmony_ci		req = ha->req_q_map[que];
26038c2ecf20Sopenharmony_ci		if (!req)
26048c2ecf20Sopenharmony_ci			continue;
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci		for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {
26078c2ecf20Sopenharmony_ci			sp = req->outstanding_cmds[cnt];
26088c2ecf20Sopenharmony_ci			if (sp) {
26098c2ecf20Sopenharmony_ci				if (((sp->type == SRB_CT_CMD) ||
26108c2ecf20Sopenharmony_ci					(sp->type == SRB_ELS_CMD_HST) ||
26118c2ecf20Sopenharmony_ci					(sp->type == SRB_FXIOCB_BCMD))
26128c2ecf20Sopenharmony_ci					&& (sp->u.bsg_job == bsg_job)) {
26138c2ecf20Sopenharmony_ci					req->outstanding_cmds[cnt] = NULL;
26148c2ecf20Sopenharmony_ci					spin_unlock_irqrestore(&ha->hardware_lock, flags);
26158c2ecf20Sopenharmony_ci					if (ha->isp_ops->abort_command(sp)) {
26168c2ecf20Sopenharmony_ci						ql_log(ql_log_warn, vha, 0x7089,
26178c2ecf20Sopenharmony_ci						    "mbx abort_command "
26188c2ecf20Sopenharmony_ci						    "failed.\n");
26198c2ecf20Sopenharmony_ci						bsg_reply->result = -EIO;
26208c2ecf20Sopenharmony_ci					} else {
26218c2ecf20Sopenharmony_ci						ql_dbg(ql_dbg_user, vha, 0x708a,
26228c2ecf20Sopenharmony_ci						    "mbx abort_command "
26238c2ecf20Sopenharmony_ci						    "success.\n");
26248c2ecf20Sopenharmony_ci						bsg_reply->result = 0;
26258c2ecf20Sopenharmony_ci					}
26268c2ecf20Sopenharmony_ci					spin_lock_irqsave(&ha->hardware_lock, flags);
26278c2ecf20Sopenharmony_ci					goto done;
26288c2ecf20Sopenharmony_ci				}
26298c2ecf20Sopenharmony_ci			}
26308c2ecf20Sopenharmony_ci		}
26318c2ecf20Sopenharmony_ci	}
26328c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
26338c2ecf20Sopenharmony_ci	ql_log(ql_log_info, vha, 0x708b, "SRB not found to abort.\n");
26348c2ecf20Sopenharmony_ci	bsg_reply->result = -ENXIO;
26358c2ecf20Sopenharmony_ci	return 0;
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_cidone:
26388c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
26398c2ecf20Sopenharmony_ci	sp->free(sp);
26408c2ecf20Sopenharmony_ci	return 0;
26418c2ecf20Sopenharmony_ci}
2642