18c2ecf20Sopenharmony_ci/*******************************************************************
28c2ecf20Sopenharmony_ci * This file is part of the Emulex Linux Device Driver for         *
38c2ecf20Sopenharmony_ci * Fibre Channel Host Bus Adapters.                                *
48c2ecf20Sopenharmony_ci * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term *
58c2ecf20Sopenharmony_ci * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.     *
68c2ecf20Sopenharmony_ci * Copyright (C) 2009-2015 Emulex.  All rights reserved.           *
78c2ecf20Sopenharmony_ci * EMULEX and SLI are trademarks of Emulex.                        *
88c2ecf20Sopenharmony_ci * www.broadcom.com                                                *
98c2ecf20Sopenharmony_ci *                                                                 *
108c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or   *
118c2ecf20Sopenharmony_ci * modify it under the terms of version 2 of the GNU General       *
128c2ecf20Sopenharmony_ci * Public License as published by the Free Software Foundation.    *
138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful. *
148c2ecf20Sopenharmony_ci * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
158c2ecf20Sopenharmony_ci * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
178c2ecf20Sopenharmony_ci * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
188c2ecf20Sopenharmony_ci * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
198c2ecf20Sopenharmony_ci * more details, a copy of which can be found in the file COPYING  *
208c2ecf20Sopenharmony_ci * included with this package.                                     *
218c2ecf20Sopenharmony_ci *******************************************************************/
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
248c2ecf20Sopenharmony_ci#include <linux/mempool.h>
258c2ecf20Sopenharmony_ci#include <linux/pci.h>
268c2ecf20Sopenharmony_ci#include <linux/slab.h>
278c2ecf20Sopenharmony_ci#include <linux/delay.h>
288c2ecf20Sopenharmony_ci#include <linux/list.h>
298c2ecf20Sopenharmony_ci#include <linux/bsg-lib.h>
308c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
338c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
348c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_fc.h>
358c2ecf20Sopenharmony_ci#include <scsi/scsi_bsg_fc.h>
368c2ecf20Sopenharmony_ci#include <scsi/fc/fc_fs.h>
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#include "lpfc_hw4.h"
398c2ecf20Sopenharmony_ci#include "lpfc_hw.h"
408c2ecf20Sopenharmony_ci#include "lpfc_sli.h"
418c2ecf20Sopenharmony_ci#include "lpfc_sli4.h"
428c2ecf20Sopenharmony_ci#include "lpfc_nl.h"
438c2ecf20Sopenharmony_ci#include "lpfc_bsg.h"
448c2ecf20Sopenharmony_ci#include "lpfc_disc.h"
458c2ecf20Sopenharmony_ci#include "lpfc_scsi.h"
468c2ecf20Sopenharmony_ci#include "lpfc.h"
478c2ecf20Sopenharmony_ci#include "lpfc_logmsg.h"
488c2ecf20Sopenharmony_ci#include "lpfc_crtn.h"
498c2ecf20Sopenharmony_ci#include "lpfc_debugfs.h"
508c2ecf20Sopenharmony_ci#include "lpfc_vport.h"
518c2ecf20Sopenharmony_ci#include "lpfc_version.h"
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistruct lpfc_bsg_event {
548c2ecf20Sopenharmony_ci	struct list_head node;
558c2ecf20Sopenharmony_ci	struct kref kref;
568c2ecf20Sopenharmony_ci	wait_queue_head_t wq;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/* Event type and waiter identifiers */
598c2ecf20Sopenharmony_ci	uint32_t type_mask;
608c2ecf20Sopenharmony_ci	uint32_t req_id;
618c2ecf20Sopenharmony_ci	uint32_t reg_id;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* next two flags are here for the auto-delete logic */
648c2ecf20Sopenharmony_ci	unsigned long wait_time_stamp;
658c2ecf20Sopenharmony_ci	int waiting;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/* seen and not seen events */
688c2ecf20Sopenharmony_ci	struct list_head events_to_get;
698c2ecf20Sopenharmony_ci	struct list_head events_to_see;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/* driver data associated with the job */
728c2ecf20Sopenharmony_ci	void *dd_data;
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistruct lpfc_bsg_iocb {
768c2ecf20Sopenharmony_ci	struct lpfc_iocbq *cmdiocbq;
778c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *rmp;
788c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistruct lpfc_bsg_mbox {
828c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *pmboxq;
838c2ecf20Sopenharmony_ci	MAILBOX_t *mb;
848c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmabuffers; /* for BIU diags */
858c2ecf20Sopenharmony_ci	uint8_t *ext; /* extended mailbox data */
868c2ecf20Sopenharmony_ci	uint32_t mbOffset; /* from app */
878c2ecf20Sopenharmony_ci	uint32_t inExtWLen; /* from app */
888c2ecf20Sopenharmony_ci	uint32_t outExtWLen; /* from app */
898c2ecf20Sopenharmony_ci};
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci#define MENLO_DID 0x0000FC0E
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistruct lpfc_bsg_menlo {
948c2ecf20Sopenharmony_ci	struct lpfc_iocbq *cmdiocbq;
958c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *rmp;
968c2ecf20Sopenharmony_ci};
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#define TYPE_EVT 	1
998c2ecf20Sopenharmony_ci#define TYPE_IOCB	2
1008c2ecf20Sopenharmony_ci#define TYPE_MBOX	3
1018c2ecf20Sopenharmony_ci#define TYPE_MENLO	4
1028c2ecf20Sopenharmony_cistruct bsg_job_data {
1038c2ecf20Sopenharmony_ci	uint32_t type;
1048c2ecf20Sopenharmony_ci	struct bsg_job *set_job; /* job waiting for this iocb to finish */
1058c2ecf20Sopenharmony_ci	union {
1068c2ecf20Sopenharmony_ci		struct lpfc_bsg_event *evt;
1078c2ecf20Sopenharmony_ci		struct lpfc_bsg_iocb iocb;
1088c2ecf20Sopenharmony_ci		struct lpfc_bsg_mbox mbox;
1098c2ecf20Sopenharmony_ci		struct lpfc_bsg_menlo menlo;
1108c2ecf20Sopenharmony_ci	} context_un;
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistruct event_data {
1148c2ecf20Sopenharmony_ci	struct list_head node;
1158c2ecf20Sopenharmony_ci	uint32_t type;
1168c2ecf20Sopenharmony_ci	uint32_t immed_dat;
1178c2ecf20Sopenharmony_ci	void *data;
1188c2ecf20Sopenharmony_ci	uint32_t len;
1198c2ecf20Sopenharmony_ci};
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#define BUF_SZ_4K 4096
1228c2ecf20Sopenharmony_ci#define SLI_CT_ELX_LOOPBACK 0x10
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cienum ELX_LOOPBACK_CMD {
1258c2ecf20Sopenharmony_ci	ELX_LOOPBACK_XRI_SETUP,
1268c2ecf20Sopenharmony_ci	ELX_LOOPBACK_DATA,
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci#define ELX_LOOPBACK_HEADER_SZ \
1308c2ecf20Sopenharmony_ci	(size_t)(&((struct lpfc_sli_ct_request *)NULL)->un)
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistruct lpfc_dmabufext {
1338c2ecf20Sopenharmony_ci	struct lpfc_dmabuf dma;
1348c2ecf20Sopenharmony_ci	uint32_t size;
1358c2ecf20Sopenharmony_ci	uint32_t flag;
1368c2ecf20Sopenharmony_ci};
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic void
1398c2ecf20Sopenharmony_cilpfc_free_bsg_buffers(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mlast, *next_mlast;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (mlist) {
1448c2ecf20Sopenharmony_ci		list_for_each_entry_safe(mlast, next_mlast, &mlist->list,
1458c2ecf20Sopenharmony_ci					 list) {
1468c2ecf20Sopenharmony_ci			lpfc_mbuf_free(phba, mlast->virt, mlast->phys);
1478c2ecf20Sopenharmony_ci			list_del(&mlast->list);
1488c2ecf20Sopenharmony_ci			kfree(mlast);
1498c2ecf20Sopenharmony_ci		}
1508c2ecf20Sopenharmony_ci		lpfc_mbuf_free(phba, mlist->virt, mlist->phys);
1518c2ecf20Sopenharmony_ci		kfree(mlist);
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci	return;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic struct lpfc_dmabuf *
1578c2ecf20Sopenharmony_cilpfc_alloc_bsg_buffers(struct lpfc_hba *phba, unsigned int size,
1588c2ecf20Sopenharmony_ci		       int outbound_buffers, struct ulp_bde64 *bpl,
1598c2ecf20Sopenharmony_ci		       int *bpl_entries)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mlist = NULL;
1628c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mp;
1638c2ecf20Sopenharmony_ci	unsigned int bytes_left = size;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* Verify we can support the size specified */
1668c2ecf20Sopenharmony_ci	if (!size || (size > (*bpl_entries * LPFC_BPL_SIZE)))
1678c2ecf20Sopenharmony_ci		return NULL;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/* Determine the number of dma buffers to allocate */
1708c2ecf20Sopenharmony_ci	*bpl_entries = (size % LPFC_BPL_SIZE ? size/LPFC_BPL_SIZE + 1 :
1718c2ecf20Sopenharmony_ci			size/LPFC_BPL_SIZE);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/* Allocate dma buffer and place in BPL passed */
1748c2ecf20Sopenharmony_ci	while (bytes_left) {
1758c2ecf20Sopenharmony_ci		/* Allocate dma buffer  */
1768c2ecf20Sopenharmony_ci		mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
1778c2ecf20Sopenharmony_ci		if (!mp) {
1788c2ecf20Sopenharmony_ci			if (mlist)
1798c2ecf20Sopenharmony_ci				lpfc_free_bsg_buffers(phba, mlist);
1808c2ecf20Sopenharmony_ci			return NULL;
1818c2ecf20Sopenharmony_ci		}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&mp->list);
1848c2ecf20Sopenharmony_ci		mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		if (!mp->virt) {
1878c2ecf20Sopenharmony_ci			kfree(mp);
1888c2ecf20Sopenharmony_ci			if (mlist)
1898c2ecf20Sopenharmony_ci				lpfc_free_bsg_buffers(phba, mlist);
1908c2ecf20Sopenharmony_ci			return NULL;
1918c2ecf20Sopenharmony_ci		}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci		/* Queue it to a linked list */
1948c2ecf20Sopenharmony_ci		if (!mlist)
1958c2ecf20Sopenharmony_ci			mlist = mp;
1968c2ecf20Sopenharmony_ci		else
1978c2ecf20Sopenharmony_ci			list_add_tail(&mp->list, &mlist->list);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci		/* Add buffer to buffer pointer list */
2008c2ecf20Sopenharmony_ci		if (outbound_buffers)
2018c2ecf20Sopenharmony_ci			bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
2028c2ecf20Sopenharmony_ci		else
2038c2ecf20Sopenharmony_ci			bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
2048c2ecf20Sopenharmony_ci		bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys));
2058c2ecf20Sopenharmony_ci		bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys));
2068c2ecf20Sopenharmony_ci		bpl->tus.f.bdeSize = (uint16_t)
2078c2ecf20Sopenharmony_ci			(bytes_left >= LPFC_BPL_SIZE ? LPFC_BPL_SIZE :
2088c2ecf20Sopenharmony_ci			 bytes_left);
2098c2ecf20Sopenharmony_ci		bytes_left -= bpl->tus.f.bdeSize;
2108c2ecf20Sopenharmony_ci		bpl->tus.w = le32_to_cpu(bpl->tus.w);
2118c2ecf20Sopenharmony_ci		bpl++;
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci	return mlist;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic unsigned int
2178c2ecf20Sopenharmony_cilpfc_bsg_copy_data(struct lpfc_dmabuf *dma_buffers,
2188c2ecf20Sopenharmony_ci		   struct bsg_buffer *bsg_buffers,
2198c2ecf20Sopenharmony_ci		   unsigned int bytes_to_transfer, int to_buffers)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mp;
2238c2ecf20Sopenharmony_ci	unsigned int transfer_bytes, bytes_copied = 0;
2248c2ecf20Sopenharmony_ci	unsigned int sg_offset, dma_offset;
2258c2ecf20Sopenharmony_ci	unsigned char *dma_address, *sg_address;
2268c2ecf20Sopenharmony_ci	LIST_HEAD(temp_list);
2278c2ecf20Sopenharmony_ci	struct sg_mapping_iter miter;
2288c2ecf20Sopenharmony_ci	unsigned long flags;
2298c2ecf20Sopenharmony_ci	unsigned int sg_flags = SG_MITER_ATOMIC;
2308c2ecf20Sopenharmony_ci	bool sg_valid;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	list_splice_init(&dma_buffers->list, &temp_list);
2338c2ecf20Sopenharmony_ci	list_add(&dma_buffers->list, &temp_list);
2348c2ecf20Sopenharmony_ci	sg_offset = 0;
2358c2ecf20Sopenharmony_ci	if (to_buffers)
2368c2ecf20Sopenharmony_ci		sg_flags |= SG_MITER_FROM_SG;
2378c2ecf20Sopenharmony_ci	else
2388c2ecf20Sopenharmony_ci		sg_flags |= SG_MITER_TO_SG;
2398c2ecf20Sopenharmony_ci	sg_miter_start(&miter, bsg_buffers->sg_list, bsg_buffers->sg_cnt,
2408c2ecf20Sopenharmony_ci		       sg_flags);
2418c2ecf20Sopenharmony_ci	local_irq_save(flags);
2428c2ecf20Sopenharmony_ci	sg_valid = sg_miter_next(&miter);
2438c2ecf20Sopenharmony_ci	list_for_each_entry(mp, &temp_list, list) {
2448c2ecf20Sopenharmony_ci		dma_offset = 0;
2458c2ecf20Sopenharmony_ci		while (bytes_to_transfer && sg_valid &&
2468c2ecf20Sopenharmony_ci		       (dma_offset < LPFC_BPL_SIZE)) {
2478c2ecf20Sopenharmony_ci			dma_address = mp->virt + dma_offset;
2488c2ecf20Sopenharmony_ci			if (sg_offset) {
2498c2ecf20Sopenharmony_ci				/* Continue previous partial transfer of sg */
2508c2ecf20Sopenharmony_ci				sg_address = miter.addr + sg_offset;
2518c2ecf20Sopenharmony_ci				transfer_bytes = miter.length - sg_offset;
2528c2ecf20Sopenharmony_ci			} else {
2538c2ecf20Sopenharmony_ci				sg_address = miter.addr;
2548c2ecf20Sopenharmony_ci				transfer_bytes = miter.length;
2558c2ecf20Sopenharmony_ci			}
2568c2ecf20Sopenharmony_ci			if (bytes_to_transfer < transfer_bytes)
2578c2ecf20Sopenharmony_ci				transfer_bytes = bytes_to_transfer;
2588c2ecf20Sopenharmony_ci			if (transfer_bytes > (LPFC_BPL_SIZE - dma_offset))
2598c2ecf20Sopenharmony_ci				transfer_bytes = LPFC_BPL_SIZE - dma_offset;
2608c2ecf20Sopenharmony_ci			if (to_buffers)
2618c2ecf20Sopenharmony_ci				memcpy(dma_address, sg_address, transfer_bytes);
2628c2ecf20Sopenharmony_ci			else
2638c2ecf20Sopenharmony_ci				memcpy(sg_address, dma_address, transfer_bytes);
2648c2ecf20Sopenharmony_ci			dma_offset += transfer_bytes;
2658c2ecf20Sopenharmony_ci			sg_offset += transfer_bytes;
2668c2ecf20Sopenharmony_ci			bytes_to_transfer -= transfer_bytes;
2678c2ecf20Sopenharmony_ci			bytes_copied += transfer_bytes;
2688c2ecf20Sopenharmony_ci			if (sg_offset >= miter.length) {
2698c2ecf20Sopenharmony_ci				sg_offset = 0;
2708c2ecf20Sopenharmony_ci				sg_valid = sg_miter_next(&miter);
2718c2ecf20Sopenharmony_ci			}
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci	sg_miter_stop(&miter);
2758c2ecf20Sopenharmony_ci	local_irq_restore(flags);
2768c2ecf20Sopenharmony_ci	list_del_init(&dma_buffers->list);
2778c2ecf20Sopenharmony_ci	list_splice(&temp_list, &dma_buffers->list);
2788c2ecf20Sopenharmony_ci	return bytes_copied;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci/**
2828c2ecf20Sopenharmony_ci * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler
2838c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
2848c2ecf20Sopenharmony_ci * @cmdiocbq: Pointer to command iocb.
2858c2ecf20Sopenharmony_ci * @rspiocbq: Pointer to response iocb.
2868c2ecf20Sopenharmony_ci *
2878c2ecf20Sopenharmony_ci * This function is the completion handler for iocbs issued using
2888c2ecf20Sopenharmony_ci * lpfc_bsg_send_mgmt_cmd function. This function is called by the
2898c2ecf20Sopenharmony_ci * ring event handler function without any lock held. This function
2908c2ecf20Sopenharmony_ci * can be called from both worker thread context and interrupt
2918c2ecf20Sopenharmony_ci * context. This function also can be called from another thread which
2928c2ecf20Sopenharmony_ci * cleans up the SLI layer objects.
2938c2ecf20Sopenharmony_ci * This function copies the contents of the response iocb to the
2948c2ecf20Sopenharmony_ci * response iocb memory object provided by the caller of
2958c2ecf20Sopenharmony_ci * lpfc_sli_issue_iocb_wait and then wakes up the thread which
2968c2ecf20Sopenharmony_ci * sleeps for the iocb completion.
2978c2ecf20Sopenharmony_ci **/
2988c2ecf20Sopenharmony_cistatic void
2998c2ecf20Sopenharmony_cilpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
3008c2ecf20Sopenharmony_ci			struct lpfc_iocbq *cmdiocbq,
3018c2ecf20Sopenharmony_ci			struct lpfc_iocbq *rspiocbq)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data;
3048c2ecf20Sopenharmony_ci	struct bsg_job *job;
3058c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
3068c2ecf20Sopenharmony_ci	IOCB_t *rsp;
3078c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *bmp, *cmp, *rmp;
3088c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
3098c2ecf20Sopenharmony_ci	struct lpfc_bsg_iocb *iocb;
3108c2ecf20Sopenharmony_ci	unsigned long flags;
3118c2ecf20Sopenharmony_ci	unsigned int rsp_size;
3128c2ecf20Sopenharmony_ci	int rc = 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	dd_data = cmdiocbq->context1;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/* Determine if job has been aborted */
3178c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
3188c2ecf20Sopenharmony_ci	job = dd_data->set_job;
3198c2ecf20Sopenharmony_ci	if (job) {
3208c2ecf20Sopenharmony_ci		bsg_reply = job->reply;
3218c2ecf20Sopenharmony_ci		/* Prevent timeout handling from trying to abort job */
3228c2ecf20Sopenharmony_ci		job->dd_data = NULL;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	/* Close the timeout handler abort window */
3278c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, flags);
3288c2ecf20Sopenharmony_ci	cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING;
3298c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, flags);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	iocb = &dd_data->context_un.iocb;
3328c2ecf20Sopenharmony_ci	ndlp = iocb->ndlp;
3338c2ecf20Sopenharmony_ci	rmp = iocb->rmp;
3348c2ecf20Sopenharmony_ci	cmp = cmdiocbq->context2;
3358c2ecf20Sopenharmony_ci	bmp = cmdiocbq->context3;
3368c2ecf20Sopenharmony_ci	rsp = &rspiocbq->iocb;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	/* Copy the completed data or set the error status */
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	if (job) {
3418c2ecf20Sopenharmony_ci		if (rsp->ulpStatus) {
3428c2ecf20Sopenharmony_ci			if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
3438c2ecf20Sopenharmony_ci				switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
3448c2ecf20Sopenharmony_ci				case IOERR_SEQUENCE_TIMEOUT:
3458c2ecf20Sopenharmony_ci					rc = -ETIMEDOUT;
3468c2ecf20Sopenharmony_ci					break;
3478c2ecf20Sopenharmony_ci				case IOERR_INVALID_RPI:
3488c2ecf20Sopenharmony_ci					rc = -EFAULT;
3498c2ecf20Sopenharmony_ci					break;
3508c2ecf20Sopenharmony_ci				default:
3518c2ecf20Sopenharmony_ci					rc = -EACCES;
3528c2ecf20Sopenharmony_ci					break;
3538c2ecf20Sopenharmony_ci				}
3548c2ecf20Sopenharmony_ci			} else {
3558c2ecf20Sopenharmony_ci				rc = -EACCES;
3568c2ecf20Sopenharmony_ci			}
3578c2ecf20Sopenharmony_ci		} else {
3588c2ecf20Sopenharmony_ci			rsp_size = rsp->un.genreq64.bdl.bdeSize;
3598c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len =
3608c2ecf20Sopenharmony_ci				lpfc_bsg_copy_data(rmp, &job->reply_payload,
3618c2ecf20Sopenharmony_ci						   rsp_size, 0);
3628c2ecf20Sopenharmony_ci		}
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	lpfc_free_bsg_buffers(phba, cmp);
3668c2ecf20Sopenharmony_ci	lpfc_free_bsg_buffers(phba, rmp);
3678c2ecf20Sopenharmony_ci	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
3688c2ecf20Sopenharmony_ci	kfree(bmp);
3698c2ecf20Sopenharmony_ci	lpfc_sli_release_iocbq(phba, cmdiocbq);
3708c2ecf20Sopenharmony_ci	lpfc_nlp_put(ndlp);
3718c2ecf20Sopenharmony_ci	kfree(dd_data);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* Complete the job if the job is still active */
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (job) {
3768c2ecf20Sopenharmony_ci		bsg_reply->result = rc;
3778c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
3788c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci	return;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci/**
3848c2ecf20Sopenharmony_ci * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request
3858c2ecf20Sopenharmony_ci * @job: fc_bsg_job to handle
3868c2ecf20Sopenharmony_ci **/
3878c2ecf20Sopenharmony_cistatic int
3888c2ecf20Sopenharmony_cilpfc_bsg_send_mgmt_cmd(struct bsg_job *job)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
3918c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
3928c2ecf20Sopenharmony_ci	struct lpfc_rport_data *rdata = fc_bsg_to_rport(job)->dd_data;
3938c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp = rdata->pnode;
3948c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
3958c2ecf20Sopenharmony_ci	struct ulp_bde64 *bpl = NULL;
3968c2ecf20Sopenharmony_ci	uint32_t timeout;
3978c2ecf20Sopenharmony_ci	struct lpfc_iocbq *cmdiocbq = NULL;
3988c2ecf20Sopenharmony_ci	IOCB_t *cmd;
3998c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL;
4008c2ecf20Sopenharmony_ci	int request_nseg;
4018c2ecf20Sopenharmony_ci	int reply_nseg;
4028c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data;
4038c2ecf20Sopenharmony_ci	unsigned long flags;
4048c2ecf20Sopenharmony_ci	uint32_t creg_val;
4058c2ecf20Sopenharmony_ci	int rc = 0;
4068c2ecf20Sopenharmony_ci	int iocb_stat;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	/* in case no data is transferred */
4098c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* allocate our bsg tracking structure */
4128c2ecf20Sopenharmony_ci	dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
4138c2ecf20Sopenharmony_ci	if (!dd_data) {
4148c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
4158c2ecf20Sopenharmony_ci				"2733 Failed allocation of dd_data\n");
4168c2ecf20Sopenharmony_ci		rc = -ENOMEM;
4178c2ecf20Sopenharmony_ci		goto no_dd_data;
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (!lpfc_nlp_get(ndlp)) {
4218c2ecf20Sopenharmony_ci		rc = -ENODEV;
4228c2ecf20Sopenharmony_ci		goto no_ndlp;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (ndlp->nlp_flag & NLP_ELS_SND_MASK) {
4268c2ecf20Sopenharmony_ci		rc = -ENODEV;
4278c2ecf20Sopenharmony_ci		goto free_ndlp;
4288c2ecf20Sopenharmony_ci	}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	cmdiocbq = lpfc_sli_get_iocbq(phba);
4318c2ecf20Sopenharmony_ci	if (!cmdiocbq) {
4328c2ecf20Sopenharmony_ci		rc = -ENOMEM;
4338c2ecf20Sopenharmony_ci		goto free_ndlp;
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	cmd = &cmdiocbq->iocb;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
4398c2ecf20Sopenharmony_ci	if (!bmp) {
4408c2ecf20Sopenharmony_ci		rc = -ENOMEM;
4418c2ecf20Sopenharmony_ci		goto free_cmdiocbq;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci	bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
4448c2ecf20Sopenharmony_ci	if (!bmp->virt) {
4458c2ecf20Sopenharmony_ci		rc = -ENOMEM;
4468c2ecf20Sopenharmony_ci		goto free_bmp;
4478c2ecf20Sopenharmony_ci	}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&bmp->list);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	bpl = (struct ulp_bde64 *) bmp->virt;
4528c2ecf20Sopenharmony_ci	request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64);
4538c2ecf20Sopenharmony_ci	cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len,
4548c2ecf20Sopenharmony_ci				     1, bpl, &request_nseg);
4558c2ecf20Sopenharmony_ci	if (!cmp) {
4568c2ecf20Sopenharmony_ci		rc = -ENOMEM;
4578c2ecf20Sopenharmony_ci		goto free_bmp;
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci	lpfc_bsg_copy_data(cmp, &job->request_payload,
4608c2ecf20Sopenharmony_ci			   job->request_payload.payload_len, 1);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	bpl += request_nseg;
4638c2ecf20Sopenharmony_ci	reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg;
4648c2ecf20Sopenharmony_ci	rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0,
4658c2ecf20Sopenharmony_ci				     bpl, &reply_nseg);
4668c2ecf20Sopenharmony_ci	if (!rmp) {
4678c2ecf20Sopenharmony_ci		rc = -ENOMEM;
4688c2ecf20Sopenharmony_ci		goto free_cmp;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	cmd->un.genreq64.bdl.ulpIoTag32 = 0;
4728c2ecf20Sopenharmony_ci	cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
4738c2ecf20Sopenharmony_ci	cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
4748c2ecf20Sopenharmony_ci	cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
4758c2ecf20Sopenharmony_ci	cmd->un.genreq64.bdl.bdeSize =
4768c2ecf20Sopenharmony_ci		(request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
4778c2ecf20Sopenharmony_ci	cmd->ulpCommand = CMD_GEN_REQUEST64_CR;
4788c2ecf20Sopenharmony_ci	cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
4798c2ecf20Sopenharmony_ci	cmd->un.genreq64.w5.hcsw.Dfctl = 0;
4808c2ecf20Sopenharmony_ci	cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
4818c2ecf20Sopenharmony_ci	cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT;
4828c2ecf20Sopenharmony_ci	cmd->ulpBdeCount = 1;
4838c2ecf20Sopenharmony_ci	cmd->ulpLe = 1;
4848c2ecf20Sopenharmony_ci	cmd->ulpClass = CLASS3;
4858c2ecf20Sopenharmony_ci	cmd->ulpContext = ndlp->nlp_rpi;
4868c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
4878c2ecf20Sopenharmony_ci		cmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
4888c2ecf20Sopenharmony_ci	cmd->ulpOwner = OWN_CHIP;
4898c2ecf20Sopenharmony_ci	cmdiocbq->vport = phba->pport;
4908c2ecf20Sopenharmony_ci	cmdiocbq->context3 = bmp;
4918c2ecf20Sopenharmony_ci	cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
4928c2ecf20Sopenharmony_ci	timeout = phba->fc_ratov * 2;
4938c2ecf20Sopenharmony_ci	cmd->ulpTimeout = timeout;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp;
4968c2ecf20Sopenharmony_ci	cmdiocbq->context1 = dd_data;
4978c2ecf20Sopenharmony_ci	cmdiocbq->context2 = cmp;
4988c2ecf20Sopenharmony_ci	cmdiocbq->context3 = bmp;
4998c2ecf20Sopenharmony_ci	cmdiocbq->context_un.ndlp = ndlp;
5008c2ecf20Sopenharmony_ci	dd_data->type = TYPE_IOCB;
5018c2ecf20Sopenharmony_ci	dd_data->set_job = job;
5028c2ecf20Sopenharmony_ci	dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
5038c2ecf20Sopenharmony_ci	dd_data->context_un.iocb.ndlp = ndlp;
5048c2ecf20Sopenharmony_ci	dd_data->context_un.iocb.rmp = rmp;
5058c2ecf20Sopenharmony_ci	job->dd_data = dd_data;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
5088c2ecf20Sopenharmony_ci		if (lpfc_readl(phba->HCregaddr, &creg_val)) {
5098c2ecf20Sopenharmony_ci			rc = -EIO ;
5108c2ecf20Sopenharmony_ci			goto free_rmp;
5118c2ecf20Sopenharmony_ci		}
5128c2ecf20Sopenharmony_ci		creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING);
5138c2ecf20Sopenharmony_ci		writel(creg_val, phba->HCregaddr);
5148c2ecf20Sopenharmony_ci		readl(phba->HCregaddr); /* flush */
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (iocb_stat == IOCB_SUCCESS) {
5208c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, flags);
5218c2ecf20Sopenharmony_ci		/* make sure the I/O had not been completed yet */
5228c2ecf20Sopenharmony_ci		if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) {
5238c2ecf20Sopenharmony_ci			/* open up abort window to timeout handler */
5248c2ecf20Sopenharmony_ci			cmdiocbq->iocb_flag |= LPFC_IO_CMD_OUTSTANDING;
5258c2ecf20Sopenharmony_ci		}
5268c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, flags);
5278c2ecf20Sopenharmony_ci		return 0; /* done for now */
5288c2ecf20Sopenharmony_ci	} else if (iocb_stat == IOCB_BUSY) {
5298c2ecf20Sopenharmony_ci		rc = -EAGAIN;
5308c2ecf20Sopenharmony_ci	} else {
5318c2ecf20Sopenharmony_ci		rc = -EIO;
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	/* iocb failed so cleanup */
5358c2ecf20Sopenharmony_ci	job->dd_data = NULL;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cifree_rmp:
5388c2ecf20Sopenharmony_ci	lpfc_free_bsg_buffers(phba, rmp);
5398c2ecf20Sopenharmony_cifree_cmp:
5408c2ecf20Sopenharmony_ci	lpfc_free_bsg_buffers(phba, cmp);
5418c2ecf20Sopenharmony_cifree_bmp:
5428c2ecf20Sopenharmony_ci	if (bmp->virt)
5438c2ecf20Sopenharmony_ci		lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
5448c2ecf20Sopenharmony_ci	kfree(bmp);
5458c2ecf20Sopenharmony_cifree_cmdiocbq:
5468c2ecf20Sopenharmony_ci	lpfc_sli_release_iocbq(phba, cmdiocbq);
5478c2ecf20Sopenharmony_cifree_ndlp:
5488c2ecf20Sopenharmony_ci	lpfc_nlp_put(ndlp);
5498c2ecf20Sopenharmony_cino_ndlp:
5508c2ecf20Sopenharmony_ci	kfree(dd_data);
5518c2ecf20Sopenharmony_cino_dd_data:
5528c2ecf20Sopenharmony_ci	/* make error code available to userspace */
5538c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
5548c2ecf20Sopenharmony_ci	job->dd_data = NULL;
5558c2ecf20Sopenharmony_ci	return rc;
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci/**
5598c2ecf20Sopenharmony_ci * lpfc_bsg_rport_els_cmp - lpfc_bsg_rport_els's completion handler
5608c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
5618c2ecf20Sopenharmony_ci * @cmdiocbq: Pointer to command iocb.
5628c2ecf20Sopenharmony_ci * @rspiocbq: Pointer to response iocb.
5638c2ecf20Sopenharmony_ci *
5648c2ecf20Sopenharmony_ci * This function is the completion handler for iocbs issued using
5658c2ecf20Sopenharmony_ci * lpfc_bsg_rport_els_cmp function. This function is called by the
5668c2ecf20Sopenharmony_ci * ring event handler function without any lock held. This function
5678c2ecf20Sopenharmony_ci * can be called from both worker thread context and interrupt
5688c2ecf20Sopenharmony_ci * context. This function also can be called from other thread which
5698c2ecf20Sopenharmony_ci * cleans up the SLI layer objects.
5708c2ecf20Sopenharmony_ci * This function copies the contents of the response iocb to the
5718c2ecf20Sopenharmony_ci * response iocb memory object provided by the caller of
5728c2ecf20Sopenharmony_ci * lpfc_sli_issue_iocb_wait and then wakes up the thread which
5738c2ecf20Sopenharmony_ci * sleeps for the iocb completion.
5748c2ecf20Sopenharmony_ci **/
5758c2ecf20Sopenharmony_cistatic void
5768c2ecf20Sopenharmony_cilpfc_bsg_rport_els_cmp(struct lpfc_hba *phba,
5778c2ecf20Sopenharmony_ci			struct lpfc_iocbq *cmdiocbq,
5788c2ecf20Sopenharmony_ci			struct lpfc_iocbq *rspiocbq)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data;
5818c2ecf20Sopenharmony_ci	struct bsg_job *job;
5828c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
5838c2ecf20Sopenharmony_ci	IOCB_t *rsp;
5848c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
5858c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *pcmd = NULL, *prsp = NULL;
5868c2ecf20Sopenharmony_ci	struct fc_bsg_ctels_reply *els_reply;
5878c2ecf20Sopenharmony_ci	uint8_t *rjt_data;
5888c2ecf20Sopenharmony_ci	unsigned long flags;
5898c2ecf20Sopenharmony_ci	unsigned int rsp_size;
5908c2ecf20Sopenharmony_ci	int rc = 0;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	dd_data = cmdiocbq->context1;
5938c2ecf20Sopenharmony_ci	ndlp = dd_data->context_un.iocb.ndlp;
5948c2ecf20Sopenharmony_ci	cmdiocbq->context1 = ndlp;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	/* Determine if job has been aborted */
5978c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
5988c2ecf20Sopenharmony_ci	job = dd_data->set_job;
5998c2ecf20Sopenharmony_ci	if (job) {
6008c2ecf20Sopenharmony_ci		bsg_reply = job->reply;
6018c2ecf20Sopenharmony_ci		/* Prevent timeout handling from trying to abort job  */
6028c2ecf20Sopenharmony_ci		job->dd_data = NULL;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* Close the timeout handler abort window */
6078c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, flags);
6088c2ecf20Sopenharmony_ci	cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING;
6098c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, flags);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	rsp = &rspiocbq->iocb;
6128c2ecf20Sopenharmony_ci	pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2;
6138c2ecf20Sopenharmony_ci	prsp = (struct lpfc_dmabuf *)pcmd->list.next;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	/* Copy the completed job data or determine the job status if job is
6168c2ecf20Sopenharmony_ci	 * still active
6178c2ecf20Sopenharmony_ci	 */
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	if (job) {
6208c2ecf20Sopenharmony_ci		if (rsp->ulpStatus == IOSTAT_SUCCESS) {
6218c2ecf20Sopenharmony_ci			rsp_size = rsp->un.elsreq64.bdl.bdeSize;
6228c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len =
6238c2ecf20Sopenharmony_ci				sg_copy_from_buffer(job->reply_payload.sg_list,
6248c2ecf20Sopenharmony_ci						    job->reply_payload.sg_cnt,
6258c2ecf20Sopenharmony_ci						    prsp->virt,
6268c2ecf20Sopenharmony_ci						    rsp_size);
6278c2ecf20Sopenharmony_ci		} else if (rsp->ulpStatus == IOSTAT_LS_RJT) {
6288c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len =
6298c2ecf20Sopenharmony_ci				sizeof(struct fc_bsg_ctels_reply);
6308c2ecf20Sopenharmony_ci			/* LS_RJT data returned in word 4 */
6318c2ecf20Sopenharmony_ci			rjt_data = (uint8_t *)&rsp->un.ulpWord[4];
6328c2ecf20Sopenharmony_ci			els_reply = &bsg_reply->reply_data.ctels_reply;
6338c2ecf20Sopenharmony_ci			els_reply->status = FC_CTELS_STATUS_REJECT;
6348c2ecf20Sopenharmony_ci			els_reply->rjt_data.action = rjt_data[3];
6358c2ecf20Sopenharmony_ci			els_reply->rjt_data.reason_code = rjt_data[2];
6368c2ecf20Sopenharmony_ci			els_reply->rjt_data.reason_explanation = rjt_data[1];
6378c2ecf20Sopenharmony_ci			els_reply->rjt_data.vendor_unique = rjt_data[0];
6388c2ecf20Sopenharmony_ci		} else {
6398c2ecf20Sopenharmony_ci			rc = -EIO;
6408c2ecf20Sopenharmony_ci		}
6418c2ecf20Sopenharmony_ci	}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	lpfc_nlp_put(ndlp);
6448c2ecf20Sopenharmony_ci	lpfc_els_free_iocb(phba, cmdiocbq);
6458c2ecf20Sopenharmony_ci	kfree(dd_data);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	/* Complete the job if the job is still active */
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	if (job) {
6508c2ecf20Sopenharmony_ci		bsg_reply->result = rc;
6518c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
6528c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
6538c2ecf20Sopenharmony_ci	}
6548c2ecf20Sopenharmony_ci	return;
6558c2ecf20Sopenharmony_ci}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci/**
6588c2ecf20Sopenharmony_ci * lpfc_bsg_rport_els - send an ELS command from a bsg request
6598c2ecf20Sopenharmony_ci * @job: fc_bsg_job to handle
6608c2ecf20Sopenharmony_ci **/
6618c2ecf20Sopenharmony_cistatic int
6628c2ecf20Sopenharmony_cilpfc_bsg_rport_els(struct bsg_job *job)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
6658c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
6668c2ecf20Sopenharmony_ci	struct lpfc_rport_data *rdata = fc_bsg_to_rport(job)->dd_data;
6678c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp = rdata->pnode;
6688c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
6698c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
6708c2ecf20Sopenharmony_ci	uint32_t elscmd;
6718c2ecf20Sopenharmony_ci	uint32_t cmdsize;
6728c2ecf20Sopenharmony_ci	struct lpfc_iocbq *cmdiocbq;
6738c2ecf20Sopenharmony_ci	uint16_t rpi = 0;
6748c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data;
6758c2ecf20Sopenharmony_ci	unsigned long flags;
6768c2ecf20Sopenharmony_ci	uint32_t creg_val;
6778c2ecf20Sopenharmony_ci	int rc = 0;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	/* in case no data is transferred */
6808c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	/* verify the els command is not greater than the
6838c2ecf20Sopenharmony_ci	 * maximum ELS transfer size.
6848c2ecf20Sopenharmony_ci	 */
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	if (job->request_payload.payload_len > FCELSSIZE) {
6878c2ecf20Sopenharmony_ci		rc = -EINVAL;
6888c2ecf20Sopenharmony_ci		goto no_dd_data;
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	/* allocate our bsg tracking structure */
6928c2ecf20Sopenharmony_ci	dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
6938c2ecf20Sopenharmony_ci	if (!dd_data) {
6948c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
6958c2ecf20Sopenharmony_ci				"2735 Failed allocation of dd_data\n");
6968c2ecf20Sopenharmony_ci		rc = -ENOMEM;
6978c2ecf20Sopenharmony_ci		goto no_dd_data;
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	elscmd = bsg_request->rqst_data.r_els.els_code;
7018c2ecf20Sopenharmony_ci	cmdsize = job->request_payload.payload_len;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	if (!lpfc_nlp_get(ndlp)) {
7048c2ecf20Sopenharmony_ci		rc = -ENODEV;
7058c2ecf20Sopenharmony_ci		goto free_dd_data;
7068c2ecf20Sopenharmony_ci	}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	/* We will use the allocated dma buffers by prep els iocb for command
7098c2ecf20Sopenharmony_ci	 * and response to ensure if the job times out and the request is freed,
7108c2ecf20Sopenharmony_ci	 * we won't be dma into memory that is no longer allocated to for the
7118c2ecf20Sopenharmony_ci	 * request.
7128c2ecf20Sopenharmony_ci	 */
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp,
7158c2ecf20Sopenharmony_ci				      ndlp->nlp_DID, elscmd);
7168c2ecf20Sopenharmony_ci	if (!cmdiocbq) {
7178c2ecf20Sopenharmony_ci		rc = -EIO;
7188c2ecf20Sopenharmony_ci		goto release_ndlp;
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	rpi = ndlp->nlp_rpi;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	/* Transfer the request payload to allocated command dma buffer */
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	sg_copy_to_buffer(job->request_payload.sg_list,
7268c2ecf20Sopenharmony_ci			  job->request_payload.sg_cnt,
7278c2ecf20Sopenharmony_ci			  ((struct lpfc_dmabuf *)cmdiocbq->context2)->virt,
7288c2ecf20Sopenharmony_ci			  cmdsize);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
7318c2ecf20Sopenharmony_ci		cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi];
7328c2ecf20Sopenharmony_ci	else
7338c2ecf20Sopenharmony_ci		cmdiocbq->iocb.ulpContext = rpi;
7348c2ecf20Sopenharmony_ci	cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
7358c2ecf20Sopenharmony_ci	cmdiocbq->context1 = dd_data;
7368c2ecf20Sopenharmony_ci	cmdiocbq->context_un.ndlp = ndlp;
7378c2ecf20Sopenharmony_ci	cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp;
7388c2ecf20Sopenharmony_ci	dd_data->type = TYPE_IOCB;
7398c2ecf20Sopenharmony_ci	dd_data->set_job = job;
7408c2ecf20Sopenharmony_ci	dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
7418c2ecf20Sopenharmony_ci	dd_data->context_un.iocb.ndlp = ndlp;
7428c2ecf20Sopenharmony_ci	dd_data->context_un.iocb.rmp = NULL;
7438c2ecf20Sopenharmony_ci	job->dd_data = dd_data;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
7468c2ecf20Sopenharmony_ci		if (lpfc_readl(phba->HCregaddr, &creg_val)) {
7478c2ecf20Sopenharmony_ci			rc = -EIO;
7488c2ecf20Sopenharmony_ci			goto linkdown_err;
7498c2ecf20Sopenharmony_ci		}
7508c2ecf20Sopenharmony_ci		creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING);
7518c2ecf20Sopenharmony_ci		writel(creg_val, phba->HCregaddr);
7528c2ecf20Sopenharmony_ci		readl(phba->HCregaddr); /* flush */
7538c2ecf20Sopenharmony_ci	}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	if (rc == IOCB_SUCCESS) {
7588c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, flags);
7598c2ecf20Sopenharmony_ci		/* make sure the I/O had not been completed/released */
7608c2ecf20Sopenharmony_ci		if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) {
7618c2ecf20Sopenharmony_ci			/* open up abort window to timeout handler */
7628c2ecf20Sopenharmony_ci			cmdiocbq->iocb_flag |= LPFC_IO_CMD_OUTSTANDING;
7638c2ecf20Sopenharmony_ci		}
7648c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, flags);
7658c2ecf20Sopenharmony_ci		return 0; /* done for now */
7668c2ecf20Sopenharmony_ci	} else if (rc == IOCB_BUSY) {
7678c2ecf20Sopenharmony_ci		rc = -EAGAIN;
7688c2ecf20Sopenharmony_ci	} else {
7698c2ecf20Sopenharmony_ci		rc = -EIO;
7708c2ecf20Sopenharmony_ci	}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	/* iocb failed so cleanup */
7738c2ecf20Sopenharmony_ci	job->dd_data = NULL;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cilinkdown_err:
7768c2ecf20Sopenharmony_ci	cmdiocbq->context1 = ndlp;
7778c2ecf20Sopenharmony_ci	lpfc_els_free_iocb(phba, cmdiocbq);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_cirelease_ndlp:
7808c2ecf20Sopenharmony_ci	lpfc_nlp_put(ndlp);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_cifree_dd_data:
7838c2ecf20Sopenharmony_ci	kfree(dd_data);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_cino_dd_data:
7868c2ecf20Sopenharmony_ci	/* make error code available to userspace */
7878c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
7888c2ecf20Sopenharmony_ci	job->dd_data = NULL;
7898c2ecf20Sopenharmony_ci	return rc;
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci/**
7938c2ecf20Sopenharmony_ci * lpfc_bsg_event_free - frees an allocated event structure
7948c2ecf20Sopenharmony_ci * @kref: Pointer to a kref.
7958c2ecf20Sopenharmony_ci *
7968c2ecf20Sopenharmony_ci * Called from kref_put. Back cast the kref into an event structure address.
7978c2ecf20Sopenharmony_ci * Free any events to get, delete associated nodes, free any events to see,
7988c2ecf20Sopenharmony_ci * free any data then free the event itself.
7998c2ecf20Sopenharmony_ci **/
8008c2ecf20Sopenharmony_cistatic void
8018c2ecf20Sopenharmony_cilpfc_bsg_event_free(struct kref *kref)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	struct lpfc_bsg_event *evt = container_of(kref, struct lpfc_bsg_event,
8048c2ecf20Sopenharmony_ci						  kref);
8058c2ecf20Sopenharmony_ci	struct event_data *ed;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	list_del(&evt->node);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	while (!list_empty(&evt->events_to_get)) {
8108c2ecf20Sopenharmony_ci		ed = list_entry(evt->events_to_get.next, typeof(*ed), node);
8118c2ecf20Sopenharmony_ci		list_del(&ed->node);
8128c2ecf20Sopenharmony_ci		kfree(ed->data);
8138c2ecf20Sopenharmony_ci		kfree(ed);
8148c2ecf20Sopenharmony_ci	}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	while (!list_empty(&evt->events_to_see)) {
8178c2ecf20Sopenharmony_ci		ed = list_entry(evt->events_to_see.next, typeof(*ed), node);
8188c2ecf20Sopenharmony_ci		list_del(&ed->node);
8198c2ecf20Sopenharmony_ci		kfree(ed->data);
8208c2ecf20Sopenharmony_ci		kfree(ed);
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	kfree(evt->dd_data);
8248c2ecf20Sopenharmony_ci	kfree(evt);
8258c2ecf20Sopenharmony_ci}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci/**
8288c2ecf20Sopenharmony_ci * lpfc_bsg_event_ref - increments the kref for an event
8298c2ecf20Sopenharmony_ci * @evt: Pointer to an event structure.
8308c2ecf20Sopenharmony_ci **/
8318c2ecf20Sopenharmony_cistatic inline void
8328c2ecf20Sopenharmony_cilpfc_bsg_event_ref(struct lpfc_bsg_event *evt)
8338c2ecf20Sopenharmony_ci{
8348c2ecf20Sopenharmony_ci	kref_get(&evt->kref);
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci/**
8388c2ecf20Sopenharmony_ci * lpfc_bsg_event_unref - Uses kref_put to free an event structure
8398c2ecf20Sopenharmony_ci * @evt: Pointer to an event structure.
8408c2ecf20Sopenharmony_ci **/
8418c2ecf20Sopenharmony_cistatic inline void
8428c2ecf20Sopenharmony_cilpfc_bsg_event_unref(struct lpfc_bsg_event *evt)
8438c2ecf20Sopenharmony_ci{
8448c2ecf20Sopenharmony_ci	kref_put(&evt->kref, lpfc_bsg_event_free);
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci/**
8488c2ecf20Sopenharmony_ci * lpfc_bsg_event_new - allocate and initialize a event structure
8498c2ecf20Sopenharmony_ci * @ev_mask: Mask of events.
8508c2ecf20Sopenharmony_ci * @ev_reg_id: Event reg id.
8518c2ecf20Sopenharmony_ci * @ev_req_id: Event request id.
8528c2ecf20Sopenharmony_ci **/
8538c2ecf20Sopenharmony_cistatic struct lpfc_bsg_event *
8548c2ecf20Sopenharmony_cilpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id)
8558c2ecf20Sopenharmony_ci{
8568c2ecf20Sopenharmony_ci	struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL);
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	if (!evt)
8598c2ecf20Sopenharmony_ci		return NULL;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&evt->events_to_get);
8628c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&evt->events_to_see);
8638c2ecf20Sopenharmony_ci	evt->type_mask = ev_mask;
8648c2ecf20Sopenharmony_ci	evt->req_id = ev_req_id;
8658c2ecf20Sopenharmony_ci	evt->reg_id = ev_reg_id;
8668c2ecf20Sopenharmony_ci	evt->wait_time_stamp = jiffies;
8678c2ecf20Sopenharmony_ci	evt->dd_data = NULL;
8688c2ecf20Sopenharmony_ci	init_waitqueue_head(&evt->wq);
8698c2ecf20Sopenharmony_ci	kref_init(&evt->kref);
8708c2ecf20Sopenharmony_ci	return evt;
8718c2ecf20Sopenharmony_ci}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci/**
8748c2ecf20Sopenharmony_ci * diag_cmd_data_free - Frees an lpfc dma buffer extension
8758c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
8768c2ecf20Sopenharmony_ci * @mlist: Pointer to an lpfc dma buffer extension.
8778c2ecf20Sopenharmony_ci **/
8788c2ecf20Sopenharmony_cistatic int
8798c2ecf20Sopenharmony_cidiag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist)
8808c2ecf20Sopenharmony_ci{
8818c2ecf20Sopenharmony_ci	struct lpfc_dmabufext *mlast;
8828c2ecf20Sopenharmony_ci	struct pci_dev *pcidev;
8838c2ecf20Sopenharmony_ci	struct list_head head, *curr, *next;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	if ((!mlist) || (!lpfc_is_link_up(phba) &&
8868c2ecf20Sopenharmony_ci		(phba->link_flag & LS_LOOPBACK_MODE))) {
8878c2ecf20Sopenharmony_ci		return 0;
8888c2ecf20Sopenharmony_ci	}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	pcidev = phba->pcidev;
8918c2ecf20Sopenharmony_ci	list_add_tail(&head, &mlist->dma.list);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	list_for_each_safe(curr, next, &head) {
8948c2ecf20Sopenharmony_ci		mlast = list_entry(curr, struct lpfc_dmabufext , dma.list);
8958c2ecf20Sopenharmony_ci		if (mlast->dma.virt)
8968c2ecf20Sopenharmony_ci			dma_free_coherent(&pcidev->dev,
8978c2ecf20Sopenharmony_ci					  mlast->size,
8988c2ecf20Sopenharmony_ci					  mlast->dma.virt,
8998c2ecf20Sopenharmony_ci					  mlast->dma.phys);
9008c2ecf20Sopenharmony_ci		kfree(mlast);
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci	return 0;
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci/**
9068c2ecf20Sopenharmony_ci * lpfc_bsg_ct_unsol_event - process an unsolicited CT command
9078c2ecf20Sopenharmony_ci * @phba:
9088c2ecf20Sopenharmony_ci * @pring:
9098c2ecf20Sopenharmony_ci * @piocbq:
9108c2ecf20Sopenharmony_ci *
9118c2ecf20Sopenharmony_ci * This function is called when an unsolicited CT command is received.  It
9128c2ecf20Sopenharmony_ci * forwards the event to any processes registered to receive CT events.
9138c2ecf20Sopenharmony_ci **/
9148c2ecf20Sopenharmony_ciint
9158c2ecf20Sopenharmony_cilpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
9168c2ecf20Sopenharmony_ci			struct lpfc_iocbq *piocbq)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	uint32_t evt_req_id = 0;
9198c2ecf20Sopenharmony_ci	uint32_t cmd;
9208c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmabuf = NULL;
9218c2ecf20Sopenharmony_ci	struct lpfc_bsg_event *evt;
9228c2ecf20Sopenharmony_ci	struct event_data *evt_dat = NULL;
9238c2ecf20Sopenharmony_ci	struct lpfc_iocbq *iocbq;
9248c2ecf20Sopenharmony_ci	size_t offset = 0;
9258c2ecf20Sopenharmony_ci	struct list_head head;
9268c2ecf20Sopenharmony_ci	struct ulp_bde64 *bde;
9278c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
9288c2ecf20Sopenharmony_ci	int i;
9298c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
9308c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
9318c2ecf20Sopenharmony_ci	struct lpfc_hbq_entry *hbqe;
9328c2ecf20Sopenharmony_ci	struct lpfc_sli_ct_request *ct_req;
9338c2ecf20Sopenharmony_ci	struct bsg_job *job = NULL;
9348c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
9358c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data = NULL;
9368c2ecf20Sopenharmony_ci	unsigned long flags;
9378c2ecf20Sopenharmony_ci	int size = 0;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&head);
9408c2ecf20Sopenharmony_ci	list_add_tail(&head, &piocbq->list);
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	if (piocbq->iocb.ulpBdeCount == 0 ||
9438c2ecf20Sopenharmony_ci	    piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0)
9448c2ecf20Sopenharmony_ci		goto error_ct_unsol_exit;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	if (phba->link_state == LPFC_HBA_ERROR ||
9478c2ecf20Sopenharmony_ci		(!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)))
9488c2ecf20Sopenharmony_ci		goto error_ct_unsol_exit;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
9518c2ecf20Sopenharmony_ci		dmabuf = bdeBuf1;
9528c2ecf20Sopenharmony_ci	else {
9538c2ecf20Sopenharmony_ci		dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh,
9548c2ecf20Sopenharmony_ci				    piocbq->iocb.un.cont64[0].addrLow);
9558c2ecf20Sopenharmony_ci		dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr);
9568c2ecf20Sopenharmony_ci	}
9578c2ecf20Sopenharmony_ci	if (dmabuf == NULL)
9588c2ecf20Sopenharmony_ci		goto error_ct_unsol_exit;
9598c2ecf20Sopenharmony_ci	ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt;
9608c2ecf20Sopenharmony_ci	evt_req_id = ct_req->FsType;
9618c2ecf20Sopenharmony_ci	cmd = ct_req->CommandResponse.bits.CmdRsp;
9628c2ecf20Sopenharmony_ci	if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
9638c2ecf20Sopenharmony_ci		lpfc_sli_ringpostbuf_put(phba, pring, dmabuf);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
9668c2ecf20Sopenharmony_ci	list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
9678c2ecf20Sopenharmony_ci		if (!(evt->type_mask & FC_REG_CT_EVENT) ||
9688c2ecf20Sopenharmony_ci			evt->req_id != evt_req_id)
9698c2ecf20Sopenharmony_ci			continue;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci		lpfc_bsg_event_ref(evt);
9728c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
9738c2ecf20Sopenharmony_ci		evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL);
9748c2ecf20Sopenharmony_ci		if (evt_dat == NULL) {
9758c2ecf20Sopenharmony_ci			spin_lock_irqsave(&phba->ct_ev_lock, flags);
9768c2ecf20Sopenharmony_ci			lpfc_bsg_event_unref(evt);
9778c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
9788c2ecf20Sopenharmony_ci					"2614 Memory allocation failed for "
9798c2ecf20Sopenharmony_ci					"CT event\n");
9808c2ecf20Sopenharmony_ci			break;
9818c2ecf20Sopenharmony_ci		}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
9848c2ecf20Sopenharmony_ci			/* take accumulated byte count from the last iocbq */
9858c2ecf20Sopenharmony_ci			iocbq = list_entry(head.prev, typeof(*iocbq), list);
9868c2ecf20Sopenharmony_ci			evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len;
9878c2ecf20Sopenharmony_ci		} else {
9888c2ecf20Sopenharmony_ci			list_for_each_entry(iocbq, &head, list) {
9898c2ecf20Sopenharmony_ci				for (i = 0; i < iocbq->iocb.ulpBdeCount; i++)
9908c2ecf20Sopenharmony_ci					evt_dat->len +=
9918c2ecf20Sopenharmony_ci					iocbq->iocb.un.cont64[i].tus.f.bdeSize;
9928c2ecf20Sopenharmony_ci			}
9938c2ecf20Sopenharmony_ci		}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci		evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL);
9968c2ecf20Sopenharmony_ci		if (evt_dat->data == NULL) {
9978c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
9988c2ecf20Sopenharmony_ci					"2615 Memory allocation failed for "
9998c2ecf20Sopenharmony_ci					"CT event data, size %d\n",
10008c2ecf20Sopenharmony_ci					evt_dat->len);
10018c2ecf20Sopenharmony_ci			kfree(evt_dat);
10028c2ecf20Sopenharmony_ci			spin_lock_irqsave(&phba->ct_ev_lock, flags);
10038c2ecf20Sopenharmony_ci			lpfc_bsg_event_unref(evt);
10048c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
10058c2ecf20Sopenharmony_ci			goto error_ct_unsol_exit;
10068c2ecf20Sopenharmony_ci		}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci		list_for_each_entry(iocbq, &head, list) {
10098c2ecf20Sopenharmony_ci			size = 0;
10108c2ecf20Sopenharmony_ci			if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
10118c2ecf20Sopenharmony_ci				bdeBuf1 = iocbq->context2;
10128c2ecf20Sopenharmony_ci				bdeBuf2 = iocbq->context3;
10138c2ecf20Sopenharmony_ci			}
10148c2ecf20Sopenharmony_ci			for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) {
10158c2ecf20Sopenharmony_ci				if (phba->sli3_options &
10168c2ecf20Sopenharmony_ci				    LPFC_SLI3_HBQ_ENABLED) {
10178c2ecf20Sopenharmony_ci					if (i == 0) {
10188c2ecf20Sopenharmony_ci						hbqe = (struct lpfc_hbq_entry *)
10198c2ecf20Sopenharmony_ci						  &iocbq->iocb.un.ulpWord[0];
10208c2ecf20Sopenharmony_ci						size = hbqe->bde.tus.f.bdeSize;
10218c2ecf20Sopenharmony_ci						dmabuf = bdeBuf1;
10228c2ecf20Sopenharmony_ci					} else if (i == 1) {
10238c2ecf20Sopenharmony_ci						hbqe = (struct lpfc_hbq_entry *)
10248c2ecf20Sopenharmony_ci							&iocbq->iocb.unsli3.
10258c2ecf20Sopenharmony_ci							sli3Words[4];
10268c2ecf20Sopenharmony_ci						size = hbqe->bde.tus.f.bdeSize;
10278c2ecf20Sopenharmony_ci						dmabuf = bdeBuf2;
10288c2ecf20Sopenharmony_ci					}
10298c2ecf20Sopenharmony_ci					if ((offset + size) > evt_dat->len)
10308c2ecf20Sopenharmony_ci						size = evt_dat->len - offset;
10318c2ecf20Sopenharmony_ci				} else {
10328c2ecf20Sopenharmony_ci					size = iocbq->iocb.un.cont64[i].
10338c2ecf20Sopenharmony_ci						tus.f.bdeSize;
10348c2ecf20Sopenharmony_ci					bde = &iocbq->iocb.un.cont64[i];
10358c2ecf20Sopenharmony_ci					dma_addr = getPaddr(bde->addrHigh,
10368c2ecf20Sopenharmony_ci							    bde->addrLow);
10378c2ecf20Sopenharmony_ci					dmabuf = lpfc_sli_ringpostbuf_get(phba,
10388c2ecf20Sopenharmony_ci							pring, dma_addr);
10398c2ecf20Sopenharmony_ci				}
10408c2ecf20Sopenharmony_ci				if (!dmabuf) {
10418c2ecf20Sopenharmony_ci					lpfc_printf_log(phba, KERN_ERR,
10428c2ecf20Sopenharmony_ci						LOG_LIBDFC, "2616 No dmabuf "
10438c2ecf20Sopenharmony_ci						"found for iocbq x%px\n",
10448c2ecf20Sopenharmony_ci						iocbq);
10458c2ecf20Sopenharmony_ci					kfree(evt_dat->data);
10468c2ecf20Sopenharmony_ci					kfree(evt_dat);
10478c2ecf20Sopenharmony_ci					spin_lock_irqsave(&phba->ct_ev_lock,
10488c2ecf20Sopenharmony_ci						flags);
10498c2ecf20Sopenharmony_ci					lpfc_bsg_event_unref(evt);
10508c2ecf20Sopenharmony_ci					spin_unlock_irqrestore(
10518c2ecf20Sopenharmony_ci						&phba->ct_ev_lock, flags);
10528c2ecf20Sopenharmony_ci					goto error_ct_unsol_exit;
10538c2ecf20Sopenharmony_ci				}
10548c2ecf20Sopenharmony_ci				memcpy((char *)(evt_dat->data) + offset,
10558c2ecf20Sopenharmony_ci				       dmabuf->virt, size);
10568c2ecf20Sopenharmony_ci				offset += size;
10578c2ecf20Sopenharmony_ci				if (evt_req_id != SLI_CT_ELX_LOOPBACK &&
10588c2ecf20Sopenharmony_ci				    !(phba->sli3_options &
10598c2ecf20Sopenharmony_ci				      LPFC_SLI3_HBQ_ENABLED)) {
10608c2ecf20Sopenharmony_ci					lpfc_sli_ringpostbuf_put(phba, pring,
10618c2ecf20Sopenharmony_ci								 dmabuf);
10628c2ecf20Sopenharmony_ci				} else {
10638c2ecf20Sopenharmony_ci					switch (cmd) {
10648c2ecf20Sopenharmony_ci					case ELX_LOOPBACK_DATA:
10658c2ecf20Sopenharmony_ci						if (phba->sli_rev <
10668c2ecf20Sopenharmony_ci						    LPFC_SLI_REV4)
10678c2ecf20Sopenharmony_ci							diag_cmd_data_free(phba,
10688c2ecf20Sopenharmony_ci							(struct lpfc_dmabufext
10698c2ecf20Sopenharmony_ci							 *)dmabuf);
10708c2ecf20Sopenharmony_ci						break;
10718c2ecf20Sopenharmony_ci					case ELX_LOOPBACK_XRI_SETUP:
10728c2ecf20Sopenharmony_ci						if ((phba->sli_rev ==
10738c2ecf20Sopenharmony_ci							LPFC_SLI_REV2) ||
10748c2ecf20Sopenharmony_ci							(phba->sli3_options &
10758c2ecf20Sopenharmony_ci							LPFC_SLI3_HBQ_ENABLED
10768c2ecf20Sopenharmony_ci							)) {
10778c2ecf20Sopenharmony_ci							lpfc_in_buf_free(phba,
10788c2ecf20Sopenharmony_ci									dmabuf);
10798c2ecf20Sopenharmony_ci						} else {
10808c2ecf20Sopenharmony_ci							lpfc_post_buffer(phba,
10818c2ecf20Sopenharmony_ci									 pring,
10828c2ecf20Sopenharmony_ci									 1);
10838c2ecf20Sopenharmony_ci						}
10848c2ecf20Sopenharmony_ci						break;
10858c2ecf20Sopenharmony_ci					default:
10868c2ecf20Sopenharmony_ci						if (!(phba->sli3_options &
10878c2ecf20Sopenharmony_ci						      LPFC_SLI3_HBQ_ENABLED))
10888c2ecf20Sopenharmony_ci							lpfc_post_buffer(phba,
10898c2ecf20Sopenharmony_ci									 pring,
10908c2ecf20Sopenharmony_ci									 1);
10918c2ecf20Sopenharmony_ci						break;
10928c2ecf20Sopenharmony_ci					}
10938c2ecf20Sopenharmony_ci				}
10948c2ecf20Sopenharmony_ci			}
10958c2ecf20Sopenharmony_ci		}
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->ct_ev_lock, flags);
10988c2ecf20Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4) {
10998c2ecf20Sopenharmony_ci			evt_dat->immed_dat = phba->ctx_idx;
11008c2ecf20Sopenharmony_ci			phba->ctx_idx = (phba->ctx_idx + 1) % LPFC_CT_CTX_MAX;
11018c2ecf20Sopenharmony_ci			/* Provide warning for over-run of the ct_ctx array */
11028c2ecf20Sopenharmony_ci			if (phba->ct_ctx[evt_dat->immed_dat].valid ==
11038c2ecf20Sopenharmony_ci			    UNSOL_VALID)
11048c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
11058c2ecf20Sopenharmony_ci						"2717 CT context array entry "
11068c2ecf20Sopenharmony_ci						"[%d] over-run: oxid:x%x, "
11078c2ecf20Sopenharmony_ci						"sid:x%x\n", phba->ctx_idx,
11088c2ecf20Sopenharmony_ci						phba->ct_ctx[
11098c2ecf20Sopenharmony_ci						    evt_dat->immed_dat].oxid,
11108c2ecf20Sopenharmony_ci						phba->ct_ctx[
11118c2ecf20Sopenharmony_ci						    evt_dat->immed_dat].SID);
11128c2ecf20Sopenharmony_ci			phba->ct_ctx[evt_dat->immed_dat].rxid =
11138c2ecf20Sopenharmony_ci				piocbq->iocb.ulpContext;
11148c2ecf20Sopenharmony_ci			phba->ct_ctx[evt_dat->immed_dat].oxid =
11158c2ecf20Sopenharmony_ci				piocbq->iocb.unsli3.rcvsli3.ox_id;
11168c2ecf20Sopenharmony_ci			phba->ct_ctx[evt_dat->immed_dat].SID =
11178c2ecf20Sopenharmony_ci				piocbq->iocb.un.rcvels.remoteID;
11188c2ecf20Sopenharmony_ci			phba->ct_ctx[evt_dat->immed_dat].valid = UNSOL_VALID;
11198c2ecf20Sopenharmony_ci		} else
11208c2ecf20Sopenharmony_ci			evt_dat->immed_dat = piocbq->iocb.ulpContext;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci		evt_dat->type = FC_REG_CT_EVENT;
11238c2ecf20Sopenharmony_ci		list_add(&evt_dat->node, &evt->events_to_see);
11248c2ecf20Sopenharmony_ci		if (evt_req_id == SLI_CT_ELX_LOOPBACK) {
11258c2ecf20Sopenharmony_ci			wake_up_interruptible(&evt->wq);
11268c2ecf20Sopenharmony_ci			lpfc_bsg_event_unref(evt);
11278c2ecf20Sopenharmony_ci			break;
11288c2ecf20Sopenharmony_ci		}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci		list_move(evt->events_to_see.prev, &evt->events_to_get);
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci		dd_data = (struct bsg_job_data *)evt->dd_data;
11338c2ecf20Sopenharmony_ci		job = dd_data->set_job;
11348c2ecf20Sopenharmony_ci		dd_data->set_job = NULL;
11358c2ecf20Sopenharmony_ci		lpfc_bsg_event_unref(evt);
11368c2ecf20Sopenharmony_ci		if (job) {
11378c2ecf20Sopenharmony_ci			bsg_reply = job->reply;
11388c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len = size;
11398c2ecf20Sopenharmony_ci			/* make error code available to userspace */
11408c2ecf20Sopenharmony_ci			bsg_reply->result = 0;
11418c2ecf20Sopenharmony_ci			job->dd_data = NULL;
11428c2ecf20Sopenharmony_ci			/* complete the job back to userspace */
11438c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
11448c2ecf20Sopenharmony_ci			bsg_job_done(job, bsg_reply->result,
11458c2ecf20Sopenharmony_ci				       bsg_reply->reply_payload_rcv_len);
11468c2ecf20Sopenharmony_ci			spin_lock_irqsave(&phba->ct_ev_lock, flags);
11478c2ecf20Sopenharmony_ci		}
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_cierror_ct_unsol_exit:
11528c2ecf20Sopenharmony_ci	if (!list_empty(&head))
11538c2ecf20Sopenharmony_ci		list_del(&head);
11548c2ecf20Sopenharmony_ci	if ((phba->sli_rev < LPFC_SLI_REV4) &&
11558c2ecf20Sopenharmony_ci	    (evt_req_id == SLI_CT_ELX_LOOPBACK))
11568c2ecf20Sopenharmony_ci		return 0;
11578c2ecf20Sopenharmony_ci	return 1;
11588c2ecf20Sopenharmony_ci}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci/**
11618c2ecf20Sopenharmony_ci * lpfc_bsg_ct_unsol_abort - handler ct abort to management plane
11628c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
11638c2ecf20Sopenharmony_ci * @dmabuf: pointer to a dmabuf that describes the FC sequence
11648c2ecf20Sopenharmony_ci *
11658c2ecf20Sopenharmony_ci * This function handles abort to the CT command toward management plane
11668c2ecf20Sopenharmony_ci * for SLI4 port.
11678c2ecf20Sopenharmony_ci *
11688c2ecf20Sopenharmony_ci * If the pending context of a CT command to management plane present, clears
11698c2ecf20Sopenharmony_ci * such context and returns 1 for handled; otherwise, it returns 0 indicating
11708c2ecf20Sopenharmony_ci * no context exists.
11718c2ecf20Sopenharmony_ci **/
11728c2ecf20Sopenharmony_ciint
11738c2ecf20Sopenharmony_cilpfc_bsg_ct_unsol_abort(struct lpfc_hba *phba, struct hbq_dmabuf *dmabuf)
11748c2ecf20Sopenharmony_ci{
11758c2ecf20Sopenharmony_ci	struct fc_frame_header fc_hdr;
11768c2ecf20Sopenharmony_ci	struct fc_frame_header *fc_hdr_ptr = &fc_hdr;
11778c2ecf20Sopenharmony_ci	int ctx_idx, handled = 0;
11788c2ecf20Sopenharmony_ci	uint16_t oxid, rxid;
11798c2ecf20Sopenharmony_ci	uint32_t sid;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	memcpy(fc_hdr_ptr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header));
11828c2ecf20Sopenharmony_ci	sid = sli4_sid_from_fc_hdr(fc_hdr_ptr);
11838c2ecf20Sopenharmony_ci	oxid = be16_to_cpu(fc_hdr_ptr->fh_ox_id);
11848c2ecf20Sopenharmony_ci	rxid = be16_to_cpu(fc_hdr_ptr->fh_rx_id);
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	for (ctx_idx = 0; ctx_idx < LPFC_CT_CTX_MAX; ctx_idx++) {
11878c2ecf20Sopenharmony_ci		if (phba->ct_ctx[ctx_idx].valid != UNSOL_VALID)
11888c2ecf20Sopenharmony_ci			continue;
11898c2ecf20Sopenharmony_ci		if (phba->ct_ctx[ctx_idx].rxid != rxid)
11908c2ecf20Sopenharmony_ci			continue;
11918c2ecf20Sopenharmony_ci		if (phba->ct_ctx[ctx_idx].oxid != oxid)
11928c2ecf20Sopenharmony_ci			continue;
11938c2ecf20Sopenharmony_ci		if (phba->ct_ctx[ctx_idx].SID != sid)
11948c2ecf20Sopenharmony_ci			continue;
11958c2ecf20Sopenharmony_ci		phba->ct_ctx[ctx_idx].valid = UNSOL_INVALID;
11968c2ecf20Sopenharmony_ci		handled = 1;
11978c2ecf20Sopenharmony_ci	}
11988c2ecf20Sopenharmony_ci	return handled;
11998c2ecf20Sopenharmony_ci}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci/**
12028c2ecf20Sopenharmony_ci * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command
12038c2ecf20Sopenharmony_ci * @job: SET_EVENT fc_bsg_job
12048c2ecf20Sopenharmony_ci **/
12058c2ecf20Sopenharmony_cistatic int
12068c2ecf20Sopenharmony_cilpfc_bsg_hba_set_event(struct bsg_job *job)
12078c2ecf20Sopenharmony_ci{
12088c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
12098c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
12108c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
12118c2ecf20Sopenharmony_ci	struct set_ct_event *event_req;
12128c2ecf20Sopenharmony_ci	struct lpfc_bsg_event *evt;
12138c2ecf20Sopenharmony_ci	int rc = 0;
12148c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data = NULL;
12158c2ecf20Sopenharmony_ci	uint32_t ev_mask;
12168c2ecf20Sopenharmony_ci	unsigned long flags;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	if (job->request_len <
12198c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) {
12208c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
12218c2ecf20Sopenharmony_ci				"2612 Received SET_CT_EVENT below minimum "
12228c2ecf20Sopenharmony_ci				"size\n");
12238c2ecf20Sopenharmony_ci		rc = -EINVAL;
12248c2ecf20Sopenharmony_ci		goto job_error;
12258c2ecf20Sopenharmony_ci	}
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	event_req = (struct set_ct_event *)
12288c2ecf20Sopenharmony_ci		bsg_request->rqst_data.h_vendor.vendor_cmd;
12298c2ecf20Sopenharmony_ci	ev_mask = ((uint32_t)(unsigned long)event_req->type_mask &
12308c2ecf20Sopenharmony_ci				FC_REG_EVENT_MASK);
12318c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
12328c2ecf20Sopenharmony_ci	list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
12338c2ecf20Sopenharmony_ci		if (evt->reg_id == event_req->ev_reg_id) {
12348c2ecf20Sopenharmony_ci			lpfc_bsg_event_ref(evt);
12358c2ecf20Sopenharmony_ci			evt->wait_time_stamp = jiffies;
12368c2ecf20Sopenharmony_ci			dd_data = (struct bsg_job_data *)evt->dd_data;
12378c2ecf20Sopenharmony_ci			break;
12388c2ecf20Sopenharmony_ci		}
12398c2ecf20Sopenharmony_ci	}
12408c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	if (&evt->node == &phba->ct_ev_waiters) {
12438c2ecf20Sopenharmony_ci		/* no event waiting struct yet - first call */
12448c2ecf20Sopenharmony_ci		dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
12458c2ecf20Sopenharmony_ci		if (dd_data == NULL) {
12468c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
12478c2ecf20Sopenharmony_ci					"2734 Failed allocation of dd_data\n");
12488c2ecf20Sopenharmony_ci			rc = -ENOMEM;
12498c2ecf20Sopenharmony_ci			goto job_error;
12508c2ecf20Sopenharmony_ci		}
12518c2ecf20Sopenharmony_ci		evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id,
12528c2ecf20Sopenharmony_ci					event_req->ev_req_id);
12538c2ecf20Sopenharmony_ci		if (!evt) {
12548c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
12558c2ecf20Sopenharmony_ci					"2617 Failed allocation of event "
12568c2ecf20Sopenharmony_ci					"waiter\n");
12578c2ecf20Sopenharmony_ci			rc = -ENOMEM;
12588c2ecf20Sopenharmony_ci			goto job_error;
12598c2ecf20Sopenharmony_ci		}
12608c2ecf20Sopenharmony_ci		dd_data->type = TYPE_EVT;
12618c2ecf20Sopenharmony_ci		dd_data->set_job = NULL;
12628c2ecf20Sopenharmony_ci		dd_data->context_un.evt = evt;
12638c2ecf20Sopenharmony_ci		evt->dd_data = (void *)dd_data;
12648c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->ct_ev_lock, flags);
12658c2ecf20Sopenharmony_ci		list_add(&evt->node, &phba->ct_ev_waiters);
12668c2ecf20Sopenharmony_ci		lpfc_bsg_event_ref(evt);
12678c2ecf20Sopenharmony_ci		evt->wait_time_stamp = jiffies;
12688c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
12698c2ecf20Sopenharmony_ci	}
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
12728c2ecf20Sopenharmony_ci	evt->waiting = 1;
12738c2ecf20Sopenharmony_ci	dd_data->set_job = job; /* for unsolicited command */
12748c2ecf20Sopenharmony_ci	job->dd_data = dd_data; /* for fc transport timeout callback*/
12758c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
12768c2ecf20Sopenharmony_ci	return 0; /* call job done later */
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_cijob_error:
12798c2ecf20Sopenharmony_ci	kfree(dd_data);
12808c2ecf20Sopenharmony_ci	job->dd_data = NULL;
12818c2ecf20Sopenharmony_ci	return rc;
12828c2ecf20Sopenharmony_ci}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci/**
12858c2ecf20Sopenharmony_ci * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command
12868c2ecf20Sopenharmony_ci * @job: GET_EVENT fc_bsg_job
12878c2ecf20Sopenharmony_ci **/
12888c2ecf20Sopenharmony_cistatic int
12898c2ecf20Sopenharmony_cilpfc_bsg_hba_get_event(struct bsg_job *job)
12908c2ecf20Sopenharmony_ci{
12918c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
12928c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
12938c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
12948c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
12958c2ecf20Sopenharmony_ci	struct get_ct_event *event_req;
12968c2ecf20Sopenharmony_ci	struct get_ct_event_reply *event_reply;
12978c2ecf20Sopenharmony_ci	struct lpfc_bsg_event *evt, *evt_next;
12988c2ecf20Sopenharmony_ci	struct event_data *evt_dat = NULL;
12998c2ecf20Sopenharmony_ci	unsigned long flags;
13008c2ecf20Sopenharmony_ci	uint32_t rc = 0;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	if (job->request_len <
13038c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) {
13048c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
13058c2ecf20Sopenharmony_ci				"2613 Received GET_CT_EVENT request below "
13068c2ecf20Sopenharmony_ci				"minimum size\n");
13078c2ecf20Sopenharmony_ci		rc = -EINVAL;
13088c2ecf20Sopenharmony_ci		goto job_error;
13098c2ecf20Sopenharmony_ci	}
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	event_req = (struct get_ct_event *)
13128c2ecf20Sopenharmony_ci		bsg_request->rqst_data.h_vendor.vendor_cmd;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	event_reply = (struct get_ct_event_reply *)
13158c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp;
13168c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
13178c2ecf20Sopenharmony_ci	list_for_each_entry_safe(evt, evt_next, &phba->ct_ev_waiters, node) {
13188c2ecf20Sopenharmony_ci		if (evt->reg_id == event_req->ev_reg_id) {
13198c2ecf20Sopenharmony_ci			if (list_empty(&evt->events_to_get))
13208c2ecf20Sopenharmony_ci				break;
13218c2ecf20Sopenharmony_ci			lpfc_bsg_event_ref(evt);
13228c2ecf20Sopenharmony_ci			evt->wait_time_stamp = jiffies;
13238c2ecf20Sopenharmony_ci			evt_dat = list_entry(evt->events_to_get.prev,
13248c2ecf20Sopenharmony_ci					     struct event_data, node);
13258c2ecf20Sopenharmony_ci			list_del(&evt_dat->node);
13268c2ecf20Sopenharmony_ci			break;
13278c2ecf20Sopenharmony_ci		}
13288c2ecf20Sopenharmony_ci	}
13298c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	/* The app may continue to ask for event data until it gets
13328c2ecf20Sopenharmony_ci	 * an error indicating that there isn't anymore
13338c2ecf20Sopenharmony_ci	 */
13348c2ecf20Sopenharmony_ci	if (evt_dat == NULL) {
13358c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len = 0;
13368c2ecf20Sopenharmony_ci		rc = -ENOENT;
13378c2ecf20Sopenharmony_ci		goto job_error;
13388c2ecf20Sopenharmony_ci	}
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	if (evt_dat->len > job->request_payload.payload_len) {
13418c2ecf20Sopenharmony_ci		evt_dat->len = job->request_payload.payload_len;
13428c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
13438c2ecf20Sopenharmony_ci				"2618 Truncated event data at %d "
13448c2ecf20Sopenharmony_ci				"bytes\n",
13458c2ecf20Sopenharmony_ci				job->request_payload.payload_len);
13468c2ecf20Sopenharmony_ci	}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	event_reply->type = evt_dat->type;
13498c2ecf20Sopenharmony_ci	event_reply->immed_data = evt_dat->immed_dat;
13508c2ecf20Sopenharmony_ci	if (evt_dat->len > 0)
13518c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len =
13528c2ecf20Sopenharmony_ci			sg_copy_from_buffer(job->request_payload.sg_list,
13538c2ecf20Sopenharmony_ci					    job->request_payload.sg_cnt,
13548c2ecf20Sopenharmony_ci					    evt_dat->data, evt_dat->len);
13558c2ecf20Sopenharmony_ci	else
13568c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len = 0;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	if (evt_dat) {
13598c2ecf20Sopenharmony_ci		kfree(evt_dat->data);
13608c2ecf20Sopenharmony_ci		kfree(evt_dat);
13618c2ecf20Sopenharmony_ci	}
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
13648c2ecf20Sopenharmony_ci	lpfc_bsg_event_unref(evt);
13658c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
13668c2ecf20Sopenharmony_ci	job->dd_data = NULL;
13678c2ecf20Sopenharmony_ci	bsg_reply->result = 0;
13688c2ecf20Sopenharmony_ci	bsg_job_done(job, bsg_reply->result,
13698c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
13708c2ecf20Sopenharmony_ci	return 0;
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_cijob_error:
13738c2ecf20Sopenharmony_ci	job->dd_data = NULL;
13748c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
13758c2ecf20Sopenharmony_ci	return rc;
13768c2ecf20Sopenharmony_ci}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci/**
13798c2ecf20Sopenharmony_ci * lpfc_issue_ct_rsp_cmp - lpfc_issue_ct_rsp's completion handler
13808c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
13818c2ecf20Sopenharmony_ci * @cmdiocbq: Pointer to command iocb.
13828c2ecf20Sopenharmony_ci * @rspiocbq: Pointer to response iocb.
13838c2ecf20Sopenharmony_ci *
13848c2ecf20Sopenharmony_ci * This function is the completion handler for iocbs issued using
13858c2ecf20Sopenharmony_ci * lpfc_issue_ct_rsp_cmp function. This function is called by the
13868c2ecf20Sopenharmony_ci * ring event handler function without any lock held. This function
13878c2ecf20Sopenharmony_ci * can be called from both worker thread context and interrupt
13888c2ecf20Sopenharmony_ci * context. This function also can be called from other thread which
13898c2ecf20Sopenharmony_ci * cleans up the SLI layer objects.
13908c2ecf20Sopenharmony_ci * This function copy the contents of the response iocb to the
13918c2ecf20Sopenharmony_ci * response iocb memory object provided by the caller of
13928c2ecf20Sopenharmony_ci * lpfc_sli_issue_iocb_wait and then wakes up the thread which
13938c2ecf20Sopenharmony_ci * sleeps for the iocb completion.
13948c2ecf20Sopenharmony_ci **/
13958c2ecf20Sopenharmony_cistatic void
13968c2ecf20Sopenharmony_cilpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba,
13978c2ecf20Sopenharmony_ci			struct lpfc_iocbq *cmdiocbq,
13988c2ecf20Sopenharmony_ci			struct lpfc_iocbq *rspiocbq)
13998c2ecf20Sopenharmony_ci{
14008c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data;
14018c2ecf20Sopenharmony_ci	struct bsg_job *job;
14028c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
14038c2ecf20Sopenharmony_ci	IOCB_t *rsp;
14048c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *bmp, *cmp;
14058c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
14068c2ecf20Sopenharmony_ci	unsigned long flags;
14078c2ecf20Sopenharmony_ci	int rc = 0;
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	dd_data = cmdiocbq->context1;
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	/* Determine if job has been aborted */
14128c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
14138c2ecf20Sopenharmony_ci	job = dd_data->set_job;
14148c2ecf20Sopenharmony_ci	if (job) {
14158c2ecf20Sopenharmony_ci		/* Prevent timeout handling from trying to abort job  */
14168c2ecf20Sopenharmony_ci		job->dd_data = NULL;
14178c2ecf20Sopenharmony_ci	}
14188c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	/* Close the timeout handler abort window */
14218c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, flags);
14228c2ecf20Sopenharmony_ci	cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING;
14238c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, flags);
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	ndlp = dd_data->context_un.iocb.ndlp;
14268c2ecf20Sopenharmony_ci	cmp = cmdiocbq->context2;
14278c2ecf20Sopenharmony_ci	bmp = cmdiocbq->context3;
14288c2ecf20Sopenharmony_ci	rsp = &rspiocbq->iocb;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	/* Copy the completed job data or set the error status */
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	if (job) {
14338c2ecf20Sopenharmony_ci		bsg_reply = job->reply;
14348c2ecf20Sopenharmony_ci		if (rsp->ulpStatus) {
14358c2ecf20Sopenharmony_ci			if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
14368c2ecf20Sopenharmony_ci				switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
14378c2ecf20Sopenharmony_ci				case IOERR_SEQUENCE_TIMEOUT:
14388c2ecf20Sopenharmony_ci					rc = -ETIMEDOUT;
14398c2ecf20Sopenharmony_ci					break;
14408c2ecf20Sopenharmony_ci				case IOERR_INVALID_RPI:
14418c2ecf20Sopenharmony_ci					rc = -EFAULT;
14428c2ecf20Sopenharmony_ci					break;
14438c2ecf20Sopenharmony_ci				default:
14448c2ecf20Sopenharmony_ci					rc = -EACCES;
14458c2ecf20Sopenharmony_ci					break;
14468c2ecf20Sopenharmony_ci				}
14478c2ecf20Sopenharmony_ci			} else {
14488c2ecf20Sopenharmony_ci				rc = -EACCES;
14498c2ecf20Sopenharmony_ci			}
14508c2ecf20Sopenharmony_ci		} else {
14518c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len = 0;
14528c2ecf20Sopenharmony_ci		}
14538c2ecf20Sopenharmony_ci	}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	lpfc_free_bsg_buffers(phba, cmp);
14568c2ecf20Sopenharmony_ci	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
14578c2ecf20Sopenharmony_ci	kfree(bmp);
14588c2ecf20Sopenharmony_ci	lpfc_sli_release_iocbq(phba, cmdiocbq);
14598c2ecf20Sopenharmony_ci	lpfc_nlp_put(ndlp);
14608c2ecf20Sopenharmony_ci	kfree(dd_data);
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	/* Complete the job if the job is still active */
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	if (job) {
14658c2ecf20Sopenharmony_ci		bsg_reply->result = rc;
14668c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
14678c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
14688c2ecf20Sopenharmony_ci	}
14698c2ecf20Sopenharmony_ci	return;
14708c2ecf20Sopenharmony_ci}
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci/**
14738c2ecf20Sopenharmony_ci * lpfc_issue_ct_rsp - issue a ct response
14748c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
14758c2ecf20Sopenharmony_ci * @job: Pointer to the job object.
14768c2ecf20Sopenharmony_ci * @tag: tag index value into the ports context exchange array.
14778c2ecf20Sopenharmony_ci * @bmp: Pointer to a dma buffer descriptor.
14788c2ecf20Sopenharmony_ci * @num_entry: Number of enties in the bde.
14798c2ecf20Sopenharmony_ci **/
14808c2ecf20Sopenharmony_cistatic int
14818c2ecf20Sopenharmony_cilpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag,
14828c2ecf20Sopenharmony_ci		  struct lpfc_dmabuf *cmp, struct lpfc_dmabuf *bmp,
14838c2ecf20Sopenharmony_ci		  int num_entry)
14848c2ecf20Sopenharmony_ci{
14858c2ecf20Sopenharmony_ci	IOCB_t *icmd;
14868c2ecf20Sopenharmony_ci	struct lpfc_iocbq *ctiocb = NULL;
14878c2ecf20Sopenharmony_ci	int rc = 0;
14888c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp = NULL;
14898c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data;
14908c2ecf20Sopenharmony_ci	unsigned long flags;
14918c2ecf20Sopenharmony_ci	uint32_t creg_val;
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci	/* allocate our bsg tracking structure */
14948c2ecf20Sopenharmony_ci	dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
14958c2ecf20Sopenharmony_ci	if (!dd_data) {
14968c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
14978c2ecf20Sopenharmony_ci				"2736 Failed allocation of dd_data\n");
14988c2ecf20Sopenharmony_ci		rc = -ENOMEM;
14998c2ecf20Sopenharmony_ci		goto no_dd_data;
15008c2ecf20Sopenharmony_ci	}
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	/* Allocate buffer for  command iocb */
15038c2ecf20Sopenharmony_ci	ctiocb = lpfc_sli_get_iocbq(phba);
15048c2ecf20Sopenharmony_ci	if (!ctiocb) {
15058c2ecf20Sopenharmony_ci		rc = -ENOMEM;
15068c2ecf20Sopenharmony_ci		goto no_ctiocb;
15078c2ecf20Sopenharmony_ci	}
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	icmd = &ctiocb->iocb;
15108c2ecf20Sopenharmony_ci	icmd->un.xseq64.bdl.ulpIoTag32 = 0;
15118c2ecf20Sopenharmony_ci	icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
15128c2ecf20Sopenharmony_ci	icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys);
15138c2ecf20Sopenharmony_ci	icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
15148c2ecf20Sopenharmony_ci	icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64));
15158c2ecf20Sopenharmony_ci	icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA);
15168c2ecf20Sopenharmony_ci	icmd->un.xseq64.w5.hcsw.Dfctl = 0;
15178c2ecf20Sopenharmony_ci	icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL;
15188c2ecf20Sopenharmony_ci	icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT;
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	/* Fill in rest of iocb */
15218c2ecf20Sopenharmony_ci	icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX;
15228c2ecf20Sopenharmony_ci	icmd->ulpBdeCount = 1;
15238c2ecf20Sopenharmony_ci	icmd->ulpLe = 1;
15248c2ecf20Sopenharmony_ci	icmd->ulpClass = CLASS3;
15258c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4) {
15268c2ecf20Sopenharmony_ci		/* Do not issue unsol response if oxid not marked as valid */
15278c2ecf20Sopenharmony_ci		if (phba->ct_ctx[tag].valid != UNSOL_VALID) {
15288c2ecf20Sopenharmony_ci			rc = IOCB_ERROR;
15298c2ecf20Sopenharmony_ci			goto issue_ct_rsp_exit;
15308c2ecf20Sopenharmony_ci		}
15318c2ecf20Sopenharmony_ci		icmd->ulpContext = phba->ct_ctx[tag].rxid;
15328c2ecf20Sopenharmony_ci		icmd->unsli3.rcvsli3.ox_id = phba->ct_ctx[tag].oxid;
15338c2ecf20Sopenharmony_ci		ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID);
15348c2ecf20Sopenharmony_ci		if (!ndlp) {
15358c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
15368c2ecf20Sopenharmony_ci				 "2721 ndlp null for oxid %x SID %x\n",
15378c2ecf20Sopenharmony_ci					icmd->ulpContext,
15388c2ecf20Sopenharmony_ci					phba->ct_ctx[tag].SID);
15398c2ecf20Sopenharmony_ci			rc = IOCB_ERROR;
15408c2ecf20Sopenharmony_ci			goto issue_ct_rsp_exit;
15418c2ecf20Sopenharmony_ci		}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci		/* Check if the ndlp is active */
15448c2ecf20Sopenharmony_ci		if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
15458c2ecf20Sopenharmony_ci			rc = IOCB_ERROR;
15468c2ecf20Sopenharmony_ci			goto issue_ct_rsp_exit;
15478c2ecf20Sopenharmony_ci		}
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci		/* get a refernece count so the ndlp doesn't go away while
15508c2ecf20Sopenharmony_ci		 * we respond
15518c2ecf20Sopenharmony_ci		 */
15528c2ecf20Sopenharmony_ci		if (!lpfc_nlp_get(ndlp)) {
15538c2ecf20Sopenharmony_ci			rc = IOCB_ERROR;
15548c2ecf20Sopenharmony_ci			goto issue_ct_rsp_exit;
15558c2ecf20Sopenharmony_ci		}
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci		icmd->un.ulpWord[3] =
15588c2ecf20Sopenharmony_ci				phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci		/* The exchange is done, mark the entry as invalid */
15618c2ecf20Sopenharmony_ci		phba->ct_ctx[tag].valid = UNSOL_INVALID;
15628c2ecf20Sopenharmony_ci	} else
15638c2ecf20Sopenharmony_ci		icmd->ulpContext = (ushort) tag;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	icmd->ulpTimeout = phba->fc_ratov * 2;
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	/* Xmit CT response on exchange <xid> */
15688c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
15698c2ecf20Sopenharmony_ci		"2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n",
15708c2ecf20Sopenharmony_ci		icmd->ulpContext, icmd->ulpIoTag, tag, phba->link_state);
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	ctiocb->iocb_flag |= LPFC_IO_LIBDFC;
15738c2ecf20Sopenharmony_ci	ctiocb->vport = phba->pport;
15748c2ecf20Sopenharmony_ci	ctiocb->context1 = dd_data;
15758c2ecf20Sopenharmony_ci	ctiocb->context2 = cmp;
15768c2ecf20Sopenharmony_ci	ctiocb->context3 = bmp;
15778c2ecf20Sopenharmony_ci	ctiocb->context_un.ndlp = ndlp;
15788c2ecf20Sopenharmony_ci	ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	dd_data->type = TYPE_IOCB;
15818c2ecf20Sopenharmony_ci	dd_data->set_job = job;
15828c2ecf20Sopenharmony_ci	dd_data->context_un.iocb.cmdiocbq = ctiocb;
15838c2ecf20Sopenharmony_ci	dd_data->context_un.iocb.ndlp = ndlp;
15848c2ecf20Sopenharmony_ci	dd_data->context_un.iocb.rmp = NULL;
15858c2ecf20Sopenharmony_ci	job->dd_data = dd_data;
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
15888c2ecf20Sopenharmony_ci		if (lpfc_readl(phba->HCregaddr, &creg_val)) {
15898c2ecf20Sopenharmony_ci			rc = -IOCB_ERROR;
15908c2ecf20Sopenharmony_ci			goto issue_ct_rsp_exit;
15918c2ecf20Sopenharmony_ci		}
15928c2ecf20Sopenharmony_ci		creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING);
15938c2ecf20Sopenharmony_ci		writel(creg_val, phba->HCregaddr);
15948c2ecf20Sopenharmony_ci		readl(phba->HCregaddr); /* flush */
15958c2ecf20Sopenharmony_ci	}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0);
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	if (rc == IOCB_SUCCESS) {
16008c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, flags);
16018c2ecf20Sopenharmony_ci		/* make sure the I/O had not been completed/released */
16028c2ecf20Sopenharmony_ci		if (ctiocb->iocb_flag & LPFC_IO_LIBDFC) {
16038c2ecf20Sopenharmony_ci			/* open up abort window to timeout handler */
16048c2ecf20Sopenharmony_ci			ctiocb->iocb_flag |= LPFC_IO_CMD_OUTSTANDING;
16058c2ecf20Sopenharmony_ci		}
16068c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, flags);
16078c2ecf20Sopenharmony_ci		return 0; /* done for now */
16088c2ecf20Sopenharmony_ci	}
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	/* iocb failed so cleanup */
16118c2ecf20Sopenharmony_ci	job->dd_data = NULL;
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ciissue_ct_rsp_exit:
16148c2ecf20Sopenharmony_ci	lpfc_sli_release_iocbq(phba, ctiocb);
16158c2ecf20Sopenharmony_cino_ctiocb:
16168c2ecf20Sopenharmony_ci	kfree(dd_data);
16178c2ecf20Sopenharmony_cino_dd_data:
16188c2ecf20Sopenharmony_ci	return rc;
16198c2ecf20Sopenharmony_ci}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci/**
16228c2ecf20Sopenharmony_ci * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command
16238c2ecf20Sopenharmony_ci * @job: SEND_MGMT_RESP fc_bsg_job
16248c2ecf20Sopenharmony_ci **/
16258c2ecf20Sopenharmony_cistatic int
16268c2ecf20Sopenharmony_cilpfc_bsg_send_mgmt_rsp(struct bsg_job *job)
16278c2ecf20Sopenharmony_ci{
16288c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
16298c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
16308c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
16318c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
16328c2ecf20Sopenharmony_ci	struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *)
16338c2ecf20Sopenharmony_ci		bsg_request->rqst_data.h_vendor.vendor_cmd;
16348c2ecf20Sopenharmony_ci	struct ulp_bde64 *bpl;
16358c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *bmp = NULL, *cmp = NULL;
16368c2ecf20Sopenharmony_ci	int bpl_entries;
16378c2ecf20Sopenharmony_ci	uint32_t tag = mgmt_resp->tag;
16388c2ecf20Sopenharmony_ci	unsigned long reqbfrcnt =
16398c2ecf20Sopenharmony_ci			(unsigned long)job->request_payload.payload_len;
16408c2ecf20Sopenharmony_ci	int rc = 0;
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	/* in case no data is transferred */
16438c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) {
16468c2ecf20Sopenharmony_ci		rc = -ERANGE;
16478c2ecf20Sopenharmony_ci		goto send_mgmt_rsp_exit;
16488c2ecf20Sopenharmony_ci	}
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci	bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
16518c2ecf20Sopenharmony_ci	if (!bmp) {
16528c2ecf20Sopenharmony_ci		rc = -ENOMEM;
16538c2ecf20Sopenharmony_ci		goto send_mgmt_rsp_exit;
16548c2ecf20Sopenharmony_ci	}
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
16578c2ecf20Sopenharmony_ci	if (!bmp->virt) {
16588c2ecf20Sopenharmony_ci		rc = -ENOMEM;
16598c2ecf20Sopenharmony_ci		goto send_mgmt_rsp_free_bmp;
16608c2ecf20Sopenharmony_ci	}
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&bmp->list);
16638c2ecf20Sopenharmony_ci	bpl = (struct ulp_bde64 *) bmp->virt;
16648c2ecf20Sopenharmony_ci	bpl_entries = (LPFC_BPL_SIZE/sizeof(struct ulp_bde64));
16658c2ecf20Sopenharmony_ci	cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len,
16668c2ecf20Sopenharmony_ci				     1, bpl, &bpl_entries);
16678c2ecf20Sopenharmony_ci	if (!cmp) {
16688c2ecf20Sopenharmony_ci		rc = -ENOMEM;
16698c2ecf20Sopenharmony_ci		goto send_mgmt_rsp_free_bmp;
16708c2ecf20Sopenharmony_ci	}
16718c2ecf20Sopenharmony_ci	lpfc_bsg_copy_data(cmp, &job->request_payload,
16728c2ecf20Sopenharmony_ci			   job->request_payload.payload_len, 1);
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	rc = lpfc_issue_ct_rsp(phba, job, tag, cmp, bmp, bpl_entries);
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	if (rc == IOCB_SUCCESS)
16778c2ecf20Sopenharmony_ci		return 0; /* done for now */
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	rc = -EACCES;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	lpfc_free_bsg_buffers(phba, cmp);
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_cisend_mgmt_rsp_free_bmp:
16848c2ecf20Sopenharmony_ci	if (bmp->virt)
16858c2ecf20Sopenharmony_ci		lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
16868c2ecf20Sopenharmony_ci	kfree(bmp);
16878c2ecf20Sopenharmony_cisend_mgmt_rsp_exit:
16888c2ecf20Sopenharmony_ci	/* make error code available to userspace */
16898c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
16908c2ecf20Sopenharmony_ci	job->dd_data = NULL;
16918c2ecf20Sopenharmony_ci	return rc;
16928c2ecf20Sopenharmony_ci}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci/**
16958c2ecf20Sopenharmony_ci * lpfc_bsg_diag_mode_enter - process preparing into device diag loopback mode
16968c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
16978c2ecf20Sopenharmony_ci *
16988c2ecf20Sopenharmony_ci * This function is responsible for preparing driver for diag loopback
16998c2ecf20Sopenharmony_ci * on device.
17008c2ecf20Sopenharmony_ci */
17018c2ecf20Sopenharmony_cistatic int
17028c2ecf20Sopenharmony_cilpfc_bsg_diag_mode_enter(struct lpfc_hba *phba)
17038c2ecf20Sopenharmony_ci{
17048c2ecf20Sopenharmony_ci	struct lpfc_vport **vports;
17058c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
17068c2ecf20Sopenharmony_ci	struct lpfc_sli *psli;
17078c2ecf20Sopenharmony_ci	struct lpfc_queue *qp = NULL;
17088c2ecf20Sopenharmony_ci	struct lpfc_sli_ring *pring;
17098c2ecf20Sopenharmony_ci	int i = 0;
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	psli = &phba->sli;
17128c2ecf20Sopenharmony_ci	if (!psli)
17138c2ecf20Sopenharmony_ci		return -ENODEV;
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	if ((phba->link_state == LPFC_HBA_ERROR) ||
17178c2ecf20Sopenharmony_ci	    (psli->sli_flag & LPFC_BLOCK_MGMT_IO) ||
17188c2ecf20Sopenharmony_ci	    (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
17198c2ecf20Sopenharmony_ci		return -EACCES;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	vports = lpfc_create_vport_work_array(phba);
17228c2ecf20Sopenharmony_ci	if (vports) {
17238c2ecf20Sopenharmony_ci		for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
17248c2ecf20Sopenharmony_ci			shost = lpfc_shost_from_vport(vports[i]);
17258c2ecf20Sopenharmony_ci			scsi_block_requests(shost);
17268c2ecf20Sopenharmony_ci		}
17278c2ecf20Sopenharmony_ci		lpfc_destroy_vport_work_array(phba, vports);
17288c2ecf20Sopenharmony_ci	} else {
17298c2ecf20Sopenharmony_ci		shost = lpfc_shost_from_vport(phba->pport);
17308c2ecf20Sopenharmony_ci		scsi_block_requests(shost);
17318c2ecf20Sopenharmony_ci	}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	if (phba->sli_rev != LPFC_SLI_REV4) {
17348c2ecf20Sopenharmony_ci		pring = &psli->sli3_ring[LPFC_FCP_RING];
17358c2ecf20Sopenharmony_ci		lpfc_emptyq_wait(phba, &pring->txcmplq, &phba->hbalock);
17368c2ecf20Sopenharmony_ci		return 0;
17378c2ecf20Sopenharmony_ci	}
17388c2ecf20Sopenharmony_ci	list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) {
17398c2ecf20Sopenharmony_ci		pring = qp->pring;
17408c2ecf20Sopenharmony_ci		if (!pring || (pring->ringno != LPFC_FCP_RING))
17418c2ecf20Sopenharmony_ci			continue;
17428c2ecf20Sopenharmony_ci		if (!lpfc_emptyq_wait(phba, &pring->txcmplq,
17438c2ecf20Sopenharmony_ci				      &pring->ring_lock))
17448c2ecf20Sopenharmony_ci			break;
17458c2ecf20Sopenharmony_ci	}
17468c2ecf20Sopenharmony_ci	return 0;
17478c2ecf20Sopenharmony_ci}
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci/**
17508c2ecf20Sopenharmony_ci * lpfc_bsg_diag_mode_exit - exit process from device diag loopback mode
17518c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
17528c2ecf20Sopenharmony_ci *
17538c2ecf20Sopenharmony_ci * This function is responsible for driver exit processing of setting up
17548c2ecf20Sopenharmony_ci * diag loopback mode on device.
17558c2ecf20Sopenharmony_ci */
17568c2ecf20Sopenharmony_cistatic void
17578c2ecf20Sopenharmony_cilpfc_bsg_diag_mode_exit(struct lpfc_hba *phba)
17588c2ecf20Sopenharmony_ci{
17598c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
17608c2ecf20Sopenharmony_ci	struct lpfc_vport **vports;
17618c2ecf20Sopenharmony_ci	int i;
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	vports = lpfc_create_vport_work_array(phba);
17648c2ecf20Sopenharmony_ci	if (vports) {
17658c2ecf20Sopenharmony_ci		for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
17668c2ecf20Sopenharmony_ci			shost = lpfc_shost_from_vport(vports[i]);
17678c2ecf20Sopenharmony_ci			scsi_unblock_requests(shost);
17688c2ecf20Sopenharmony_ci		}
17698c2ecf20Sopenharmony_ci		lpfc_destroy_vport_work_array(phba, vports);
17708c2ecf20Sopenharmony_ci	} else {
17718c2ecf20Sopenharmony_ci		shost = lpfc_shost_from_vport(phba->pport);
17728c2ecf20Sopenharmony_ci		scsi_unblock_requests(shost);
17738c2ecf20Sopenharmony_ci	}
17748c2ecf20Sopenharmony_ci	return;
17758c2ecf20Sopenharmony_ci}
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci/**
17788c2ecf20Sopenharmony_ci * lpfc_sli3_bsg_diag_loopback_mode - process an sli3 bsg vendor command
17798c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
17808c2ecf20Sopenharmony_ci * @job: LPFC_BSG_VENDOR_DIAG_MODE
17818c2ecf20Sopenharmony_ci *
17828c2ecf20Sopenharmony_ci * This function is responsible for placing an sli3  port into diagnostic
17838c2ecf20Sopenharmony_ci * loopback mode in order to perform a diagnostic loopback test.
17848c2ecf20Sopenharmony_ci * All new scsi requests are blocked, a small delay is used to allow the
17858c2ecf20Sopenharmony_ci * scsi requests to complete then the link is brought down. If the link is
17868c2ecf20Sopenharmony_ci * is placed in loopback mode then scsi requests are again allowed
17878c2ecf20Sopenharmony_ci * so the scsi mid-layer doesn't give up on the port.
17888c2ecf20Sopenharmony_ci * All of this is done in-line.
17898c2ecf20Sopenharmony_ci */
17908c2ecf20Sopenharmony_cistatic int
17918c2ecf20Sopenharmony_cilpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job)
17928c2ecf20Sopenharmony_ci{
17938c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
17948c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
17958c2ecf20Sopenharmony_ci	struct diag_mode_set *loopback_mode;
17968c2ecf20Sopenharmony_ci	uint32_t link_flags;
17978c2ecf20Sopenharmony_ci	uint32_t timeout;
17988c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *pmboxq  = NULL;
17998c2ecf20Sopenharmony_ci	int mbxstatus = MBX_SUCCESS;
18008c2ecf20Sopenharmony_ci	int i = 0;
18018c2ecf20Sopenharmony_ci	int rc = 0;
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	/* no data to return just the return code */
18048c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	if (job->request_len < sizeof(struct fc_bsg_request) +
18078c2ecf20Sopenharmony_ci	    sizeof(struct diag_mode_set)) {
18088c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
18098c2ecf20Sopenharmony_ci				"2738 Received DIAG MODE request size:%d "
18108c2ecf20Sopenharmony_ci				"below the minimum size:%d\n",
18118c2ecf20Sopenharmony_ci				job->request_len,
18128c2ecf20Sopenharmony_ci				(int)(sizeof(struct fc_bsg_request) +
18138c2ecf20Sopenharmony_ci				sizeof(struct diag_mode_set)));
18148c2ecf20Sopenharmony_ci		rc = -EINVAL;
18158c2ecf20Sopenharmony_ci		goto job_error;
18168c2ecf20Sopenharmony_ci	}
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	rc = lpfc_bsg_diag_mode_enter(phba);
18198c2ecf20Sopenharmony_ci	if (rc)
18208c2ecf20Sopenharmony_ci		goto job_error;
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	/* bring the link to diagnostic mode */
18238c2ecf20Sopenharmony_ci	loopback_mode = (struct diag_mode_set *)
18248c2ecf20Sopenharmony_ci		bsg_request->rqst_data.h_vendor.vendor_cmd;
18258c2ecf20Sopenharmony_ci	link_flags = loopback_mode->type;
18268c2ecf20Sopenharmony_ci	timeout = loopback_mode->timeout * 100;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
18298c2ecf20Sopenharmony_ci	if (!pmboxq) {
18308c2ecf20Sopenharmony_ci		rc = -ENOMEM;
18318c2ecf20Sopenharmony_ci		goto loopback_mode_exit;
18328c2ecf20Sopenharmony_ci	}
18338c2ecf20Sopenharmony_ci	memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t));
18348c2ecf20Sopenharmony_ci	pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK;
18358c2ecf20Sopenharmony_ci	pmboxq->u.mb.mbxOwner = OWN_HOST;
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) {
18408c2ecf20Sopenharmony_ci		/* wait for link down before proceeding */
18418c2ecf20Sopenharmony_ci		i = 0;
18428c2ecf20Sopenharmony_ci		while (phba->link_state != LPFC_LINK_DOWN) {
18438c2ecf20Sopenharmony_ci			if (i++ > timeout) {
18448c2ecf20Sopenharmony_ci				rc = -ETIMEDOUT;
18458c2ecf20Sopenharmony_ci				goto loopback_mode_exit;
18468c2ecf20Sopenharmony_ci			}
18478c2ecf20Sopenharmony_ci			msleep(10);
18488c2ecf20Sopenharmony_ci		}
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci		memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t));
18518c2ecf20Sopenharmony_ci		if (link_flags == INTERNAL_LOOP_BACK)
18528c2ecf20Sopenharmony_ci			pmboxq->u.mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB;
18538c2ecf20Sopenharmony_ci		else
18548c2ecf20Sopenharmony_ci			pmboxq->u.mb.un.varInitLnk.link_flags =
18558c2ecf20Sopenharmony_ci				FLAGS_TOPOLOGY_MODE_LOOP;
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci		pmboxq->u.mb.mbxCommand = MBX_INIT_LINK;
18588c2ecf20Sopenharmony_ci		pmboxq->u.mb.mbxOwner = OWN_HOST;
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci		mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq,
18618c2ecf20Sopenharmony_ci						     LPFC_MBOX_TMO);
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci		if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus))
18648c2ecf20Sopenharmony_ci			rc = -ENODEV;
18658c2ecf20Sopenharmony_ci		else {
18668c2ecf20Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
18678c2ecf20Sopenharmony_ci			phba->link_flag |= LS_LOOPBACK_MODE;
18688c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
18698c2ecf20Sopenharmony_ci			/* wait for the link attention interrupt */
18708c2ecf20Sopenharmony_ci			msleep(100);
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci			i = 0;
18738c2ecf20Sopenharmony_ci			while (phba->link_state != LPFC_HBA_READY) {
18748c2ecf20Sopenharmony_ci				if (i++ > timeout) {
18758c2ecf20Sopenharmony_ci					rc = -ETIMEDOUT;
18768c2ecf20Sopenharmony_ci					break;
18778c2ecf20Sopenharmony_ci				}
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci				msleep(10);
18808c2ecf20Sopenharmony_ci			}
18818c2ecf20Sopenharmony_ci		}
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	} else
18848c2ecf20Sopenharmony_ci		rc = -ENODEV;
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ciloopback_mode_exit:
18878c2ecf20Sopenharmony_ci	lpfc_bsg_diag_mode_exit(phba);
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	/*
18908c2ecf20Sopenharmony_ci	 * Let SLI layer release mboxq if mbox command completed after timeout.
18918c2ecf20Sopenharmony_ci	 */
18928c2ecf20Sopenharmony_ci	if (pmboxq && mbxstatus != MBX_TIMEOUT)
18938c2ecf20Sopenharmony_ci		mempool_free(pmboxq, phba->mbox_mem_pool);
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_cijob_error:
18968c2ecf20Sopenharmony_ci	/* make error code available to userspace */
18978c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
18988c2ecf20Sopenharmony_ci	/* complete the job back to userspace if no error */
18998c2ecf20Sopenharmony_ci	if (rc == 0)
19008c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
19018c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
19028c2ecf20Sopenharmony_ci	return rc;
19038c2ecf20Sopenharmony_ci}
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci/**
19068c2ecf20Sopenharmony_ci * lpfc_sli4_bsg_set_link_diag_state - set sli4 link diag state
19078c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
19088c2ecf20Sopenharmony_ci * @diag: Flag for set link to diag or nomral operation state.
19098c2ecf20Sopenharmony_ci *
19108c2ecf20Sopenharmony_ci * This function is responsible for issuing a sli4 mailbox command for setting
19118c2ecf20Sopenharmony_ci * link to either diag state or normal operation state.
19128c2ecf20Sopenharmony_ci */
19138c2ecf20Sopenharmony_cistatic int
19148c2ecf20Sopenharmony_cilpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag)
19158c2ecf20Sopenharmony_ci{
19168c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *pmboxq;
19178c2ecf20Sopenharmony_ci	struct lpfc_mbx_set_link_diag_state *link_diag_state;
19188c2ecf20Sopenharmony_ci	uint32_t req_len, alloc_len;
19198c2ecf20Sopenharmony_ci	int mbxstatus = MBX_SUCCESS, rc;
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
19228c2ecf20Sopenharmony_ci	if (!pmboxq)
19238c2ecf20Sopenharmony_ci		return -ENOMEM;
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) -
19268c2ecf20Sopenharmony_ci		   sizeof(struct lpfc_sli4_cfg_mhdr));
19278c2ecf20Sopenharmony_ci	alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
19288c2ecf20Sopenharmony_ci				LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE,
19298c2ecf20Sopenharmony_ci				req_len, LPFC_SLI4_MBX_EMBED);
19308c2ecf20Sopenharmony_ci	if (alloc_len != req_len) {
19318c2ecf20Sopenharmony_ci		rc = -ENOMEM;
19328c2ecf20Sopenharmony_ci		goto link_diag_state_set_out;
19338c2ecf20Sopenharmony_ci	}
19348c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
19358c2ecf20Sopenharmony_ci			"3128 Set link to diagnostic state:x%x (x%x/x%x)\n",
19368c2ecf20Sopenharmony_ci			diag, phba->sli4_hba.lnk_info.lnk_tp,
19378c2ecf20Sopenharmony_ci			phba->sli4_hba.lnk_info.lnk_no);
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	link_diag_state = &pmboxq->u.mqe.un.link_diag_state;
19408c2ecf20Sopenharmony_ci	bf_set(lpfc_mbx_set_diag_state_diag_bit_valid, &link_diag_state->u.req,
19418c2ecf20Sopenharmony_ci	       LPFC_DIAG_STATE_DIAG_BIT_VALID_CHANGE);
19428c2ecf20Sopenharmony_ci	bf_set(lpfc_mbx_set_diag_state_link_num, &link_diag_state->u.req,
19438c2ecf20Sopenharmony_ci	       phba->sli4_hba.lnk_info.lnk_no);
19448c2ecf20Sopenharmony_ci	bf_set(lpfc_mbx_set_diag_state_link_type, &link_diag_state->u.req,
19458c2ecf20Sopenharmony_ci	       phba->sli4_hba.lnk_info.lnk_tp);
19468c2ecf20Sopenharmony_ci	if (diag)
19478c2ecf20Sopenharmony_ci		bf_set(lpfc_mbx_set_diag_state_diag,
19488c2ecf20Sopenharmony_ci		       &link_diag_state->u.req, 1);
19498c2ecf20Sopenharmony_ci	else
19508c2ecf20Sopenharmony_ci		bf_set(lpfc_mbx_set_diag_state_diag,
19518c2ecf20Sopenharmony_ci		       &link_diag_state->u.req, 0);
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0))
19568c2ecf20Sopenharmony_ci		rc = 0;
19578c2ecf20Sopenharmony_ci	else
19588c2ecf20Sopenharmony_ci		rc = -ENODEV;
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_cilink_diag_state_set_out:
19618c2ecf20Sopenharmony_ci	if (pmboxq && (mbxstatus != MBX_TIMEOUT))
19628c2ecf20Sopenharmony_ci		mempool_free(pmboxq, phba->mbox_mem_pool);
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci	return rc;
19658c2ecf20Sopenharmony_ci}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci/**
19688c2ecf20Sopenharmony_ci * lpfc_sli4_bsg_set_loopback_mode - set sli4 internal loopback diagnostic
19698c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
19708c2ecf20Sopenharmony_ci * @mode: loopback mode to set
19718c2ecf20Sopenharmony_ci * @link_no: link number for loopback mode to set
19728c2ecf20Sopenharmony_ci *
19738c2ecf20Sopenharmony_ci * This function is responsible for issuing a sli4 mailbox command for setting
19748c2ecf20Sopenharmony_ci * up loopback diagnostic for a link.
19758c2ecf20Sopenharmony_ci */
19768c2ecf20Sopenharmony_cistatic int
19778c2ecf20Sopenharmony_cilpfc_sli4_bsg_set_loopback_mode(struct lpfc_hba *phba, int mode,
19788c2ecf20Sopenharmony_ci				uint32_t link_no)
19798c2ecf20Sopenharmony_ci{
19808c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *pmboxq;
19818c2ecf20Sopenharmony_ci	uint32_t req_len, alloc_len;
19828c2ecf20Sopenharmony_ci	struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback;
19838c2ecf20Sopenharmony_ci	int mbxstatus = MBX_SUCCESS, rc = 0;
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
19868c2ecf20Sopenharmony_ci	if (!pmboxq)
19878c2ecf20Sopenharmony_ci		return -ENOMEM;
19888c2ecf20Sopenharmony_ci	req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) -
19898c2ecf20Sopenharmony_ci		   sizeof(struct lpfc_sli4_cfg_mhdr));
19908c2ecf20Sopenharmony_ci	alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
19918c2ecf20Sopenharmony_ci				LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK,
19928c2ecf20Sopenharmony_ci				req_len, LPFC_SLI4_MBX_EMBED);
19938c2ecf20Sopenharmony_ci	if (alloc_len != req_len) {
19948c2ecf20Sopenharmony_ci		mempool_free(pmboxq, phba->mbox_mem_pool);
19958c2ecf20Sopenharmony_ci		return -ENOMEM;
19968c2ecf20Sopenharmony_ci	}
19978c2ecf20Sopenharmony_ci	link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback;
19988c2ecf20Sopenharmony_ci	bf_set(lpfc_mbx_set_diag_state_link_num,
19998c2ecf20Sopenharmony_ci	       &link_diag_loopback->u.req, link_no);
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci	if (phba->sli4_hba.conf_trunk & (1 << link_no)) {
20028c2ecf20Sopenharmony_ci		bf_set(lpfc_mbx_set_diag_state_link_type,
20038c2ecf20Sopenharmony_ci		       &link_diag_loopback->u.req, LPFC_LNK_FC_TRUNKED);
20048c2ecf20Sopenharmony_ci	} else {
20058c2ecf20Sopenharmony_ci		bf_set(lpfc_mbx_set_diag_state_link_type,
20068c2ecf20Sopenharmony_ci		       &link_diag_loopback->u.req,
20078c2ecf20Sopenharmony_ci		       phba->sli4_hba.lnk_info.lnk_tp);
20088c2ecf20Sopenharmony_ci	}
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci	bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req,
20118c2ecf20Sopenharmony_ci	       mode);
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
20148c2ecf20Sopenharmony_ci	if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) {
20158c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
20168c2ecf20Sopenharmony_ci				"3127 Failed setup loopback mode mailbox "
20178c2ecf20Sopenharmony_ci				"command, rc:x%x, status:x%x\n", mbxstatus,
20188c2ecf20Sopenharmony_ci				pmboxq->u.mb.mbxStatus);
20198c2ecf20Sopenharmony_ci		rc = -ENODEV;
20208c2ecf20Sopenharmony_ci	}
20218c2ecf20Sopenharmony_ci	if (pmboxq && (mbxstatus != MBX_TIMEOUT))
20228c2ecf20Sopenharmony_ci		mempool_free(pmboxq, phba->mbox_mem_pool);
20238c2ecf20Sopenharmony_ci	return rc;
20248c2ecf20Sopenharmony_ci}
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci/**
20278c2ecf20Sopenharmony_ci * lpfc_sli4_diag_fcport_reg_setup - setup port registrations for diagnostic
20288c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
20298c2ecf20Sopenharmony_ci *
20308c2ecf20Sopenharmony_ci * This function set up SLI4 FC port registrations for diagnostic run, which
20318c2ecf20Sopenharmony_ci * includes all the rpis, vfi, and also vpi.
20328c2ecf20Sopenharmony_ci */
20338c2ecf20Sopenharmony_cistatic int
20348c2ecf20Sopenharmony_cilpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba)
20358c2ecf20Sopenharmony_ci{
20368c2ecf20Sopenharmony_ci	int rc;
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	if (phba->pport->fc_flag & FC_VFI_REGISTERED) {
20398c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
20408c2ecf20Sopenharmony_ci				"3136 Port still had vfi registered: "
20418c2ecf20Sopenharmony_ci				"mydid:x%x, fcfi:%d, vfi:%d, vpi:%d\n",
20428c2ecf20Sopenharmony_ci				phba->pport->fc_myDID, phba->fcf.fcfi,
20438c2ecf20Sopenharmony_ci				phba->sli4_hba.vfi_ids[phba->pport->vfi],
20448c2ecf20Sopenharmony_ci				phba->vpi_ids[phba->pport->vpi]);
20458c2ecf20Sopenharmony_ci		return -EINVAL;
20468c2ecf20Sopenharmony_ci	}
20478c2ecf20Sopenharmony_ci	rc = lpfc_issue_reg_vfi(phba->pport);
20488c2ecf20Sopenharmony_ci	return rc;
20498c2ecf20Sopenharmony_ci}
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci/**
20528c2ecf20Sopenharmony_ci * lpfc_sli4_bsg_diag_loopback_mode - process an sli4 bsg vendor command
20538c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
20548c2ecf20Sopenharmony_ci * @job: LPFC_BSG_VENDOR_DIAG_MODE
20558c2ecf20Sopenharmony_ci *
20568c2ecf20Sopenharmony_ci * This function is responsible for placing an sli4 port into diagnostic
20578c2ecf20Sopenharmony_ci * loopback mode in order to perform a diagnostic loopback test.
20588c2ecf20Sopenharmony_ci */
20598c2ecf20Sopenharmony_cistatic int
20608c2ecf20Sopenharmony_cilpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job)
20618c2ecf20Sopenharmony_ci{
20628c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
20638c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
20648c2ecf20Sopenharmony_ci	struct diag_mode_set *loopback_mode;
20658c2ecf20Sopenharmony_ci	uint32_t link_flags, timeout, link_no;
20668c2ecf20Sopenharmony_ci	int i, rc = 0;
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	/* no data to return just the return code */
20698c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	if (job->request_len < sizeof(struct fc_bsg_request) +
20728c2ecf20Sopenharmony_ci	    sizeof(struct diag_mode_set)) {
20738c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
20748c2ecf20Sopenharmony_ci				"3011 Received DIAG MODE request size:%d "
20758c2ecf20Sopenharmony_ci				"below the minimum size:%d\n",
20768c2ecf20Sopenharmony_ci				job->request_len,
20778c2ecf20Sopenharmony_ci				(int)(sizeof(struct fc_bsg_request) +
20788c2ecf20Sopenharmony_ci				sizeof(struct diag_mode_set)));
20798c2ecf20Sopenharmony_ci		rc = -EINVAL;
20808c2ecf20Sopenharmony_ci		goto job_done;
20818c2ecf20Sopenharmony_ci	}
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	loopback_mode = (struct diag_mode_set *)
20848c2ecf20Sopenharmony_ci		bsg_request->rqst_data.h_vendor.vendor_cmd;
20858c2ecf20Sopenharmony_ci	link_flags = loopback_mode->type;
20868c2ecf20Sopenharmony_ci	timeout = loopback_mode->timeout * 100;
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	if (loopback_mode->physical_link == -1)
20898c2ecf20Sopenharmony_ci		link_no = phba->sli4_hba.lnk_info.lnk_no;
20908c2ecf20Sopenharmony_ci	else
20918c2ecf20Sopenharmony_ci		link_no = loopback_mode->physical_link;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	if (link_flags == DISABLE_LOOP_BACK) {
20948c2ecf20Sopenharmony_ci		rc = lpfc_sli4_bsg_set_loopback_mode(phba,
20958c2ecf20Sopenharmony_ci					LPFC_DIAG_LOOPBACK_TYPE_DISABLE,
20968c2ecf20Sopenharmony_ci					link_no);
20978c2ecf20Sopenharmony_ci		if (!rc) {
20988c2ecf20Sopenharmony_ci			/* Unset the need disable bit */
20998c2ecf20Sopenharmony_ci			phba->sli4_hba.conf_trunk &= ~((1 << link_no) << 4);
21008c2ecf20Sopenharmony_ci		}
21018c2ecf20Sopenharmony_ci		goto job_done;
21028c2ecf20Sopenharmony_ci	} else {
21038c2ecf20Sopenharmony_ci		/* Check if we need to disable the loopback state */
21048c2ecf20Sopenharmony_ci		if (phba->sli4_hba.conf_trunk & ((1 << link_no) << 4)) {
21058c2ecf20Sopenharmony_ci			rc = -EPERM;
21068c2ecf20Sopenharmony_ci			goto job_done;
21078c2ecf20Sopenharmony_ci		}
21088c2ecf20Sopenharmony_ci	}
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci	rc = lpfc_bsg_diag_mode_enter(phba);
21118c2ecf20Sopenharmony_ci	if (rc)
21128c2ecf20Sopenharmony_ci		goto job_done;
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	/* indicate we are in loobpack diagnostic mode */
21158c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
21168c2ecf20Sopenharmony_ci	phba->link_flag |= LS_LOOPBACK_MODE;
21178c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci	/* reset port to start frome scratch */
21208c2ecf20Sopenharmony_ci	rc = lpfc_selective_reset(phba);
21218c2ecf20Sopenharmony_ci	if (rc)
21228c2ecf20Sopenharmony_ci		goto job_done;
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	/* bring the link to diagnostic mode */
21258c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
21268c2ecf20Sopenharmony_ci			"3129 Bring link to diagnostic state.\n");
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1);
21298c2ecf20Sopenharmony_ci	if (rc) {
21308c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
21318c2ecf20Sopenharmony_ci				"3130 Failed to bring link to diagnostic "
21328c2ecf20Sopenharmony_ci				"state, rc:x%x\n", rc);
21338c2ecf20Sopenharmony_ci		goto loopback_mode_exit;
21348c2ecf20Sopenharmony_ci	}
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci	/* wait for link down before proceeding */
21378c2ecf20Sopenharmony_ci	i = 0;
21388c2ecf20Sopenharmony_ci	while (phba->link_state != LPFC_LINK_DOWN) {
21398c2ecf20Sopenharmony_ci		if (i++ > timeout) {
21408c2ecf20Sopenharmony_ci			rc = -ETIMEDOUT;
21418c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
21428c2ecf20Sopenharmony_ci					"3131 Timeout waiting for link to "
21438c2ecf20Sopenharmony_ci					"diagnostic mode, timeout:%d ms\n",
21448c2ecf20Sopenharmony_ci					timeout * 10);
21458c2ecf20Sopenharmony_ci			goto loopback_mode_exit;
21468c2ecf20Sopenharmony_ci		}
21478c2ecf20Sopenharmony_ci		msleep(10);
21488c2ecf20Sopenharmony_ci	}
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	/* set up loopback mode */
21518c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
21528c2ecf20Sopenharmony_ci			"3132 Set up loopback mode:x%x\n", link_flags);
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	switch (link_flags) {
21558c2ecf20Sopenharmony_ci	case INTERNAL_LOOP_BACK:
21568c2ecf20Sopenharmony_ci		if (phba->sli4_hba.conf_trunk & (1 << link_no)) {
21578c2ecf20Sopenharmony_ci			rc = lpfc_sli4_bsg_set_loopback_mode(phba,
21588c2ecf20Sopenharmony_ci					LPFC_DIAG_LOOPBACK_TYPE_INTERNAL,
21598c2ecf20Sopenharmony_ci					link_no);
21608c2ecf20Sopenharmony_ci		} else {
21618c2ecf20Sopenharmony_ci			/* Trunk is configured, but link is not in this trunk */
21628c2ecf20Sopenharmony_ci			if (phba->sli4_hba.conf_trunk) {
21638c2ecf20Sopenharmony_ci				rc = -ELNRNG;
21648c2ecf20Sopenharmony_ci				goto loopback_mode_exit;
21658c2ecf20Sopenharmony_ci			}
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci			rc = lpfc_sli4_bsg_set_loopback_mode(phba,
21688c2ecf20Sopenharmony_ci					LPFC_DIAG_LOOPBACK_TYPE_INTERNAL,
21698c2ecf20Sopenharmony_ci					link_no);
21708c2ecf20Sopenharmony_ci		}
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci		if (!rc) {
21738c2ecf20Sopenharmony_ci			/* Set the need disable bit */
21748c2ecf20Sopenharmony_ci			phba->sli4_hba.conf_trunk |= (1 << link_no) << 4;
21758c2ecf20Sopenharmony_ci		}
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci		break;
21788c2ecf20Sopenharmony_ci	case EXTERNAL_LOOP_BACK:
21798c2ecf20Sopenharmony_ci		if (phba->sli4_hba.conf_trunk & (1 << link_no)) {
21808c2ecf20Sopenharmony_ci			rc = lpfc_sli4_bsg_set_loopback_mode(phba,
21818c2ecf20Sopenharmony_ci				LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL_TRUNKED,
21828c2ecf20Sopenharmony_ci				link_no);
21838c2ecf20Sopenharmony_ci		} else {
21848c2ecf20Sopenharmony_ci			/* Trunk is configured, but link is not in this trunk */
21858c2ecf20Sopenharmony_ci			if (phba->sli4_hba.conf_trunk) {
21868c2ecf20Sopenharmony_ci				rc = -ELNRNG;
21878c2ecf20Sopenharmony_ci				goto loopback_mode_exit;
21888c2ecf20Sopenharmony_ci			}
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci			rc = lpfc_sli4_bsg_set_loopback_mode(phba,
21918c2ecf20Sopenharmony_ci						LPFC_DIAG_LOOPBACK_TYPE_SERDES,
21928c2ecf20Sopenharmony_ci						link_no);
21938c2ecf20Sopenharmony_ci		}
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci		if (!rc) {
21968c2ecf20Sopenharmony_ci			/* Set the need disable bit */
21978c2ecf20Sopenharmony_ci			phba->sli4_hba.conf_trunk |= (1 << link_no) << 4;
21988c2ecf20Sopenharmony_ci		}
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci		break;
22018c2ecf20Sopenharmony_ci	default:
22028c2ecf20Sopenharmony_ci		rc = -EINVAL;
22038c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
22048c2ecf20Sopenharmony_ci				"3141 Loopback mode:x%x not supported\n",
22058c2ecf20Sopenharmony_ci				link_flags);
22068c2ecf20Sopenharmony_ci		goto loopback_mode_exit;
22078c2ecf20Sopenharmony_ci	}
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	if (!rc) {
22108c2ecf20Sopenharmony_ci		/* wait for the link attention interrupt */
22118c2ecf20Sopenharmony_ci		msleep(100);
22128c2ecf20Sopenharmony_ci		i = 0;
22138c2ecf20Sopenharmony_ci		while (phba->link_state < LPFC_LINK_UP) {
22148c2ecf20Sopenharmony_ci			if (i++ > timeout) {
22158c2ecf20Sopenharmony_ci				rc = -ETIMEDOUT;
22168c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
22178c2ecf20Sopenharmony_ci					"3137 Timeout waiting for link up "
22188c2ecf20Sopenharmony_ci					"in loopback mode, timeout:%d ms\n",
22198c2ecf20Sopenharmony_ci					timeout * 10);
22208c2ecf20Sopenharmony_ci				break;
22218c2ecf20Sopenharmony_ci			}
22228c2ecf20Sopenharmony_ci			msleep(10);
22238c2ecf20Sopenharmony_ci		}
22248c2ecf20Sopenharmony_ci	}
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_ci	/* port resource registration setup for loopback diagnostic */
22278c2ecf20Sopenharmony_ci	if (!rc) {
22288c2ecf20Sopenharmony_ci		/* set up a none zero myDID for loopback test */
22298c2ecf20Sopenharmony_ci		phba->pport->fc_myDID = 1;
22308c2ecf20Sopenharmony_ci		rc = lpfc_sli4_diag_fcport_reg_setup(phba);
22318c2ecf20Sopenharmony_ci	} else
22328c2ecf20Sopenharmony_ci		goto loopback_mode_exit;
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	if (!rc) {
22358c2ecf20Sopenharmony_ci		/* wait for the port ready */
22368c2ecf20Sopenharmony_ci		msleep(100);
22378c2ecf20Sopenharmony_ci		i = 0;
22388c2ecf20Sopenharmony_ci		while (phba->link_state != LPFC_HBA_READY) {
22398c2ecf20Sopenharmony_ci			if (i++ > timeout) {
22408c2ecf20Sopenharmony_ci				rc = -ETIMEDOUT;
22418c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
22428c2ecf20Sopenharmony_ci					"3133 Timeout waiting for port "
22438c2ecf20Sopenharmony_ci					"loopback mode ready, timeout:%d ms\n",
22448c2ecf20Sopenharmony_ci					timeout * 10);
22458c2ecf20Sopenharmony_ci				break;
22468c2ecf20Sopenharmony_ci			}
22478c2ecf20Sopenharmony_ci			msleep(10);
22488c2ecf20Sopenharmony_ci		}
22498c2ecf20Sopenharmony_ci	}
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ciloopback_mode_exit:
22528c2ecf20Sopenharmony_ci	/* clear loopback diagnostic mode */
22538c2ecf20Sopenharmony_ci	if (rc) {
22548c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
22558c2ecf20Sopenharmony_ci		phba->link_flag &= ~LS_LOOPBACK_MODE;
22568c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
22578c2ecf20Sopenharmony_ci	}
22588c2ecf20Sopenharmony_ci	lpfc_bsg_diag_mode_exit(phba);
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_cijob_done:
22618c2ecf20Sopenharmony_ci	/* make error code available to userspace */
22628c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
22638c2ecf20Sopenharmony_ci	/* complete the job back to userspace if no error */
22648c2ecf20Sopenharmony_ci	if (rc == 0)
22658c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
22668c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
22678c2ecf20Sopenharmony_ci	return rc;
22688c2ecf20Sopenharmony_ci}
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci/**
22718c2ecf20Sopenharmony_ci * lpfc_bsg_diag_loopback_mode - bsg vendor command for diag loopback mode
22728c2ecf20Sopenharmony_ci * @job: LPFC_BSG_VENDOR_DIAG_MODE
22738c2ecf20Sopenharmony_ci *
22748c2ecf20Sopenharmony_ci * This function is responsible for responding to check and dispatch bsg diag
22758c2ecf20Sopenharmony_ci * command from the user to proper driver action routines.
22768c2ecf20Sopenharmony_ci */
22778c2ecf20Sopenharmony_cistatic int
22788c2ecf20Sopenharmony_cilpfc_bsg_diag_loopback_mode(struct bsg_job *job)
22798c2ecf20Sopenharmony_ci{
22808c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
22818c2ecf20Sopenharmony_ci	struct lpfc_vport *vport;
22828c2ecf20Sopenharmony_ci	struct lpfc_hba *phba;
22838c2ecf20Sopenharmony_ci	int rc;
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci	shost = fc_bsg_to_shost(job);
22868c2ecf20Sopenharmony_ci	if (!shost)
22878c2ecf20Sopenharmony_ci		return -ENODEV;
22888c2ecf20Sopenharmony_ci	vport = shost_priv(shost);
22898c2ecf20Sopenharmony_ci	if (!vport)
22908c2ecf20Sopenharmony_ci		return -ENODEV;
22918c2ecf20Sopenharmony_ci	phba = vport->phba;
22928c2ecf20Sopenharmony_ci	if (!phba)
22938c2ecf20Sopenharmony_ci		return -ENODEV;
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
22968c2ecf20Sopenharmony_ci		rc = lpfc_sli3_bsg_diag_loopback_mode(phba, job);
22978c2ecf20Sopenharmony_ci	else if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >=
22988c2ecf20Sopenharmony_ci		 LPFC_SLI_INTF_IF_TYPE_2)
22998c2ecf20Sopenharmony_ci		rc = lpfc_sli4_bsg_diag_loopback_mode(phba, job);
23008c2ecf20Sopenharmony_ci	else
23018c2ecf20Sopenharmony_ci		rc = -ENODEV;
23028c2ecf20Sopenharmony_ci
23038c2ecf20Sopenharmony_ci	return rc;
23048c2ecf20Sopenharmony_ci}
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci/**
23078c2ecf20Sopenharmony_ci * lpfc_sli4_bsg_diag_mode_end - sli4 bsg vendor command for ending diag mode
23088c2ecf20Sopenharmony_ci * @job: LPFC_BSG_VENDOR_DIAG_MODE_END
23098c2ecf20Sopenharmony_ci *
23108c2ecf20Sopenharmony_ci * This function is responsible for responding to check and dispatch bsg diag
23118c2ecf20Sopenharmony_ci * command from the user to proper driver action routines.
23128c2ecf20Sopenharmony_ci */
23138c2ecf20Sopenharmony_cistatic int
23148c2ecf20Sopenharmony_cilpfc_sli4_bsg_diag_mode_end(struct bsg_job *job)
23158c2ecf20Sopenharmony_ci{
23168c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
23178c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
23188c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
23198c2ecf20Sopenharmony_ci	struct lpfc_vport *vport;
23208c2ecf20Sopenharmony_ci	struct lpfc_hba *phba;
23218c2ecf20Sopenharmony_ci	struct diag_mode_set *loopback_mode_end_cmd;
23228c2ecf20Sopenharmony_ci	uint32_t timeout;
23238c2ecf20Sopenharmony_ci	int rc, i;
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	shost = fc_bsg_to_shost(job);
23268c2ecf20Sopenharmony_ci	if (!shost)
23278c2ecf20Sopenharmony_ci		return -ENODEV;
23288c2ecf20Sopenharmony_ci	vport = shost_priv(shost);
23298c2ecf20Sopenharmony_ci	if (!vport)
23308c2ecf20Sopenharmony_ci		return -ENODEV;
23318c2ecf20Sopenharmony_ci	phba = vport->phba;
23328c2ecf20Sopenharmony_ci	if (!phba)
23338c2ecf20Sopenharmony_ci		return -ENODEV;
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
23368c2ecf20Sopenharmony_ci		return -ENODEV;
23378c2ecf20Sopenharmony_ci	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
23388c2ecf20Sopenharmony_ci	    LPFC_SLI_INTF_IF_TYPE_2)
23398c2ecf20Sopenharmony_ci		return -ENODEV;
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	/* clear loopback diagnostic mode */
23428c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
23438c2ecf20Sopenharmony_ci	phba->link_flag &= ~LS_LOOPBACK_MODE;
23448c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
23458c2ecf20Sopenharmony_ci	loopback_mode_end_cmd = (struct diag_mode_set *)
23468c2ecf20Sopenharmony_ci			bsg_request->rqst_data.h_vendor.vendor_cmd;
23478c2ecf20Sopenharmony_ci	timeout = loopback_mode_end_cmd->timeout * 100;
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0);
23508c2ecf20Sopenharmony_ci	if (rc) {
23518c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
23528c2ecf20Sopenharmony_ci				"3139 Failed to bring link to diagnostic "
23538c2ecf20Sopenharmony_ci				"state, rc:x%x\n", rc);
23548c2ecf20Sopenharmony_ci		goto loopback_mode_end_exit;
23558c2ecf20Sopenharmony_ci	}
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_ci	/* wait for link down before proceeding */
23588c2ecf20Sopenharmony_ci	i = 0;
23598c2ecf20Sopenharmony_ci	while (phba->link_state != LPFC_LINK_DOWN) {
23608c2ecf20Sopenharmony_ci		if (i++ > timeout) {
23618c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
23628c2ecf20Sopenharmony_ci					"3140 Timeout waiting for link to "
23638c2ecf20Sopenharmony_ci					"diagnostic mode_end, timeout:%d ms\n",
23648c2ecf20Sopenharmony_ci					timeout * 10);
23658c2ecf20Sopenharmony_ci			/* there is nothing much we can do here */
23668c2ecf20Sopenharmony_ci			break;
23678c2ecf20Sopenharmony_ci		}
23688c2ecf20Sopenharmony_ci		msleep(10);
23698c2ecf20Sopenharmony_ci	}
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	/* reset port resource registrations */
23728c2ecf20Sopenharmony_ci	rc = lpfc_selective_reset(phba);
23738c2ecf20Sopenharmony_ci	phba->pport->fc_myDID = 0;
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ciloopback_mode_end_exit:
23768c2ecf20Sopenharmony_ci	/* make return code available to userspace */
23778c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
23788c2ecf20Sopenharmony_ci	/* complete the job back to userspace if no error */
23798c2ecf20Sopenharmony_ci	if (rc == 0)
23808c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
23818c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
23828c2ecf20Sopenharmony_ci	return rc;
23838c2ecf20Sopenharmony_ci}
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci/**
23868c2ecf20Sopenharmony_ci * lpfc_sli4_bsg_link_diag_test - sli4 bsg vendor command for diag link test
23878c2ecf20Sopenharmony_ci * @job: LPFC_BSG_VENDOR_DIAG_LINK_TEST
23888c2ecf20Sopenharmony_ci *
23898c2ecf20Sopenharmony_ci * This function is to perform SLI4 diag link test request from the user
23908c2ecf20Sopenharmony_ci * applicaiton.
23918c2ecf20Sopenharmony_ci */
23928c2ecf20Sopenharmony_cistatic int
23938c2ecf20Sopenharmony_cilpfc_sli4_bsg_link_diag_test(struct bsg_job *job)
23948c2ecf20Sopenharmony_ci{
23958c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
23968c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
23978c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
23988c2ecf20Sopenharmony_ci	struct lpfc_vport *vport;
23998c2ecf20Sopenharmony_ci	struct lpfc_hba *phba;
24008c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *pmboxq;
24018c2ecf20Sopenharmony_ci	struct sli4_link_diag *link_diag_test_cmd;
24028c2ecf20Sopenharmony_ci	uint32_t req_len, alloc_len;
24038c2ecf20Sopenharmony_ci	struct lpfc_mbx_run_link_diag_test *run_link_diag_test;
24048c2ecf20Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
24058c2ecf20Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
24068c2ecf20Sopenharmony_ci	struct diag_status *diag_status_reply;
24078c2ecf20Sopenharmony_ci	int mbxstatus, rc = -ENODEV, rc1 = 0;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci	shost = fc_bsg_to_shost(job);
24108c2ecf20Sopenharmony_ci	if (!shost)
24118c2ecf20Sopenharmony_ci		goto job_error;
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	vport = shost_priv(shost);
24148c2ecf20Sopenharmony_ci	if (!vport)
24158c2ecf20Sopenharmony_ci		goto job_error;
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	phba = vport->phba;
24188c2ecf20Sopenharmony_ci	if (!phba)
24198c2ecf20Sopenharmony_ci		goto job_error;
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
24238c2ecf20Sopenharmony_ci		goto job_error;
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
24268c2ecf20Sopenharmony_ci	    LPFC_SLI_INTF_IF_TYPE_2)
24278c2ecf20Sopenharmony_ci		goto job_error;
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci	if (job->request_len < sizeof(struct fc_bsg_request) +
24308c2ecf20Sopenharmony_ci	    sizeof(struct sli4_link_diag)) {
24318c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
24328c2ecf20Sopenharmony_ci				"3013 Received LINK DIAG TEST request "
24338c2ecf20Sopenharmony_ci				" size:%d below the minimum size:%d\n",
24348c2ecf20Sopenharmony_ci				job->request_len,
24358c2ecf20Sopenharmony_ci				(int)(sizeof(struct fc_bsg_request) +
24368c2ecf20Sopenharmony_ci				sizeof(struct sli4_link_diag)));
24378c2ecf20Sopenharmony_ci		rc = -EINVAL;
24388c2ecf20Sopenharmony_ci		goto job_error;
24398c2ecf20Sopenharmony_ci	}
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	rc = lpfc_bsg_diag_mode_enter(phba);
24428c2ecf20Sopenharmony_ci	if (rc)
24438c2ecf20Sopenharmony_ci		goto job_error;
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	link_diag_test_cmd = (struct sli4_link_diag *)
24468c2ecf20Sopenharmony_ci			 bsg_request->rqst_data.h_vendor.vendor_cmd;
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci	rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1);
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_ci	if (rc)
24518c2ecf20Sopenharmony_ci		goto job_error;
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
24548c2ecf20Sopenharmony_ci	if (!pmboxq)
24558c2ecf20Sopenharmony_ci		goto link_diag_test_exit;
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci	req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) -
24588c2ecf20Sopenharmony_ci		   sizeof(struct lpfc_sli4_cfg_mhdr));
24598c2ecf20Sopenharmony_ci	alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
24608c2ecf20Sopenharmony_ci				     LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE,
24618c2ecf20Sopenharmony_ci				     req_len, LPFC_SLI4_MBX_EMBED);
24628c2ecf20Sopenharmony_ci	if (alloc_len != req_len) {
24638c2ecf20Sopenharmony_ci		rc = -ENOMEM;
24648c2ecf20Sopenharmony_ci		goto link_diag_test_exit;
24658c2ecf20Sopenharmony_ci	}
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test;
24688c2ecf20Sopenharmony_ci	bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req,
24698c2ecf20Sopenharmony_ci	       phba->sli4_hba.lnk_info.lnk_no);
24708c2ecf20Sopenharmony_ci	bf_set(lpfc_mbx_run_diag_test_link_type, &run_link_diag_test->u.req,
24718c2ecf20Sopenharmony_ci	       phba->sli4_hba.lnk_info.lnk_tp);
24728c2ecf20Sopenharmony_ci	bf_set(lpfc_mbx_run_diag_test_test_id, &run_link_diag_test->u.req,
24738c2ecf20Sopenharmony_ci	       link_diag_test_cmd->test_id);
24748c2ecf20Sopenharmony_ci	bf_set(lpfc_mbx_run_diag_test_loops, &run_link_diag_test->u.req,
24758c2ecf20Sopenharmony_ci	       link_diag_test_cmd->loops);
24768c2ecf20Sopenharmony_ci	bf_set(lpfc_mbx_run_diag_test_test_ver, &run_link_diag_test->u.req,
24778c2ecf20Sopenharmony_ci	       link_diag_test_cmd->test_version);
24788c2ecf20Sopenharmony_ci	bf_set(lpfc_mbx_run_diag_test_err_act, &run_link_diag_test->u.req,
24798c2ecf20Sopenharmony_ci	       link_diag_test_cmd->error_action);
24808c2ecf20Sopenharmony_ci
24818c2ecf20Sopenharmony_ci	mbxstatus = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)
24848c2ecf20Sopenharmony_ci		&pmboxq->u.mqe.un.sli4_config.header.cfg_shdr;
24858c2ecf20Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
24868c2ecf20Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
24878c2ecf20Sopenharmony_ci	if (shdr_status || shdr_add_status || mbxstatus) {
24888c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
24898c2ecf20Sopenharmony_ci				"3010 Run link diag test mailbox failed with "
24908c2ecf20Sopenharmony_ci				"mbx_status x%x status x%x, add_status x%x\n",
24918c2ecf20Sopenharmony_ci				mbxstatus, shdr_status, shdr_add_status);
24928c2ecf20Sopenharmony_ci	}
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	diag_status_reply = (struct diag_status *)
24958c2ecf20Sopenharmony_ci			    bsg_reply->reply_data.vendor_reply.vendor_rsp;
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci	if (job->reply_len < sizeof(*bsg_reply) + sizeof(*diag_status_reply)) {
24988c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
24998c2ecf20Sopenharmony_ci				"3012 Received Run link diag test reply "
25008c2ecf20Sopenharmony_ci				"below minimum size (%d): reply_len:%d\n",
25018c2ecf20Sopenharmony_ci				(int)(sizeof(*bsg_reply) +
25028c2ecf20Sopenharmony_ci				sizeof(*diag_status_reply)),
25038c2ecf20Sopenharmony_ci				job->reply_len);
25048c2ecf20Sopenharmony_ci		rc = -EINVAL;
25058c2ecf20Sopenharmony_ci		goto job_error;
25068c2ecf20Sopenharmony_ci	}
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci	diag_status_reply->mbox_status = mbxstatus;
25098c2ecf20Sopenharmony_ci	diag_status_reply->shdr_status = shdr_status;
25108c2ecf20Sopenharmony_ci	diag_status_reply->shdr_add_status = shdr_add_status;
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_cilink_diag_test_exit:
25138c2ecf20Sopenharmony_ci	rc1 = lpfc_sli4_bsg_set_link_diag_state(phba, 0);
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	if (pmboxq)
25168c2ecf20Sopenharmony_ci		mempool_free(pmboxq, phba->mbox_mem_pool);
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	lpfc_bsg_diag_mode_exit(phba);
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_cijob_error:
25218c2ecf20Sopenharmony_ci	/* make error code available to userspace */
25228c2ecf20Sopenharmony_ci	if (rc1 && !rc)
25238c2ecf20Sopenharmony_ci		rc = rc1;
25248c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
25258c2ecf20Sopenharmony_ci	/* complete the job back to userspace if no error */
25268c2ecf20Sopenharmony_ci	if (rc == 0)
25278c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
25288c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
25298c2ecf20Sopenharmony_ci	return rc;
25308c2ecf20Sopenharmony_ci}
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci/**
25338c2ecf20Sopenharmony_ci * lpfcdiag_loop_self_reg - obtains a remote port login id
25348c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object
25358c2ecf20Sopenharmony_ci * @rpi: Pointer to a remote port login id
25368c2ecf20Sopenharmony_ci *
25378c2ecf20Sopenharmony_ci * This function obtains a remote port login id so the diag loopback test
25388c2ecf20Sopenharmony_ci * can send and receive its own unsolicited CT command.
25398c2ecf20Sopenharmony_ci **/
25408c2ecf20Sopenharmony_cistatic int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi)
25418c2ecf20Sopenharmony_ci{
25428c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
25438c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmabuff;
25448c2ecf20Sopenharmony_ci	int status;
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
25478c2ecf20Sopenharmony_ci	if (!mbox)
25488c2ecf20Sopenharmony_ci		return -ENOMEM;
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
25518c2ecf20Sopenharmony_ci		status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID,
25528c2ecf20Sopenharmony_ci				(uint8_t *)&phba->pport->fc_sparam,
25538c2ecf20Sopenharmony_ci				mbox, *rpi);
25548c2ecf20Sopenharmony_ci	else {
25558c2ecf20Sopenharmony_ci		*rpi = lpfc_sli4_alloc_rpi(phba);
25568c2ecf20Sopenharmony_ci		if (*rpi == LPFC_RPI_ALLOC_ERROR) {
25578c2ecf20Sopenharmony_ci			mempool_free(mbox, phba->mbox_mem_pool);
25588c2ecf20Sopenharmony_ci			return -EBUSY;
25598c2ecf20Sopenharmony_ci		}
25608c2ecf20Sopenharmony_ci		status = lpfc_reg_rpi(phba, phba->pport->vpi,
25618c2ecf20Sopenharmony_ci				phba->pport->fc_myDID,
25628c2ecf20Sopenharmony_ci				(uint8_t *)&phba->pport->fc_sparam,
25638c2ecf20Sopenharmony_ci				mbox, *rpi);
25648c2ecf20Sopenharmony_ci	}
25658c2ecf20Sopenharmony_ci
25668c2ecf20Sopenharmony_ci	if (status) {
25678c2ecf20Sopenharmony_ci		mempool_free(mbox, phba->mbox_mem_pool);
25688c2ecf20Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4)
25698c2ecf20Sopenharmony_ci			lpfc_sli4_free_rpi(phba, *rpi);
25708c2ecf20Sopenharmony_ci		return -ENOMEM;
25718c2ecf20Sopenharmony_ci	}
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	dmabuff = (struct lpfc_dmabuf *)mbox->ctx_buf;
25748c2ecf20Sopenharmony_ci	mbox->ctx_buf = NULL;
25758c2ecf20Sopenharmony_ci	mbox->ctx_ndlp = NULL;
25768c2ecf20Sopenharmony_ci	status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) {
25798c2ecf20Sopenharmony_ci		lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys);
25808c2ecf20Sopenharmony_ci		kfree(dmabuff);
25818c2ecf20Sopenharmony_ci		if (status != MBX_TIMEOUT)
25828c2ecf20Sopenharmony_ci			mempool_free(mbox, phba->mbox_mem_pool);
25838c2ecf20Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4)
25848c2ecf20Sopenharmony_ci			lpfc_sli4_free_rpi(phba, *rpi);
25858c2ecf20Sopenharmony_ci		return -ENODEV;
25868c2ecf20Sopenharmony_ci	}
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
25898c2ecf20Sopenharmony_ci		*rpi = mbox->u.mb.un.varWords[0];
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci	lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys);
25928c2ecf20Sopenharmony_ci	kfree(dmabuff);
25938c2ecf20Sopenharmony_ci	mempool_free(mbox, phba->mbox_mem_pool);
25948c2ecf20Sopenharmony_ci	return 0;
25958c2ecf20Sopenharmony_ci}
25968c2ecf20Sopenharmony_ci
25978c2ecf20Sopenharmony_ci/**
25988c2ecf20Sopenharmony_ci * lpfcdiag_loop_self_unreg - unregs from the rpi
25998c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object
26008c2ecf20Sopenharmony_ci * @rpi: Remote port login id
26018c2ecf20Sopenharmony_ci *
26028c2ecf20Sopenharmony_ci * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg
26038c2ecf20Sopenharmony_ci **/
26048c2ecf20Sopenharmony_cistatic int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi)
26058c2ecf20Sopenharmony_ci{
26068c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
26078c2ecf20Sopenharmony_ci	int status;
26088c2ecf20Sopenharmony_ci
26098c2ecf20Sopenharmony_ci	/* Allocate mboxq structure */
26108c2ecf20Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
26118c2ecf20Sopenharmony_ci	if (mbox == NULL)
26128c2ecf20Sopenharmony_ci		return -ENOMEM;
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
26158c2ecf20Sopenharmony_ci		lpfc_unreg_login(phba, 0, rpi, mbox);
26168c2ecf20Sopenharmony_ci	else
26178c2ecf20Sopenharmony_ci		lpfc_unreg_login(phba, phba->pport->vpi,
26188c2ecf20Sopenharmony_ci				 phba->sli4_hba.rpi_ids[rpi], mbox);
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) {
26238c2ecf20Sopenharmony_ci		if (status != MBX_TIMEOUT)
26248c2ecf20Sopenharmony_ci			mempool_free(mbox, phba->mbox_mem_pool);
26258c2ecf20Sopenharmony_ci		return -EIO;
26268c2ecf20Sopenharmony_ci	}
26278c2ecf20Sopenharmony_ci	mempool_free(mbox, phba->mbox_mem_pool);
26288c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
26298c2ecf20Sopenharmony_ci		lpfc_sli4_free_rpi(phba, rpi);
26308c2ecf20Sopenharmony_ci	return 0;
26318c2ecf20Sopenharmony_ci}
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_ci/**
26348c2ecf20Sopenharmony_ci * lpfcdiag_loop_get_xri - obtains the transmit and receive ids
26358c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object
26368c2ecf20Sopenharmony_ci * @rpi: Remote port login id
26378c2ecf20Sopenharmony_ci * @txxri: Pointer to transmit exchange id
26388c2ecf20Sopenharmony_ci * @rxxri: Pointer to response exchabge id
26398c2ecf20Sopenharmony_ci *
26408c2ecf20Sopenharmony_ci * This function obtains the transmit and receive ids required to send
26418c2ecf20Sopenharmony_ci * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp
26428c2ecf20Sopenharmony_ci * flags are used to the unsolicted response handler is able to process
26438c2ecf20Sopenharmony_ci * the ct command sent on the same port.
26448c2ecf20Sopenharmony_ci **/
26458c2ecf20Sopenharmony_cistatic int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
26468c2ecf20Sopenharmony_ci			 uint16_t *txxri, uint16_t * rxxri)
26478c2ecf20Sopenharmony_ci{
26488c2ecf20Sopenharmony_ci	struct lpfc_bsg_event *evt;
26498c2ecf20Sopenharmony_ci	struct lpfc_iocbq *cmdiocbq, *rspiocbq;
26508c2ecf20Sopenharmony_ci	IOCB_t *cmd, *rsp;
26518c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
26528c2ecf20Sopenharmony_ci	struct ulp_bde64 *bpl = NULL;
26538c2ecf20Sopenharmony_ci	struct lpfc_sli_ct_request *ctreq = NULL;
26548c2ecf20Sopenharmony_ci	int ret_val = 0;
26558c2ecf20Sopenharmony_ci	int time_left;
26568c2ecf20Sopenharmony_ci	int iocb_stat = IOCB_SUCCESS;
26578c2ecf20Sopenharmony_ci	unsigned long flags;
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci	*txxri = 0;
26608c2ecf20Sopenharmony_ci	*rxxri = 0;
26618c2ecf20Sopenharmony_ci	evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid,
26628c2ecf20Sopenharmony_ci				SLI_CT_ELX_LOOPBACK);
26638c2ecf20Sopenharmony_ci	if (!evt)
26648c2ecf20Sopenharmony_ci		return -ENOMEM;
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
26678c2ecf20Sopenharmony_ci	list_add(&evt->node, &phba->ct_ev_waiters);
26688c2ecf20Sopenharmony_ci	lpfc_bsg_event_ref(evt);
26698c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_ci	cmdiocbq = lpfc_sli_get_iocbq(phba);
26728c2ecf20Sopenharmony_ci	rspiocbq = lpfc_sli_get_iocbq(phba);
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_ci	dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
26758c2ecf20Sopenharmony_ci	if (dmabuf) {
26768c2ecf20Sopenharmony_ci		dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys);
26778c2ecf20Sopenharmony_ci		if (dmabuf->virt) {
26788c2ecf20Sopenharmony_ci			INIT_LIST_HEAD(&dmabuf->list);
26798c2ecf20Sopenharmony_ci			bpl = (struct ulp_bde64 *) dmabuf->virt;
26808c2ecf20Sopenharmony_ci			memset(bpl, 0, sizeof(*bpl));
26818c2ecf20Sopenharmony_ci			ctreq = (struct lpfc_sli_ct_request *)(bpl + 1);
26828c2ecf20Sopenharmony_ci			bpl->addrHigh =
26838c2ecf20Sopenharmony_ci				le32_to_cpu(putPaddrHigh(dmabuf->phys +
26848c2ecf20Sopenharmony_ci					sizeof(*bpl)));
26858c2ecf20Sopenharmony_ci			bpl->addrLow =
26868c2ecf20Sopenharmony_ci				le32_to_cpu(putPaddrLow(dmabuf->phys +
26878c2ecf20Sopenharmony_ci					sizeof(*bpl)));
26888c2ecf20Sopenharmony_ci			bpl->tus.f.bdeFlags = 0;
26898c2ecf20Sopenharmony_ci			bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ;
26908c2ecf20Sopenharmony_ci			bpl->tus.w = le32_to_cpu(bpl->tus.w);
26918c2ecf20Sopenharmony_ci		}
26928c2ecf20Sopenharmony_ci	}
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_ci	if (cmdiocbq == NULL || rspiocbq == NULL ||
26958c2ecf20Sopenharmony_ci	    dmabuf == NULL || bpl == NULL || ctreq == NULL ||
26968c2ecf20Sopenharmony_ci		dmabuf->virt == NULL) {
26978c2ecf20Sopenharmony_ci		ret_val = -ENOMEM;
26988c2ecf20Sopenharmony_ci		goto err_get_xri_exit;
26998c2ecf20Sopenharmony_ci	}
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci	cmd = &cmdiocbq->iocb;
27028c2ecf20Sopenharmony_ci	rsp = &rspiocbq->iocb;
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ);
27058c2ecf20Sopenharmony_ci
27068c2ecf20Sopenharmony_ci	ctreq->RevisionId.bits.Revision = SLI_CT_REVISION;
27078c2ecf20Sopenharmony_ci	ctreq->RevisionId.bits.InId = 0;
27088c2ecf20Sopenharmony_ci	ctreq->FsType = SLI_CT_ELX_LOOPBACK;
27098c2ecf20Sopenharmony_ci	ctreq->FsSubType = 0;
27108c2ecf20Sopenharmony_ci	ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP;
27118c2ecf20Sopenharmony_ci	ctreq->CommandResponse.bits.Size = 0;
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_ci
27148c2ecf20Sopenharmony_ci	cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys);
27158c2ecf20Sopenharmony_ci	cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys);
27168c2ecf20Sopenharmony_ci	cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
27178c2ecf20Sopenharmony_ci	cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl);
27188c2ecf20Sopenharmony_ci
27198c2ecf20Sopenharmony_ci	cmd->un.xseq64.w5.hcsw.Fctl = LA;
27208c2ecf20Sopenharmony_ci	cmd->un.xseq64.w5.hcsw.Dfctl = 0;
27218c2ecf20Sopenharmony_ci	cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
27228c2ecf20Sopenharmony_ci	cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT;
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_ci	cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR;
27258c2ecf20Sopenharmony_ci	cmd->ulpBdeCount = 1;
27268c2ecf20Sopenharmony_ci	cmd->ulpLe = 1;
27278c2ecf20Sopenharmony_ci	cmd->ulpClass = CLASS3;
27288c2ecf20Sopenharmony_ci	cmd->ulpContext = rpi;
27298c2ecf20Sopenharmony_ci
27308c2ecf20Sopenharmony_ci	cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
27318c2ecf20Sopenharmony_ci	cmdiocbq->vport = phba->pport;
27328c2ecf20Sopenharmony_ci	cmdiocbq->iocb_cmpl = NULL;
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci	iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
27358c2ecf20Sopenharmony_ci				rspiocbq,
27368c2ecf20Sopenharmony_ci				(phba->fc_ratov * 2)
27378c2ecf20Sopenharmony_ci				+ LPFC_DRVR_TIMEOUT);
27388c2ecf20Sopenharmony_ci	if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOSTAT_SUCCESS)) {
27398c2ecf20Sopenharmony_ci		ret_val = -EIO;
27408c2ecf20Sopenharmony_ci		goto err_get_xri_exit;
27418c2ecf20Sopenharmony_ci	}
27428c2ecf20Sopenharmony_ci	*txxri =  rsp->ulpContext;
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci	evt->waiting = 1;
27458c2ecf20Sopenharmony_ci	evt->wait_time_stamp = jiffies;
27468c2ecf20Sopenharmony_ci	time_left = wait_event_interruptible_timeout(
27478c2ecf20Sopenharmony_ci		evt->wq, !list_empty(&evt->events_to_see),
27488c2ecf20Sopenharmony_ci		msecs_to_jiffies(1000 *
27498c2ecf20Sopenharmony_ci			((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT)));
27508c2ecf20Sopenharmony_ci	if (list_empty(&evt->events_to_see))
27518c2ecf20Sopenharmony_ci		ret_val = (time_left) ? -EINTR : -ETIMEDOUT;
27528c2ecf20Sopenharmony_ci	else {
27538c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->ct_ev_lock, flags);
27548c2ecf20Sopenharmony_ci		list_move(evt->events_to_see.prev, &evt->events_to_get);
27558c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
27568c2ecf20Sopenharmony_ci		*rxxri = (list_entry(evt->events_to_get.prev,
27578c2ecf20Sopenharmony_ci				     typeof(struct event_data),
27588c2ecf20Sopenharmony_ci				     node))->immed_dat;
27598c2ecf20Sopenharmony_ci	}
27608c2ecf20Sopenharmony_ci	evt->waiting = 0;
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_cierr_get_xri_exit:
27638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
27648c2ecf20Sopenharmony_ci	lpfc_bsg_event_unref(evt); /* release ref */
27658c2ecf20Sopenharmony_ci	lpfc_bsg_event_unref(evt); /* delete */
27668c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
27678c2ecf20Sopenharmony_ci
27688c2ecf20Sopenharmony_ci	if (dmabuf) {
27698c2ecf20Sopenharmony_ci		if (dmabuf->virt)
27708c2ecf20Sopenharmony_ci			lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
27718c2ecf20Sopenharmony_ci		kfree(dmabuf);
27728c2ecf20Sopenharmony_ci	}
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_ci	if (cmdiocbq && (iocb_stat != IOCB_TIMEDOUT))
27758c2ecf20Sopenharmony_ci		lpfc_sli_release_iocbq(phba, cmdiocbq);
27768c2ecf20Sopenharmony_ci	if (rspiocbq)
27778c2ecf20Sopenharmony_ci		lpfc_sli_release_iocbq(phba, rspiocbq);
27788c2ecf20Sopenharmony_ci	return ret_val;
27798c2ecf20Sopenharmony_ci}
27808c2ecf20Sopenharmony_ci
27818c2ecf20Sopenharmony_ci/**
27828c2ecf20Sopenharmony_ci * lpfc_bsg_dma_page_alloc - allocate a bsg mbox page sized dma buffers
27838c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object
27848c2ecf20Sopenharmony_ci *
27858c2ecf20Sopenharmony_ci * This function allocates BSG_MBOX_SIZE (4KB) page size dma buffer and
27868c2ecf20Sopenharmony_ci * returns the pointer to the buffer.
27878c2ecf20Sopenharmony_ci **/
27888c2ecf20Sopenharmony_cistatic struct lpfc_dmabuf *
27898c2ecf20Sopenharmony_cilpfc_bsg_dma_page_alloc(struct lpfc_hba *phba)
27908c2ecf20Sopenharmony_ci{
27918c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
27928c2ecf20Sopenharmony_ci	struct pci_dev *pcidev = phba->pcidev;
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_ci	/* allocate dma buffer struct */
27958c2ecf20Sopenharmony_ci	dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
27968c2ecf20Sopenharmony_ci	if (!dmabuf)
27978c2ecf20Sopenharmony_ci		return NULL;
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dmabuf->list);
28008c2ecf20Sopenharmony_ci
28018c2ecf20Sopenharmony_ci	/* now, allocate dma buffer */
28028c2ecf20Sopenharmony_ci	dmabuf->virt = dma_alloc_coherent(&pcidev->dev, BSG_MBOX_SIZE,
28038c2ecf20Sopenharmony_ci					  &(dmabuf->phys), GFP_KERNEL);
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci	if (!dmabuf->virt) {
28068c2ecf20Sopenharmony_ci		kfree(dmabuf);
28078c2ecf20Sopenharmony_ci		return NULL;
28088c2ecf20Sopenharmony_ci	}
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ci	return dmabuf;
28118c2ecf20Sopenharmony_ci}
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci/**
28148c2ecf20Sopenharmony_ci * lpfc_bsg_dma_page_free - free a bsg mbox page sized dma buffer
28158c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
28168c2ecf20Sopenharmony_ci * @dmabuf: Pointer to the bsg mbox page sized dma buffer descriptor.
28178c2ecf20Sopenharmony_ci *
28188c2ecf20Sopenharmony_ci * This routine just simply frees a dma buffer and its associated buffer
28198c2ecf20Sopenharmony_ci * descriptor referred by @dmabuf.
28208c2ecf20Sopenharmony_ci **/
28218c2ecf20Sopenharmony_cistatic void
28228c2ecf20Sopenharmony_cilpfc_bsg_dma_page_free(struct lpfc_hba *phba, struct lpfc_dmabuf *dmabuf)
28238c2ecf20Sopenharmony_ci{
28248c2ecf20Sopenharmony_ci	struct pci_dev *pcidev = phba->pcidev;
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_ci	if (!dmabuf)
28278c2ecf20Sopenharmony_ci		return;
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci	if (dmabuf->virt)
28308c2ecf20Sopenharmony_ci		dma_free_coherent(&pcidev->dev, BSG_MBOX_SIZE,
28318c2ecf20Sopenharmony_ci				  dmabuf->virt, dmabuf->phys);
28328c2ecf20Sopenharmony_ci	kfree(dmabuf);
28338c2ecf20Sopenharmony_ci	return;
28348c2ecf20Sopenharmony_ci}
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci/**
28378c2ecf20Sopenharmony_ci * lpfc_bsg_dma_page_list_free - free a list of bsg mbox page sized dma buffers
28388c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
28398c2ecf20Sopenharmony_ci * @dmabuf_list: Pointer to a list of bsg mbox page sized dma buffer descs.
28408c2ecf20Sopenharmony_ci *
28418c2ecf20Sopenharmony_ci * This routine just simply frees all dma buffers and their associated buffer
28428c2ecf20Sopenharmony_ci * descriptors referred by @dmabuf_list.
28438c2ecf20Sopenharmony_ci **/
28448c2ecf20Sopenharmony_cistatic void
28458c2ecf20Sopenharmony_cilpfc_bsg_dma_page_list_free(struct lpfc_hba *phba,
28468c2ecf20Sopenharmony_ci			    struct list_head *dmabuf_list)
28478c2ecf20Sopenharmony_ci{
28488c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmabuf, *next_dmabuf;
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_ci	if (list_empty(dmabuf_list))
28518c2ecf20Sopenharmony_ci		return;
28528c2ecf20Sopenharmony_ci
28538c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dmabuf, next_dmabuf, dmabuf_list, list) {
28548c2ecf20Sopenharmony_ci		list_del_init(&dmabuf->list);
28558c2ecf20Sopenharmony_ci		lpfc_bsg_dma_page_free(phba, dmabuf);
28568c2ecf20Sopenharmony_ci	}
28578c2ecf20Sopenharmony_ci	return;
28588c2ecf20Sopenharmony_ci}
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci/**
28618c2ecf20Sopenharmony_ci * diag_cmd_data_alloc - fills in a bde struct with dma buffers
28628c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object
28638c2ecf20Sopenharmony_ci * @bpl: Pointer to 64 bit bde structure
28648c2ecf20Sopenharmony_ci * @size: Number of bytes to process
28658c2ecf20Sopenharmony_ci * @nocopydata: Flag to copy user data into the allocated buffer
28668c2ecf20Sopenharmony_ci *
28678c2ecf20Sopenharmony_ci * This function allocates page size buffers and populates an lpfc_dmabufext.
28688c2ecf20Sopenharmony_ci * If allowed the user data pointed to with indataptr is copied into the kernel
28698c2ecf20Sopenharmony_ci * memory. The chained list of page size buffers is returned.
28708c2ecf20Sopenharmony_ci **/
28718c2ecf20Sopenharmony_cistatic struct lpfc_dmabufext *
28728c2ecf20Sopenharmony_cidiag_cmd_data_alloc(struct lpfc_hba *phba,
28738c2ecf20Sopenharmony_ci		   struct ulp_bde64 *bpl, uint32_t size,
28748c2ecf20Sopenharmony_ci		   int nocopydata)
28758c2ecf20Sopenharmony_ci{
28768c2ecf20Sopenharmony_ci	struct lpfc_dmabufext *mlist = NULL;
28778c2ecf20Sopenharmony_ci	struct lpfc_dmabufext *dmp;
28788c2ecf20Sopenharmony_ci	int cnt, offset = 0, i = 0;
28798c2ecf20Sopenharmony_ci	struct pci_dev *pcidev;
28808c2ecf20Sopenharmony_ci
28818c2ecf20Sopenharmony_ci	pcidev = phba->pcidev;
28828c2ecf20Sopenharmony_ci
28838c2ecf20Sopenharmony_ci	while (size) {
28848c2ecf20Sopenharmony_ci		/* We get chunks of 4K */
28858c2ecf20Sopenharmony_ci		if (size > BUF_SZ_4K)
28868c2ecf20Sopenharmony_ci			cnt = BUF_SZ_4K;
28878c2ecf20Sopenharmony_ci		else
28888c2ecf20Sopenharmony_ci			cnt = size;
28898c2ecf20Sopenharmony_ci
28908c2ecf20Sopenharmony_ci		/* allocate struct lpfc_dmabufext buffer header */
28918c2ecf20Sopenharmony_ci		dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL);
28928c2ecf20Sopenharmony_ci		if (!dmp)
28938c2ecf20Sopenharmony_ci			goto out;
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&dmp->dma.list);
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_ci		/* Queue it to a linked list */
28988c2ecf20Sopenharmony_ci		if (mlist)
28998c2ecf20Sopenharmony_ci			list_add_tail(&dmp->dma.list, &mlist->dma.list);
29008c2ecf20Sopenharmony_ci		else
29018c2ecf20Sopenharmony_ci			mlist = dmp;
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci		/* allocate buffer */
29048c2ecf20Sopenharmony_ci		dmp->dma.virt = dma_alloc_coherent(&pcidev->dev,
29058c2ecf20Sopenharmony_ci						   cnt,
29068c2ecf20Sopenharmony_ci						   &(dmp->dma.phys),
29078c2ecf20Sopenharmony_ci						   GFP_KERNEL);
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci		if (!dmp->dma.virt)
29108c2ecf20Sopenharmony_ci			goto out;
29118c2ecf20Sopenharmony_ci
29128c2ecf20Sopenharmony_ci		dmp->size = cnt;
29138c2ecf20Sopenharmony_ci
29148c2ecf20Sopenharmony_ci		if (nocopydata) {
29158c2ecf20Sopenharmony_ci			bpl->tus.f.bdeFlags = 0;
29168c2ecf20Sopenharmony_ci		} else {
29178c2ecf20Sopenharmony_ci			memset((uint8_t *)dmp->dma.virt, 0, cnt);
29188c2ecf20Sopenharmony_ci			bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
29198c2ecf20Sopenharmony_ci		}
29208c2ecf20Sopenharmony_ci
29218c2ecf20Sopenharmony_ci		/* build buffer ptr list for IOCB */
29228c2ecf20Sopenharmony_ci		bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys));
29238c2ecf20Sopenharmony_ci		bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys));
29248c2ecf20Sopenharmony_ci		bpl->tus.f.bdeSize = (ushort) cnt;
29258c2ecf20Sopenharmony_ci		bpl->tus.w = le32_to_cpu(bpl->tus.w);
29268c2ecf20Sopenharmony_ci		bpl++;
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci		i++;
29298c2ecf20Sopenharmony_ci		offset += cnt;
29308c2ecf20Sopenharmony_ci		size -= cnt;
29318c2ecf20Sopenharmony_ci	}
29328c2ecf20Sopenharmony_ci
29338c2ecf20Sopenharmony_ci	if (mlist) {
29348c2ecf20Sopenharmony_ci		mlist->flag = i;
29358c2ecf20Sopenharmony_ci		return mlist;
29368c2ecf20Sopenharmony_ci	}
29378c2ecf20Sopenharmony_ciout:
29388c2ecf20Sopenharmony_ci	diag_cmd_data_free(phba, mlist);
29398c2ecf20Sopenharmony_ci	return NULL;
29408c2ecf20Sopenharmony_ci}
29418c2ecf20Sopenharmony_ci
29428c2ecf20Sopenharmony_ci/**
29438c2ecf20Sopenharmony_ci * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd
29448c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object
29458c2ecf20Sopenharmony_ci * @rxxri: Receive exchange id
29468c2ecf20Sopenharmony_ci * @len: Number of data bytes
29478c2ecf20Sopenharmony_ci *
29488c2ecf20Sopenharmony_ci * This function allocates and posts a data buffer of sufficient size to receive
29498c2ecf20Sopenharmony_ci * an unsolicted CT command.
29508c2ecf20Sopenharmony_ci **/
29518c2ecf20Sopenharmony_cistatic int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri,
29528c2ecf20Sopenharmony_ci			     size_t len)
29538c2ecf20Sopenharmony_ci{
29548c2ecf20Sopenharmony_ci	struct lpfc_sli_ring *pring;
29558c2ecf20Sopenharmony_ci	struct lpfc_iocbq *cmdiocbq;
29568c2ecf20Sopenharmony_ci	IOCB_t *cmd = NULL;
29578c2ecf20Sopenharmony_ci	struct list_head head, *curr, *next;
29588c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *rxbmp;
29598c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmp;
29608c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mp[2] = {NULL, NULL};
29618c2ecf20Sopenharmony_ci	struct ulp_bde64 *rxbpl = NULL;
29628c2ecf20Sopenharmony_ci	uint32_t num_bde;
29638c2ecf20Sopenharmony_ci	struct lpfc_dmabufext *rxbuffer = NULL;
29648c2ecf20Sopenharmony_ci	int ret_val = 0;
29658c2ecf20Sopenharmony_ci	int iocb_stat;
29668c2ecf20Sopenharmony_ci	int i = 0;
29678c2ecf20Sopenharmony_ci
29688c2ecf20Sopenharmony_ci	pring = lpfc_phba_elsring(phba);
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci	cmdiocbq = lpfc_sli_get_iocbq(phba);
29718c2ecf20Sopenharmony_ci	rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
29728c2ecf20Sopenharmony_ci	if (rxbmp != NULL) {
29738c2ecf20Sopenharmony_ci		rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
29748c2ecf20Sopenharmony_ci		if (rxbmp->virt) {
29758c2ecf20Sopenharmony_ci			INIT_LIST_HEAD(&rxbmp->list);
29768c2ecf20Sopenharmony_ci			rxbpl = (struct ulp_bde64 *) rxbmp->virt;
29778c2ecf20Sopenharmony_ci			rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0);
29788c2ecf20Sopenharmony_ci		}
29798c2ecf20Sopenharmony_ci	}
29808c2ecf20Sopenharmony_ci
29818c2ecf20Sopenharmony_ci	if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer || !pring) {
29828c2ecf20Sopenharmony_ci		ret_val = -ENOMEM;
29838c2ecf20Sopenharmony_ci		goto err_post_rxbufs_exit;
29848c2ecf20Sopenharmony_ci	}
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci	/* Queue buffers for the receive exchange */
29878c2ecf20Sopenharmony_ci	num_bde = (uint32_t)rxbuffer->flag;
29888c2ecf20Sopenharmony_ci	dmp = &rxbuffer->dma;
29898c2ecf20Sopenharmony_ci
29908c2ecf20Sopenharmony_ci	cmd = &cmdiocbq->iocb;
29918c2ecf20Sopenharmony_ci	i = 0;
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&head);
29948c2ecf20Sopenharmony_ci	list_add_tail(&head, &dmp->list);
29958c2ecf20Sopenharmony_ci	list_for_each_safe(curr, next, &head) {
29968c2ecf20Sopenharmony_ci		mp[i] = list_entry(curr, struct lpfc_dmabuf, list);
29978c2ecf20Sopenharmony_ci		list_del(curr);
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_ci		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
30008c2ecf20Sopenharmony_ci			mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba);
30018c2ecf20Sopenharmony_ci			cmd->un.quexri64cx.buff.bde.addrHigh =
30028c2ecf20Sopenharmony_ci				putPaddrHigh(mp[i]->phys);
30038c2ecf20Sopenharmony_ci			cmd->un.quexri64cx.buff.bde.addrLow =
30048c2ecf20Sopenharmony_ci				putPaddrLow(mp[i]->phys);
30058c2ecf20Sopenharmony_ci			cmd->un.quexri64cx.buff.bde.tus.f.bdeSize =
30068c2ecf20Sopenharmony_ci				((struct lpfc_dmabufext *)mp[i])->size;
30078c2ecf20Sopenharmony_ci			cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag;
30088c2ecf20Sopenharmony_ci			cmd->ulpCommand = CMD_QUE_XRI64_CX;
30098c2ecf20Sopenharmony_ci			cmd->ulpPU = 0;
30108c2ecf20Sopenharmony_ci			cmd->ulpLe = 1;
30118c2ecf20Sopenharmony_ci			cmd->ulpBdeCount = 1;
30128c2ecf20Sopenharmony_ci			cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0;
30138c2ecf20Sopenharmony_ci
30148c2ecf20Sopenharmony_ci		} else {
30158c2ecf20Sopenharmony_ci			cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys);
30168c2ecf20Sopenharmony_ci			cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys);
30178c2ecf20Sopenharmony_ci			cmd->un.cont64[i].tus.f.bdeSize =
30188c2ecf20Sopenharmony_ci				((struct lpfc_dmabufext *)mp[i])->size;
30198c2ecf20Sopenharmony_ci			cmd->ulpBdeCount = ++i;
30208c2ecf20Sopenharmony_ci
30218c2ecf20Sopenharmony_ci			if ((--num_bde > 0) && (i < 2))
30228c2ecf20Sopenharmony_ci				continue;
30238c2ecf20Sopenharmony_ci
30248c2ecf20Sopenharmony_ci			cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX;
30258c2ecf20Sopenharmony_ci			cmd->ulpLe = 1;
30268c2ecf20Sopenharmony_ci		}
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci		cmd->ulpClass = CLASS3;
30298c2ecf20Sopenharmony_ci		cmd->ulpContext = rxxri;
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_ci		iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq,
30328c2ecf20Sopenharmony_ci						0);
30338c2ecf20Sopenharmony_ci		if (iocb_stat == IOCB_ERROR) {
30348c2ecf20Sopenharmony_ci			diag_cmd_data_free(phba,
30358c2ecf20Sopenharmony_ci				(struct lpfc_dmabufext *)mp[0]);
30368c2ecf20Sopenharmony_ci			if (mp[1])
30378c2ecf20Sopenharmony_ci				diag_cmd_data_free(phba,
30388c2ecf20Sopenharmony_ci					  (struct lpfc_dmabufext *)mp[1]);
30398c2ecf20Sopenharmony_ci			dmp = list_entry(next, struct lpfc_dmabuf, list);
30408c2ecf20Sopenharmony_ci			ret_val = -EIO;
30418c2ecf20Sopenharmony_ci			goto err_post_rxbufs_exit;
30428c2ecf20Sopenharmony_ci		}
30438c2ecf20Sopenharmony_ci
30448c2ecf20Sopenharmony_ci		lpfc_sli_ringpostbuf_put(phba, pring, mp[0]);
30458c2ecf20Sopenharmony_ci		if (mp[1]) {
30468c2ecf20Sopenharmony_ci			lpfc_sli_ringpostbuf_put(phba, pring, mp[1]);
30478c2ecf20Sopenharmony_ci			mp[1] = NULL;
30488c2ecf20Sopenharmony_ci		}
30498c2ecf20Sopenharmony_ci
30508c2ecf20Sopenharmony_ci		/* The iocb was freed by lpfc_sli_issue_iocb */
30518c2ecf20Sopenharmony_ci		cmdiocbq = lpfc_sli_get_iocbq(phba);
30528c2ecf20Sopenharmony_ci		if (!cmdiocbq) {
30538c2ecf20Sopenharmony_ci			dmp = list_entry(next, struct lpfc_dmabuf, list);
30548c2ecf20Sopenharmony_ci			ret_val = -EIO;
30558c2ecf20Sopenharmony_ci			goto err_post_rxbufs_exit;
30568c2ecf20Sopenharmony_ci		}
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci		cmd = &cmdiocbq->iocb;
30598c2ecf20Sopenharmony_ci		i = 0;
30608c2ecf20Sopenharmony_ci	}
30618c2ecf20Sopenharmony_ci	list_del(&head);
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_cierr_post_rxbufs_exit:
30648c2ecf20Sopenharmony_ci
30658c2ecf20Sopenharmony_ci	if (rxbmp) {
30668c2ecf20Sopenharmony_ci		if (rxbmp->virt)
30678c2ecf20Sopenharmony_ci			lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys);
30688c2ecf20Sopenharmony_ci		kfree(rxbmp);
30698c2ecf20Sopenharmony_ci	}
30708c2ecf20Sopenharmony_ci
30718c2ecf20Sopenharmony_ci	if (cmdiocbq)
30728c2ecf20Sopenharmony_ci		lpfc_sli_release_iocbq(phba, cmdiocbq);
30738c2ecf20Sopenharmony_ci	return ret_val;
30748c2ecf20Sopenharmony_ci}
30758c2ecf20Sopenharmony_ci
30768c2ecf20Sopenharmony_ci/**
30778c2ecf20Sopenharmony_ci * lpfc_bsg_diag_loopback_run - run loopback on a port by issue ct cmd to itself
30788c2ecf20Sopenharmony_ci * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job
30798c2ecf20Sopenharmony_ci *
30808c2ecf20Sopenharmony_ci * This function receives a user data buffer to be transmitted and received on
30818c2ecf20Sopenharmony_ci * the same port, the link must be up and in loopback mode prior
30828c2ecf20Sopenharmony_ci * to being called.
30838c2ecf20Sopenharmony_ci * 1. A kernel buffer is allocated to copy the user data into.
30848c2ecf20Sopenharmony_ci * 2. The port registers with "itself".
30858c2ecf20Sopenharmony_ci * 3. The transmit and receive exchange ids are obtained.
30868c2ecf20Sopenharmony_ci * 4. The receive exchange id is posted.
30878c2ecf20Sopenharmony_ci * 5. A new els loopback event is created.
30888c2ecf20Sopenharmony_ci * 6. The command and response iocbs are allocated.
30898c2ecf20Sopenharmony_ci * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback.
30908c2ecf20Sopenharmony_ci *
30918c2ecf20Sopenharmony_ci * This function is meant to be called n times while the port is in loopback
30928c2ecf20Sopenharmony_ci * so it is the apps responsibility to issue a reset to take the port out
30938c2ecf20Sopenharmony_ci * of loopback mode.
30948c2ecf20Sopenharmony_ci **/
30958c2ecf20Sopenharmony_cistatic int
30968c2ecf20Sopenharmony_cilpfc_bsg_diag_loopback_run(struct bsg_job *job)
30978c2ecf20Sopenharmony_ci{
30988c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
30998c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
31008c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
31018c2ecf20Sopenharmony_ci	struct lpfc_bsg_event *evt;
31028c2ecf20Sopenharmony_ci	struct event_data *evdat;
31038c2ecf20Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
31048c2ecf20Sopenharmony_ci	uint32_t size;
31058c2ecf20Sopenharmony_ci	uint32_t full_size;
31068c2ecf20Sopenharmony_ci	size_t segment_len = 0, segment_offset = 0, current_offset = 0;
31078c2ecf20Sopenharmony_ci	uint16_t rpi = 0;
31088c2ecf20Sopenharmony_ci	struct lpfc_iocbq *cmdiocbq, *rspiocbq = NULL;
31098c2ecf20Sopenharmony_ci	IOCB_t *cmd, *rsp = NULL;
31108c2ecf20Sopenharmony_ci	struct lpfc_sli_ct_request *ctreq;
31118c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *txbmp;
31128c2ecf20Sopenharmony_ci	struct ulp_bde64 *txbpl = NULL;
31138c2ecf20Sopenharmony_ci	struct lpfc_dmabufext *txbuffer = NULL;
31148c2ecf20Sopenharmony_ci	struct list_head head;
31158c2ecf20Sopenharmony_ci	struct lpfc_dmabuf  *curr;
31168c2ecf20Sopenharmony_ci	uint16_t txxri = 0, rxxri;
31178c2ecf20Sopenharmony_ci	uint32_t num_bde;
31188c2ecf20Sopenharmony_ci	uint8_t *ptr = NULL, *rx_databuf = NULL;
31198c2ecf20Sopenharmony_ci	int rc = 0;
31208c2ecf20Sopenharmony_ci	int time_left;
31218c2ecf20Sopenharmony_ci	int iocb_stat = IOCB_SUCCESS;
31228c2ecf20Sopenharmony_ci	unsigned long flags;
31238c2ecf20Sopenharmony_ci	void *dataout = NULL;
31248c2ecf20Sopenharmony_ci	uint32_t total_mem;
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_ci	/* in case no data is returned return just the return code */
31278c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	if (job->request_len <
31308c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) {
31318c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
31328c2ecf20Sopenharmony_ci				"2739 Received DIAG TEST request below minimum "
31338c2ecf20Sopenharmony_ci				"size\n");
31348c2ecf20Sopenharmony_ci		rc = -EINVAL;
31358c2ecf20Sopenharmony_ci		goto loopback_test_exit;
31368c2ecf20Sopenharmony_ci	}
31378c2ecf20Sopenharmony_ci
31388c2ecf20Sopenharmony_ci	if (job->request_payload.payload_len !=
31398c2ecf20Sopenharmony_ci		job->reply_payload.payload_len) {
31408c2ecf20Sopenharmony_ci		rc = -EINVAL;
31418c2ecf20Sopenharmony_ci		goto loopback_test_exit;
31428c2ecf20Sopenharmony_ci	}
31438c2ecf20Sopenharmony_ci
31448c2ecf20Sopenharmony_ci	if ((phba->link_state == LPFC_HBA_ERROR) ||
31458c2ecf20Sopenharmony_ci	    (psli->sli_flag & LPFC_BLOCK_MGMT_IO) ||
31468c2ecf20Sopenharmony_ci	    (!(psli->sli_flag & LPFC_SLI_ACTIVE))) {
31478c2ecf20Sopenharmony_ci		rc = -EACCES;
31488c2ecf20Sopenharmony_ci		goto loopback_test_exit;
31498c2ecf20Sopenharmony_ci	}
31508c2ecf20Sopenharmony_ci
31518c2ecf20Sopenharmony_ci	if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) {
31528c2ecf20Sopenharmony_ci		rc = -EACCES;
31538c2ecf20Sopenharmony_ci		goto loopback_test_exit;
31548c2ecf20Sopenharmony_ci	}
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_ci	size = job->request_payload.payload_len;
31578c2ecf20Sopenharmony_ci	full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */
31588c2ecf20Sopenharmony_ci
31598c2ecf20Sopenharmony_ci	if ((size == 0) || (size > 80 * BUF_SZ_4K)) {
31608c2ecf20Sopenharmony_ci		rc = -ERANGE;
31618c2ecf20Sopenharmony_ci		goto loopback_test_exit;
31628c2ecf20Sopenharmony_ci	}
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci	if (full_size >= BUF_SZ_4K) {
31658c2ecf20Sopenharmony_ci		/*
31668c2ecf20Sopenharmony_ci		 * Allocate memory for ioctl data. If buffer is bigger than 64k,
31678c2ecf20Sopenharmony_ci		 * then we allocate 64k and re-use that buffer over and over to
31688c2ecf20Sopenharmony_ci		 * xfer the whole block. This is because Linux kernel has a
31698c2ecf20Sopenharmony_ci		 * problem allocating more than 120k of kernel space memory. Saw
31708c2ecf20Sopenharmony_ci		 * problem with GET_FCPTARGETMAPPING...
31718c2ecf20Sopenharmony_ci		 */
31728c2ecf20Sopenharmony_ci		if (size <= (64 * 1024))
31738c2ecf20Sopenharmony_ci			total_mem = full_size;
31748c2ecf20Sopenharmony_ci		else
31758c2ecf20Sopenharmony_ci			total_mem = 64 * 1024;
31768c2ecf20Sopenharmony_ci	} else
31778c2ecf20Sopenharmony_ci		/* Allocate memory for ioctl data */
31788c2ecf20Sopenharmony_ci		total_mem = BUF_SZ_4K;
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci	dataout = kmalloc(total_mem, GFP_KERNEL);
31818c2ecf20Sopenharmony_ci	if (dataout == NULL) {
31828c2ecf20Sopenharmony_ci		rc = -ENOMEM;
31838c2ecf20Sopenharmony_ci		goto loopback_test_exit;
31848c2ecf20Sopenharmony_ci	}
31858c2ecf20Sopenharmony_ci
31868c2ecf20Sopenharmony_ci	ptr = dataout;
31878c2ecf20Sopenharmony_ci	ptr += ELX_LOOPBACK_HEADER_SZ;
31888c2ecf20Sopenharmony_ci	sg_copy_to_buffer(job->request_payload.sg_list,
31898c2ecf20Sopenharmony_ci				job->request_payload.sg_cnt,
31908c2ecf20Sopenharmony_ci				ptr, size);
31918c2ecf20Sopenharmony_ci	rc = lpfcdiag_loop_self_reg(phba, &rpi);
31928c2ecf20Sopenharmony_ci	if (rc)
31938c2ecf20Sopenharmony_ci		goto loopback_test_exit;
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4) {
31968c2ecf20Sopenharmony_ci		rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri);
31978c2ecf20Sopenharmony_ci		if (rc) {
31988c2ecf20Sopenharmony_ci			lpfcdiag_loop_self_unreg(phba, rpi);
31998c2ecf20Sopenharmony_ci			goto loopback_test_exit;
32008c2ecf20Sopenharmony_ci		}
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_ci		rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size);
32038c2ecf20Sopenharmony_ci		if (rc) {
32048c2ecf20Sopenharmony_ci			lpfcdiag_loop_self_unreg(phba, rpi);
32058c2ecf20Sopenharmony_ci			goto loopback_test_exit;
32068c2ecf20Sopenharmony_ci		}
32078c2ecf20Sopenharmony_ci	}
32088c2ecf20Sopenharmony_ci	evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid,
32098c2ecf20Sopenharmony_ci				SLI_CT_ELX_LOOPBACK);
32108c2ecf20Sopenharmony_ci	if (!evt) {
32118c2ecf20Sopenharmony_ci		lpfcdiag_loop_self_unreg(phba, rpi);
32128c2ecf20Sopenharmony_ci		rc = -ENOMEM;
32138c2ecf20Sopenharmony_ci		goto loopback_test_exit;
32148c2ecf20Sopenharmony_ci	}
32158c2ecf20Sopenharmony_ci
32168c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
32178c2ecf20Sopenharmony_ci	list_add(&evt->node, &phba->ct_ev_waiters);
32188c2ecf20Sopenharmony_ci	lpfc_bsg_event_ref(evt);
32198c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
32208c2ecf20Sopenharmony_ci
32218c2ecf20Sopenharmony_ci	cmdiocbq = lpfc_sli_get_iocbq(phba);
32228c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
32238c2ecf20Sopenharmony_ci		rspiocbq = lpfc_sli_get_iocbq(phba);
32248c2ecf20Sopenharmony_ci	txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
32258c2ecf20Sopenharmony_ci
32268c2ecf20Sopenharmony_ci	if (txbmp) {
32278c2ecf20Sopenharmony_ci		txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys);
32288c2ecf20Sopenharmony_ci		if (txbmp->virt) {
32298c2ecf20Sopenharmony_ci			INIT_LIST_HEAD(&txbmp->list);
32308c2ecf20Sopenharmony_ci			txbpl = (struct ulp_bde64 *) txbmp->virt;
32318c2ecf20Sopenharmony_ci			txbuffer = diag_cmd_data_alloc(phba,
32328c2ecf20Sopenharmony_ci							txbpl, full_size, 0);
32338c2ecf20Sopenharmony_ci		}
32348c2ecf20Sopenharmony_ci	}
32358c2ecf20Sopenharmony_ci
32368c2ecf20Sopenharmony_ci	if (!cmdiocbq || !txbmp || !txbpl || !txbuffer || !txbmp->virt) {
32378c2ecf20Sopenharmony_ci		rc = -ENOMEM;
32388c2ecf20Sopenharmony_ci		goto err_loopback_test_exit;
32398c2ecf20Sopenharmony_ci	}
32408c2ecf20Sopenharmony_ci	if ((phba->sli_rev < LPFC_SLI_REV4) && !rspiocbq) {
32418c2ecf20Sopenharmony_ci		rc = -ENOMEM;
32428c2ecf20Sopenharmony_ci		goto err_loopback_test_exit;
32438c2ecf20Sopenharmony_ci	}
32448c2ecf20Sopenharmony_ci
32458c2ecf20Sopenharmony_ci	cmd = &cmdiocbq->iocb;
32468c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
32478c2ecf20Sopenharmony_ci		rsp = &rspiocbq->iocb;
32488c2ecf20Sopenharmony_ci
32498c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&head);
32508c2ecf20Sopenharmony_ci	list_add_tail(&head, &txbuffer->dma.list);
32518c2ecf20Sopenharmony_ci	list_for_each_entry(curr, &head, list) {
32528c2ecf20Sopenharmony_ci		segment_len = ((struct lpfc_dmabufext *)curr)->size;
32538c2ecf20Sopenharmony_ci		if (current_offset == 0) {
32548c2ecf20Sopenharmony_ci			ctreq = curr->virt;
32558c2ecf20Sopenharmony_ci			memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ);
32568c2ecf20Sopenharmony_ci			ctreq->RevisionId.bits.Revision = SLI_CT_REVISION;
32578c2ecf20Sopenharmony_ci			ctreq->RevisionId.bits.InId = 0;
32588c2ecf20Sopenharmony_ci			ctreq->FsType = SLI_CT_ELX_LOOPBACK;
32598c2ecf20Sopenharmony_ci			ctreq->FsSubType = 0;
32608c2ecf20Sopenharmony_ci			ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA;
32618c2ecf20Sopenharmony_ci			ctreq->CommandResponse.bits.Size   = size;
32628c2ecf20Sopenharmony_ci			segment_offset = ELX_LOOPBACK_HEADER_SZ;
32638c2ecf20Sopenharmony_ci		} else
32648c2ecf20Sopenharmony_ci			segment_offset = 0;
32658c2ecf20Sopenharmony_ci
32668c2ecf20Sopenharmony_ci		BUG_ON(segment_offset >= segment_len);
32678c2ecf20Sopenharmony_ci		memcpy(curr->virt + segment_offset,
32688c2ecf20Sopenharmony_ci			ptr + current_offset,
32698c2ecf20Sopenharmony_ci			segment_len - segment_offset);
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_ci		current_offset += segment_len - segment_offset;
32728c2ecf20Sopenharmony_ci		BUG_ON(current_offset > size);
32738c2ecf20Sopenharmony_ci	}
32748c2ecf20Sopenharmony_ci	list_del(&head);
32758c2ecf20Sopenharmony_ci
32768c2ecf20Sopenharmony_ci	/* Build the XMIT_SEQUENCE iocb */
32778c2ecf20Sopenharmony_ci	num_bde = (uint32_t)txbuffer->flag;
32788c2ecf20Sopenharmony_ci
32798c2ecf20Sopenharmony_ci	cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys);
32808c2ecf20Sopenharmony_ci	cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys);
32818c2ecf20Sopenharmony_ci	cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
32828c2ecf20Sopenharmony_ci	cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64));
32838c2ecf20Sopenharmony_ci
32848c2ecf20Sopenharmony_ci	cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA);
32858c2ecf20Sopenharmony_ci	cmd->un.xseq64.w5.hcsw.Dfctl = 0;
32868c2ecf20Sopenharmony_ci	cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
32878c2ecf20Sopenharmony_ci	cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT;
32888c2ecf20Sopenharmony_ci
32898c2ecf20Sopenharmony_ci	cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX;
32908c2ecf20Sopenharmony_ci	cmd->ulpBdeCount = 1;
32918c2ecf20Sopenharmony_ci	cmd->ulpLe = 1;
32928c2ecf20Sopenharmony_ci	cmd->ulpClass = CLASS3;
32938c2ecf20Sopenharmony_ci
32948c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4) {
32958c2ecf20Sopenharmony_ci		cmd->ulpContext = txxri;
32968c2ecf20Sopenharmony_ci	} else {
32978c2ecf20Sopenharmony_ci		cmd->un.xseq64.bdl.ulpIoTag32 = 0;
32988c2ecf20Sopenharmony_ci		cmd->un.ulpWord[3] = phba->sli4_hba.rpi_ids[rpi];
32998c2ecf20Sopenharmony_ci		cmdiocbq->context3 = txbmp;
33008c2ecf20Sopenharmony_ci		cmdiocbq->sli4_xritag = NO_XRI;
33018c2ecf20Sopenharmony_ci		cmd->unsli3.rcvsli3.ox_id = 0xffff;
33028c2ecf20Sopenharmony_ci	}
33038c2ecf20Sopenharmony_ci	cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
33048c2ecf20Sopenharmony_ci	cmdiocbq->iocb_flag |= LPFC_IO_LOOPBACK;
33058c2ecf20Sopenharmony_ci	cmdiocbq->vport = phba->pport;
33068c2ecf20Sopenharmony_ci	cmdiocbq->iocb_cmpl = NULL;
33078c2ecf20Sopenharmony_ci	iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
33088c2ecf20Sopenharmony_ci					     rspiocbq, (phba->fc_ratov * 2) +
33098c2ecf20Sopenharmony_ci					     LPFC_DRVR_TIMEOUT);
33108c2ecf20Sopenharmony_ci
33118c2ecf20Sopenharmony_ci	if ((iocb_stat != IOCB_SUCCESS) ||
33128c2ecf20Sopenharmony_ci	    ((phba->sli_rev < LPFC_SLI_REV4) &&
33138c2ecf20Sopenharmony_ci	     (rsp->ulpStatus != IOSTAT_SUCCESS))) {
33148c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
33158c2ecf20Sopenharmony_ci				"3126 Failed loopback test issue iocb: "
33168c2ecf20Sopenharmony_ci				"iocb_stat:x%x\n", iocb_stat);
33178c2ecf20Sopenharmony_ci		rc = -EIO;
33188c2ecf20Sopenharmony_ci		goto err_loopback_test_exit;
33198c2ecf20Sopenharmony_ci	}
33208c2ecf20Sopenharmony_ci
33218c2ecf20Sopenharmony_ci	evt->waiting = 1;
33228c2ecf20Sopenharmony_ci	time_left = wait_event_interruptible_timeout(
33238c2ecf20Sopenharmony_ci		evt->wq, !list_empty(&evt->events_to_see),
33248c2ecf20Sopenharmony_ci		msecs_to_jiffies(1000 *
33258c2ecf20Sopenharmony_ci			((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT)));
33268c2ecf20Sopenharmony_ci	evt->waiting = 0;
33278c2ecf20Sopenharmony_ci	if (list_empty(&evt->events_to_see)) {
33288c2ecf20Sopenharmony_ci		rc = (time_left) ? -EINTR : -ETIMEDOUT;
33298c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
33308c2ecf20Sopenharmony_ci				"3125 Not receiving unsolicited event, "
33318c2ecf20Sopenharmony_ci				"rc:x%x\n", rc);
33328c2ecf20Sopenharmony_ci	} else {
33338c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->ct_ev_lock, flags);
33348c2ecf20Sopenharmony_ci		list_move(evt->events_to_see.prev, &evt->events_to_get);
33358c2ecf20Sopenharmony_ci		evdat = list_entry(evt->events_to_get.prev,
33368c2ecf20Sopenharmony_ci				   typeof(*evdat), node);
33378c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
33388c2ecf20Sopenharmony_ci		rx_databuf = evdat->data;
33398c2ecf20Sopenharmony_ci		if (evdat->len != full_size) {
33408c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
33418c2ecf20Sopenharmony_ci				"1603 Loopback test did not receive expected "
33428c2ecf20Sopenharmony_ci				"data length. actual length 0x%x expected "
33438c2ecf20Sopenharmony_ci				"length 0x%x\n",
33448c2ecf20Sopenharmony_ci				evdat->len, full_size);
33458c2ecf20Sopenharmony_ci			rc = -EIO;
33468c2ecf20Sopenharmony_ci		} else if (rx_databuf == NULL)
33478c2ecf20Sopenharmony_ci			rc = -EIO;
33488c2ecf20Sopenharmony_ci		else {
33498c2ecf20Sopenharmony_ci			rc = IOCB_SUCCESS;
33508c2ecf20Sopenharmony_ci			/* skip over elx loopback header */
33518c2ecf20Sopenharmony_ci			rx_databuf += ELX_LOOPBACK_HEADER_SZ;
33528c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len =
33538c2ecf20Sopenharmony_ci				sg_copy_from_buffer(job->reply_payload.sg_list,
33548c2ecf20Sopenharmony_ci						    job->reply_payload.sg_cnt,
33558c2ecf20Sopenharmony_ci						    rx_databuf, size);
33568c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len = size;
33578c2ecf20Sopenharmony_ci		}
33588c2ecf20Sopenharmony_ci	}
33598c2ecf20Sopenharmony_ci
33608c2ecf20Sopenharmony_cierr_loopback_test_exit:
33618c2ecf20Sopenharmony_ci	lpfcdiag_loop_self_unreg(phba, rpi);
33628c2ecf20Sopenharmony_ci
33638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
33648c2ecf20Sopenharmony_ci	lpfc_bsg_event_unref(evt); /* release ref */
33658c2ecf20Sopenharmony_ci	lpfc_bsg_event_unref(evt); /* delete */
33668c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
33678c2ecf20Sopenharmony_ci
33688c2ecf20Sopenharmony_ci	if ((cmdiocbq != NULL) && (iocb_stat != IOCB_TIMEDOUT))
33698c2ecf20Sopenharmony_ci		lpfc_sli_release_iocbq(phba, cmdiocbq);
33708c2ecf20Sopenharmony_ci
33718c2ecf20Sopenharmony_ci	if (rspiocbq != NULL)
33728c2ecf20Sopenharmony_ci		lpfc_sli_release_iocbq(phba, rspiocbq);
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ci	if (txbmp != NULL) {
33758c2ecf20Sopenharmony_ci		if (txbpl != NULL) {
33768c2ecf20Sopenharmony_ci			if (txbuffer != NULL)
33778c2ecf20Sopenharmony_ci				diag_cmd_data_free(phba, txbuffer);
33788c2ecf20Sopenharmony_ci			lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys);
33798c2ecf20Sopenharmony_ci		}
33808c2ecf20Sopenharmony_ci		kfree(txbmp);
33818c2ecf20Sopenharmony_ci	}
33828c2ecf20Sopenharmony_ci
33838c2ecf20Sopenharmony_ciloopback_test_exit:
33848c2ecf20Sopenharmony_ci	kfree(dataout);
33858c2ecf20Sopenharmony_ci	/* make error code available to userspace */
33868c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
33878c2ecf20Sopenharmony_ci	job->dd_data = NULL;
33888c2ecf20Sopenharmony_ci	/* complete the job back to userspace if no error */
33898c2ecf20Sopenharmony_ci	if (rc == IOCB_SUCCESS)
33908c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
33918c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
33928c2ecf20Sopenharmony_ci	return rc;
33938c2ecf20Sopenharmony_ci}
33948c2ecf20Sopenharmony_ci
33958c2ecf20Sopenharmony_ci/**
33968c2ecf20Sopenharmony_ci * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command
33978c2ecf20Sopenharmony_ci * @job: GET_DFC_REV fc_bsg_job
33988c2ecf20Sopenharmony_ci **/
33998c2ecf20Sopenharmony_cistatic int
34008c2ecf20Sopenharmony_cilpfc_bsg_get_dfc_rev(struct bsg_job *job)
34018c2ecf20Sopenharmony_ci{
34028c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
34038c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
34048c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
34058c2ecf20Sopenharmony_ci	struct get_mgmt_rev_reply *event_reply;
34068c2ecf20Sopenharmony_ci	int rc = 0;
34078c2ecf20Sopenharmony_ci
34088c2ecf20Sopenharmony_ci	if (job->request_len <
34098c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) {
34108c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
34118c2ecf20Sopenharmony_ci				"2740 Received GET_DFC_REV request below "
34128c2ecf20Sopenharmony_ci				"minimum size\n");
34138c2ecf20Sopenharmony_ci		rc = -EINVAL;
34148c2ecf20Sopenharmony_ci		goto job_error;
34158c2ecf20Sopenharmony_ci	}
34168c2ecf20Sopenharmony_ci
34178c2ecf20Sopenharmony_ci	event_reply = (struct get_mgmt_rev_reply *)
34188c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp;
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_ci	if (job->reply_len < sizeof(*bsg_reply) + sizeof(*event_reply)) {
34218c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
34228c2ecf20Sopenharmony_ci				"2741 Received GET_DFC_REV reply below "
34238c2ecf20Sopenharmony_ci				"minimum size\n");
34248c2ecf20Sopenharmony_ci		rc = -EINVAL;
34258c2ecf20Sopenharmony_ci		goto job_error;
34268c2ecf20Sopenharmony_ci	}
34278c2ecf20Sopenharmony_ci
34288c2ecf20Sopenharmony_ci	event_reply->info.a_Major = MANAGEMENT_MAJOR_REV;
34298c2ecf20Sopenharmony_ci	event_reply->info.a_Minor = MANAGEMENT_MINOR_REV;
34308c2ecf20Sopenharmony_cijob_error:
34318c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
34328c2ecf20Sopenharmony_ci	if (rc == 0)
34338c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
34348c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
34358c2ecf20Sopenharmony_ci	return rc;
34368c2ecf20Sopenharmony_ci}
34378c2ecf20Sopenharmony_ci
34388c2ecf20Sopenharmony_ci/**
34398c2ecf20Sopenharmony_ci * lpfc_bsg_issue_mbox_cmpl - lpfc_bsg_issue_mbox mbox completion handler
34408c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
34418c2ecf20Sopenharmony_ci * @pmboxq: Pointer to mailbox command.
34428c2ecf20Sopenharmony_ci *
34438c2ecf20Sopenharmony_ci * This is completion handler function for mailbox commands issued from
34448c2ecf20Sopenharmony_ci * lpfc_bsg_issue_mbox function. This function is called by the
34458c2ecf20Sopenharmony_ci * mailbox event handler function with no lock held. This function
34468c2ecf20Sopenharmony_ci * will wake up thread waiting on the wait queue pointed by context1
34478c2ecf20Sopenharmony_ci * of the mailbox.
34488c2ecf20Sopenharmony_ci **/
34498c2ecf20Sopenharmony_cistatic void
34508c2ecf20Sopenharmony_cilpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
34518c2ecf20Sopenharmony_ci{
34528c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data;
34538c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
34548c2ecf20Sopenharmony_ci	struct bsg_job *job;
34558c2ecf20Sopenharmony_ci	uint32_t size;
34568c2ecf20Sopenharmony_ci	unsigned long flags;
34578c2ecf20Sopenharmony_ci	uint8_t *pmb, *pmb_buf;
34588c2ecf20Sopenharmony_ci
34598c2ecf20Sopenharmony_ci	dd_data = pmboxq->ctx_ndlp;
34608c2ecf20Sopenharmony_ci
34618c2ecf20Sopenharmony_ci	/*
34628c2ecf20Sopenharmony_ci	 * The outgoing buffer is readily referred from the dma buffer,
34638c2ecf20Sopenharmony_ci	 * just need to get header part from mailboxq structure.
34648c2ecf20Sopenharmony_ci	 */
34658c2ecf20Sopenharmony_ci	pmb = (uint8_t *)&pmboxq->u.mb;
34668c2ecf20Sopenharmony_ci	pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb;
34678c2ecf20Sopenharmony_ci	memcpy(pmb_buf, pmb, sizeof(MAILBOX_t));
34688c2ecf20Sopenharmony_ci
34698c2ecf20Sopenharmony_ci	/* Determine if job has been aborted */
34708c2ecf20Sopenharmony_ci
34718c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
34728c2ecf20Sopenharmony_ci	job = dd_data->set_job;
34738c2ecf20Sopenharmony_ci	if (job) {
34748c2ecf20Sopenharmony_ci		/* Prevent timeout handling from trying to abort job  */
34758c2ecf20Sopenharmony_ci		job->dd_data = NULL;
34768c2ecf20Sopenharmony_ci	}
34778c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
34788c2ecf20Sopenharmony_ci
34798c2ecf20Sopenharmony_ci	/* Copy the mailbox data to the job if it is still active */
34808c2ecf20Sopenharmony_ci
34818c2ecf20Sopenharmony_ci	if (job) {
34828c2ecf20Sopenharmony_ci		bsg_reply = job->reply;
34838c2ecf20Sopenharmony_ci		size = job->reply_payload.payload_len;
34848c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len =
34858c2ecf20Sopenharmony_ci			sg_copy_from_buffer(job->reply_payload.sg_list,
34868c2ecf20Sopenharmony_ci					    job->reply_payload.sg_cnt,
34878c2ecf20Sopenharmony_ci					    pmb_buf, size);
34888c2ecf20Sopenharmony_ci	}
34898c2ecf20Sopenharmony_ci
34908c2ecf20Sopenharmony_ci	dd_data->set_job = NULL;
34918c2ecf20Sopenharmony_ci	mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool);
34928c2ecf20Sopenharmony_ci	lpfc_bsg_dma_page_free(phba, dd_data->context_un.mbox.dmabuffers);
34938c2ecf20Sopenharmony_ci	kfree(dd_data);
34948c2ecf20Sopenharmony_ci
34958c2ecf20Sopenharmony_ci	/* Complete the job if the job is still active */
34968c2ecf20Sopenharmony_ci
34978c2ecf20Sopenharmony_ci	if (job) {
34988c2ecf20Sopenharmony_ci		bsg_reply->result = 0;
34998c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
35008c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
35018c2ecf20Sopenharmony_ci	}
35028c2ecf20Sopenharmony_ci	return;
35038c2ecf20Sopenharmony_ci}
35048c2ecf20Sopenharmony_ci
35058c2ecf20Sopenharmony_ci/**
35068c2ecf20Sopenharmony_ci * lpfc_bsg_check_cmd_access - test for a supported mailbox command
35078c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
35088c2ecf20Sopenharmony_ci * @mb: Pointer to a mailbox object.
35098c2ecf20Sopenharmony_ci * @vport: Pointer to a vport object.
35108c2ecf20Sopenharmony_ci *
35118c2ecf20Sopenharmony_ci * Some commands require the port to be offline, some may not be called from
35128c2ecf20Sopenharmony_ci * the application.
35138c2ecf20Sopenharmony_ci **/
35148c2ecf20Sopenharmony_cistatic int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
35158c2ecf20Sopenharmony_ci	MAILBOX_t *mb, struct lpfc_vport *vport)
35168c2ecf20Sopenharmony_ci{
35178c2ecf20Sopenharmony_ci	/* return negative error values for bsg job */
35188c2ecf20Sopenharmony_ci	switch (mb->mbxCommand) {
35198c2ecf20Sopenharmony_ci	/* Offline only */
35208c2ecf20Sopenharmony_ci	case MBX_INIT_LINK:
35218c2ecf20Sopenharmony_ci	case MBX_DOWN_LINK:
35228c2ecf20Sopenharmony_ci	case MBX_CONFIG_LINK:
35238c2ecf20Sopenharmony_ci	case MBX_CONFIG_RING:
35248c2ecf20Sopenharmony_ci	case MBX_RESET_RING:
35258c2ecf20Sopenharmony_ci	case MBX_UNREG_LOGIN:
35268c2ecf20Sopenharmony_ci	case MBX_CLEAR_LA:
35278c2ecf20Sopenharmony_ci	case MBX_DUMP_CONTEXT:
35288c2ecf20Sopenharmony_ci	case MBX_RUN_DIAGS:
35298c2ecf20Sopenharmony_ci	case MBX_RESTART:
35308c2ecf20Sopenharmony_ci	case MBX_SET_MASK:
35318c2ecf20Sopenharmony_ci		if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
35328c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
35338c2ecf20Sopenharmony_ci				"2743 Command 0x%x is illegal in on-line "
35348c2ecf20Sopenharmony_ci				"state\n",
35358c2ecf20Sopenharmony_ci				mb->mbxCommand);
35368c2ecf20Sopenharmony_ci			return -EPERM;
35378c2ecf20Sopenharmony_ci		}
35388c2ecf20Sopenharmony_ci	case MBX_WRITE_NV:
35398c2ecf20Sopenharmony_ci	case MBX_WRITE_VPARMS:
35408c2ecf20Sopenharmony_ci	case MBX_LOAD_SM:
35418c2ecf20Sopenharmony_ci	case MBX_READ_NV:
35428c2ecf20Sopenharmony_ci	case MBX_READ_CONFIG:
35438c2ecf20Sopenharmony_ci	case MBX_READ_RCONFIG:
35448c2ecf20Sopenharmony_ci	case MBX_READ_STATUS:
35458c2ecf20Sopenharmony_ci	case MBX_READ_XRI:
35468c2ecf20Sopenharmony_ci	case MBX_READ_REV:
35478c2ecf20Sopenharmony_ci	case MBX_READ_LNK_STAT:
35488c2ecf20Sopenharmony_ci	case MBX_DUMP_MEMORY:
35498c2ecf20Sopenharmony_ci	case MBX_DOWN_LOAD:
35508c2ecf20Sopenharmony_ci	case MBX_UPDATE_CFG:
35518c2ecf20Sopenharmony_ci	case MBX_KILL_BOARD:
35528c2ecf20Sopenharmony_ci	case MBX_READ_TOPOLOGY:
35538c2ecf20Sopenharmony_ci	case MBX_LOAD_AREA:
35548c2ecf20Sopenharmony_ci	case MBX_LOAD_EXP_ROM:
35558c2ecf20Sopenharmony_ci	case MBX_BEACON:
35568c2ecf20Sopenharmony_ci	case MBX_DEL_LD_ENTRY:
35578c2ecf20Sopenharmony_ci	case MBX_SET_DEBUG:
35588c2ecf20Sopenharmony_ci	case MBX_WRITE_WWN:
35598c2ecf20Sopenharmony_ci	case MBX_SLI4_CONFIG:
35608c2ecf20Sopenharmony_ci	case MBX_READ_EVENT_LOG:
35618c2ecf20Sopenharmony_ci	case MBX_READ_EVENT_LOG_STATUS:
35628c2ecf20Sopenharmony_ci	case MBX_WRITE_EVENT_LOG:
35638c2ecf20Sopenharmony_ci	case MBX_PORT_CAPABILITIES:
35648c2ecf20Sopenharmony_ci	case MBX_PORT_IOV_CONTROL:
35658c2ecf20Sopenharmony_ci	case MBX_RUN_BIU_DIAG64:
35668c2ecf20Sopenharmony_ci		break;
35678c2ecf20Sopenharmony_ci	case MBX_SET_VARIABLE:
35688c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
35698c2ecf20Sopenharmony_ci			"1226 mbox: set_variable 0x%x, 0x%x\n",
35708c2ecf20Sopenharmony_ci			mb->un.varWords[0],
35718c2ecf20Sopenharmony_ci			mb->un.varWords[1]);
35728c2ecf20Sopenharmony_ci		if ((mb->un.varWords[0] == SETVAR_MLOMNT)
35738c2ecf20Sopenharmony_ci			&& (mb->un.varWords[1] == 1)) {
35748c2ecf20Sopenharmony_ci			phba->wait_4_mlo_maint_flg = 1;
35758c2ecf20Sopenharmony_ci		} else if (mb->un.varWords[0] == SETVAR_MLORST) {
35768c2ecf20Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
35778c2ecf20Sopenharmony_ci			phba->link_flag &= ~LS_LOOPBACK_MODE;
35788c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
35798c2ecf20Sopenharmony_ci			phba->fc_topology = LPFC_TOPOLOGY_PT_PT;
35808c2ecf20Sopenharmony_ci		}
35818c2ecf20Sopenharmony_ci		break;
35828c2ecf20Sopenharmony_ci	case MBX_READ_SPARM64:
35838c2ecf20Sopenharmony_ci	case MBX_REG_LOGIN:
35848c2ecf20Sopenharmony_ci	case MBX_REG_LOGIN64:
35858c2ecf20Sopenharmony_ci	case MBX_CONFIG_PORT:
35868c2ecf20Sopenharmony_ci	case MBX_RUN_BIU_DIAG:
35878c2ecf20Sopenharmony_ci	default:
35888c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
35898c2ecf20Sopenharmony_ci			"2742 Unknown Command 0x%x\n",
35908c2ecf20Sopenharmony_ci			mb->mbxCommand);
35918c2ecf20Sopenharmony_ci		return -EPERM;
35928c2ecf20Sopenharmony_ci	}
35938c2ecf20Sopenharmony_ci
35948c2ecf20Sopenharmony_ci	return 0; /* ok */
35958c2ecf20Sopenharmony_ci}
35968c2ecf20Sopenharmony_ci
35978c2ecf20Sopenharmony_ci/**
35988c2ecf20Sopenharmony_ci * lpfc_bsg_mbox_ext_cleanup - clean up context of multi-buffer mbox session
35998c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
36008c2ecf20Sopenharmony_ci *
36018c2ecf20Sopenharmony_ci * This is routine clean up and reset BSG handling of multi-buffer mbox
36028c2ecf20Sopenharmony_ci * command session.
36038c2ecf20Sopenharmony_ci **/
36048c2ecf20Sopenharmony_cistatic void
36058c2ecf20Sopenharmony_cilpfc_bsg_mbox_ext_session_reset(struct lpfc_hba *phba)
36068c2ecf20Sopenharmony_ci{
36078c2ecf20Sopenharmony_ci	if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE)
36088c2ecf20Sopenharmony_ci		return;
36098c2ecf20Sopenharmony_ci
36108c2ecf20Sopenharmony_ci	/* free all memory, including dma buffers */
36118c2ecf20Sopenharmony_ci	lpfc_bsg_dma_page_list_free(phba,
36128c2ecf20Sopenharmony_ci				    &phba->mbox_ext_buf_ctx.ext_dmabuf_list);
36138c2ecf20Sopenharmony_ci	lpfc_bsg_dma_page_free(phba, phba->mbox_ext_buf_ctx.mbx_dmabuf);
36148c2ecf20Sopenharmony_ci	/* multi-buffer write mailbox command pass-through complete */
36158c2ecf20Sopenharmony_ci	memset((char *)&phba->mbox_ext_buf_ctx, 0,
36168c2ecf20Sopenharmony_ci	       sizeof(struct lpfc_mbox_ext_buf_ctx));
36178c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&phba->mbox_ext_buf_ctx.ext_dmabuf_list);
36188c2ecf20Sopenharmony_ci
36198c2ecf20Sopenharmony_ci	return;
36208c2ecf20Sopenharmony_ci}
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ci/**
36238c2ecf20Sopenharmony_ci * lpfc_bsg_issue_mbox_ext_handle_job - job handler for multi-buffer mbox cmpl
36248c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
36258c2ecf20Sopenharmony_ci * @pmboxq: Pointer to mailbox command.
36268c2ecf20Sopenharmony_ci *
36278c2ecf20Sopenharmony_ci * This is routine handles BSG job for mailbox commands completions with
36288c2ecf20Sopenharmony_ci * multiple external buffers.
36298c2ecf20Sopenharmony_ci **/
36308c2ecf20Sopenharmony_cistatic struct bsg_job *
36318c2ecf20Sopenharmony_cilpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
36328c2ecf20Sopenharmony_ci{
36338c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data;
36348c2ecf20Sopenharmony_ci	struct bsg_job *job;
36358c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
36368c2ecf20Sopenharmony_ci	uint8_t *pmb, *pmb_buf;
36378c2ecf20Sopenharmony_ci	unsigned long flags;
36388c2ecf20Sopenharmony_ci	uint32_t size;
36398c2ecf20Sopenharmony_ci	int rc = 0;
36408c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
36418c2ecf20Sopenharmony_ci	struct lpfc_sli_config_mbox *sli_cfg_mbx;
36428c2ecf20Sopenharmony_ci	uint8_t *pmbx;
36438c2ecf20Sopenharmony_ci
36448c2ecf20Sopenharmony_ci	dd_data = pmboxq->ctx_buf;
36458c2ecf20Sopenharmony_ci
36468c2ecf20Sopenharmony_ci	/* Determine if job has been aborted */
36478c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
36488c2ecf20Sopenharmony_ci	job = dd_data->set_job;
36498c2ecf20Sopenharmony_ci	if (job) {
36508c2ecf20Sopenharmony_ci		bsg_reply = job->reply;
36518c2ecf20Sopenharmony_ci		/* Prevent timeout handling from trying to abort job  */
36528c2ecf20Sopenharmony_ci		job->dd_data = NULL;
36538c2ecf20Sopenharmony_ci	}
36548c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
36558c2ecf20Sopenharmony_ci
36568c2ecf20Sopenharmony_ci	/*
36578c2ecf20Sopenharmony_ci	 * The outgoing buffer is readily referred from the dma buffer,
36588c2ecf20Sopenharmony_ci	 * just need to get header part from mailboxq structure.
36598c2ecf20Sopenharmony_ci	 */
36608c2ecf20Sopenharmony_ci
36618c2ecf20Sopenharmony_ci	pmb = (uint8_t *)&pmboxq->u.mb;
36628c2ecf20Sopenharmony_ci	pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb;
36638c2ecf20Sopenharmony_ci	/* Copy the byte swapped response mailbox back to the user */
36648c2ecf20Sopenharmony_ci	memcpy(pmb_buf, pmb, sizeof(MAILBOX_t));
36658c2ecf20Sopenharmony_ci	/* if there is any non-embedded extended data copy that too */
36668c2ecf20Sopenharmony_ci	dmabuf = phba->mbox_ext_buf_ctx.mbx_dmabuf;
36678c2ecf20Sopenharmony_ci	sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt;
36688c2ecf20Sopenharmony_ci	if (!bsg_bf_get(lpfc_mbox_hdr_emb,
36698c2ecf20Sopenharmony_ci	    &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) {
36708c2ecf20Sopenharmony_ci		pmbx = (uint8_t *)dmabuf->virt;
36718c2ecf20Sopenharmony_ci		/* byte swap the extended data following the mailbox command */
36728c2ecf20Sopenharmony_ci		lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)],
36738c2ecf20Sopenharmony_ci			&pmbx[sizeof(MAILBOX_t)],
36748c2ecf20Sopenharmony_ci			sli_cfg_mbx->un.sli_config_emb0_subsys.mse[0].buf_len);
36758c2ecf20Sopenharmony_ci	}
36768c2ecf20Sopenharmony_ci
36778c2ecf20Sopenharmony_ci	/* Complete the job if the job is still active */
36788c2ecf20Sopenharmony_ci
36798c2ecf20Sopenharmony_ci	if (job) {
36808c2ecf20Sopenharmony_ci		size = job->reply_payload.payload_len;
36818c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len =
36828c2ecf20Sopenharmony_ci			sg_copy_from_buffer(job->reply_payload.sg_list,
36838c2ecf20Sopenharmony_ci					    job->reply_payload.sg_cnt,
36848c2ecf20Sopenharmony_ci					    pmb_buf, size);
36858c2ecf20Sopenharmony_ci
36868c2ecf20Sopenharmony_ci		/* result for successful */
36878c2ecf20Sopenharmony_ci		bsg_reply->result = 0;
36888c2ecf20Sopenharmony_ci
36898c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
36908c2ecf20Sopenharmony_ci				"2937 SLI_CONFIG ext-buffer mailbox command "
36918c2ecf20Sopenharmony_ci				"(x%x/x%x) complete bsg job done, bsize:%d\n",
36928c2ecf20Sopenharmony_ci				phba->mbox_ext_buf_ctx.nembType,
36938c2ecf20Sopenharmony_ci				phba->mbox_ext_buf_ctx.mboxType, size);
36948c2ecf20Sopenharmony_ci		lpfc_idiag_mbxacc_dump_bsg_mbox(phba,
36958c2ecf20Sopenharmony_ci					phba->mbox_ext_buf_ctx.nembType,
36968c2ecf20Sopenharmony_ci					phba->mbox_ext_buf_ctx.mboxType,
36978c2ecf20Sopenharmony_ci					dma_ebuf, sta_pos_addr,
36988c2ecf20Sopenharmony_ci					phba->mbox_ext_buf_ctx.mbx_dmabuf, 0);
36998c2ecf20Sopenharmony_ci	} else {
37008c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
37018c2ecf20Sopenharmony_ci				"2938 SLI_CONFIG ext-buffer mailbox "
37028c2ecf20Sopenharmony_ci				"command (x%x/x%x) failure, rc:x%x\n",
37038c2ecf20Sopenharmony_ci				phba->mbox_ext_buf_ctx.nembType,
37048c2ecf20Sopenharmony_ci				phba->mbox_ext_buf_ctx.mboxType, rc);
37058c2ecf20Sopenharmony_ci	}
37068c2ecf20Sopenharmony_ci
37078c2ecf20Sopenharmony_ci
37088c2ecf20Sopenharmony_ci	/* state change */
37098c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_DONE;
37108c2ecf20Sopenharmony_ci	kfree(dd_data);
37118c2ecf20Sopenharmony_ci	return job;
37128c2ecf20Sopenharmony_ci}
37138c2ecf20Sopenharmony_ci
37148c2ecf20Sopenharmony_ci/**
37158c2ecf20Sopenharmony_ci * lpfc_bsg_issue_read_mbox_ext_cmpl - compl handler for multi-buffer read mbox
37168c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
37178c2ecf20Sopenharmony_ci * @pmboxq: Pointer to mailbox command.
37188c2ecf20Sopenharmony_ci *
37198c2ecf20Sopenharmony_ci * This is completion handler function for mailbox read commands with multiple
37208c2ecf20Sopenharmony_ci * external buffers.
37218c2ecf20Sopenharmony_ci **/
37228c2ecf20Sopenharmony_cistatic void
37238c2ecf20Sopenharmony_cilpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
37248c2ecf20Sopenharmony_ci{
37258c2ecf20Sopenharmony_ci	struct bsg_job *job;
37268c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
37278c2ecf20Sopenharmony_ci
37288c2ecf20Sopenharmony_ci	job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
37298c2ecf20Sopenharmony_ci
37308c2ecf20Sopenharmony_ci	/* handle the BSG job with mailbox command */
37318c2ecf20Sopenharmony_ci	if (!job)
37328c2ecf20Sopenharmony_ci		pmboxq->u.mb.mbxStatus = MBXERR_ERROR;
37338c2ecf20Sopenharmony_ci
37348c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
37358c2ecf20Sopenharmony_ci			"2939 SLI_CONFIG ext-buffer rd mailbox command "
37368c2ecf20Sopenharmony_ci			"complete, ctxState:x%x, mbxStatus:x%x\n",
37378c2ecf20Sopenharmony_ci			phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus);
37388c2ecf20Sopenharmony_ci
37398c2ecf20Sopenharmony_ci	if (pmboxq->u.mb.mbxStatus || phba->mbox_ext_buf_ctx.numBuf == 1)
37408c2ecf20Sopenharmony_ci		lpfc_bsg_mbox_ext_session_reset(phba);
37418c2ecf20Sopenharmony_ci
37428c2ecf20Sopenharmony_ci	/* free base driver mailbox structure memory */
37438c2ecf20Sopenharmony_ci	mempool_free(pmboxq, phba->mbox_mem_pool);
37448c2ecf20Sopenharmony_ci
37458c2ecf20Sopenharmony_ci	/* if the job is still active, call job done */
37468c2ecf20Sopenharmony_ci	if (job) {
37478c2ecf20Sopenharmony_ci		bsg_reply = job->reply;
37488c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
37498c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
37508c2ecf20Sopenharmony_ci	}
37518c2ecf20Sopenharmony_ci	return;
37528c2ecf20Sopenharmony_ci}
37538c2ecf20Sopenharmony_ci
37548c2ecf20Sopenharmony_ci/**
37558c2ecf20Sopenharmony_ci * lpfc_bsg_issue_write_mbox_ext_cmpl - cmpl handler for multi-buffer write mbox
37568c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
37578c2ecf20Sopenharmony_ci * @pmboxq: Pointer to mailbox command.
37588c2ecf20Sopenharmony_ci *
37598c2ecf20Sopenharmony_ci * This is completion handler function for mailbox write commands with multiple
37608c2ecf20Sopenharmony_ci * external buffers.
37618c2ecf20Sopenharmony_ci **/
37628c2ecf20Sopenharmony_cistatic void
37638c2ecf20Sopenharmony_cilpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
37648c2ecf20Sopenharmony_ci{
37658c2ecf20Sopenharmony_ci	struct bsg_job *job;
37668c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
37678c2ecf20Sopenharmony_ci
37688c2ecf20Sopenharmony_ci	job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
37698c2ecf20Sopenharmony_ci
37708c2ecf20Sopenharmony_ci	/* handle the BSG job with the mailbox command */
37718c2ecf20Sopenharmony_ci	if (!job)
37728c2ecf20Sopenharmony_ci		pmboxq->u.mb.mbxStatus = MBXERR_ERROR;
37738c2ecf20Sopenharmony_ci
37748c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
37758c2ecf20Sopenharmony_ci			"2940 SLI_CONFIG ext-buffer wr mailbox command "
37768c2ecf20Sopenharmony_ci			"complete, ctxState:x%x, mbxStatus:x%x\n",
37778c2ecf20Sopenharmony_ci			phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus);
37788c2ecf20Sopenharmony_ci
37798c2ecf20Sopenharmony_ci	/* free all memory, including dma buffers */
37808c2ecf20Sopenharmony_ci	mempool_free(pmboxq, phba->mbox_mem_pool);
37818c2ecf20Sopenharmony_ci	lpfc_bsg_mbox_ext_session_reset(phba);
37828c2ecf20Sopenharmony_ci
37838c2ecf20Sopenharmony_ci	/* if the job is still active, call job done */
37848c2ecf20Sopenharmony_ci	if (job) {
37858c2ecf20Sopenharmony_ci		bsg_reply = job->reply;
37868c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
37878c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
37888c2ecf20Sopenharmony_ci	}
37898c2ecf20Sopenharmony_ci
37908c2ecf20Sopenharmony_ci	return;
37918c2ecf20Sopenharmony_ci}
37928c2ecf20Sopenharmony_ci
37938c2ecf20Sopenharmony_cistatic void
37948c2ecf20Sopenharmony_cilpfc_bsg_sli_cfg_dma_desc_setup(struct lpfc_hba *phba, enum nemb_type nemb_tp,
37958c2ecf20Sopenharmony_ci				uint32_t index, struct lpfc_dmabuf *mbx_dmabuf,
37968c2ecf20Sopenharmony_ci				struct lpfc_dmabuf *ext_dmabuf)
37978c2ecf20Sopenharmony_ci{
37988c2ecf20Sopenharmony_ci	struct lpfc_sli_config_mbox *sli_cfg_mbx;
37998c2ecf20Sopenharmony_ci
38008c2ecf20Sopenharmony_ci	/* pointer to the start of mailbox command */
38018c2ecf20Sopenharmony_ci	sli_cfg_mbx = (struct lpfc_sli_config_mbox *)mbx_dmabuf->virt;
38028c2ecf20Sopenharmony_ci
38038c2ecf20Sopenharmony_ci	if (nemb_tp == nemb_mse) {
38048c2ecf20Sopenharmony_ci		if (index == 0) {
38058c2ecf20Sopenharmony_ci			sli_cfg_mbx->un.sli_config_emb0_subsys.
38068c2ecf20Sopenharmony_ci				mse[index].pa_hi =
38078c2ecf20Sopenharmony_ci				putPaddrHigh(mbx_dmabuf->phys +
38088c2ecf20Sopenharmony_ci					     sizeof(MAILBOX_t));
38098c2ecf20Sopenharmony_ci			sli_cfg_mbx->un.sli_config_emb0_subsys.
38108c2ecf20Sopenharmony_ci				mse[index].pa_lo =
38118c2ecf20Sopenharmony_ci				putPaddrLow(mbx_dmabuf->phys +
38128c2ecf20Sopenharmony_ci					    sizeof(MAILBOX_t));
38138c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
38148c2ecf20Sopenharmony_ci					"2943 SLI_CONFIG(mse)[%d], "
38158c2ecf20Sopenharmony_ci					"bufLen:%d, addrHi:x%x, addrLo:x%x\n",
38168c2ecf20Sopenharmony_ci					index,
38178c2ecf20Sopenharmony_ci					sli_cfg_mbx->un.sli_config_emb0_subsys.
38188c2ecf20Sopenharmony_ci					mse[index].buf_len,
38198c2ecf20Sopenharmony_ci					sli_cfg_mbx->un.sli_config_emb0_subsys.
38208c2ecf20Sopenharmony_ci					mse[index].pa_hi,
38218c2ecf20Sopenharmony_ci					sli_cfg_mbx->un.sli_config_emb0_subsys.
38228c2ecf20Sopenharmony_ci					mse[index].pa_lo);
38238c2ecf20Sopenharmony_ci		} else {
38248c2ecf20Sopenharmony_ci			sli_cfg_mbx->un.sli_config_emb0_subsys.
38258c2ecf20Sopenharmony_ci				mse[index].pa_hi =
38268c2ecf20Sopenharmony_ci				putPaddrHigh(ext_dmabuf->phys);
38278c2ecf20Sopenharmony_ci			sli_cfg_mbx->un.sli_config_emb0_subsys.
38288c2ecf20Sopenharmony_ci				mse[index].pa_lo =
38298c2ecf20Sopenharmony_ci				putPaddrLow(ext_dmabuf->phys);
38308c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
38318c2ecf20Sopenharmony_ci					"2944 SLI_CONFIG(mse)[%d], "
38328c2ecf20Sopenharmony_ci					"bufLen:%d, addrHi:x%x, addrLo:x%x\n",
38338c2ecf20Sopenharmony_ci					index,
38348c2ecf20Sopenharmony_ci					sli_cfg_mbx->un.sli_config_emb0_subsys.
38358c2ecf20Sopenharmony_ci					mse[index].buf_len,
38368c2ecf20Sopenharmony_ci					sli_cfg_mbx->un.sli_config_emb0_subsys.
38378c2ecf20Sopenharmony_ci					mse[index].pa_hi,
38388c2ecf20Sopenharmony_ci					sli_cfg_mbx->un.sli_config_emb0_subsys.
38398c2ecf20Sopenharmony_ci					mse[index].pa_lo);
38408c2ecf20Sopenharmony_ci		}
38418c2ecf20Sopenharmony_ci	} else {
38428c2ecf20Sopenharmony_ci		if (index == 0) {
38438c2ecf20Sopenharmony_ci			sli_cfg_mbx->un.sli_config_emb1_subsys.
38448c2ecf20Sopenharmony_ci				hbd[index].pa_hi =
38458c2ecf20Sopenharmony_ci				putPaddrHigh(mbx_dmabuf->phys +
38468c2ecf20Sopenharmony_ci					     sizeof(MAILBOX_t));
38478c2ecf20Sopenharmony_ci			sli_cfg_mbx->un.sli_config_emb1_subsys.
38488c2ecf20Sopenharmony_ci				hbd[index].pa_lo =
38498c2ecf20Sopenharmony_ci				putPaddrLow(mbx_dmabuf->phys +
38508c2ecf20Sopenharmony_ci					    sizeof(MAILBOX_t));
38518c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
38528c2ecf20Sopenharmony_ci					"3007 SLI_CONFIG(hbd)[%d], "
38538c2ecf20Sopenharmony_ci					"bufLen:%d, addrHi:x%x, addrLo:x%x\n",
38548c2ecf20Sopenharmony_ci				index,
38558c2ecf20Sopenharmony_ci				bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len,
38568c2ecf20Sopenharmony_ci				&sli_cfg_mbx->un.
38578c2ecf20Sopenharmony_ci				sli_config_emb1_subsys.hbd[index]),
38588c2ecf20Sopenharmony_ci				sli_cfg_mbx->un.sli_config_emb1_subsys.
38598c2ecf20Sopenharmony_ci				hbd[index].pa_hi,
38608c2ecf20Sopenharmony_ci				sli_cfg_mbx->un.sli_config_emb1_subsys.
38618c2ecf20Sopenharmony_ci				hbd[index].pa_lo);
38628c2ecf20Sopenharmony_ci
38638c2ecf20Sopenharmony_ci		} else {
38648c2ecf20Sopenharmony_ci			sli_cfg_mbx->un.sli_config_emb1_subsys.
38658c2ecf20Sopenharmony_ci				hbd[index].pa_hi =
38668c2ecf20Sopenharmony_ci				putPaddrHigh(ext_dmabuf->phys);
38678c2ecf20Sopenharmony_ci			sli_cfg_mbx->un.sli_config_emb1_subsys.
38688c2ecf20Sopenharmony_ci				hbd[index].pa_lo =
38698c2ecf20Sopenharmony_ci				putPaddrLow(ext_dmabuf->phys);
38708c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
38718c2ecf20Sopenharmony_ci					"3008 SLI_CONFIG(hbd)[%d], "
38728c2ecf20Sopenharmony_ci					"bufLen:%d, addrHi:x%x, addrLo:x%x\n",
38738c2ecf20Sopenharmony_ci				index,
38748c2ecf20Sopenharmony_ci				bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len,
38758c2ecf20Sopenharmony_ci				&sli_cfg_mbx->un.
38768c2ecf20Sopenharmony_ci				sli_config_emb1_subsys.hbd[index]),
38778c2ecf20Sopenharmony_ci				sli_cfg_mbx->un.sli_config_emb1_subsys.
38788c2ecf20Sopenharmony_ci				hbd[index].pa_hi,
38798c2ecf20Sopenharmony_ci				sli_cfg_mbx->un.sli_config_emb1_subsys.
38808c2ecf20Sopenharmony_ci				hbd[index].pa_lo);
38818c2ecf20Sopenharmony_ci		}
38828c2ecf20Sopenharmony_ci	}
38838c2ecf20Sopenharmony_ci	return;
38848c2ecf20Sopenharmony_ci}
38858c2ecf20Sopenharmony_ci
38868c2ecf20Sopenharmony_ci/**
38878c2ecf20Sopenharmony_ci * lpfc_bsg_sli_cfg_mse_read_cmd_ext - sli_config non-embedded mailbox cmd read
38888c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
38898c2ecf20Sopenharmony_ci * @mb: Pointer to a BSG mailbox object.
38908c2ecf20Sopenharmony_ci * @nemb_tp: Enumerate of non-embedded mailbox command type.
38918c2ecf20Sopenharmony_ci * @dmabuff: Pointer to a DMA buffer descriptor.
38928c2ecf20Sopenharmony_ci *
38938c2ecf20Sopenharmony_ci * This routine performs SLI_CONFIG (0x9B) read mailbox command operation with
38948c2ecf20Sopenharmony_ci * non-embedded external bufffers.
38958c2ecf20Sopenharmony_ci **/
38968c2ecf20Sopenharmony_cistatic int
38978c2ecf20Sopenharmony_cilpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job,
38988c2ecf20Sopenharmony_ci			      enum nemb_type nemb_tp,
38998c2ecf20Sopenharmony_ci			      struct lpfc_dmabuf *dmabuf)
39008c2ecf20Sopenharmony_ci{
39018c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
39028c2ecf20Sopenharmony_ci	struct lpfc_sli_config_mbox *sli_cfg_mbx;
39038c2ecf20Sopenharmony_ci	struct dfc_mbox_req *mbox_req;
39048c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *curr_dmabuf, *next_dmabuf;
39058c2ecf20Sopenharmony_ci	uint32_t ext_buf_cnt, ext_buf_index;
39068c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *ext_dmabuf = NULL;
39078c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data = NULL;
39088c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *pmboxq = NULL;
39098c2ecf20Sopenharmony_ci	MAILBOX_t *pmb;
39108c2ecf20Sopenharmony_ci	uint8_t *pmbx;
39118c2ecf20Sopenharmony_ci	int rc, i;
39128c2ecf20Sopenharmony_ci
39138c2ecf20Sopenharmony_ci	mbox_req =
39148c2ecf20Sopenharmony_ci	   (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd;
39158c2ecf20Sopenharmony_ci
39168c2ecf20Sopenharmony_ci	/* pointer to the start of mailbox command */
39178c2ecf20Sopenharmony_ci	sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt;
39188c2ecf20Sopenharmony_ci
39198c2ecf20Sopenharmony_ci	if (nemb_tp == nemb_mse) {
39208c2ecf20Sopenharmony_ci		ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt,
39218c2ecf20Sopenharmony_ci			&sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr);
39228c2ecf20Sopenharmony_ci		if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) {
39238c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
39248c2ecf20Sopenharmony_ci					"2945 Handled SLI_CONFIG(mse) rd, "
39258c2ecf20Sopenharmony_ci					"ext_buf_cnt(%d) out of range(%d)\n",
39268c2ecf20Sopenharmony_ci					ext_buf_cnt,
39278c2ecf20Sopenharmony_ci					LPFC_MBX_SLI_CONFIG_MAX_MSE);
39288c2ecf20Sopenharmony_ci			rc = -ERANGE;
39298c2ecf20Sopenharmony_ci			goto job_error;
39308c2ecf20Sopenharmony_ci		}
39318c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
39328c2ecf20Sopenharmony_ci				"2941 Handled SLI_CONFIG(mse) rd, "
39338c2ecf20Sopenharmony_ci				"ext_buf_cnt:%d\n", ext_buf_cnt);
39348c2ecf20Sopenharmony_ci	} else {
39358c2ecf20Sopenharmony_ci		/* sanity check on interface type for support */
39368c2ecf20Sopenharmony_ci		if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
39378c2ecf20Sopenharmony_ci		    LPFC_SLI_INTF_IF_TYPE_2) {
39388c2ecf20Sopenharmony_ci			rc = -ENODEV;
39398c2ecf20Sopenharmony_ci			goto job_error;
39408c2ecf20Sopenharmony_ci		}
39418c2ecf20Sopenharmony_ci		/* nemb_tp == nemb_hbd */
39428c2ecf20Sopenharmony_ci		ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count;
39438c2ecf20Sopenharmony_ci		if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) {
39448c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
39458c2ecf20Sopenharmony_ci					"2946 Handled SLI_CONFIG(hbd) rd, "
39468c2ecf20Sopenharmony_ci					"ext_buf_cnt(%d) out of range(%d)\n",
39478c2ecf20Sopenharmony_ci					ext_buf_cnt,
39488c2ecf20Sopenharmony_ci					LPFC_MBX_SLI_CONFIG_MAX_HBD);
39498c2ecf20Sopenharmony_ci			rc = -ERANGE;
39508c2ecf20Sopenharmony_ci			goto job_error;
39518c2ecf20Sopenharmony_ci		}
39528c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
39538c2ecf20Sopenharmony_ci				"2942 Handled SLI_CONFIG(hbd) rd, "
39548c2ecf20Sopenharmony_ci				"ext_buf_cnt:%d\n", ext_buf_cnt);
39558c2ecf20Sopenharmony_ci	}
39568c2ecf20Sopenharmony_ci
39578c2ecf20Sopenharmony_ci	/* before dma descriptor setup */
39588c2ecf20Sopenharmony_ci	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox,
39598c2ecf20Sopenharmony_ci					sta_pre_addr, dmabuf, ext_buf_cnt);
39608c2ecf20Sopenharmony_ci
39618c2ecf20Sopenharmony_ci	/* reject non-embedded mailbox command with none external buffer */
39628c2ecf20Sopenharmony_ci	if (ext_buf_cnt == 0) {
39638c2ecf20Sopenharmony_ci		rc = -EPERM;
39648c2ecf20Sopenharmony_ci		goto job_error;
39658c2ecf20Sopenharmony_ci	} else if (ext_buf_cnt > 1) {
39668c2ecf20Sopenharmony_ci		/* additional external read buffers */
39678c2ecf20Sopenharmony_ci		for (i = 1; i < ext_buf_cnt; i++) {
39688c2ecf20Sopenharmony_ci			ext_dmabuf = lpfc_bsg_dma_page_alloc(phba);
39698c2ecf20Sopenharmony_ci			if (!ext_dmabuf) {
39708c2ecf20Sopenharmony_ci				rc = -ENOMEM;
39718c2ecf20Sopenharmony_ci				goto job_error;
39728c2ecf20Sopenharmony_ci			}
39738c2ecf20Sopenharmony_ci			list_add_tail(&ext_dmabuf->list,
39748c2ecf20Sopenharmony_ci				      &phba->mbox_ext_buf_ctx.ext_dmabuf_list);
39758c2ecf20Sopenharmony_ci		}
39768c2ecf20Sopenharmony_ci	}
39778c2ecf20Sopenharmony_ci
39788c2ecf20Sopenharmony_ci	/* bsg tracking structure */
39798c2ecf20Sopenharmony_ci	dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
39808c2ecf20Sopenharmony_ci	if (!dd_data) {
39818c2ecf20Sopenharmony_ci		rc = -ENOMEM;
39828c2ecf20Sopenharmony_ci		goto job_error;
39838c2ecf20Sopenharmony_ci	}
39848c2ecf20Sopenharmony_ci
39858c2ecf20Sopenharmony_ci	/* mailbox command structure for base driver */
39868c2ecf20Sopenharmony_ci	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
39878c2ecf20Sopenharmony_ci	if (!pmboxq) {
39888c2ecf20Sopenharmony_ci		rc = -ENOMEM;
39898c2ecf20Sopenharmony_ci		goto job_error;
39908c2ecf20Sopenharmony_ci	}
39918c2ecf20Sopenharmony_ci	memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
39928c2ecf20Sopenharmony_ci
39938c2ecf20Sopenharmony_ci	/* for the first external buffer */
39948c2ecf20Sopenharmony_ci	lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf);
39958c2ecf20Sopenharmony_ci
39968c2ecf20Sopenharmony_ci	/* for the rest of external buffer descriptors if any */
39978c2ecf20Sopenharmony_ci	if (ext_buf_cnt > 1) {
39988c2ecf20Sopenharmony_ci		ext_buf_index = 1;
39998c2ecf20Sopenharmony_ci		list_for_each_entry_safe(curr_dmabuf, next_dmabuf,
40008c2ecf20Sopenharmony_ci				&phba->mbox_ext_buf_ctx.ext_dmabuf_list, list) {
40018c2ecf20Sopenharmony_ci			lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp,
40028c2ecf20Sopenharmony_ci						ext_buf_index, dmabuf,
40038c2ecf20Sopenharmony_ci						curr_dmabuf);
40048c2ecf20Sopenharmony_ci			ext_buf_index++;
40058c2ecf20Sopenharmony_ci		}
40068c2ecf20Sopenharmony_ci	}
40078c2ecf20Sopenharmony_ci
40088c2ecf20Sopenharmony_ci	/* after dma descriptor setup */
40098c2ecf20Sopenharmony_ci	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox,
40108c2ecf20Sopenharmony_ci					sta_pos_addr, dmabuf, ext_buf_cnt);
40118c2ecf20Sopenharmony_ci
40128c2ecf20Sopenharmony_ci	/* construct base driver mbox command */
40138c2ecf20Sopenharmony_ci	pmb = &pmboxq->u.mb;
40148c2ecf20Sopenharmony_ci	pmbx = (uint8_t *)dmabuf->virt;
40158c2ecf20Sopenharmony_ci	memcpy(pmb, pmbx, sizeof(*pmb));
40168c2ecf20Sopenharmony_ci	pmb->mbxOwner = OWN_HOST;
40178c2ecf20Sopenharmony_ci	pmboxq->vport = phba->pport;
40188c2ecf20Sopenharmony_ci
40198c2ecf20Sopenharmony_ci	/* multi-buffer handling context */
40208c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.nembType = nemb_tp;
40218c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.mboxType = mbox_rd;
40228c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt;
40238c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag;
40248c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum;
40258c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf;
40268c2ecf20Sopenharmony_ci
40278c2ecf20Sopenharmony_ci	/* callback for multi-buffer read mailbox command */
40288c2ecf20Sopenharmony_ci	pmboxq->mbox_cmpl = lpfc_bsg_issue_read_mbox_ext_cmpl;
40298c2ecf20Sopenharmony_ci
40308c2ecf20Sopenharmony_ci	/* context fields to callback function */
40318c2ecf20Sopenharmony_ci	pmboxq->ctx_buf = dd_data;
40328c2ecf20Sopenharmony_ci	dd_data->type = TYPE_MBOX;
40338c2ecf20Sopenharmony_ci	dd_data->set_job = job;
40348c2ecf20Sopenharmony_ci	dd_data->context_un.mbox.pmboxq = pmboxq;
40358c2ecf20Sopenharmony_ci	dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx;
40368c2ecf20Sopenharmony_ci	job->dd_data = dd_data;
40378c2ecf20Sopenharmony_ci
40388c2ecf20Sopenharmony_ci	/* state change */
40398c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT;
40408c2ecf20Sopenharmony_ci
40418c2ecf20Sopenharmony_ci	/*
40428c2ecf20Sopenharmony_ci	 * Non-embedded mailbox subcommand data gets byte swapped here because
40438c2ecf20Sopenharmony_ci	 * the lower level driver code only does the first 64 mailbox words.
40448c2ecf20Sopenharmony_ci	 */
40458c2ecf20Sopenharmony_ci	if ((!bsg_bf_get(lpfc_mbox_hdr_emb,
40468c2ecf20Sopenharmony_ci	    &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) &&
40478c2ecf20Sopenharmony_ci		(nemb_tp == nemb_mse))
40488c2ecf20Sopenharmony_ci		lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)],
40498c2ecf20Sopenharmony_ci			&pmbx[sizeof(MAILBOX_t)],
40508c2ecf20Sopenharmony_ci				sli_cfg_mbx->un.sli_config_emb0_subsys.
40518c2ecf20Sopenharmony_ci					mse[0].buf_len);
40528c2ecf20Sopenharmony_ci
40538c2ecf20Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
40548c2ecf20Sopenharmony_ci	if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) {
40558c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
40568c2ecf20Sopenharmony_ci				"2947 Issued SLI_CONFIG ext-buffer "
40578c2ecf20Sopenharmony_ci				"mailbox command, rc:x%x\n", rc);
40588c2ecf20Sopenharmony_ci		return SLI_CONFIG_HANDLED;
40598c2ecf20Sopenharmony_ci	}
40608c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
40618c2ecf20Sopenharmony_ci			"2948 Failed to issue SLI_CONFIG ext-buffer "
40628c2ecf20Sopenharmony_ci			"mailbox command, rc:x%x\n", rc);
40638c2ecf20Sopenharmony_ci	rc = -EPIPE;
40648c2ecf20Sopenharmony_ci
40658c2ecf20Sopenharmony_cijob_error:
40668c2ecf20Sopenharmony_ci	if (pmboxq)
40678c2ecf20Sopenharmony_ci		mempool_free(pmboxq, phba->mbox_mem_pool);
40688c2ecf20Sopenharmony_ci	lpfc_bsg_dma_page_list_free(phba,
40698c2ecf20Sopenharmony_ci				    &phba->mbox_ext_buf_ctx.ext_dmabuf_list);
40708c2ecf20Sopenharmony_ci	kfree(dd_data);
40718c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE;
40728c2ecf20Sopenharmony_ci	return rc;
40738c2ecf20Sopenharmony_ci}
40748c2ecf20Sopenharmony_ci
40758c2ecf20Sopenharmony_ci/**
40768c2ecf20Sopenharmony_ci * lpfc_bsg_sli_cfg_write_cmd_ext - sli_config non-embedded mailbox cmd write
40778c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
40788c2ecf20Sopenharmony_ci * @mb: Pointer to a BSG mailbox object.
40798c2ecf20Sopenharmony_ci * @dmabuff: Pointer to a DMA buffer descriptor.
40808c2ecf20Sopenharmony_ci *
40818c2ecf20Sopenharmony_ci * This routine performs SLI_CONFIG (0x9B) write mailbox command operation with
40828c2ecf20Sopenharmony_ci * non-embedded external bufffers.
40838c2ecf20Sopenharmony_ci **/
40848c2ecf20Sopenharmony_cistatic int
40858c2ecf20Sopenharmony_cilpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job,
40868c2ecf20Sopenharmony_ci			       enum nemb_type nemb_tp,
40878c2ecf20Sopenharmony_ci			       struct lpfc_dmabuf *dmabuf)
40888c2ecf20Sopenharmony_ci{
40898c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
40908c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
40918c2ecf20Sopenharmony_ci	struct dfc_mbox_req *mbox_req;
40928c2ecf20Sopenharmony_ci	struct lpfc_sli_config_mbox *sli_cfg_mbx;
40938c2ecf20Sopenharmony_ci	uint32_t ext_buf_cnt;
40948c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data = NULL;
40958c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *pmboxq = NULL;
40968c2ecf20Sopenharmony_ci	MAILBOX_t *pmb;
40978c2ecf20Sopenharmony_ci	uint8_t *mbx;
40988c2ecf20Sopenharmony_ci	int rc = SLI_CONFIG_NOT_HANDLED, i;
40998c2ecf20Sopenharmony_ci
41008c2ecf20Sopenharmony_ci	mbox_req =
41018c2ecf20Sopenharmony_ci	   (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd;
41028c2ecf20Sopenharmony_ci
41038c2ecf20Sopenharmony_ci	/* pointer to the start of mailbox command */
41048c2ecf20Sopenharmony_ci	sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt;
41058c2ecf20Sopenharmony_ci
41068c2ecf20Sopenharmony_ci	if (nemb_tp == nemb_mse) {
41078c2ecf20Sopenharmony_ci		ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt,
41088c2ecf20Sopenharmony_ci			&sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr);
41098c2ecf20Sopenharmony_ci		if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) {
41108c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
41118c2ecf20Sopenharmony_ci					"2953 Failed SLI_CONFIG(mse) wr, "
41128c2ecf20Sopenharmony_ci					"ext_buf_cnt(%d) out of range(%d)\n",
41138c2ecf20Sopenharmony_ci					ext_buf_cnt,
41148c2ecf20Sopenharmony_ci					LPFC_MBX_SLI_CONFIG_MAX_MSE);
41158c2ecf20Sopenharmony_ci			return -ERANGE;
41168c2ecf20Sopenharmony_ci		}
41178c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
41188c2ecf20Sopenharmony_ci				"2949 Handled SLI_CONFIG(mse) wr, "
41198c2ecf20Sopenharmony_ci				"ext_buf_cnt:%d\n", ext_buf_cnt);
41208c2ecf20Sopenharmony_ci	} else {
41218c2ecf20Sopenharmony_ci		/* sanity check on interface type for support */
41228c2ecf20Sopenharmony_ci		if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
41238c2ecf20Sopenharmony_ci		    LPFC_SLI_INTF_IF_TYPE_2)
41248c2ecf20Sopenharmony_ci			return -ENODEV;
41258c2ecf20Sopenharmony_ci		/* nemb_tp == nemb_hbd */
41268c2ecf20Sopenharmony_ci		ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count;
41278c2ecf20Sopenharmony_ci		if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) {
41288c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
41298c2ecf20Sopenharmony_ci					"2954 Failed SLI_CONFIG(hbd) wr, "
41308c2ecf20Sopenharmony_ci					"ext_buf_cnt(%d) out of range(%d)\n",
41318c2ecf20Sopenharmony_ci					ext_buf_cnt,
41328c2ecf20Sopenharmony_ci					LPFC_MBX_SLI_CONFIG_MAX_HBD);
41338c2ecf20Sopenharmony_ci			return -ERANGE;
41348c2ecf20Sopenharmony_ci		}
41358c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
41368c2ecf20Sopenharmony_ci				"2950 Handled SLI_CONFIG(hbd) wr, "
41378c2ecf20Sopenharmony_ci				"ext_buf_cnt:%d\n", ext_buf_cnt);
41388c2ecf20Sopenharmony_ci	}
41398c2ecf20Sopenharmony_ci
41408c2ecf20Sopenharmony_ci	/* before dma buffer descriptor setup */
41418c2ecf20Sopenharmony_ci	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox,
41428c2ecf20Sopenharmony_ci					sta_pre_addr, dmabuf, ext_buf_cnt);
41438c2ecf20Sopenharmony_ci
41448c2ecf20Sopenharmony_ci	if (ext_buf_cnt == 0)
41458c2ecf20Sopenharmony_ci		return -EPERM;
41468c2ecf20Sopenharmony_ci
41478c2ecf20Sopenharmony_ci	/* for the first external buffer */
41488c2ecf20Sopenharmony_ci	lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf);
41498c2ecf20Sopenharmony_ci
41508c2ecf20Sopenharmony_ci	/* after dma descriptor setup */
41518c2ecf20Sopenharmony_ci	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox,
41528c2ecf20Sopenharmony_ci					sta_pos_addr, dmabuf, ext_buf_cnt);
41538c2ecf20Sopenharmony_ci
41548c2ecf20Sopenharmony_ci	/* log for looking forward */
41558c2ecf20Sopenharmony_ci	for (i = 1; i < ext_buf_cnt; i++) {
41568c2ecf20Sopenharmony_ci		if (nemb_tp == nemb_mse)
41578c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
41588c2ecf20Sopenharmony_ci				"2951 SLI_CONFIG(mse), buf[%d]-length:%d\n",
41598c2ecf20Sopenharmony_ci				i, sli_cfg_mbx->un.sli_config_emb0_subsys.
41608c2ecf20Sopenharmony_ci				mse[i].buf_len);
41618c2ecf20Sopenharmony_ci		else
41628c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
41638c2ecf20Sopenharmony_ci				"2952 SLI_CONFIG(hbd), buf[%d]-length:%d\n",
41648c2ecf20Sopenharmony_ci				i, bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len,
41658c2ecf20Sopenharmony_ci				&sli_cfg_mbx->un.sli_config_emb1_subsys.
41668c2ecf20Sopenharmony_ci				hbd[i]));
41678c2ecf20Sopenharmony_ci	}
41688c2ecf20Sopenharmony_ci
41698c2ecf20Sopenharmony_ci	/* multi-buffer handling context */
41708c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.nembType = nemb_tp;
41718c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.mboxType = mbox_wr;
41728c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt;
41738c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag;
41748c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum;
41758c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf;
41768c2ecf20Sopenharmony_ci
41778c2ecf20Sopenharmony_ci	if (ext_buf_cnt == 1) {
41788c2ecf20Sopenharmony_ci		/* bsg tracking structure */
41798c2ecf20Sopenharmony_ci		dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
41808c2ecf20Sopenharmony_ci		if (!dd_data) {
41818c2ecf20Sopenharmony_ci			rc = -ENOMEM;
41828c2ecf20Sopenharmony_ci			goto job_error;
41838c2ecf20Sopenharmony_ci		}
41848c2ecf20Sopenharmony_ci
41858c2ecf20Sopenharmony_ci		/* mailbox command structure for base driver */
41868c2ecf20Sopenharmony_ci		pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
41878c2ecf20Sopenharmony_ci		if (!pmboxq) {
41888c2ecf20Sopenharmony_ci			rc = -ENOMEM;
41898c2ecf20Sopenharmony_ci			goto job_error;
41908c2ecf20Sopenharmony_ci		}
41918c2ecf20Sopenharmony_ci		memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
41928c2ecf20Sopenharmony_ci		pmb = &pmboxq->u.mb;
41938c2ecf20Sopenharmony_ci		mbx = (uint8_t *)dmabuf->virt;
41948c2ecf20Sopenharmony_ci		memcpy(pmb, mbx, sizeof(*pmb));
41958c2ecf20Sopenharmony_ci		pmb->mbxOwner = OWN_HOST;
41968c2ecf20Sopenharmony_ci		pmboxq->vport = phba->pport;
41978c2ecf20Sopenharmony_ci
41988c2ecf20Sopenharmony_ci		/* callback for multi-buffer read mailbox command */
41998c2ecf20Sopenharmony_ci		pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl;
42008c2ecf20Sopenharmony_ci
42018c2ecf20Sopenharmony_ci		/* context fields to callback function */
42028c2ecf20Sopenharmony_ci		pmboxq->ctx_buf = dd_data;
42038c2ecf20Sopenharmony_ci		dd_data->type = TYPE_MBOX;
42048c2ecf20Sopenharmony_ci		dd_data->set_job = job;
42058c2ecf20Sopenharmony_ci		dd_data->context_un.mbox.pmboxq = pmboxq;
42068c2ecf20Sopenharmony_ci		dd_data->context_un.mbox.mb = (MAILBOX_t *)mbx;
42078c2ecf20Sopenharmony_ci		job->dd_data = dd_data;
42088c2ecf20Sopenharmony_ci
42098c2ecf20Sopenharmony_ci		/* state change */
42108c2ecf20Sopenharmony_ci
42118c2ecf20Sopenharmony_ci		phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT;
42128c2ecf20Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
42138c2ecf20Sopenharmony_ci		if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) {
42148c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
42158c2ecf20Sopenharmony_ci					"2955 Issued SLI_CONFIG ext-buffer "
42168c2ecf20Sopenharmony_ci					"mailbox command, rc:x%x\n", rc);
42178c2ecf20Sopenharmony_ci			return SLI_CONFIG_HANDLED;
42188c2ecf20Sopenharmony_ci		}
42198c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
42208c2ecf20Sopenharmony_ci				"2956 Failed to issue SLI_CONFIG ext-buffer "
42218c2ecf20Sopenharmony_ci				"mailbox command, rc:x%x\n", rc);
42228c2ecf20Sopenharmony_ci		rc = -EPIPE;
42238c2ecf20Sopenharmony_ci		goto job_error;
42248c2ecf20Sopenharmony_ci	}
42258c2ecf20Sopenharmony_ci
42268c2ecf20Sopenharmony_ci	/* wait for additoinal external buffers */
42278c2ecf20Sopenharmony_ci
42288c2ecf20Sopenharmony_ci	bsg_reply->result = 0;
42298c2ecf20Sopenharmony_ci	bsg_job_done(job, bsg_reply->result,
42308c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
42318c2ecf20Sopenharmony_ci	return SLI_CONFIG_HANDLED;
42328c2ecf20Sopenharmony_ci
42338c2ecf20Sopenharmony_cijob_error:
42348c2ecf20Sopenharmony_ci	if (pmboxq)
42358c2ecf20Sopenharmony_ci		mempool_free(pmboxq, phba->mbox_mem_pool);
42368c2ecf20Sopenharmony_ci	kfree(dd_data);
42378c2ecf20Sopenharmony_ci
42388c2ecf20Sopenharmony_ci	return rc;
42398c2ecf20Sopenharmony_ci}
42408c2ecf20Sopenharmony_ci
42418c2ecf20Sopenharmony_ci/**
42428c2ecf20Sopenharmony_ci * lpfc_bsg_handle_sli_cfg_mbox - handle sli-cfg mailbox cmd with ext buffer
42438c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
42448c2ecf20Sopenharmony_ci * @mb: Pointer to a BSG mailbox object.
42458c2ecf20Sopenharmony_ci * @dmabuff: Pointer to a DMA buffer descriptor.
42468c2ecf20Sopenharmony_ci *
42478c2ecf20Sopenharmony_ci * This routine handles SLI_CONFIG (0x9B) mailbox command with non-embedded
42488c2ecf20Sopenharmony_ci * external bufffers, including both 0x9B with non-embedded MSEs and 0x9B
42498c2ecf20Sopenharmony_ci * with embedded sussystem 0x1 and opcodes with external HBDs.
42508c2ecf20Sopenharmony_ci **/
42518c2ecf20Sopenharmony_cistatic int
42528c2ecf20Sopenharmony_cilpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct bsg_job *job,
42538c2ecf20Sopenharmony_ci			     struct lpfc_dmabuf *dmabuf)
42548c2ecf20Sopenharmony_ci{
42558c2ecf20Sopenharmony_ci	struct lpfc_sli_config_mbox *sli_cfg_mbx;
42568c2ecf20Sopenharmony_ci	uint32_t subsys;
42578c2ecf20Sopenharmony_ci	uint32_t opcode;
42588c2ecf20Sopenharmony_ci	int rc = SLI_CONFIG_NOT_HANDLED;
42598c2ecf20Sopenharmony_ci
42608c2ecf20Sopenharmony_ci	/* state change on new multi-buffer pass-through mailbox command */
42618c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_HOST;
42628c2ecf20Sopenharmony_ci
42638c2ecf20Sopenharmony_ci	sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt;
42648c2ecf20Sopenharmony_ci
42658c2ecf20Sopenharmony_ci	if (!bsg_bf_get(lpfc_mbox_hdr_emb,
42668c2ecf20Sopenharmony_ci	    &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) {
42678c2ecf20Sopenharmony_ci		subsys = bsg_bf_get(lpfc_emb0_subcmnd_subsys,
42688c2ecf20Sopenharmony_ci				    &sli_cfg_mbx->un.sli_config_emb0_subsys);
42698c2ecf20Sopenharmony_ci		opcode = bsg_bf_get(lpfc_emb0_subcmnd_opcode,
42708c2ecf20Sopenharmony_ci				    &sli_cfg_mbx->un.sli_config_emb0_subsys);
42718c2ecf20Sopenharmony_ci		if (subsys == SLI_CONFIG_SUBSYS_FCOE) {
42728c2ecf20Sopenharmony_ci			switch (opcode) {
42738c2ecf20Sopenharmony_ci			case FCOE_OPCODE_READ_FCF:
42748c2ecf20Sopenharmony_ci			case FCOE_OPCODE_GET_DPORT_RESULTS:
42758c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
42768c2ecf20Sopenharmony_ci						"2957 Handled SLI_CONFIG "
42778c2ecf20Sopenharmony_ci						"subsys_fcoe, opcode:x%x\n",
42788c2ecf20Sopenharmony_ci						opcode);
42798c2ecf20Sopenharmony_ci				rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job,
42808c2ecf20Sopenharmony_ci							nemb_mse, dmabuf);
42818c2ecf20Sopenharmony_ci				break;
42828c2ecf20Sopenharmony_ci			case FCOE_OPCODE_ADD_FCF:
42838c2ecf20Sopenharmony_ci			case FCOE_OPCODE_SET_DPORT_MODE:
42848c2ecf20Sopenharmony_ci			case LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE:
42858c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
42868c2ecf20Sopenharmony_ci						"2958 Handled SLI_CONFIG "
42878c2ecf20Sopenharmony_ci						"subsys_fcoe, opcode:x%x\n",
42888c2ecf20Sopenharmony_ci						opcode);
42898c2ecf20Sopenharmony_ci				rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job,
42908c2ecf20Sopenharmony_ci							nemb_mse, dmabuf);
42918c2ecf20Sopenharmony_ci				break;
42928c2ecf20Sopenharmony_ci			default:
42938c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
42948c2ecf20Sopenharmony_ci						"2959 Reject SLI_CONFIG "
42958c2ecf20Sopenharmony_ci						"subsys_fcoe, opcode:x%x\n",
42968c2ecf20Sopenharmony_ci						opcode);
42978c2ecf20Sopenharmony_ci				rc = -EPERM;
42988c2ecf20Sopenharmony_ci				break;
42998c2ecf20Sopenharmony_ci			}
43008c2ecf20Sopenharmony_ci		} else if (subsys == SLI_CONFIG_SUBSYS_COMN) {
43018c2ecf20Sopenharmony_ci			switch (opcode) {
43028c2ecf20Sopenharmony_ci			case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES:
43038c2ecf20Sopenharmony_ci			case COMN_OPCODE_GET_CNTL_ATTRIBUTES:
43048c2ecf20Sopenharmony_ci			case COMN_OPCODE_GET_PROFILE_CONFIG:
43058c2ecf20Sopenharmony_ci			case COMN_OPCODE_SET_FEATURES:
43068c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
43078c2ecf20Sopenharmony_ci						"3106 Handled SLI_CONFIG "
43088c2ecf20Sopenharmony_ci						"subsys_comn, opcode:x%x\n",
43098c2ecf20Sopenharmony_ci						opcode);
43108c2ecf20Sopenharmony_ci				rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job,
43118c2ecf20Sopenharmony_ci							nemb_mse, dmabuf);
43128c2ecf20Sopenharmony_ci				break;
43138c2ecf20Sopenharmony_ci			default:
43148c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
43158c2ecf20Sopenharmony_ci						"3107 Reject SLI_CONFIG "
43168c2ecf20Sopenharmony_ci						"subsys_comn, opcode:x%x\n",
43178c2ecf20Sopenharmony_ci						opcode);
43188c2ecf20Sopenharmony_ci				rc = -EPERM;
43198c2ecf20Sopenharmony_ci				break;
43208c2ecf20Sopenharmony_ci			}
43218c2ecf20Sopenharmony_ci		} else {
43228c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
43238c2ecf20Sopenharmony_ci					"2977 Reject SLI_CONFIG "
43248c2ecf20Sopenharmony_ci					"subsys:x%d, opcode:x%x\n",
43258c2ecf20Sopenharmony_ci					subsys, opcode);
43268c2ecf20Sopenharmony_ci			rc = -EPERM;
43278c2ecf20Sopenharmony_ci		}
43288c2ecf20Sopenharmony_ci	} else {
43298c2ecf20Sopenharmony_ci		subsys = bsg_bf_get(lpfc_emb1_subcmnd_subsys,
43308c2ecf20Sopenharmony_ci				    &sli_cfg_mbx->un.sli_config_emb1_subsys);
43318c2ecf20Sopenharmony_ci		opcode = bsg_bf_get(lpfc_emb1_subcmnd_opcode,
43328c2ecf20Sopenharmony_ci				    &sli_cfg_mbx->un.sli_config_emb1_subsys);
43338c2ecf20Sopenharmony_ci		if (subsys == SLI_CONFIG_SUBSYS_COMN) {
43348c2ecf20Sopenharmony_ci			switch (opcode) {
43358c2ecf20Sopenharmony_ci			case COMN_OPCODE_READ_OBJECT:
43368c2ecf20Sopenharmony_ci			case COMN_OPCODE_READ_OBJECT_LIST:
43378c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
43388c2ecf20Sopenharmony_ci						"2960 Handled SLI_CONFIG "
43398c2ecf20Sopenharmony_ci						"subsys_comn, opcode:x%x\n",
43408c2ecf20Sopenharmony_ci						opcode);
43418c2ecf20Sopenharmony_ci				rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job,
43428c2ecf20Sopenharmony_ci							nemb_hbd, dmabuf);
43438c2ecf20Sopenharmony_ci				break;
43448c2ecf20Sopenharmony_ci			case COMN_OPCODE_WRITE_OBJECT:
43458c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
43468c2ecf20Sopenharmony_ci						"2961 Handled SLI_CONFIG "
43478c2ecf20Sopenharmony_ci						"subsys_comn, opcode:x%x\n",
43488c2ecf20Sopenharmony_ci						opcode);
43498c2ecf20Sopenharmony_ci				rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job,
43508c2ecf20Sopenharmony_ci							nemb_hbd, dmabuf);
43518c2ecf20Sopenharmony_ci				break;
43528c2ecf20Sopenharmony_ci			default:
43538c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
43548c2ecf20Sopenharmony_ci						"2962 Not handled SLI_CONFIG "
43558c2ecf20Sopenharmony_ci						"subsys_comn, opcode:x%x\n",
43568c2ecf20Sopenharmony_ci						opcode);
43578c2ecf20Sopenharmony_ci				rc = SLI_CONFIG_NOT_HANDLED;
43588c2ecf20Sopenharmony_ci				break;
43598c2ecf20Sopenharmony_ci			}
43608c2ecf20Sopenharmony_ci		} else {
43618c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
43628c2ecf20Sopenharmony_ci					"2978 Not handled SLI_CONFIG "
43638c2ecf20Sopenharmony_ci					"subsys:x%d, opcode:x%x\n",
43648c2ecf20Sopenharmony_ci					subsys, opcode);
43658c2ecf20Sopenharmony_ci			rc = SLI_CONFIG_NOT_HANDLED;
43668c2ecf20Sopenharmony_ci		}
43678c2ecf20Sopenharmony_ci	}
43688c2ecf20Sopenharmony_ci
43698c2ecf20Sopenharmony_ci	/* state reset on not handled new multi-buffer mailbox command */
43708c2ecf20Sopenharmony_ci	if (rc != SLI_CONFIG_HANDLED)
43718c2ecf20Sopenharmony_ci		phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE;
43728c2ecf20Sopenharmony_ci
43738c2ecf20Sopenharmony_ci	return rc;
43748c2ecf20Sopenharmony_ci}
43758c2ecf20Sopenharmony_ci
43768c2ecf20Sopenharmony_ci/**
43778c2ecf20Sopenharmony_ci * lpfc_bsg_mbox_ext_abort_req - request to abort mbox command with ext buffers
43788c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
43798c2ecf20Sopenharmony_ci *
43808c2ecf20Sopenharmony_ci * This routine is for requesting to abort a pass-through mailbox command with
43818c2ecf20Sopenharmony_ci * multiple external buffers due to error condition.
43828c2ecf20Sopenharmony_ci **/
43838c2ecf20Sopenharmony_cistatic void
43848c2ecf20Sopenharmony_cilpfc_bsg_mbox_ext_abort(struct lpfc_hba *phba)
43858c2ecf20Sopenharmony_ci{
43868c2ecf20Sopenharmony_ci	if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT)
43878c2ecf20Sopenharmony_ci		phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS;
43888c2ecf20Sopenharmony_ci	else
43898c2ecf20Sopenharmony_ci		lpfc_bsg_mbox_ext_session_reset(phba);
43908c2ecf20Sopenharmony_ci	return;
43918c2ecf20Sopenharmony_ci}
43928c2ecf20Sopenharmony_ci
43938c2ecf20Sopenharmony_ci/**
43948c2ecf20Sopenharmony_ci * lpfc_bsg_read_ebuf_get - get the next mailbox read external buffer
43958c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
43968c2ecf20Sopenharmony_ci * @dmabuf: Pointer to a DMA buffer descriptor.
43978c2ecf20Sopenharmony_ci *
43988c2ecf20Sopenharmony_ci * This routine extracts the next mailbox read external buffer back to
43998c2ecf20Sopenharmony_ci * user space through BSG.
44008c2ecf20Sopenharmony_ci **/
44018c2ecf20Sopenharmony_cistatic int
44028c2ecf20Sopenharmony_cilpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct bsg_job *job)
44038c2ecf20Sopenharmony_ci{
44048c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
44058c2ecf20Sopenharmony_ci	struct lpfc_sli_config_mbox *sli_cfg_mbx;
44068c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
44078c2ecf20Sopenharmony_ci	uint8_t *pbuf;
44088c2ecf20Sopenharmony_ci	uint32_t size;
44098c2ecf20Sopenharmony_ci	uint32_t index;
44108c2ecf20Sopenharmony_ci
44118c2ecf20Sopenharmony_ci	index = phba->mbox_ext_buf_ctx.seqNum;
44128c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.seqNum++;
44138c2ecf20Sopenharmony_ci
44148c2ecf20Sopenharmony_ci	sli_cfg_mbx = (struct lpfc_sli_config_mbox *)
44158c2ecf20Sopenharmony_ci			phba->mbox_ext_buf_ctx.mbx_dmabuf->virt;
44168c2ecf20Sopenharmony_ci
44178c2ecf20Sopenharmony_ci	if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) {
44188c2ecf20Sopenharmony_ci		size = bsg_bf_get(lpfc_mbox_sli_config_mse_len,
44198c2ecf20Sopenharmony_ci			&sli_cfg_mbx->un.sli_config_emb0_subsys.mse[index]);
44208c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
44218c2ecf20Sopenharmony_ci				"2963 SLI_CONFIG (mse) ext-buffer rd get "
44228c2ecf20Sopenharmony_ci				"buffer[%d], size:%d\n", index, size);
44238c2ecf20Sopenharmony_ci	} else {
44248c2ecf20Sopenharmony_ci		size = bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len,
44258c2ecf20Sopenharmony_ci			&sli_cfg_mbx->un.sli_config_emb1_subsys.hbd[index]);
44268c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
44278c2ecf20Sopenharmony_ci				"2964 SLI_CONFIG (hbd) ext-buffer rd get "
44288c2ecf20Sopenharmony_ci				"buffer[%d], size:%d\n", index, size);
44298c2ecf20Sopenharmony_ci	}
44308c2ecf20Sopenharmony_ci	if (list_empty(&phba->mbox_ext_buf_ctx.ext_dmabuf_list))
44318c2ecf20Sopenharmony_ci		return -EPIPE;
44328c2ecf20Sopenharmony_ci	dmabuf = list_first_entry(&phba->mbox_ext_buf_ctx.ext_dmabuf_list,
44338c2ecf20Sopenharmony_ci				  struct lpfc_dmabuf, list);
44348c2ecf20Sopenharmony_ci	list_del_init(&dmabuf->list);
44358c2ecf20Sopenharmony_ci
44368c2ecf20Sopenharmony_ci	/* after dma buffer descriptor setup */
44378c2ecf20Sopenharmony_ci	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType,
44388c2ecf20Sopenharmony_ci					mbox_rd, dma_ebuf, sta_pos_addr,
44398c2ecf20Sopenharmony_ci					dmabuf, index);
44408c2ecf20Sopenharmony_ci
44418c2ecf20Sopenharmony_ci	pbuf = (uint8_t *)dmabuf->virt;
44428c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len =
44438c2ecf20Sopenharmony_ci		sg_copy_from_buffer(job->reply_payload.sg_list,
44448c2ecf20Sopenharmony_ci				    job->reply_payload.sg_cnt,
44458c2ecf20Sopenharmony_ci				    pbuf, size);
44468c2ecf20Sopenharmony_ci
44478c2ecf20Sopenharmony_ci	lpfc_bsg_dma_page_free(phba, dmabuf);
44488c2ecf20Sopenharmony_ci
44498c2ecf20Sopenharmony_ci	if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) {
44508c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
44518c2ecf20Sopenharmony_ci				"2965 SLI_CONFIG (hbd) ext-buffer rd mbox "
44528c2ecf20Sopenharmony_ci				"command session done\n");
44538c2ecf20Sopenharmony_ci		lpfc_bsg_mbox_ext_session_reset(phba);
44548c2ecf20Sopenharmony_ci	}
44558c2ecf20Sopenharmony_ci
44568c2ecf20Sopenharmony_ci	bsg_reply->result = 0;
44578c2ecf20Sopenharmony_ci	bsg_job_done(job, bsg_reply->result,
44588c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
44598c2ecf20Sopenharmony_ci
44608c2ecf20Sopenharmony_ci	return SLI_CONFIG_HANDLED;
44618c2ecf20Sopenharmony_ci}
44628c2ecf20Sopenharmony_ci
44638c2ecf20Sopenharmony_ci/**
44648c2ecf20Sopenharmony_ci * lpfc_bsg_write_ebuf_set - set the next mailbox write external buffer
44658c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
44668c2ecf20Sopenharmony_ci * @dmabuf: Pointer to a DMA buffer descriptor.
44678c2ecf20Sopenharmony_ci *
44688c2ecf20Sopenharmony_ci * This routine sets up the next mailbox read external buffer obtained
44698c2ecf20Sopenharmony_ci * from user space through BSG.
44708c2ecf20Sopenharmony_ci **/
44718c2ecf20Sopenharmony_cistatic int
44728c2ecf20Sopenharmony_cilpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job,
44738c2ecf20Sopenharmony_ci			struct lpfc_dmabuf *dmabuf)
44748c2ecf20Sopenharmony_ci{
44758c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
44768c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data = NULL;
44778c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *pmboxq = NULL;
44788c2ecf20Sopenharmony_ci	MAILBOX_t *pmb;
44798c2ecf20Sopenharmony_ci	enum nemb_type nemb_tp;
44808c2ecf20Sopenharmony_ci	uint8_t *pbuf;
44818c2ecf20Sopenharmony_ci	uint32_t size;
44828c2ecf20Sopenharmony_ci	uint32_t index;
44838c2ecf20Sopenharmony_ci	int rc;
44848c2ecf20Sopenharmony_ci
44858c2ecf20Sopenharmony_ci	index = phba->mbox_ext_buf_ctx.seqNum;
44868c2ecf20Sopenharmony_ci	phba->mbox_ext_buf_ctx.seqNum++;
44878c2ecf20Sopenharmony_ci	nemb_tp = phba->mbox_ext_buf_ctx.nembType;
44888c2ecf20Sopenharmony_ci
44898c2ecf20Sopenharmony_ci	pbuf = (uint8_t *)dmabuf->virt;
44908c2ecf20Sopenharmony_ci	size = job->request_payload.payload_len;
44918c2ecf20Sopenharmony_ci	sg_copy_to_buffer(job->request_payload.sg_list,
44928c2ecf20Sopenharmony_ci			  job->request_payload.sg_cnt,
44938c2ecf20Sopenharmony_ci			  pbuf, size);
44948c2ecf20Sopenharmony_ci
44958c2ecf20Sopenharmony_ci	if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) {
44968c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
44978c2ecf20Sopenharmony_ci				"2966 SLI_CONFIG (mse) ext-buffer wr set "
44988c2ecf20Sopenharmony_ci				"buffer[%d], size:%d\n",
44998c2ecf20Sopenharmony_ci				phba->mbox_ext_buf_ctx.seqNum, size);
45008c2ecf20Sopenharmony_ci
45018c2ecf20Sopenharmony_ci	} else {
45028c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
45038c2ecf20Sopenharmony_ci				"2967 SLI_CONFIG (hbd) ext-buffer wr set "
45048c2ecf20Sopenharmony_ci				"buffer[%d], size:%d\n",
45058c2ecf20Sopenharmony_ci				phba->mbox_ext_buf_ctx.seqNum, size);
45068c2ecf20Sopenharmony_ci
45078c2ecf20Sopenharmony_ci	}
45088c2ecf20Sopenharmony_ci
45098c2ecf20Sopenharmony_ci	/* set up external buffer descriptor and add to external buffer list */
45108c2ecf20Sopenharmony_ci	lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, index,
45118c2ecf20Sopenharmony_ci					phba->mbox_ext_buf_ctx.mbx_dmabuf,
45128c2ecf20Sopenharmony_ci					dmabuf);
45138c2ecf20Sopenharmony_ci	list_add_tail(&dmabuf->list, &phba->mbox_ext_buf_ctx.ext_dmabuf_list);
45148c2ecf20Sopenharmony_ci
45158c2ecf20Sopenharmony_ci	/* after write dma buffer */
45168c2ecf20Sopenharmony_ci	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType,
45178c2ecf20Sopenharmony_ci					mbox_wr, dma_ebuf, sta_pos_addr,
45188c2ecf20Sopenharmony_ci					dmabuf, index);
45198c2ecf20Sopenharmony_ci
45208c2ecf20Sopenharmony_ci	if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) {
45218c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
45228c2ecf20Sopenharmony_ci				"2968 SLI_CONFIG ext-buffer wr all %d "
45238c2ecf20Sopenharmony_ci				"ebuffers received\n",
45248c2ecf20Sopenharmony_ci				phba->mbox_ext_buf_ctx.numBuf);
45258c2ecf20Sopenharmony_ci
45268c2ecf20Sopenharmony_ci		dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
45278c2ecf20Sopenharmony_ci		if (!dd_data) {
45288c2ecf20Sopenharmony_ci			rc = -ENOMEM;
45298c2ecf20Sopenharmony_ci			goto job_error;
45308c2ecf20Sopenharmony_ci		}
45318c2ecf20Sopenharmony_ci
45328c2ecf20Sopenharmony_ci		/* mailbox command structure for base driver */
45338c2ecf20Sopenharmony_ci		pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
45348c2ecf20Sopenharmony_ci		if (!pmboxq) {
45358c2ecf20Sopenharmony_ci			rc = -ENOMEM;
45368c2ecf20Sopenharmony_ci			goto job_error;
45378c2ecf20Sopenharmony_ci		}
45388c2ecf20Sopenharmony_ci		memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
45398c2ecf20Sopenharmony_ci		pbuf = (uint8_t *)phba->mbox_ext_buf_ctx.mbx_dmabuf->virt;
45408c2ecf20Sopenharmony_ci		pmb = &pmboxq->u.mb;
45418c2ecf20Sopenharmony_ci		memcpy(pmb, pbuf, sizeof(*pmb));
45428c2ecf20Sopenharmony_ci		pmb->mbxOwner = OWN_HOST;
45438c2ecf20Sopenharmony_ci		pmboxq->vport = phba->pport;
45448c2ecf20Sopenharmony_ci
45458c2ecf20Sopenharmony_ci		/* callback for multi-buffer write mailbox command */
45468c2ecf20Sopenharmony_ci		pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl;
45478c2ecf20Sopenharmony_ci
45488c2ecf20Sopenharmony_ci		/* context fields to callback function */
45498c2ecf20Sopenharmony_ci		pmboxq->ctx_buf = dd_data;
45508c2ecf20Sopenharmony_ci		dd_data->type = TYPE_MBOX;
45518c2ecf20Sopenharmony_ci		dd_data->set_job = job;
45528c2ecf20Sopenharmony_ci		dd_data->context_un.mbox.pmboxq = pmboxq;
45538c2ecf20Sopenharmony_ci		dd_data->context_un.mbox.mb = (MAILBOX_t *)pbuf;
45548c2ecf20Sopenharmony_ci		job->dd_data = dd_data;
45558c2ecf20Sopenharmony_ci
45568c2ecf20Sopenharmony_ci		/* state change */
45578c2ecf20Sopenharmony_ci		phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT;
45588c2ecf20Sopenharmony_ci
45598c2ecf20Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
45608c2ecf20Sopenharmony_ci		if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) {
45618c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
45628c2ecf20Sopenharmony_ci					"2969 Issued SLI_CONFIG ext-buffer "
45638c2ecf20Sopenharmony_ci					"mailbox command, rc:x%x\n", rc);
45648c2ecf20Sopenharmony_ci			return SLI_CONFIG_HANDLED;
45658c2ecf20Sopenharmony_ci		}
45668c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
45678c2ecf20Sopenharmony_ci				"2970 Failed to issue SLI_CONFIG ext-buffer "
45688c2ecf20Sopenharmony_ci				"mailbox command, rc:x%x\n", rc);
45698c2ecf20Sopenharmony_ci		rc = -EPIPE;
45708c2ecf20Sopenharmony_ci		goto job_error;
45718c2ecf20Sopenharmony_ci	}
45728c2ecf20Sopenharmony_ci
45738c2ecf20Sopenharmony_ci	/* wait for additoinal external buffers */
45748c2ecf20Sopenharmony_ci	bsg_reply->result = 0;
45758c2ecf20Sopenharmony_ci	bsg_job_done(job, bsg_reply->result,
45768c2ecf20Sopenharmony_ci		       bsg_reply->reply_payload_rcv_len);
45778c2ecf20Sopenharmony_ci	return SLI_CONFIG_HANDLED;
45788c2ecf20Sopenharmony_ci
45798c2ecf20Sopenharmony_cijob_error:
45808c2ecf20Sopenharmony_ci	if (pmboxq)
45818c2ecf20Sopenharmony_ci		mempool_free(pmboxq, phba->mbox_mem_pool);
45828c2ecf20Sopenharmony_ci	lpfc_bsg_dma_page_free(phba, dmabuf);
45838c2ecf20Sopenharmony_ci	kfree(dd_data);
45848c2ecf20Sopenharmony_ci
45858c2ecf20Sopenharmony_ci	return rc;
45868c2ecf20Sopenharmony_ci}
45878c2ecf20Sopenharmony_ci
45888c2ecf20Sopenharmony_ci/**
45898c2ecf20Sopenharmony_ci * lpfc_bsg_handle_sli_cfg_ebuf - handle ext buffer with sli-cfg mailbox cmd
45908c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
45918c2ecf20Sopenharmony_ci * @mb: Pointer to a BSG mailbox object.
45928c2ecf20Sopenharmony_ci * @dmabuff: Pointer to a DMA buffer descriptor.
45938c2ecf20Sopenharmony_ci *
45948c2ecf20Sopenharmony_ci * This routine handles the external buffer with SLI_CONFIG (0x9B) mailbox
45958c2ecf20Sopenharmony_ci * command with multiple non-embedded external buffers.
45968c2ecf20Sopenharmony_ci **/
45978c2ecf20Sopenharmony_cistatic int
45988c2ecf20Sopenharmony_cilpfc_bsg_handle_sli_cfg_ebuf(struct lpfc_hba *phba, struct bsg_job *job,
45998c2ecf20Sopenharmony_ci			     struct lpfc_dmabuf *dmabuf)
46008c2ecf20Sopenharmony_ci{
46018c2ecf20Sopenharmony_ci	int rc;
46028c2ecf20Sopenharmony_ci
46038c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
46048c2ecf20Sopenharmony_ci			"2971 SLI_CONFIG buffer (type:x%x)\n",
46058c2ecf20Sopenharmony_ci			phba->mbox_ext_buf_ctx.mboxType);
46068c2ecf20Sopenharmony_ci
46078c2ecf20Sopenharmony_ci	if (phba->mbox_ext_buf_ctx.mboxType == mbox_rd) {
46088c2ecf20Sopenharmony_ci		if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_DONE) {
46098c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
46108c2ecf20Sopenharmony_ci					"2972 SLI_CONFIG rd buffer state "
46118c2ecf20Sopenharmony_ci					"mismatch:x%x\n",
46128c2ecf20Sopenharmony_ci					phba->mbox_ext_buf_ctx.state);
46138c2ecf20Sopenharmony_ci			lpfc_bsg_mbox_ext_abort(phba);
46148c2ecf20Sopenharmony_ci			return -EPIPE;
46158c2ecf20Sopenharmony_ci		}
46168c2ecf20Sopenharmony_ci		rc = lpfc_bsg_read_ebuf_get(phba, job);
46178c2ecf20Sopenharmony_ci		if (rc == SLI_CONFIG_HANDLED)
46188c2ecf20Sopenharmony_ci			lpfc_bsg_dma_page_free(phba, dmabuf);
46198c2ecf20Sopenharmony_ci	} else { /* phba->mbox_ext_buf_ctx.mboxType == mbox_wr */
46208c2ecf20Sopenharmony_ci		if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_HOST) {
46218c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
46228c2ecf20Sopenharmony_ci					"2973 SLI_CONFIG wr buffer state "
46238c2ecf20Sopenharmony_ci					"mismatch:x%x\n",
46248c2ecf20Sopenharmony_ci					phba->mbox_ext_buf_ctx.state);
46258c2ecf20Sopenharmony_ci			lpfc_bsg_mbox_ext_abort(phba);
46268c2ecf20Sopenharmony_ci			return -EPIPE;
46278c2ecf20Sopenharmony_ci		}
46288c2ecf20Sopenharmony_ci		rc = lpfc_bsg_write_ebuf_set(phba, job, dmabuf);
46298c2ecf20Sopenharmony_ci	}
46308c2ecf20Sopenharmony_ci	return rc;
46318c2ecf20Sopenharmony_ci}
46328c2ecf20Sopenharmony_ci
46338c2ecf20Sopenharmony_ci/**
46348c2ecf20Sopenharmony_ci * lpfc_bsg_handle_sli_cfg_ext - handle sli-cfg mailbox with external buffer
46358c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
46368c2ecf20Sopenharmony_ci * @mb: Pointer to a BSG mailbox object.
46378c2ecf20Sopenharmony_ci * @dmabuff: Pointer to a DMA buffer descriptor.
46388c2ecf20Sopenharmony_ci *
46398c2ecf20Sopenharmony_ci * This routine checkes and handles non-embedded multi-buffer SLI_CONFIG
46408c2ecf20Sopenharmony_ci * (0x9B) mailbox commands and external buffers.
46418c2ecf20Sopenharmony_ci **/
46428c2ecf20Sopenharmony_cistatic int
46438c2ecf20Sopenharmony_cilpfc_bsg_handle_sli_cfg_ext(struct lpfc_hba *phba, struct bsg_job *job,
46448c2ecf20Sopenharmony_ci			    struct lpfc_dmabuf *dmabuf)
46458c2ecf20Sopenharmony_ci{
46468c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
46478c2ecf20Sopenharmony_ci	struct dfc_mbox_req *mbox_req;
46488c2ecf20Sopenharmony_ci	int rc = SLI_CONFIG_NOT_HANDLED;
46498c2ecf20Sopenharmony_ci
46508c2ecf20Sopenharmony_ci	mbox_req =
46518c2ecf20Sopenharmony_ci	   (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd;
46528c2ecf20Sopenharmony_ci
46538c2ecf20Sopenharmony_ci	/* mbox command with/without single external buffer */
46548c2ecf20Sopenharmony_ci	if (mbox_req->extMboxTag == 0 && mbox_req->extSeqNum == 0)
46558c2ecf20Sopenharmony_ci		return rc;
46568c2ecf20Sopenharmony_ci
46578c2ecf20Sopenharmony_ci	/* mbox command and first external buffer */
46588c2ecf20Sopenharmony_ci	if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) {
46598c2ecf20Sopenharmony_ci		if (mbox_req->extSeqNum == 1) {
46608c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
46618c2ecf20Sopenharmony_ci					"2974 SLI_CONFIG mailbox: tag:%d, "
46628c2ecf20Sopenharmony_ci					"seq:%d\n", mbox_req->extMboxTag,
46638c2ecf20Sopenharmony_ci					mbox_req->extSeqNum);
46648c2ecf20Sopenharmony_ci			rc = lpfc_bsg_handle_sli_cfg_mbox(phba, job, dmabuf);
46658c2ecf20Sopenharmony_ci			return rc;
46668c2ecf20Sopenharmony_ci		} else
46678c2ecf20Sopenharmony_ci			goto sli_cfg_ext_error;
46688c2ecf20Sopenharmony_ci	}
46698c2ecf20Sopenharmony_ci
46708c2ecf20Sopenharmony_ci	/*
46718c2ecf20Sopenharmony_ci	 * handle additional external buffers
46728c2ecf20Sopenharmony_ci	 */
46738c2ecf20Sopenharmony_ci
46748c2ecf20Sopenharmony_ci	/* check broken pipe conditions */
46758c2ecf20Sopenharmony_ci	if (mbox_req->extMboxTag != phba->mbox_ext_buf_ctx.mbxTag)
46768c2ecf20Sopenharmony_ci		goto sli_cfg_ext_error;
46778c2ecf20Sopenharmony_ci	if (mbox_req->extSeqNum > phba->mbox_ext_buf_ctx.numBuf)
46788c2ecf20Sopenharmony_ci		goto sli_cfg_ext_error;
46798c2ecf20Sopenharmony_ci	if (mbox_req->extSeqNum != phba->mbox_ext_buf_ctx.seqNum + 1)
46808c2ecf20Sopenharmony_ci		goto sli_cfg_ext_error;
46818c2ecf20Sopenharmony_ci
46828c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
46838c2ecf20Sopenharmony_ci			"2975 SLI_CONFIG mailbox external buffer: "
46848c2ecf20Sopenharmony_ci			"extSta:x%x, tag:%d, seq:%d\n",
46858c2ecf20Sopenharmony_ci			phba->mbox_ext_buf_ctx.state, mbox_req->extMboxTag,
46868c2ecf20Sopenharmony_ci			mbox_req->extSeqNum);
46878c2ecf20Sopenharmony_ci	rc = lpfc_bsg_handle_sli_cfg_ebuf(phba, job, dmabuf);
46888c2ecf20Sopenharmony_ci	return rc;
46898c2ecf20Sopenharmony_ci
46908c2ecf20Sopenharmony_cisli_cfg_ext_error:
46918c2ecf20Sopenharmony_ci	/* all other cases, broken pipe */
46928c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
46938c2ecf20Sopenharmony_ci			"2976 SLI_CONFIG mailbox broken pipe: "
46948c2ecf20Sopenharmony_ci			"ctxSta:x%x, ctxNumBuf:%d "
46958c2ecf20Sopenharmony_ci			"ctxTag:%d, ctxSeq:%d, tag:%d, seq:%d\n",
46968c2ecf20Sopenharmony_ci			phba->mbox_ext_buf_ctx.state,
46978c2ecf20Sopenharmony_ci			phba->mbox_ext_buf_ctx.numBuf,
46988c2ecf20Sopenharmony_ci			phba->mbox_ext_buf_ctx.mbxTag,
46998c2ecf20Sopenharmony_ci			phba->mbox_ext_buf_ctx.seqNum,
47008c2ecf20Sopenharmony_ci			mbox_req->extMboxTag, mbox_req->extSeqNum);
47018c2ecf20Sopenharmony_ci
47028c2ecf20Sopenharmony_ci	lpfc_bsg_mbox_ext_session_reset(phba);
47038c2ecf20Sopenharmony_ci
47048c2ecf20Sopenharmony_ci	return -EPIPE;
47058c2ecf20Sopenharmony_ci}
47068c2ecf20Sopenharmony_ci
47078c2ecf20Sopenharmony_ci/**
47088c2ecf20Sopenharmony_ci * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app
47098c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
47108c2ecf20Sopenharmony_ci * @mb: Pointer to a mailbox object.
47118c2ecf20Sopenharmony_ci * @vport: Pointer to a vport object.
47128c2ecf20Sopenharmony_ci *
47138c2ecf20Sopenharmony_ci * Allocate a tracking object, mailbox command memory, get a mailbox
47148c2ecf20Sopenharmony_ci * from the mailbox pool, copy the caller mailbox command.
47158c2ecf20Sopenharmony_ci *
47168c2ecf20Sopenharmony_ci * If offline and the sli is active we need to poll for the command (port is
47178c2ecf20Sopenharmony_ci * being reset) and com-plete the job, otherwise issue the mailbox command and
47188c2ecf20Sopenharmony_ci * let our completion handler finish the command.
47198c2ecf20Sopenharmony_ci **/
47208c2ecf20Sopenharmony_cistatic int
47218c2ecf20Sopenharmony_cilpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct bsg_job *job,
47228c2ecf20Sopenharmony_ci	struct lpfc_vport *vport)
47238c2ecf20Sopenharmony_ci{
47248c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
47258c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
47268c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */
47278c2ecf20Sopenharmony_ci	MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */
47288c2ecf20Sopenharmony_ci	/* a 4k buffer to hold the mb and extended data from/to the bsg */
47298c2ecf20Sopenharmony_ci	uint8_t *pmbx = NULL;
47308c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */
47318c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmabuf = NULL;
47328c2ecf20Sopenharmony_ci	struct dfc_mbox_req *mbox_req;
47338c2ecf20Sopenharmony_ci	struct READ_EVENT_LOG_VAR *rdEventLog;
47348c2ecf20Sopenharmony_ci	uint32_t transmit_length, receive_length, mode;
47358c2ecf20Sopenharmony_ci	struct lpfc_mbx_sli4_config *sli4_config;
47368c2ecf20Sopenharmony_ci	struct lpfc_mbx_nembed_cmd *nembed_sge;
47378c2ecf20Sopenharmony_ci	struct ulp_bde64 *bde;
47388c2ecf20Sopenharmony_ci	uint8_t *ext = NULL;
47398c2ecf20Sopenharmony_ci	int rc = 0;
47408c2ecf20Sopenharmony_ci	uint8_t *from;
47418c2ecf20Sopenharmony_ci	uint32_t size;
47428c2ecf20Sopenharmony_ci
47438c2ecf20Sopenharmony_ci	/* in case no data is transferred */
47448c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
47458c2ecf20Sopenharmony_ci
47468c2ecf20Sopenharmony_ci	/* sanity check to protect driver */
47478c2ecf20Sopenharmony_ci	if (job->reply_payload.payload_len > BSG_MBOX_SIZE ||
47488c2ecf20Sopenharmony_ci	    job->request_payload.payload_len > BSG_MBOX_SIZE) {
47498c2ecf20Sopenharmony_ci		rc = -ERANGE;
47508c2ecf20Sopenharmony_ci		goto job_done;
47518c2ecf20Sopenharmony_ci	}
47528c2ecf20Sopenharmony_ci
47538c2ecf20Sopenharmony_ci	/*
47548c2ecf20Sopenharmony_ci	 * Don't allow mailbox commands to be sent when blocked or when in
47558c2ecf20Sopenharmony_ci	 * the middle of discovery
47568c2ecf20Sopenharmony_ci	 */
47578c2ecf20Sopenharmony_ci	if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
47588c2ecf20Sopenharmony_ci		rc = -EAGAIN;
47598c2ecf20Sopenharmony_ci		goto job_done;
47608c2ecf20Sopenharmony_ci	}
47618c2ecf20Sopenharmony_ci
47628c2ecf20Sopenharmony_ci	mbox_req =
47638c2ecf20Sopenharmony_ci	    (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd;
47648c2ecf20Sopenharmony_ci
47658c2ecf20Sopenharmony_ci	/* check if requested extended data lengths are valid */
47668c2ecf20Sopenharmony_ci	if ((mbox_req->inExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t)) ||
47678c2ecf20Sopenharmony_ci	    (mbox_req->outExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t))) {
47688c2ecf20Sopenharmony_ci		rc = -ERANGE;
47698c2ecf20Sopenharmony_ci		goto job_done;
47708c2ecf20Sopenharmony_ci	}
47718c2ecf20Sopenharmony_ci
47728c2ecf20Sopenharmony_ci	dmabuf = lpfc_bsg_dma_page_alloc(phba);
47738c2ecf20Sopenharmony_ci	if (!dmabuf || !dmabuf->virt) {
47748c2ecf20Sopenharmony_ci		rc = -ENOMEM;
47758c2ecf20Sopenharmony_ci		goto job_done;
47768c2ecf20Sopenharmony_ci	}
47778c2ecf20Sopenharmony_ci
47788c2ecf20Sopenharmony_ci	/* Get the mailbox command or external buffer from BSG */
47798c2ecf20Sopenharmony_ci	pmbx = (uint8_t *)dmabuf->virt;
47808c2ecf20Sopenharmony_ci	size = job->request_payload.payload_len;
47818c2ecf20Sopenharmony_ci	sg_copy_to_buffer(job->request_payload.sg_list,
47828c2ecf20Sopenharmony_ci			  job->request_payload.sg_cnt, pmbx, size);
47838c2ecf20Sopenharmony_ci
47848c2ecf20Sopenharmony_ci	/* Handle possible SLI_CONFIG with non-embedded payloads */
47858c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4) {
47868c2ecf20Sopenharmony_ci		rc = lpfc_bsg_handle_sli_cfg_ext(phba, job, dmabuf);
47878c2ecf20Sopenharmony_ci		if (rc == SLI_CONFIG_HANDLED)
47888c2ecf20Sopenharmony_ci			goto job_cont;
47898c2ecf20Sopenharmony_ci		if (rc)
47908c2ecf20Sopenharmony_ci			goto job_done;
47918c2ecf20Sopenharmony_ci		/* SLI_CONFIG_NOT_HANDLED for other mailbox commands */
47928c2ecf20Sopenharmony_ci	}
47938c2ecf20Sopenharmony_ci
47948c2ecf20Sopenharmony_ci	rc = lpfc_bsg_check_cmd_access(phba, (MAILBOX_t *)pmbx, vport);
47958c2ecf20Sopenharmony_ci	if (rc != 0)
47968c2ecf20Sopenharmony_ci		goto job_done; /* must be negative */
47978c2ecf20Sopenharmony_ci
47988c2ecf20Sopenharmony_ci	/* allocate our bsg tracking structure */
47998c2ecf20Sopenharmony_ci	dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
48008c2ecf20Sopenharmony_ci	if (!dd_data) {
48018c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
48028c2ecf20Sopenharmony_ci				"2727 Failed allocation of dd_data\n");
48038c2ecf20Sopenharmony_ci		rc = -ENOMEM;
48048c2ecf20Sopenharmony_ci		goto job_done;
48058c2ecf20Sopenharmony_ci	}
48068c2ecf20Sopenharmony_ci
48078c2ecf20Sopenharmony_ci	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
48088c2ecf20Sopenharmony_ci	if (!pmboxq) {
48098c2ecf20Sopenharmony_ci		rc = -ENOMEM;
48108c2ecf20Sopenharmony_ci		goto job_done;
48118c2ecf20Sopenharmony_ci	}
48128c2ecf20Sopenharmony_ci	memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
48138c2ecf20Sopenharmony_ci
48148c2ecf20Sopenharmony_ci	pmb = &pmboxq->u.mb;
48158c2ecf20Sopenharmony_ci	memcpy(pmb, pmbx, sizeof(*pmb));
48168c2ecf20Sopenharmony_ci	pmb->mbxOwner = OWN_HOST;
48178c2ecf20Sopenharmony_ci	pmboxq->vport = vport;
48188c2ecf20Sopenharmony_ci
48198c2ecf20Sopenharmony_ci	/* If HBA encountered an error attention, allow only DUMP
48208c2ecf20Sopenharmony_ci	 * or RESTART mailbox commands until the HBA is restarted.
48218c2ecf20Sopenharmony_ci	 */
48228c2ecf20Sopenharmony_ci	if (phba->pport->stopped &&
48238c2ecf20Sopenharmony_ci	    pmb->mbxCommand != MBX_DUMP_MEMORY &&
48248c2ecf20Sopenharmony_ci	    pmb->mbxCommand != MBX_RESTART &&
48258c2ecf20Sopenharmony_ci	    pmb->mbxCommand != MBX_WRITE_VPARMS &&
48268c2ecf20Sopenharmony_ci	    pmb->mbxCommand != MBX_WRITE_WWN)
48278c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
48288c2ecf20Sopenharmony_ci				"2797 mbox: Issued mailbox cmd "
48298c2ecf20Sopenharmony_ci				"0x%x while in stopped state.\n",
48308c2ecf20Sopenharmony_ci				pmb->mbxCommand);
48318c2ecf20Sopenharmony_ci
48328c2ecf20Sopenharmony_ci	/* extended mailbox commands will need an extended buffer */
48338c2ecf20Sopenharmony_ci	if (mbox_req->inExtWLen || mbox_req->outExtWLen) {
48348c2ecf20Sopenharmony_ci		from = pmbx;
48358c2ecf20Sopenharmony_ci		ext = from + sizeof(MAILBOX_t);
48368c2ecf20Sopenharmony_ci		pmboxq->ctx_buf = ext;
48378c2ecf20Sopenharmony_ci		pmboxq->in_ext_byte_len =
48388c2ecf20Sopenharmony_ci			mbox_req->inExtWLen * sizeof(uint32_t);
48398c2ecf20Sopenharmony_ci		pmboxq->out_ext_byte_len =
48408c2ecf20Sopenharmony_ci			mbox_req->outExtWLen * sizeof(uint32_t);
48418c2ecf20Sopenharmony_ci		pmboxq->mbox_offset_word = mbox_req->mbOffset;
48428c2ecf20Sopenharmony_ci	}
48438c2ecf20Sopenharmony_ci
48448c2ecf20Sopenharmony_ci	/* biu diag will need a kernel buffer to transfer the data
48458c2ecf20Sopenharmony_ci	 * allocate our own buffer and setup the mailbox command to
48468c2ecf20Sopenharmony_ci	 * use ours
48478c2ecf20Sopenharmony_ci	 */
48488c2ecf20Sopenharmony_ci	if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) {
48498c2ecf20Sopenharmony_ci		transmit_length = pmb->un.varWords[1];
48508c2ecf20Sopenharmony_ci		receive_length = pmb->un.varWords[4];
48518c2ecf20Sopenharmony_ci		/* transmit length cannot be greater than receive length or
48528c2ecf20Sopenharmony_ci		 * mailbox extension size
48538c2ecf20Sopenharmony_ci		 */
48548c2ecf20Sopenharmony_ci		if ((transmit_length > receive_length) ||
48558c2ecf20Sopenharmony_ci			(transmit_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t))) {
48568c2ecf20Sopenharmony_ci			rc = -ERANGE;
48578c2ecf20Sopenharmony_ci			goto job_done;
48588c2ecf20Sopenharmony_ci		}
48598c2ecf20Sopenharmony_ci		pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh =
48608c2ecf20Sopenharmony_ci			putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t));
48618c2ecf20Sopenharmony_ci		pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow =
48628c2ecf20Sopenharmony_ci			putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t));
48638c2ecf20Sopenharmony_ci
48648c2ecf20Sopenharmony_ci		pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh =
48658c2ecf20Sopenharmony_ci			putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t)
48668c2ecf20Sopenharmony_ci			  + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize);
48678c2ecf20Sopenharmony_ci		pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow =
48688c2ecf20Sopenharmony_ci			putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t)
48698c2ecf20Sopenharmony_ci			  + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize);
48708c2ecf20Sopenharmony_ci	} else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) {
48718c2ecf20Sopenharmony_ci		rdEventLog = &pmb->un.varRdEventLog;
48728c2ecf20Sopenharmony_ci		receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize;
48738c2ecf20Sopenharmony_ci		mode = bf_get(lpfc_event_log, rdEventLog);
48748c2ecf20Sopenharmony_ci
48758c2ecf20Sopenharmony_ci		/* receive length cannot be greater than mailbox
48768c2ecf20Sopenharmony_ci		 * extension size
48778c2ecf20Sopenharmony_ci		 */
48788c2ecf20Sopenharmony_ci		if (receive_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t)) {
48798c2ecf20Sopenharmony_ci			rc = -ERANGE;
48808c2ecf20Sopenharmony_ci			goto job_done;
48818c2ecf20Sopenharmony_ci		}
48828c2ecf20Sopenharmony_ci
48838c2ecf20Sopenharmony_ci		/* mode zero uses a bde like biu diags command */
48848c2ecf20Sopenharmony_ci		if (mode == 0) {
48858c2ecf20Sopenharmony_ci			pmb->un.varWords[3] = putPaddrLow(dmabuf->phys
48868c2ecf20Sopenharmony_ci							+ sizeof(MAILBOX_t));
48878c2ecf20Sopenharmony_ci			pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys
48888c2ecf20Sopenharmony_ci							+ sizeof(MAILBOX_t));
48898c2ecf20Sopenharmony_ci		}
48908c2ecf20Sopenharmony_ci	} else if (phba->sli_rev == LPFC_SLI_REV4) {
48918c2ecf20Sopenharmony_ci		/* Let type 4 (well known data) through because the data is
48928c2ecf20Sopenharmony_ci		 * returned in varwords[4-8]
48938c2ecf20Sopenharmony_ci		 * otherwise check the recieve length and fetch the buffer addr
48948c2ecf20Sopenharmony_ci		 */
48958c2ecf20Sopenharmony_ci		if ((pmb->mbxCommand == MBX_DUMP_MEMORY) &&
48968c2ecf20Sopenharmony_ci			(pmb->un.varDmp.type != DMP_WELL_KNOWN)) {
48978c2ecf20Sopenharmony_ci			/* rebuild the command for sli4 using our own buffers
48988c2ecf20Sopenharmony_ci			* like we do for biu diags
48998c2ecf20Sopenharmony_ci			*/
49008c2ecf20Sopenharmony_ci			receive_length = pmb->un.varWords[2];
49018c2ecf20Sopenharmony_ci			/* receive length cannot be greater than mailbox
49028c2ecf20Sopenharmony_ci			 * extension size
49038c2ecf20Sopenharmony_ci			 */
49048c2ecf20Sopenharmony_ci			if (receive_length == 0) {
49058c2ecf20Sopenharmony_ci				rc = -ERANGE;
49068c2ecf20Sopenharmony_ci				goto job_done;
49078c2ecf20Sopenharmony_ci			}
49088c2ecf20Sopenharmony_ci			pmb->un.varWords[3] = putPaddrLow(dmabuf->phys
49098c2ecf20Sopenharmony_ci						+ sizeof(MAILBOX_t));
49108c2ecf20Sopenharmony_ci			pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys
49118c2ecf20Sopenharmony_ci						+ sizeof(MAILBOX_t));
49128c2ecf20Sopenharmony_ci		} else if ((pmb->mbxCommand == MBX_UPDATE_CFG) &&
49138c2ecf20Sopenharmony_ci			pmb->un.varUpdateCfg.co) {
49148c2ecf20Sopenharmony_ci			bde = (struct ulp_bde64 *)&pmb->un.varWords[4];
49158c2ecf20Sopenharmony_ci
49168c2ecf20Sopenharmony_ci			/* bde size cannot be greater than mailbox ext size */
49178c2ecf20Sopenharmony_ci			if (bde->tus.f.bdeSize >
49188c2ecf20Sopenharmony_ci			    BSG_MBOX_SIZE - sizeof(MAILBOX_t)) {
49198c2ecf20Sopenharmony_ci				rc = -ERANGE;
49208c2ecf20Sopenharmony_ci				goto job_done;
49218c2ecf20Sopenharmony_ci			}
49228c2ecf20Sopenharmony_ci			bde->addrHigh = putPaddrHigh(dmabuf->phys
49238c2ecf20Sopenharmony_ci						+ sizeof(MAILBOX_t));
49248c2ecf20Sopenharmony_ci			bde->addrLow = putPaddrLow(dmabuf->phys
49258c2ecf20Sopenharmony_ci						+ sizeof(MAILBOX_t));
49268c2ecf20Sopenharmony_ci		} else if (pmb->mbxCommand == MBX_SLI4_CONFIG) {
49278c2ecf20Sopenharmony_ci			/* Handling non-embedded SLI_CONFIG mailbox command */
49288c2ecf20Sopenharmony_ci			sli4_config = &pmboxq->u.mqe.un.sli4_config;
49298c2ecf20Sopenharmony_ci			if (!bf_get(lpfc_mbox_hdr_emb,
49308c2ecf20Sopenharmony_ci			    &sli4_config->header.cfg_mhdr)) {
49318c2ecf20Sopenharmony_ci				/* rebuild the command for sli4 using our
49328c2ecf20Sopenharmony_ci				 * own buffers like we do for biu diags
49338c2ecf20Sopenharmony_ci				 */
49348c2ecf20Sopenharmony_ci				nembed_sge = (struct lpfc_mbx_nembed_cmd *)
49358c2ecf20Sopenharmony_ci						&pmb->un.varWords[0];
49368c2ecf20Sopenharmony_ci				receive_length = nembed_sge->sge[0].length;
49378c2ecf20Sopenharmony_ci
49388c2ecf20Sopenharmony_ci				/* receive length cannot be greater than
49398c2ecf20Sopenharmony_ci				 * mailbox extension size
49408c2ecf20Sopenharmony_ci				 */
49418c2ecf20Sopenharmony_ci				if ((receive_length == 0) ||
49428c2ecf20Sopenharmony_ci				    (receive_length >
49438c2ecf20Sopenharmony_ci				     BSG_MBOX_SIZE - sizeof(MAILBOX_t))) {
49448c2ecf20Sopenharmony_ci					rc = -ERANGE;
49458c2ecf20Sopenharmony_ci					goto job_done;
49468c2ecf20Sopenharmony_ci				}
49478c2ecf20Sopenharmony_ci
49488c2ecf20Sopenharmony_ci				nembed_sge->sge[0].pa_hi =
49498c2ecf20Sopenharmony_ci						putPaddrHigh(dmabuf->phys
49508c2ecf20Sopenharmony_ci						   + sizeof(MAILBOX_t));
49518c2ecf20Sopenharmony_ci				nembed_sge->sge[0].pa_lo =
49528c2ecf20Sopenharmony_ci						putPaddrLow(dmabuf->phys
49538c2ecf20Sopenharmony_ci						   + sizeof(MAILBOX_t));
49548c2ecf20Sopenharmony_ci			}
49558c2ecf20Sopenharmony_ci		}
49568c2ecf20Sopenharmony_ci	}
49578c2ecf20Sopenharmony_ci
49588c2ecf20Sopenharmony_ci	dd_data->context_un.mbox.dmabuffers = dmabuf;
49598c2ecf20Sopenharmony_ci
49608c2ecf20Sopenharmony_ci	/* setup wake call as IOCB callback */
49618c2ecf20Sopenharmony_ci	pmboxq->mbox_cmpl = lpfc_bsg_issue_mbox_cmpl;
49628c2ecf20Sopenharmony_ci
49638c2ecf20Sopenharmony_ci	/* setup context field to pass wait_queue pointer to wake function */
49648c2ecf20Sopenharmony_ci	pmboxq->ctx_ndlp = dd_data;
49658c2ecf20Sopenharmony_ci	dd_data->type = TYPE_MBOX;
49668c2ecf20Sopenharmony_ci	dd_data->set_job = job;
49678c2ecf20Sopenharmony_ci	dd_data->context_un.mbox.pmboxq = pmboxq;
49688c2ecf20Sopenharmony_ci	dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx;
49698c2ecf20Sopenharmony_ci	dd_data->context_un.mbox.ext = ext;
49708c2ecf20Sopenharmony_ci	dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset;
49718c2ecf20Sopenharmony_ci	dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen;
49728c2ecf20Sopenharmony_ci	dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen;
49738c2ecf20Sopenharmony_ci	job->dd_data = dd_data;
49748c2ecf20Sopenharmony_ci
49758c2ecf20Sopenharmony_ci	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
49768c2ecf20Sopenharmony_ci	    (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
49778c2ecf20Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
49788c2ecf20Sopenharmony_ci		if (rc != MBX_SUCCESS) {
49798c2ecf20Sopenharmony_ci			rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
49808c2ecf20Sopenharmony_ci			goto job_done;
49818c2ecf20Sopenharmony_ci		}
49828c2ecf20Sopenharmony_ci
49838c2ecf20Sopenharmony_ci		/* job finished, copy the data */
49848c2ecf20Sopenharmony_ci		memcpy(pmbx, pmb, sizeof(*pmb));
49858c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len =
49868c2ecf20Sopenharmony_ci			sg_copy_from_buffer(job->reply_payload.sg_list,
49878c2ecf20Sopenharmony_ci					    job->reply_payload.sg_cnt,
49888c2ecf20Sopenharmony_ci					    pmbx, size);
49898c2ecf20Sopenharmony_ci		/* not waiting mbox already done */
49908c2ecf20Sopenharmony_ci		rc = 0;
49918c2ecf20Sopenharmony_ci		goto job_done;
49928c2ecf20Sopenharmony_ci	}
49938c2ecf20Sopenharmony_ci
49948c2ecf20Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
49958c2ecf20Sopenharmony_ci	if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY))
49968c2ecf20Sopenharmony_ci		return 1; /* job started */
49978c2ecf20Sopenharmony_ci
49988c2ecf20Sopenharmony_cijob_done:
49998c2ecf20Sopenharmony_ci	/* common exit for error or job completed inline */
50008c2ecf20Sopenharmony_ci	if (pmboxq)
50018c2ecf20Sopenharmony_ci		mempool_free(pmboxq, phba->mbox_mem_pool);
50028c2ecf20Sopenharmony_ci	lpfc_bsg_dma_page_free(phba, dmabuf);
50038c2ecf20Sopenharmony_ci	kfree(dd_data);
50048c2ecf20Sopenharmony_ci
50058c2ecf20Sopenharmony_cijob_cont:
50068c2ecf20Sopenharmony_ci	return rc;
50078c2ecf20Sopenharmony_ci}
50088c2ecf20Sopenharmony_ci
50098c2ecf20Sopenharmony_ci/**
50108c2ecf20Sopenharmony_ci * lpfc_bsg_mbox_cmd - process an fc bsg LPFC_BSG_VENDOR_MBOX command
50118c2ecf20Sopenharmony_ci * @job: MBOX fc_bsg_job for LPFC_BSG_VENDOR_MBOX.
50128c2ecf20Sopenharmony_ci **/
50138c2ecf20Sopenharmony_cistatic int
50148c2ecf20Sopenharmony_cilpfc_bsg_mbox_cmd(struct bsg_job *job)
50158c2ecf20Sopenharmony_ci{
50168c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
50178c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
50188c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
50198c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
50208c2ecf20Sopenharmony_ci	struct dfc_mbox_req *mbox_req;
50218c2ecf20Sopenharmony_ci	int rc = 0;
50228c2ecf20Sopenharmony_ci
50238c2ecf20Sopenharmony_ci	/* mix-and-match backward compatibility */
50248c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
50258c2ecf20Sopenharmony_ci	if (job->request_len <
50268c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) {
50278c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
50288c2ecf20Sopenharmony_ci				"2737 Mix-and-match backward compatibility "
50298c2ecf20Sopenharmony_ci				"between MBOX_REQ old size:%d and "
50308c2ecf20Sopenharmony_ci				"new request size:%d\n",
50318c2ecf20Sopenharmony_ci				(int)(job->request_len -
50328c2ecf20Sopenharmony_ci				      sizeof(struct fc_bsg_request)),
50338c2ecf20Sopenharmony_ci				(int)sizeof(struct dfc_mbox_req));
50348c2ecf20Sopenharmony_ci		mbox_req = (struct dfc_mbox_req *)
50358c2ecf20Sopenharmony_ci				bsg_request->rqst_data.h_vendor.vendor_cmd;
50368c2ecf20Sopenharmony_ci		mbox_req->extMboxTag = 0;
50378c2ecf20Sopenharmony_ci		mbox_req->extSeqNum = 0;
50388c2ecf20Sopenharmony_ci	}
50398c2ecf20Sopenharmony_ci
50408c2ecf20Sopenharmony_ci	rc = lpfc_bsg_issue_mbox(phba, job, vport);
50418c2ecf20Sopenharmony_ci
50428c2ecf20Sopenharmony_ci	if (rc == 0) {
50438c2ecf20Sopenharmony_ci		/* job done */
50448c2ecf20Sopenharmony_ci		bsg_reply->result = 0;
50458c2ecf20Sopenharmony_ci		job->dd_data = NULL;
50468c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
50478c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
50488c2ecf20Sopenharmony_ci	} else if (rc == 1)
50498c2ecf20Sopenharmony_ci		/* job submitted, will complete later*/
50508c2ecf20Sopenharmony_ci		rc = 0; /* return zero, no error */
50518c2ecf20Sopenharmony_ci	else {
50528c2ecf20Sopenharmony_ci		/* some error occurred */
50538c2ecf20Sopenharmony_ci		bsg_reply->result = rc;
50548c2ecf20Sopenharmony_ci		job->dd_data = NULL;
50558c2ecf20Sopenharmony_ci	}
50568c2ecf20Sopenharmony_ci
50578c2ecf20Sopenharmony_ci	return rc;
50588c2ecf20Sopenharmony_ci}
50598c2ecf20Sopenharmony_ci
50608c2ecf20Sopenharmony_ci/**
50618c2ecf20Sopenharmony_ci * lpfc_bsg_menlo_cmd_cmp - lpfc_menlo_cmd completion handler
50628c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
50638c2ecf20Sopenharmony_ci * @cmdiocbq: Pointer to command iocb.
50648c2ecf20Sopenharmony_ci * @rspiocbq: Pointer to response iocb.
50658c2ecf20Sopenharmony_ci *
50668c2ecf20Sopenharmony_ci * This function is the completion handler for iocbs issued using
50678c2ecf20Sopenharmony_ci * lpfc_menlo_cmd function. This function is called by the
50688c2ecf20Sopenharmony_ci * ring event handler function without any lock held. This function
50698c2ecf20Sopenharmony_ci * can be called from both worker thread context and interrupt
50708c2ecf20Sopenharmony_ci * context. This function also can be called from another thread which
50718c2ecf20Sopenharmony_ci * cleans up the SLI layer objects.
50728c2ecf20Sopenharmony_ci * This function copies the contents of the response iocb to the
50738c2ecf20Sopenharmony_ci * response iocb memory object provided by the caller of
50748c2ecf20Sopenharmony_ci * lpfc_sli_issue_iocb_wait and then wakes up the thread which
50758c2ecf20Sopenharmony_ci * sleeps for the iocb completion.
50768c2ecf20Sopenharmony_ci **/
50778c2ecf20Sopenharmony_cistatic void
50788c2ecf20Sopenharmony_cilpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba,
50798c2ecf20Sopenharmony_ci			struct lpfc_iocbq *cmdiocbq,
50808c2ecf20Sopenharmony_ci			struct lpfc_iocbq *rspiocbq)
50818c2ecf20Sopenharmony_ci{
50828c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data;
50838c2ecf20Sopenharmony_ci	struct bsg_job *job;
50848c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
50858c2ecf20Sopenharmony_ci	IOCB_t *rsp;
50868c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *bmp, *cmp, *rmp;
50878c2ecf20Sopenharmony_ci	struct lpfc_bsg_menlo *menlo;
50888c2ecf20Sopenharmony_ci	unsigned long flags;
50898c2ecf20Sopenharmony_ci	struct menlo_response *menlo_resp;
50908c2ecf20Sopenharmony_ci	unsigned int rsp_size;
50918c2ecf20Sopenharmony_ci	int rc = 0;
50928c2ecf20Sopenharmony_ci
50938c2ecf20Sopenharmony_ci	dd_data = cmdiocbq->context1;
50948c2ecf20Sopenharmony_ci	cmp = cmdiocbq->context2;
50958c2ecf20Sopenharmony_ci	bmp = cmdiocbq->context3;
50968c2ecf20Sopenharmony_ci	menlo = &dd_data->context_un.menlo;
50978c2ecf20Sopenharmony_ci	rmp = menlo->rmp;
50988c2ecf20Sopenharmony_ci	rsp = &rspiocbq->iocb;
50998c2ecf20Sopenharmony_ci
51008c2ecf20Sopenharmony_ci	/* Determine if job has been aborted */
51018c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
51028c2ecf20Sopenharmony_ci	job = dd_data->set_job;
51038c2ecf20Sopenharmony_ci	if (job) {
51048c2ecf20Sopenharmony_ci		bsg_reply = job->reply;
51058c2ecf20Sopenharmony_ci		/* Prevent timeout handling from trying to abort job  */
51068c2ecf20Sopenharmony_ci		job->dd_data = NULL;
51078c2ecf20Sopenharmony_ci	}
51088c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
51098c2ecf20Sopenharmony_ci
51108c2ecf20Sopenharmony_ci	/* Copy the job data or set the failing status for the job */
51118c2ecf20Sopenharmony_ci
51128c2ecf20Sopenharmony_ci	if (job) {
51138c2ecf20Sopenharmony_ci		/* always return the xri, this would be used in the case
51148c2ecf20Sopenharmony_ci		 * of a menlo download to allow the data to be sent as a
51158c2ecf20Sopenharmony_ci		 * continuation of the exchange.
51168c2ecf20Sopenharmony_ci		 */
51178c2ecf20Sopenharmony_ci
51188c2ecf20Sopenharmony_ci		menlo_resp = (struct menlo_response *)
51198c2ecf20Sopenharmony_ci			bsg_reply->reply_data.vendor_reply.vendor_rsp;
51208c2ecf20Sopenharmony_ci		menlo_resp->xri = rsp->ulpContext;
51218c2ecf20Sopenharmony_ci		if (rsp->ulpStatus) {
51228c2ecf20Sopenharmony_ci			if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
51238c2ecf20Sopenharmony_ci				switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
51248c2ecf20Sopenharmony_ci				case IOERR_SEQUENCE_TIMEOUT:
51258c2ecf20Sopenharmony_ci					rc = -ETIMEDOUT;
51268c2ecf20Sopenharmony_ci					break;
51278c2ecf20Sopenharmony_ci				case IOERR_INVALID_RPI:
51288c2ecf20Sopenharmony_ci					rc = -EFAULT;
51298c2ecf20Sopenharmony_ci					break;
51308c2ecf20Sopenharmony_ci				default:
51318c2ecf20Sopenharmony_ci					rc = -EACCES;
51328c2ecf20Sopenharmony_ci					break;
51338c2ecf20Sopenharmony_ci				}
51348c2ecf20Sopenharmony_ci			} else {
51358c2ecf20Sopenharmony_ci				rc = -EACCES;
51368c2ecf20Sopenharmony_ci			}
51378c2ecf20Sopenharmony_ci		} else {
51388c2ecf20Sopenharmony_ci			rsp_size = rsp->un.genreq64.bdl.bdeSize;
51398c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len =
51408c2ecf20Sopenharmony_ci				lpfc_bsg_copy_data(rmp, &job->reply_payload,
51418c2ecf20Sopenharmony_ci						   rsp_size, 0);
51428c2ecf20Sopenharmony_ci		}
51438c2ecf20Sopenharmony_ci
51448c2ecf20Sopenharmony_ci	}
51458c2ecf20Sopenharmony_ci
51468c2ecf20Sopenharmony_ci	lpfc_sli_release_iocbq(phba, cmdiocbq);
51478c2ecf20Sopenharmony_ci	lpfc_free_bsg_buffers(phba, cmp);
51488c2ecf20Sopenharmony_ci	lpfc_free_bsg_buffers(phba, rmp);
51498c2ecf20Sopenharmony_ci	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
51508c2ecf20Sopenharmony_ci	kfree(bmp);
51518c2ecf20Sopenharmony_ci	kfree(dd_data);
51528c2ecf20Sopenharmony_ci
51538c2ecf20Sopenharmony_ci	/* Complete the job if active */
51548c2ecf20Sopenharmony_ci
51558c2ecf20Sopenharmony_ci	if (job) {
51568c2ecf20Sopenharmony_ci		bsg_reply->result = rc;
51578c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
51588c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
51598c2ecf20Sopenharmony_ci	}
51608c2ecf20Sopenharmony_ci
51618c2ecf20Sopenharmony_ci	return;
51628c2ecf20Sopenharmony_ci}
51638c2ecf20Sopenharmony_ci
51648c2ecf20Sopenharmony_ci/**
51658c2ecf20Sopenharmony_ci * lpfc_menlo_cmd - send an ioctl for menlo hardware
51668c2ecf20Sopenharmony_ci * @job: fc_bsg_job to handle
51678c2ecf20Sopenharmony_ci *
51688c2ecf20Sopenharmony_ci * This function issues a gen request 64 CR ioctl for all menlo cmd requests,
51698c2ecf20Sopenharmony_ci * all the command completions will return the xri for the command.
51708c2ecf20Sopenharmony_ci * For menlo data requests a gen request 64 CX is used to continue the exchange
51718c2ecf20Sopenharmony_ci * supplied in the menlo request header xri field.
51728c2ecf20Sopenharmony_ci **/
51738c2ecf20Sopenharmony_cistatic int
51748c2ecf20Sopenharmony_cilpfc_menlo_cmd(struct bsg_job *job)
51758c2ecf20Sopenharmony_ci{
51768c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
51778c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
51788c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
51798c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
51808c2ecf20Sopenharmony_ci	struct lpfc_iocbq *cmdiocbq;
51818c2ecf20Sopenharmony_ci	IOCB_t *cmd;
51828c2ecf20Sopenharmony_ci	int rc = 0;
51838c2ecf20Sopenharmony_ci	struct menlo_command *menlo_cmd;
51848c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL;
51858c2ecf20Sopenharmony_ci	int request_nseg;
51868c2ecf20Sopenharmony_ci	int reply_nseg;
51878c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data;
51888c2ecf20Sopenharmony_ci	struct ulp_bde64 *bpl = NULL;
51898c2ecf20Sopenharmony_ci
51908c2ecf20Sopenharmony_ci	/* in case no data is returned return just the return code */
51918c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
51928c2ecf20Sopenharmony_ci
51938c2ecf20Sopenharmony_ci	if (job->request_len <
51948c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) +
51958c2ecf20Sopenharmony_ci		sizeof(struct menlo_command)) {
51968c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
51978c2ecf20Sopenharmony_ci				"2784 Received MENLO_CMD request below "
51988c2ecf20Sopenharmony_ci				"minimum size\n");
51998c2ecf20Sopenharmony_ci		rc = -ERANGE;
52008c2ecf20Sopenharmony_ci		goto no_dd_data;
52018c2ecf20Sopenharmony_ci	}
52028c2ecf20Sopenharmony_ci
52038c2ecf20Sopenharmony_ci	if (job->reply_len < sizeof(*bsg_reply) +
52048c2ecf20Sopenharmony_ci				sizeof(struct menlo_response)) {
52058c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
52068c2ecf20Sopenharmony_ci				"2785 Received MENLO_CMD reply below "
52078c2ecf20Sopenharmony_ci				"minimum size\n");
52088c2ecf20Sopenharmony_ci		rc = -ERANGE;
52098c2ecf20Sopenharmony_ci		goto no_dd_data;
52108c2ecf20Sopenharmony_ci	}
52118c2ecf20Sopenharmony_ci
52128c2ecf20Sopenharmony_ci	if (!(phba->menlo_flag & HBA_MENLO_SUPPORT)) {
52138c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
52148c2ecf20Sopenharmony_ci				"2786 Adapter does not support menlo "
52158c2ecf20Sopenharmony_ci				"commands\n");
52168c2ecf20Sopenharmony_ci		rc = -EPERM;
52178c2ecf20Sopenharmony_ci		goto no_dd_data;
52188c2ecf20Sopenharmony_ci	}
52198c2ecf20Sopenharmony_ci
52208c2ecf20Sopenharmony_ci	menlo_cmd = (struct menlo_command *)
52218c2ecf20Sopenharmony_ci		bsg_request->rqst_data.h_vendor.vendor_cmd;
52228c2ecf20Sopenharmony_ci
52238c2ecf20Sopenharmony_ci	/* allocate our bsg tracking structure */
52248c2ecf20Sopenharmony_ci	dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
52258c2ecf20Sopenharmony_ci	if (!dd_data) {
52268c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
52278c2ecf20Sopenharmony_ci				"2787 Failed allocation of dd_data\n");
52288c2ecf20Sopenharmony_ci		rc = -ENOMEM;
52298c2ecf20Sopenharmony_ci		goto no_dd_data;
52308c2ecf20Sopenharmony_ci	}
52318c2ecf20Sopenharmony_ci
52328c2ecf20Sopenharmony_ci	bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
52338c2ecf20Sopenharmony_ci	if (!bmp) {
52348c2ecf20Sopenharmony_ci		rc = -ENOMEM;
52358c2ecf20Sopenharmony_ci		goto free_dd;
52368c2ecf20Sopenharmony_ci	}
52378c2ecf20Sopenharmony_ci
52388c2ecf20Sopenharmony_ci	bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
52398c2ecf20Sopenharmony_ci	if (!bmp->virt) {
52408c2ecf20Sopenharmony_ci		rc = -ENOMEM;
52418c2ecf20Sopenharmony_ci		goto free_bmp;
52428c2ecf20Sopenharmony_ci	}
52438c2ecf20Sopenharmony_ci
52448c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&bmp->list);
52458c2ecf20Sopenharmony_ci
52468c2ecf20Sopenharmony_ci	bpl = (struct ulp_bde64 *)bmp->virt;
52478c2ecf20Sopenharmony_ci	request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64);
52488c2ecf20Sopenharmony_ci	cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len,
52498c2ecf20Sopenharmony_ci				     1, bpl, &request_nseg);
52508c2ecf20Sopenharmony_ci	if (!cmp) {
52518c2ecf20Sopenharmony_ci		rc = -ENOMEM;
52528c2ecf20Sopenharmony_ci		goto free_bmp;
52538c2ecf20Sopenharmony_ci	}
52548c2ecf20Sopenharmony_ci	lpfc_bsg_copy_data(cmp, &job->request_payload,
52558c2ecf20Sopenharmony_ci			   job->request_payload.payload_len, 1);
52568c2ecf20Sopenharmony_ci
52578c2ecf20Sopenharmony_ci	bpl += request_nseg;
52588c2ecf20Sopenharmony_ci	reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg;
52598c2ecf20Sopenharmony_ci	rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0,
52608c2ecf20Sopenharmony_ci				     bpl, &reply_nseg);
52618c2ecf20Sopenharmony_ci	if (!rmp) {
52628c2ecf20Sopenharmony_ci		rc = -ENOMEM;
52638c2ecf20Sopenharmony_ci		goto free_cmp;
52648c2ecf20Sopenharmony_ci	}
52658c2ecf20Sopenharmony_ci
52668c2ecf20Sopenharmony_ci	cmdiocbq = lpfc_sli_get_iocbq(phba);
52678c2ecf20Sopenharmony_ci	if (!cmdiocbq) {
52688c2ecf20Sopenharmony_ci		rc = -ENOMEM;
52698c2ecf20Sopenharmony_ci		goto free_rmp;
52708c2ecf20Sopenharmony_ci	}
52718c2ecf20Sopenharmony_ci
52728c2ecf20Sopenharmony_ci	cmd = &cmdiocbq->iocb;
52738c2ecf20Sopenharmony_ci	cmd->un.genreq64.bdl.ulpIoTag32 = 0;
52748c2ecf20Sopenharmony_ci	cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
52758c2ecf20Sopenharmony_ci	cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
52768c2ecf20Sopenharmony_ci	cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
52778c2ecf20Sopenharmony_ci	cmd->un.genreq64.bdl.bdeSize =
52788c2ecf20Sopenharmony_ci	    (request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
52798c2ecf20Sopenharmony_ci	cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
52808c2ecf20Sopenharmony_ci	cmd->un.genreq64.w5.hcsw.Dfctl = 0;
52818c2ecf20Sopenharmony_ci	cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CMD;
52828c2ecf20Sopenharmony_ci	cmd->un.genreq64.w5.hcsw.Type = MENLO_TRANSPORT_TYPE; /* 0xfe */
52838c2ecf20Sopenharmony_ci	cmd->ulpBdeCount = 1;
52848c2ecf20Sopenharmony_ci	cmd->ulpClass = CLASS3;
52858c2ecf20Sopenharmony_ci	cmd->ulpOwner = OWN_CHIP;
52868c2ecf20Sopenharmony_ci	cmd->ulpLe = 1; /* Limited Edition */
52878c2ecf20Sopenharmony_ci	cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
52888c2ecf20Sopenharmony_ci	cmdiocbq->vport = phba->pport;
52898c2ecf20Sopenharmony_ci	/* We want the firmware to timeout before we do */
52908c2ecf20Sopenharmony_ci	cmd->ulpTimeout = MENLO_TIMEOUT - 5;
52918c2ecf20Sopenharmony_ci	cmdiocbq->iocb_cmpl = lpfc_bsg_menlo_cmd_cmp;
52928c2ecf20Sopenharmony_ci	cmdiocbq->context1 = dd_data;
52938c2ecf20Sopenharmony_ci	cmdiocbq->context2 = cmp;
52948c2ecf20Sopenharmony_ci	cmdiocbq->context3 = bmp;
52958c2ecf20Sopenharmony_ci	if (menlo_cmd->cmd == LPFC_BSG_VENDOR_MENLO_CMD) {
52968c2ecf20Sopenharmony_ci		cmd->ulpCommand = CMD_GEN_REQUEST64_CR;
52978c2ecf20Sopenharmony_ci		cmd->ulpPU = MENLO_PU; /* 3 */
52988c2ecf20Sopenharmony_ci		cmd->un.ulpWord[4] = MENLO_DID; /* 0x0000FC0E */
52998c2ecf20Sopenharmony_ci		cmd->ulpContext = MENLO_CONTEXT; /* 0 */
53008c2ecf20Sopenharmony_ci	} else {
53018c2ecf20Sopenharmony_ci		cmd->ulpCommand = CMD_GEN_REQUEST64_CX;
53028c2ecf20Sopenharmony_ci		cmd->ulpPU = 1;
53038c2ecf20Sopenharmony_ci		cmd->un.ulpWord[4] = 0;
53048c2ecf20Sopenharmony_ci		cmd->ulpContext = menlo_cmd->xri;
53058c2ecf20Sopenharmony_ci	}
53068c2ecf20Sopenharmony_ci
53078c2ecf20Sopenharmony_ci	dd_data->type = TYPE_MENLO;
53088c2ecf20Sopenharmony_ci	dd_data->set_job = job;
53098c2ecf20Sopenharmony_ci	dd_data->context_un.menlo.cmdiocbq = cmdiocbq;
53108c2ecf20Sopenharmony_ci	dd_data->context_un.menlo.rmp = rmp;
53118c2ecf20Sopenharmony_ci	job->dd_data = dd_data;
53128c2ecf20Sopenharmony_ci
53138c2ecf20Sopenharmony_ci	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq,
53148c2ecf20Sopenharmony_ci		MENLO_TIMEOUT - 5);
53158c2ecf20Sopenharmony_ci	if (rc == IOCB_SUCCESS)
53168c2ecf20Sopenharmony_ci		return 0; /* done for now */
53178c2ecf20Sopenharmony_ci
53188c2ecf20Sopenharmony_ci	lpfc_sli_release_iocbq(phba, cmdiocbq);
53198c2ecf20Sopenharmony_ci
53208c2ecf20Sopenharmony_cifree_rmp:
53218c2ecf20Sopenharmony_ci	lpfc_free_bsg_buffers(phba, rmp);
53228c2ecf20Sopenharmony_cifree_cmp:
53238c2ecf20Sopenharmony_ci	lpfc_free_bsg_buffers(phba, cmp);
53248c2ecf20Sopenharmony_cifree_bmp:
53258c2ecf20Sopenharmony_ci	if (bmp->virt)
53268c2ecf20Sopenharmony_ci		lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
53278c2ecf20Sopenharmony_ci	kfree(bmp);
53288c2ecf20Sopenharmony_cifree_dd:
53298c2ecf20Sopenharmony_ci	kfree(dd_data);
53308c2ecf20Sopenharmony_cino_dd_data:
53318c2ecf20Sopenharmony_ci	/* make error code available to userspace */
53328c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
53338c2ecf20Sopenharmony_ci	job->dd_data = NULL;
53348c2ecf20Sopenharmony_ci	return rc;
53358c2ecf20Sopenharmony_ci}
53368c2ecf20Sopenharmony_ci
53378c2ecf20Sopenharmony_cistatic int
53388c2ecf20Sopenharmony_cilpfc_forced_link_speed(struct bsg_job *job)
53398c2ecf20Sopenharmony_ci{
53408c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = fc_bsg_to_shost(job);
53418c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(shost);
53428c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
53438c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
53448c2ecf20Sopenharmony_ci	struct forced_link_speed_support_reply *forced_reply;
53458c2ecf20Sopenharmony_ci	int rc = 0;
53468c2ecf20Sopenharmony_ci
53478c2ecf20Sopenharmony_ci	if (job->request_len <
53488c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) +
53498c2ecf20Sopenharmony_ci	    sizeof(struct get_forced_link_speed_support)) {
53508c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
53518c2ecf20Sopenharmony_ci				"0048 Received FORCED_LINK_SPEED request "
53528c2ecf20Sopenharmony_ci				"below minimum size\n");
53538c2ecf20Sopenharmony_ci		rc = -EINVAL;
53548c2ecf20Sopenharmony_ci		goto job_error;
53558c2ecf20Sopenharmony_ci	}
53568c2ecf20Sopenharmony_ci
53578c2ecf20Sopenharmony_ci	forced_reply = (struct forced_link_speed_support_reply *)
53588c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp;
53598c2ecf20Sopenharmony_ci
53608c2ecf20Sopenharmony_ci	if (job->reply_len < sizeof(*bsg_reply) + sizeof(*forced_reply)) {
53618c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
53628c2ecf20Sopenharmony_ci				"0049 Received FORCED_LINK_SPEED reply below "
53638c2ecf20Sopenharmony_ci				"minimum size\n");
53648c2ecf20Sopenharmony_ci		rc = -EINVAL;
53658c2ecf20Sopenharmony_ci		goto job_error;
53668c2ecf20Sopenharmony_ci	}
53678c2ecf20Sopenharmony_ci
53688c2ecf20Sopenharmony_ci	forced_reply->supported = (phba->hba_flag & HBA_FORCED_LINK_SPEED)
53698c2ecf20Sopenharmony_ci				   ? LPFC_FORCED_LINK_SPEED_SUPPORTED
53708c2ecf20Sopenharmony_ci				   : LPFC_FORCED_LINK_SPEED_NOT_SUPPORTED;
53718c2ecf20Sopenharmony_cijob_error:
53728c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
53738c2ecf20Sopenharmony_ci	if (rc == 0)
53748c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
53758c2ecf20Sopenharmony_ci			       bsg_reply->reply_payload_rcv_len);
53768c2ecf20Sopenharmony_ci	return rc;
53778c2ecf20Sopenharmony_ci}
53788c2ecf20Sopenharmony_ci
53798c2ecf20Sopenharmony_ci/**
53808c2ecf20Sopenharmony_ci * lpfc_check_fwlog_support: Check FW log support on the adapter
53818c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
53828c2ecf20Sopenharmony_ci *
53838c2ecf20Sopenharmony_ci * Check if FW Logging support by the adapter
53848c2ecf20Sopenharmony_ci **/
53858c2ecf20Sopenharmony_ciint
53868c2ecf20Sopenharmony_cilpfc_check_fwlog_support(struct lpfc_hba *phba)
53878c2ecf20Sopenharmony_ci{
53888c2ecf20Sopenharmony_ci	struct lpfc_ras_fwlog *ras_fwlog = NULL;
53898c2ecf20Sopenharmony_ci
53908c2ecf20Sopenharmony_ci	ras_fwlog = &phba->ras_fwlog;
53918c2ecf20Sopenharmony_ci
53928c2ecf20Sopenharmony_ci	if (ras_fwlog->ras_hwsupport == false)
53938c2ecf20Sopenharmony_ci		return -EACCES;
53948c2ecf20Sopenharmony_ci	else if (ras_fwlog->ras_enabled == false)
53958c2ecf20Sopenharmony_ci		return -EPERM;
53968c2ecf20Sopenharmony_ci	else
53978c2ecf20Sopenharmony_ci		return 0;
53988c2ecf20Sopenharmony_ci}
53998c2ecf20Sopenharmony_ci
54008c2ecf20Sopenharmony_ci/**
54018c2ecf20Sopenharmony_ci * lpfc_bsg_get_ras_config: Get RAS configuration settings
54028c2ecf20Sopenharmony_ci * @job: fc_bsg_job to handle
54038c2ecf20Sopenharmony_ci *
54048c2ecf20Sopenharmony_ci * Get RAS configuration values set.
54058c2ecf20Sopenharmony_ci **/
54068c2ecf20Sopenharmony_cistatic int
54078c2ecf20Sopenharmony_cilpfc_bsg_get_ras_config(struct bsg_job *job)
54088c2ecf20Sopenharmony_ci{
54098c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = fc_bsg_to_shost(job);
54108c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(shost);
54118c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
54128c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
54138c2ecf20Sopenharmony_ci	struct lpfc_bsg_get_ras_config_reply *ras_reply;
54148c2ecf20Sopenharmony_ci	struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
54158c2ecf20Sopenharmony_ci	int rc = 0;
54168c2ecf20Sopenharmony_ci
54178c2ecf20Sopenharmony_ci	if (job->request_len <
54188c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) +
54198c2ecf20Sopenharmony_ci	    sizeof(struct lpfc_bsg_ras_req)) {
54208c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
54218c2ecf20Sopenharmony_ci				"6192 FW_LOG request received "
54228c2ecf20Sopenharmony_ci				"below minimum size\n");
54238c2ecf20Sopenharmony_ci		rc = -EINVAL;
54248c2ecf20Sopenharmony_ci		goto ras_job_error;
54258c2ecf20Sopenharmony_ci	}
54268c2ecf20Sopenharmony_ci
54278c2ecf20Sopenharmony_ci	/* Check FW log status */
54288c2ecf20Sopenharmony_ci	rc = lpfc_check_fwlog_support(phba);
54298c2ecf20Sopenharmony_ci	if (rc)
54308c2ecf20Sopenharmony_ci		goto ras_job_error;
54318c2ecf20Sopenharmony_ci
54328c2ecf20Sopenharmony_ci	ras_reply = (struct lpfc_bsg_get_ras_config_reply *)
54338c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp;
54348c2ecf20Sopenharmony_ci
54358c2ecf20Sopenharmony_ci	/* Current logging state */
54368c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
54378c2ecf20Sopenharmony_ci	if (ras_fwlog->state == ACTIVE)
54388c2ecf20Sopenharmony_ci		ras_reply->state = LPFC_RASLOG_STATE_RUNNING;
54398c2ecf20Sopenharmony_ci	else
54408c2ecf20Sopenharmony_ci		ras_reply->state = LPFC_RASLOG_STATE_STOPPED;
54418c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
54428c2ecf20Sopenharmony_ci
54438c2ecf20Sopenharmony_ci	ras_reply->log_level = phba->ras_fwlog.fw_loglevel;
54448c2ecf20Sopenharmony_ci	ras_reply->log_buff_sz = phba->cfg_ras_fwlog_buffsize;
54458c2ecf20Sopenharmony_ci
54468c2ecf20Sopenharmony_ciras_job_error:
54478c2ecf20Sopenharmony_ci	/* make error code available to userspace */
54488c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
54498c2ecf20Sopenharmony_ci
54508c2ecf20Sopenharmony_ci	/* complete the job back to userspace */
54518c2ecf20Sopenharmony_ci	if (!rc)
54528c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
54538c2ecf20Sopenharmony_ci			     bsg_reply->reply_payload_rcv_len);
54548c2ecf20Sopenharmony_ci	return rc;
54558c2ecf20Sopenharmony_ci}
54568c2ecf20Sopenharmony_ci
54578c2ecf20Sopenharmony_ci/**
54588c2ecf20Sopenharmony_ci * lpfc_bsg_set_ras_config: Set FW logging parameters
54598c2ecf20Sopenharmony_ci * @job: fc_bsg_job to handle
54608c2ecf20Sopenharmony_ci *
54618c2ecf20Sopenharmony_ci * Set log-level parameters for FW-logging in host memory
54628c2ecf20Sopenharmony_ci **/
54638c2ecf20Sopenharmony_cistatic int
54648c2ecf20Sopenharmony_cilpfc_bsg_set_ras_config(struct bsg_job *job)
54658c2ecf20Sopenharmony_ci{
54668c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = fc_bsg_to_shost(job);
54678c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(shost);
54688c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
54698c2ecf20Sopenharmony_ci	struct lpfc_bsg_set_ras_config_req *ras_req;
54708c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
54718c2ecf20Sopenharmony_ci	struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
54728c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
54738c2ecf20Sopenharmony_ci	uint8_t action = 0, log_level = 0;
54748c2ecf20Sopenharmony_ci	int rc = 0, action_status = 0;
54758c2ecf20Sopenharmony_ci
54768c2ecf20Sopenharmony_ci	if (job->request_len <
54778c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) +
54788c2ecf20Sopenharmony_ci	    sizeof(struct lpfc_bsg_set_ras_config_req)) {
54798c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
54808c2ecf20Sopenharmony_ci				"6182 Received RAS_LOG request "
54818c2ecf20Sopenharmony_ci				"below minimum size\n");
54828c2ecf20Sopenharmony_ci		rc = -EINVAL;
54838c2ecf20Sopenharmony_ci		goto ras_job_error;
54848c2ecf20Sopenharmony_ci	}
54858c2ecf20Sopenharmony_ci
54868c2ecf20Sopenharmony_ci	/* Check FW log status */
54878c2ecf20Sopenharmony_ci	rc = lpfc_check_fwlog_support(phba);
54888c2ecf20Sopenharmony_ci	if (rc)
54898c2ecf20Sopenharmony_ci		goto ras_job_error;
54908c2ecf20Sopenharmony_ci
54918c2ecf20Sopenharmony_ci	ras_req = (struct lpfc_bsg_set_ras_config_req *)
54928c2ecf20Sopenharmony_ci		bsg_request->rqst_data.h_vendor.vendor_cmd;
54938c2ecf20Sopenharmony_ci	action = ras_req->action;
54948c2ecf20Sopenharmony_ci	log_level = ras_req->log_level;
54958c2ecf20Sopenharmony_ci
54968c2ecf20Sopenharmony_ci	if (action == LPFC_RASACTION_STOP_LOGGING) {
54978c2ecf20Sopenharmony_ci		/* Check if already disabled */
54988c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
54998c2ecf20Sopenharmony_ci		if (ras_fwlog->state != ACTIVE) {
55008c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
55018c2ecf20Sopenharmony_ci			rc = -ESRCH;
55028c2ecf20Sopenharmony_ci			goto ras_job_error;
55038c2ecf20Sopenharmony_ci		}
55048c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
55058c2ecf20Sopenharmony_ci
55068c2ecf20Sopenharmony_ci		/* Disable logging */
55078c2ecf20Sopenharmony_ci		lpfc_ras_stop_fwlog(phba);
55088c2ecf20Sopenharmony_ci	} else {
55098c2ecf20Sopenharmony_ci		/*action = LPFC_RASACTION_START_LOGGING*/
55108c2ecf20Sopenharmony_ci
55118c2ecf20Sopenharmony_ci		/* Even though FW-logging is active re-initialize
55128c2ecf20Sopenharmony_ci		 * FW-logging with new log-level. Return status
55138c2ecf20Sopenharmony_ci		 * "Logging already Running" to caller.
55148c2ecf20Sopenharmony_ci		 **/
55158c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
55168c2ecf20Sopenharmony_ci		if (ras_fwlog->state != INACTIVE)
55178c2ecf20Sopenharmony_ci			action_status = -EINPROGRESS;
55188c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
55198c2ecf20Sopenharmony_ci
55208c2ecf20Sopenharmony_ci		/* Enable logging */
55218c2ecf20Sopenharmony_ci		rc = lpfc_sli4_ras_fwlog_init(phba, log_level,
55228c2ecf20Sopenharmony_ci					      LPFC_RAS_ENABLE_LOGGING);
55238c2ecf20Sopenharmony_ci		if (rc) {
55248c2ecf20Sopenharmony_ci			rc = -EINVAL;
55258c2ecf20Sopenharmony_ci			goto ras_job_error;
55268c2ecf20Sopenharmony_ci		}
55278c2ecf20Sopenharmony_ci
55288c2ecf20Sopenharmony_ci		/* Check if FW-logging is re-initialized */
55298c2ecf20Sopenharmony_ci		if (action_status == -EINPROGRESS)
55308c2ecf20Sopenharmony_ci			rc = action_status;
55318c2ecf20Sopenharmony_ci	}
55328c2ecf20Sopenharmony_ciras_job_error:
55338c2ecf20Sopenharmony_ci	/* make error code available to userspace */
55348c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
55358c2ecf20Sopenharmony_ci
55368c2ecf20Sopenharmony_ci	/* complete the job back to userspace */
55378c2ecf20Sopenharmony_ci	if (!rc)
55388c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
55398c2ecf20Sopenharmony_ci			     bsg_reply->reply_payload_rcv_len);
55408c2ecf20Sopenharmony_ci
55418c2ecf20Sopenharmony_ci	return rc;
55428c2ecf20Sopenharmony_ci}
55438c2ecf20Sopenharmony_ci
55448c2ecf20Sopenharmony_ci/**
55458c2ecf20Sopenharmony_ci * lpfc_bsg_get_ras_lwpd: Get log write position data
55468c2ecf20Sopenharmony_ci * @job: fc_bsg_job to handle
55478c2ecf20Sopenharmony_ci *
55488c2ecf20Sopenharmony_ci * Get Offset/Wrap count of the log message written
55498c2ecf20Sopenharmony_ci * in host memory
55508c2ecf20Sopenharmony_ci **/
55518c2ecf20Sopenharmony_cistatic int
55528c2ecf20Sopenharmony_cilpfc_bsg_get_ras_lwpd(struct bsg_job *job)
55538c2ecf20Sopenharmony_ci{
55548c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = fc_bsg_to_shost(job);
55558c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(shost);
55568c2ecf20Sopenharmony_ci	struct lpfc_bsg_get_ras_lwpd *ras_reply;
55578c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
55588c2ecf20Sopenharmony_ci	struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
55598c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
55608c2ecf20Sopenharmony_ci	u32 *lwpd_ptr = NULL;
55618c2ecf20Sopenharmony_ci	int rc = 0;
55628c2ecf20Sopenharmony_ci
55638c2ecf20Sopenharmony_ci	rc = lpfc_check_fwlog_support(phba);
55648c2ecf20Sopenharmony_ci	if (rc)
55658c2ecf20Sopenharmony_ci		goto ras_job_error;
55668c2ecf20Sopenharmony_ci
55678c2ecf20Sopenharmony_ci	if (job->request_len <
55688c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) +
55698c2ecf20Sopenharmony_ci	    sizeof(struct lpfc_bsg_ras_req)) {
55708c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
55718c2ecf20Sopenharmony_ci				"6183 Received RAS_LOG request "
55728c2ecf20Sopenharmony_ci				"below minimum size\n");
55738c2ecf20Sopenharmony_ci		rc = -EINVAL;
55748c2ecf20Sopenharmony_ci		goto ras_job_error;
55758c2ecf20Sopenharmony_ci	}
55768c2ecf20Sopenharmony_ci
55778c2ecf20Sopenharmony_ci	ras_reply = (struct lpfc_bsg_get_ras_lwpd *)
55788c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp;
55798c2ecf20Sopenharmony_ci
55808c2ecf20Sopenharmony_ci	if (!ras_fwlog->lwpd.virt) {
55818c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
55828c2ecf20Sopenharmony_ci				"6193 Restart FW Logging\n");
55838c2ecf20Sopenharmony_ci		rc = -EINVAL;
55848c2ecf20Sopenharmony_ci		goto ras_job_error;
55858c2ecf20Sopenharmony_ci	}
55868c2ecf20Sopenharmony_ci
55878c2ecf20Sopenharmony_ci	/* Get lwpd offset */
55888c2ecf20Sopenharmony_ci	lwpd_ptr = (uint32_t *)(ras_fwlog->lwpd.virt);
55898c2ecf20Sopenharmony_ci	ras_reply->offset = be32_to_cpu(*lwpd_ptr & 0xffffffff);
55908c2ecf20Sopenharmony_ci
55918c2ecf20Sopenharmony_ci	/* Get wrap count */
55928c2ecf20Sopenharmony_ci	ras_reply->wrap_count = be32_to_cpu(*(++lwpd_ptr) & 0xffffffff);
55938c2ecf20Sopenharmony_ci
55948c2ecf20Sopenharmony_ciras_job_error:
55958c2ecf20Sopenharmony_ci	/* make error code available to userspace */
55968c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
55978c2ecf20Sopenharmony_ci
55988c2ecf20Sopenharmony_ci	/* complete the job back to userspace */
55998c2ecf20Sopenharmony_ci	if (!rc)
56008c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
56018c2ecf20Sopenharmony_ci			     bsg_reply->reply_payload_rcv_len);
56028c2ecf20Sopenharmony_ci
56038c2ecf20Sopenharmony_ci	return rc;
56048c2ecf20Sopenharmony_ci}
56058c2ecf20Sopenharmony_ci
56068c2ecf20Sopenharmony_ci/**
56078c2ecf20Sopenharmony_ci * lpfc_bsg_get_ras_fwlog: Read FW log
56088c2ecf20Sopenharmony_ci * @job: fc_bsg_job to handle
56098c2ecf20Sopenharmony_ci *
56108c2ecf20Sopenharmony_ci * Copy the FW log into the passed buffer.
56118c2ecf20Sopenharmony_ci **/
56128c2ecf20Sopenharmony_cistatic int
56138c2ecf20Sopenharmony_cilpfc_bsg_get_ras_fwlog(struct bsg_job *job)
56148c2ecf20Sopenharmony_ci{
56158c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = fc_bsg_to_shost(job);
56168c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(shost);
56178c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
56188c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
56198c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
56208c2ecf20Sopenharmony_ci	struct lpfc_bsg_get_fwlog_req *ras_req;
56218c2ecf20Sopenharmony_ci	u32 rd_offset, rd_index, offset;
56228c2ecf20Sopenharmony_ci	void *src, *fwlog_buff;
56238c2ecf20Sopenharmony_ci	struct lpfc_ras_fwlog *ras_fwlog = NULL;
56248c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmabuf, *next;
56258c2ecf20Sopenharmony_ci	int rc = 0;
56268c2ecf20Sopenharmony_ci
56278c2ecf20Sopenharmony_ci	ras_fwlog = &phba->ras_fwlog;
56288c2ecf20Sopenharmony_ci
56298c2ecf20Sopenharmony_ci	rc = lpfc_check_fwlog_support(phba);
56308c2ecf20Sopenharmony_ci	if (rc)
56318c2ecf20Sopenharmony_ci		goto ras_job_error;
56328c2ecf20Sopenharmony_ci
56338c2ecf20Sopenharmony_ci	/* Logging to be stopped before reading */
56348c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
56358c2ecf20Sopenharmony_ci	if (ras_fwlog->state == ACTIVE) {
56368c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
56378c2ecf20Sopenharmony_ci		rc = -EINPROGRESS;
56388c2ecf20Sopenharmony_ci		goto ras_job_error;
56398c2ecf20Sopenharmony_ci	}
56408c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
56418c2ecf20Sopenharmony_ci
56428c2ecf20Sopenharmony_ci	if (job->request_len <
56438c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) +
56448c2ecf20Sopenharmony_ci	    sizeof(struct lpfc_bsg_get_fwlog_req)) {
56458c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
56468c2ecf20Sopenharmony_ci				"6184 Received RAS_LOG request "
56478c2ecf20Sopenharmony_ci				"below minimum size\n");
56488c2ecf20Sopenharmony_ci		rc = -EINVAL;
56498c2ecf20Sopenharmony_ci		goto ras_job_error;
56508c2ecf20Sopenharmony_ci	}
56518c2ecf20Sopenharmony_ci
56528c2ecf20Sopenharmony_ci	ras_req = (struct lpfc_bsg_get_fwlog_req *)
56538c2ecf20Sopenharmony_ci		bsg_request->rqst_data.h_vendor.vendor_cmd;
56548c2ecf20Sopenharmony_ci	rd_offset = ras_req->read_offset;
56558c2ecf20Sopenharmony_ci
56568c2ecf20Sopenharmony_ci	/* Allocate memory to read fw log*/
56578c2ecf20Sopenharmony_ci	fwlog_buff = vmalloc(ras_req->read_size);
56588c2ecf20Sopenharmony_ci	if (!fwlog_buff) {
56598c2ecf20Sopenharmony_ci		rc = -ENOMEM;
56608c2ecf20Sopenharmony_ci		goto ras_job_error;
56618c2ecf20Sopenharmony_ci	}
56628c2ecf20Sopenharmony_ci
56638c2ecf20Sopenharmony_ci	rd_index = (rd_offset / LPFC_RAS_MAX_ENTRY_SIZE);
56648c2ecf20Sopenharmony_ci	offset = (rd_offset % LPFC_RAS_MAX_ENTRY_SIZE);
56658c2ecf20Sopenharmony_ci
56668c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dmabuf, next,
56678c2ecf20Sopenharmony_ci			      &ras_fwlog->fwlog_buff_list, list) {
56688c2ecf20Sopenharmony_ci
56698c2ecf20Sopenharmony_ci		if (dmabuf->buffer_tag < rd_index)
56708c2ecf20Sopenharmony_ci			continue;
56718c2ecf20Sopenharmony_ci
56728c2ecf20Sopenharmony_ci		src = dmabuf->virt + offset;
56738c2ecf20Sopenharmony_ci		memcpy(fwlog_buff, src, ras_req->read_size);
56748c2ecf20Sopenharmony_ci		break;
56758c2ecf20Sopenharmony_ci	}
56768c2ecf20Sopenharmony_ci
56778c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len =
56788c2ecf20Sopenharmony_ci		sg_copy_from_buffer(job->reply_payload.sg_list,
56798c2ecf20Sopenharmony_ci				    job->reply_payload.sg_cnt,
56808c2ecf20Sopenharmony_ci				    fwlog_buff, ras_req->read_size);
56818c2ecf20Sopenharmony_ci
56828c2ecf20Sopenharmony_ci	vfree(fwlog_buff);
56838c2ecf20Sopenharmony_ci
56848c2ecf20Sopenharmony_ciras_job_error:
56858c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
56868c2ecf20Sopenharmony_ci	if (!rc)
56878c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
56888c2ecf20Sopenharmony_ci			     bsg_reply->reply_payload_rcv_len);
56898c2ecf20Sopenharmony_ci
56908c2ecf20Sopenharmony_ci	return rc;
56918c2ecf20Sopenharmony_ci}
56928c2ecf20Sopenharmony_ci
56938c2ecf20Sopenharmony_cistatic int
56948c2ecf20Sopenharmony_cilpfc_get_trunk_info(struct bsg_job *job)
56958c2ecf20Sopenharmony_ci{
56968c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
56978c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
56988c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
56998c2ecf20Sopenharmony_ci	struct lpfc_trunk_info *event_reply;
57008c2ecf20Sopenharmony_ci	int rc = 0;
57018c2ecf20Sopenharmony_ci
57028c2ecf20Sopenharmony_ci	if (job->request_len <
57038c2ecf20Sopenharmony_ci	    sizeof(struct fc_bsg_request) + sizeof(struct get_trunk_info_req)) {
57048c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
57058c2ecf20Sopenharmony_ci				"2744 Received GET TRUNK _INFO request below "
57068c2ecf20Sopenharmony_ci				"minimum size\n");
57078c2ecf20Sopenharmony_ci		rc = -EINVAL;
57088c2ecf20Sopenharmony_ci		goto job_error;
57098c2ecf20Sopenharmony_ci	}
57108c2ecf20Sopenharmony_ci
57118c2ecf20Sopenharmony_ci	event_reply = (struct lpfc_trunk_info *)
57128c2ecf20Sopenharmony_ci		bsg_reply->reply_data.vendor_reply.vendor_rsp;
57138c2ecf20Sopenharmony_ci
57148c2ecf20Sopenharmony_ci	if (job->reply_len < sizeof(*bsg_reply) + sizeof(*event_reply)) {
57158c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
57168c2ecf20Sopenharmony_ci				"2728 Received GET TRUNK _INFO reply below "
57178c2ecf20Sopenharmony_ci				"minimum size\n");
57188c2ecf20Sopenharmony_ci		rc = -EINVAL;
57198c2ecf20Sopenharmony_ci		goto job_error;
57208c2ecf20Sopenharmony_ci	}
57218c2ecf20Sopenharmony_ci	if (event_reply == NULL) {
57228c2ecf20Sopenharmony_ci		rc = -EINVAL;
57238c2ecf20Sopenharmony_ci		goto job_error;
57248c2ecf20Sopenharmony_ci	}
57258c2ecf20Sopenharmony_ci
57268c2ecf20Sopenharmony_ci	bsg_bf_set(lpfc_trunk_info_link_status, event_reply,
57278c2ecf20Sopenharmony_ci		   (phba->link_state >= LPFC_LINK_UP) ? 1 : 0);
57288c2ecf20Sopenharmony_ci
57298c2ecf20Sopenharmony_ci	bsg_bf_set(lpfc_trunk_info_trunk_active0, event_reply,
57308c2ecf20Sopenharmony_ci		   (phba->trunk_link.link0.state == LPFC_LINK_UP) ? 1 : 0);
57318c2ecf20Sopenharmony_ci
57328c2ecf20Sopenharmony_ci	bsg_bf_set(lpfc_trunk_info_trunk_active1, event_reply,
57338c2ecf20Sopenharmony_ci		   (phba->trunk_link.link1.state == LPFC_LINK_UP) ? 1 : 0);
57348c2ecf20Sopenharmony_ci
57358c2ecf20Sopenharmony_ci	bsg_bf_set(lpfc_trunk_info_trunk_active2, event_reply,
57368c2ecf20Sopenharmony_ci		   (phba->trunk_link.link2.state == LPFC_LINK_UP) ? 1 : 0);
57378c2ecf20Sopenharmony_ci
57388c2ecf20Sopenharmony_ci	bsg_bf_set(lpfc_trunk_info_trunk_active3, event_reply,
57398c2ecf20Sopenharmony_ci		   (phba->trunk_link.link3.state == LPFC_LINK_UP) ? 1 : 0);
57408c2ecf20Sopenharmony_ci
57418c2ecf20Sopenharmony_ci	bsg_bf_set(lpfc_trunk_info_trunk_config0, event_reply,
57428c2ecf20Sopenharmony_ci		   bf_get(lpfc_conf_trunk_port0, &phba->sli4_hba));
57438c2ecf20Sopenharmony_ci
57448c2ecf20Sopenharmony_ci	bsg_bf_set(lpfc_trunk_info_trunk_config1, event_reply,
57458c2ecf20Sopenharmony_ci		   bf_get(lpfc_conf_trunk_port1, &phba->sli4_hba));
57468c2ecf20Sopenharmony_ci
57478c2ecf20Sopenharmony_ci	bsg_bf_set(lpfc_trunk_info_trunk_config2, event_reply,
57488c2ecf20Sopenharmony_ci		   bf_get(lpfc_conf_trunk_port2, &phba->sli4_hba));
57498c2ecf20Sopenharmony_ci
57508c2ecf20Sopenharmony_ci	bsg_bf_set(lpfc_trunk_info_trunk_config3, event_reply,
57518c2ecf20Sopenharmony_ci		   bf_get(lpfc_conf_trunk_port3, &phba->sli4_hba));
57528c2ecf20Sopenharmony_ci
57538c2ecf20Sopenharmony_ci	event_reply->port_speed = phba->sli4_hba.link_state.speed / 1000;
57548c2ecf20Sopenharmony_ci	event_reply->logical_speed =
57558c2ecf20Sopenharmony_ci				phba->sli4_hba.link_state.logical_speed / 1000;
57568c2ecf20Sopenharmony_cijob_error:
57578c2ecf20Sopenharmony_ci	bsg_reply->result = rc;
57588c2ecf20Sopenharmony_ci	if (!rc)
57598c2ecf20Sopenharmony_ci		bsg_job_done(job, bsg_reply->result,
57608c2ecf20Sopenharmony_ci			     bsg_reply->reply_payload_rcv_len);
57618c2ecf20Sopenharmony_ci	return rc;
57628c2ecf20Sopenharmony_ci
57638c2ecf20Sopenharmony_ci}
57648c2ecf20Sopenharmony_ci
57658c2ecf20Sopenharmony_ci/**
57668c2ecf20Sopenharmony_ci * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job
57678c2ecf20Sopenharmony_ci * @job: fc_bsg_job to handle
57688c2ecf20Sopenharmony_ci **/
57698c2ecf20Sopenharmony_cistatic int
57708c2ecf20Sopenharmony_cilpfc_bsg_hst_vendor(struct bsg_job *job)
57718c2ecf20Sopenharmony_ci{
57728c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
57738c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
57748c2ecf20Sopenharmony_ci	int command = bsg_request->rqst_data.h_vendor.vendor_cmd[0];
57758c2ecf20Sopenharmony_ci	int rc;
57768c2ecf20Sopenharmony_ci
57778c2ecf20Sopenharmony_ci	switch (command) {
57788c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_SET_CT_EVENT:
57798c2ecf20Sopenharmony_ci		rc = lpfc_bsg_hba_set_event(job);
57808c2ecf20Sopenharmony_ci		break;
57818c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_GET_CT_EVENT:
57828c2ecf20Sopenharmony_ci		rc = lpfc_bsg_hba_get_event(job);
57838c2ecf20Sopenharmony_ci		break;
57848c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_SEND_MGMT_RESP:
57858c2ecf20Sopenharmony_ci		rc = lpfc_bsg_send_mgmt_rsp(job);
57868c2ecf20Sopenharmony_ci		break;
57878c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_DIAG_MODE:
57888c2ecf20Sopenharmony_ci		rc = lpfc_bsg_diag_loopback_mode(job);
57898c2ecf20Sopenharmony_ci		break;
57908c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_DIAG_MODE_END:
57918c2ecf20Sopenharmony_ci		rc = lpfc_sli4_bsg_diag_mode_end(job);
57928c2ecf20Sopenharmony_ci		break;
57938c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_DIAG_RUN_LOOPBACK:
57948c2ecf20Sopenharmony_ci		rc = lpfc_bsg_diag_loopback_run(job);
57958c2ecf20Sopenharmony_ci		break;
57968c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_LINK_DIAG_TEST:
57978c2ecf20Sopenharmony_ci		rc = lpfc_sli4_bsg_link_diag_test(job);
57988c2ecf20Sopenharmony_ci		break;
57998c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_GET_MGMT_REV:
58008c2ecf20Sopenharmony_ci		rc = lpfc_bsg_get_dfc_rev(job);
58018c2ecf20Sopenharmony_ci		break;
58028c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_MBOX:
58038c2ecf20Sopenharmony_ci		rc = lpfc_bsg_mbox_cmd(job);
58048c2ecf20Sopenharmony_ci		break;
58058c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_MENLO_CMD:
58068c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_MENLO_DATA:
58078c2ecf20Sopenharmony_ci		rc = lpfc_menlo_cmd(job);
58088c2ecf20Sopenharmony_ci		break;
58098c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_FORCED_LINK_SPEED:
58108c2ecf20Sopenharmony_ci		rc = lpfc_forced_link_speed(job);
58118c2ecf20Sopenharmony_ci		break;
58128c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_RAS_GET_LWPD:
58138c2ecf20Sopenharmony_ci		rc = lpfc_bsg_get_ras_lwpd(job);
58148c2ecf20Sopenharmony_ci		break;
58158c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_RAS_GET_FWLOG:
58168c2ecf20Sopenharmony_ci		rc = lpfc_bsg_get_ras_fwlog(job);
58178c2ecf20Sopenharmony_ci		break;
58188c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_RAS_GET_CONFIG:
58198c2ecf20Sopenharmony_ci		rc = lpfc_bsg_get_ras_config(job);
58208c2ecf20Sopenharmony_ci		break;
58218c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_RAS_SET_CONFIG:
58228c2ecf20Sopenharmony_ci		rc = lpfc_bsg_set_ras_config(job);
58238c2ecf20Sopenharmony_ci		break;
58248c2ecf20Sopenharmony_ci	case LPFC_BSG_VENDOR_GET_TRUNK_INFO:
58258c2ecf20Sopenharmony_ci		rc = lpfc_get_trunk_info(job);
58268c2ecf20Sopenharmony_ci		break;
58278c2ecf20Sopenharmony_ci	default:
58288c2ecf20Sopenharmony_ci		rc = -EINVAL;
58298c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len = 0;
58308c2ecf20Sopenharmony_ci		/* make error code available to userspace */
58318c2ecf20Sopenharmony_ci		bsg_reply->result = rc;
58328c2ecf20Sopenharmony_ci		break;
58338c2ecf20Sopenharmony_ci	}
58348c2ecf20Sopenharmony_ci
58358c2ecf20Sopenharmony_ci	return rc;
58368c2ecf20Sopenharmony_ci}
58378c2ecf20Sopenharmony_ci
58388c2ecf20Sopenharmony_ci/**
58398c2ecf20Sopenharmony_ci * lpfc_bsg_request - handle a bsg request from the FC transport
58408c2ecf20Sopenharmony_ci * @job: bsg_job to handle
58418c2ecf20Sopenharmony_ci **/
58428c2ecf20Sopenharmony_ciint
58438c2ecf20Sopenharmony_cilpfc_bsg_request(struct bsg_job *job)
58448c2ecf20Sopenharmony_ci{
58458c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request = job->request;
58468c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = job->reply;
58478c2ecf20Sopenharmony_ci	uint32_t msgcode;
58488c2ecf20Sopenharmony_ci	int rc;
58498c2ecf20Sopenharmony_ci
58508c2ecf20Sopenharmony_ci	msgcode = bsg_request->msgcode;
58518c2ecf20Sopenharmony_ci	switch (msgcode) {
58528c2ecf20Sopenharmony_ci	case FC_BSG_HST_VENDOR:
58538c2ecf20Sopenharmony_ci		rc = lpfc_bsg_hst_vendor(job);
58548c2ecf20Sopenharmony_ci		break;
58558c2ecf20Sopenharmony_ci	case FC_BSG_RPT_ELS:
58568c2ecf20Sopenharmony_ci		rc = lpfc_bsg_rport_els(job);
58578c2ecf20Sopenharmony_ci		break;
58588c2ecf20Sopenharmony_ci	case FC_BSG_RPT_CT:
58598c2ecf20Sopenharmony_ci		rc = lpfc_bsg_send_mgmt_cmd(job);
58608c2ecf20Sopenharmony_ci		break;
58618c2ecf20Sopenharmony_ci	default:
58628c2ecf20Sopenharmony_ci		rc = -EINVAL;
58638c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len = 0;
58648c2ecf20Sopenharmony_ci		/* make error code available to userspace */
58658c2ecf20Sopenharmony_ci		bsg_reply->result = rc;
58668c2ecf20Sopenharmony_ci		break;
58678c2ecf20Sopenharmony_ci	}
58688c2ecf20Sopenharmony_ci
58698c2ecf20Sopenharmony_ci	return rc;
58708c2ecf20Sopenharmony_ci}
58718c2ecf20Sopenharmony_ci
58728c2ecf20Sopenharmony_ci/**
58738c2ecf20Sopenharmony_ci * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport
58748c2ecf20Sopenharmony_ci * @job: bsg_job that has timed out
58758c2ecf20Sopenharmony_ci *
58768c2ecf20Sopenharmony_ci * This function just aborts the job's IOCB.  The aborted IOCB will return to
58778c2ecf20Sopenharmony_ci * the waiting function which will handle passing the error back to userspace
58788c2ecf20Sopenharmony_ci **/
58798c2ecf20Sopenharmony_ciint
58808c2ecf20Sopenharmony_cilpfc_bsg_timeout(struct bsg_job *job)
58818c2ecf20Sopenharmony_ci{
58828c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
58838c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
58848c2ecf20Sopenharmony_ci	struct lpfc_iocbq *cmdiocb;
58858c2ecf20Sopenharmony_ci	struct lpfc_sli_ring *pring;
58868c2ecf20Sopenharmony_ci	struct bsg_job_data *dd_data;
58878c2ecf20Sopenharmony_ci	unsigned long flags;
58888c2ecf20Sopenharmony_ci	int rc = 0;
58898c2ecf20Sopenharmony_ci	LIST_HEAD(completions);
58908c2ecf20Sopenharmony_ci	struct lpfc_iocbq *check_iocb, *next_iocb;
58918c2ecf20Sopenharmony_ci
58928c2ecf20Sopenharmony_ci	pring = lpfc_phba_elsring(phba);
58938c2ecf20Sopenharmony_ci	if (unlikely(!pring))
58948c2ecf20Sopenharmony_ci		return -EIO;
58958c2ecf20Sopenharmony_ci
58968c2ecf20Sopenharmony_ci	/* if job's driver data is NULL, the command completed or is in the
58978c2ecf20Sopenharmony_ci	 * the process of completing.  In this case, return status to request
58988c2ecf20Sopenharmony_ci	 * so the timeout is retried.  This avoids double completion issues
58998c2ecf20Sopenharmony_ci	 * and the request will be pulled off the timer queue when the
59008c2ecf20Sopenharmony_ci	 * command's completion handler executes.  Otherwise, prevent the
59018c2ecf20Sopenharmony_ci	 * command's completion handler from executing the job done callback
59028c2ecf20Sopenharmony_ci	 * and continue processing to abort the outstanding the command.
59038c2ecf20Sopenharmony_ci	 */
59048c2ecf20Sopenharmony_ci
59058c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ct_ev_lock, flags);
59068c2ecf20Sopenharmony_ci	dd_data = (struct bsg_job_data *)job->dd_data;
59078c2ecf20Sopenharmony_ci	if (dd_data) {
59088c2ecf20Sopenharmony_ci		dd_data->set_job = NULL;
59098c2ecf20Sopenharmony_ci		job->dd_data = NULL;
59108c2ecf20Sopenharmony_ci	} else {
59118c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
59128c2ecf20Sopenharmony_ci		return -EAGAIN;
59138c2ecf20Sopenharmony_ci	}
59148c2ecf20Sopenharmony_ci
59158c2ecf20Sopenharmony_ci	switch (dd_data->type) {
59168c2ecf20Sopenharmony_ci	case TYPE_IOCB:
59178c2ecf20Sopenharmony_ci		/* Check to see if IOCB was issued to the port or not. If not,
59188c2ecf20Sopenharmony_ci		 * remove it from the txq queue and call cancel iocbs.
59198c2ecf20Sopenharmony_ci		 * Otherwise, call abort iotag
59208c2ecf20Sopenharmony_ci		 */
59218c2ecf20Sopenharmony_ci		cmdiocb = dd_data->context_un.iocb.cmdiocbq;
59228c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
59238c2ecf20Sopenharmony_ci
59248c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, flags);
59258c2ecf20Sopenharmony_ci		/* make sure the I/O abort window is still open */
59268c2ecf20Sopenharmony_ci		if (!(cmdiocb->iocb_flag & LPFC_IO_CMD_OUTSTANDING)) {
59278c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, flags);
59288c2ecf20Sopenharmony_ci			return -EAGAIN;
59298c2ecf20Sopenharmony_ci		}
59308c2ecf20Sopenharmony_ci		list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
59318c2ecf20Sopenharmony_ci					 list) {
59328c2ecf20Sopenharmony_ci			if (check_iocb == cmdiocb) {
59338c2ecf20Sopenharmony_ci				list_move_tail(&check_iocb->list, &completions);
59348c2ecf20Sopenharmony_ci				break;
59358c2ecf20Sopenharmony_ci			}
59368c2ecf20Sopenharmony_ci		}
59378c2ecf20Sopenharmony_ci		if (list_empty(&completions))
59388c2ecf20Sopenharmony_ci			lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
59398c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, flags);
59408c2ecf20Sopenharmony_ci		if (!list_empty(&completions)) {
59418c2ecf20Sopenharmony_ci			lpfc_sli_cancel_iocbs(phba, &completions,
59428c2ecf20Sopenharmony_ci					      IOSTAT_LOCAL_REJECT,
59438c2ecf20Sopenharmony_ci					      IOERR_SLI_ABORTED);
59448c2ecf20Sopenharmony_ci		}
59458c2ecf20Sopenharmony_ci		break;
59468c2ecf20Sopenharmony_ci
59478c2ecf20Sopenharmony_ci	case TYPE_EVT:
59488c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
59498c2ecf20Sopenharmony_ci		break;
59508c2ecf20Sopenharmony_ci
59518c2ecf20Sopenharmony_ci	case TYPE_MBOX:
59528c2ecf20Sopenharmony_ci		/* Update the ext buf ctx state if needed */
59538c2ecf20Sopenharmony_ci
59548c2ecf20Sopenharmony_ci		if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT)
59558c2ecf20Sopenharmony_ci			phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS;
59568c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
59578c2ecf20Sopenharmony_ci		break;
59588c2ecf20Sopenharmony_ci	case TYPE_MENLO:
59598c2ecf20Sopenharmony_ci		/* Check to see if IOCB was issued to the port or not. If not,
59608c2ecf20Sopenharmony_ci		 * remove it from the txq queue and call cancel iocbs.
59618c2ecf20Sopenharmony_ci		 * Otherwise, call abort iotag.
59628c2ecf20Sopenharmony_ci		 */
59638c2ecf20Sopenharmony_ci		cmdiocb = dd_data->context_un.menlo.cmdiocbq;
59648c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
59658c2ecf20Sopenharmony_ci
59668c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, flags);
59678c2ecf20Sopenharmony_ci		list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
59688c2ecf20Sopenharmony_ci					 list) {
59698c2ecf20Sopenharmony_ci			if (check_iocb == cmdiocb) {
59708c2ecf20Sopenharmony_ci				list_move_tail(&check_iocb->list, &completions);
59718c2ecf20Sopenharmony_ci				break;
59728c2ecf20Sopenharmony_ci			}
59738c2ecf20Sopenharmony_ci		}
59748c2ecf20Sopenharmony_ci		if (list_empty(&completions))
59758c2ecf20Sopenharmony_ci			lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
59768c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, flags);
59778c2ecf20Sopenharmony_ci		if (!list_empty(&completions)) {
59788c2ecf20Sopenharmony_ci			lpfc_sli_cancel_iocbs(phba, &completions,
59798c2ecf20Sopenharmony_ci					      IOSTAT_LOCAL_REJECT,
59808c2ecf20Sopenharmony_ci					      IOERR_SLI_ABORTED);
59818c2ecf20Sopenharmony_ci		}
59828c2ecf20Sopenharmony_ci		break;
59838c2ecf20Sopenharmony_ci	default:
59848c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
59858c2ecf20Sopenharmony_ci		break;
59868c2ecf20Sopenharmony_ci	}
59878c2ecf20Sopenharmony_ci
59888c2ecf20Sopenharmony_ci	/* scsi transport fc fc_bsg_job_timeout expects a zero return code,
59898c2ecf20Sopenharmony_ci	 * otherwise an error message will be displayed on the console
59908c2ecf20Sopenharmony_ci	 * so always return success (zero)
59918c2ecf20Sopenharmony_ci	 */
59928c2ecf20Sopenharmony_ci	return rc;
59938c2ecf20Sopenharmony_ci}
5994