162306a36Sopenharmony_ci/*******************************************************************
262306a36Sopenharmony_ci * This file is part of the Emulex Linux Device Driver for         *
362306a36Sopenharmony_ci * Fibre Channel Host Bus Adapters.                                *
462306a36Sopenharmony_ci * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
562306a36Sopenharmony_ci * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.     *
662306a36Sopenharmony_ci * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
762306a36Sopenharmony_ci * EMULEX and SLI are trademarks of Emulex.                        *
862306a36Sopenharmony_ci * www.broadcom.com                                                *
962306a36Sopenharmony_ci * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
1062306a36Sopenharmony_ci *                                                                 *
1162306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or   *
1262306a36Sopenharmony_ci * modify it under the terms of version 2 of the GNU General       *
1362306a36Sopenharmony_ci * Public License as published by the Free Software Foundation.    *
1462306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful. *
1562306a36Sopenharmony_ci * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
1662306a36Sopenharmony_ci * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
1862306a36Sopenharmony_ci * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
1962306a36Sopenharmony_ci * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
2062306a36Sopenharmony_ci * more details, a copy of which can be found in the file COPYING  *
2162306a36Sopenharmony_ci * included with this package.                                     *
2262306a36Sopenharmony_ci *******************************************************************/
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <linux/blkdev.h>
2562306a36Sopenharmony_ci#include <linux/pci.h>
2662306a36Sopenharmony_ci#include <linux/interrupt.h>
2762306a36Sopenharmony_ci#include <linux/delay.h>
2862306a36Sopenharmony_ci#include <linux/slab.h>
2962306a36Sopenharmony_ci#include <linux/lockdep.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <scsi/scsi.h>
3262306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
3362306a36Sopenharmony_ci#include <scsi/scsi_device.h>
3462306a36Sopenharmony_ci#include <scsi/scsi_host.h>
3562306a36Sopenharmony_ci#include <scsi/scsi_transport_fc.h>
3662306a36Sopenharmony_ci#include <scsi/fc/fc_fs.h>
3762306a36Sopenharmony_ci#include <linux/crash_dump.h>
3862306a36Sopenharmony_ci#ifdef CONFIG_X86
3962306a36Sopenharmony_ci#include <asm/set_memory.h>
4062306a36Sopenharmony_ci#endif
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include "lpfc_hw4.h"
4362306a36Sopenharmony_ci#include "lpfc_hw.h"
4462306a36Sopenharmony_ci#include "lpfc_sli.h"
4562306a36Sopenharmony_ci#include "lpfc_sli4.h"
4662306a36Sopenharmony_ci#include "lpfc_nl.h"
4762306a36Sopenharmony_ci#include "lpfc_disc.h"
4862306a36Sopenharmony_ci#include "lpfc.h"
4962306a36Sopenharmony_ci#include "lpfc_scsi.h"
5062306a36Sopenharmony_ci#include "lpfc_nvme.h"
5162306a36Sopenharmony_ci#include "lpfc_crtn.h"
5262306a36Sopenharmony_ci#include "lpfc_logmsg.h"
5362306a36Sopenharmony_ci#include "lpfc_compat.h"
5462306a36Sopenharmony_ci#include "lpfc_debugfs.h"
5562306a36Sopenharmony_ci#include "lpfc_vport.h"
5662306a36Sopenharmony_ci#include "lpfc_version.h"
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/* There are only four IOCB completion types. */
5962306a36Sopenharmony_citypedef enum _lpfc_iocb_type {
6062306a36Sopenharmony_ci	LPFC_UNKNOWN_IOCB,
6162306a36Sopenharmony_ci	LPFC_UNSOL_IOCB,
6262306a36Sopenharmony_ci	LPFC_SOL_IOCB,
6362306a36Sopenharmony_ci	LPFC_ABORT_IOCB
6462306a36Sopenharmony_ci} lpfc_iocb_type;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* Provide function prototypes local to this module. */
6862306a36Sopenharmony_cistatic int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *,
6962306a36Sopenharmony_ci				  uint32_t);
7062306a36Sopenharmony_cistatic int lpfc_sli4_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *,
7162306a36Sopenharmony_ci			      uint8_t *, uint32_t *);
7262306a36Sopenharmony_cistatic struct lpfc_iocbq *
7362306a36Sopenharmony_cilpfc_sli4_els_preprocess_rspiocbq(struct lpfc_hba *phba,
7462306a36Sopenharmony_ci				  struct lpfc_iocbq *rspiocbq);
7562306a36Sopenharmony_cistatic void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *,
7662306a36Sopenharmony_ci				      struct hbq_dmabuf *);
7762306a36Sopenharmony_cistatic void lpfc_sli4_handle_mds_loopback(struct lpfc_vport *vport,
7862306a36Sopenharmony_ci					  struct hbq_dmabuf *dmabuf);
7962306a36Sopenharmony_cistatic bool lpfc_sli4_fp_handle_cqe(struct lpfc_hba *phba,
8062306a36Sopenharmony_ci				   struct lpfc_queue *cq, struct lpfc_cqe *cqe);
8162306a36Sopenharmony_cistatic int lpfc_sli4_post_sgl_list(struct lpfc_hba *, struct list_head *,
8262306a36Sopenharmony_ci				       int);
8362306a36Sopenharmony_cistatic void lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba,
8462306a36Sopenharmony_ci				     struct lpfc_queue *eq,
8562306a36Sopenharmony_ci				     struct lpfc_eqe *eqe,
8662306a36Sopenharmony_ci				     enum lpfc_poll_mode poll_mode);
8762306a36Sopenharmony_cistatic bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba);
8862306a36Sopenharmony_cistatic bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba);
8962306a36Sopenharmony_cistatic struct lpfc_cqe *lpfc_sli4_cq_get(struct lpfc_queue *q);
9062306a36Sopenharmony_cistatic void __lpfc_sli4_consume_cqe(struct lpfc_hba *phba,
9162306a36Sopenharmony_ci				    struct lpfc_queue *cq,
9262306a36Sopenharmony_ci				    struct lpfc_cqe *cqe);
9362306a36Sopenharmony_cistatic uint16_t lpfc_wqe_bpl2sgl(struct lpfc_hba *phba,
9462306a36Sopenharmony_ci				 struct lpfc_iocbq *pwqeq,
9562306a36Sopenharmony_ci				 struct lpfc_sglq *sglq);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ciunion lpfc_wqe128 lpfc_iread_cmd_template;
9862306a36Sopenharmony_ciunion lpfc_wqe128 lpfc_iwrite_cmd_template;
9962306a36Sopenharmony_ciunion lpfc_wqe128 lpfc_icmnd_cmd_template;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* Setup WQE templates for IOs */
10262306a36Sopenharmony_civoid lpfc_wqe_cmd_template(void)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	union lpfc_wqe128 *wqe;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/* IREAD template */
10762306a36Sopenharmony_ci	wqe = &lpfc_iread_cmd_template;
10862306a36Sopenharmony_ci	memset(wqe, 0, sizeof(union lpfc_wqe128));
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* Word 0, 1, 2 - BDE is variable */
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* Word 3 - cmd_buff_len, payload_offset_len is zero */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/* Word 4 - total_xfer_len is variable */
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* Word 5 - is zero */
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* Word 6 - ctxt_tag, xri_tag is variable */
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* Word 7 */
12162306a36Sopenharmony_ci	bf_set(wqe_cmnd, &wqe->fcp_iread.wqe_com, CMD_FCP_IREAD64_WQE);
12262306a36Sopenharmony_ci	bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, PARM_READ_CHECK);
12362306a36Sopenharmony_ci	bf_set(wqe_class, &wqe->fcp_iread.wqe_com, CLASS3);
12462306a36Sopenharmony_ci	bf_set(wqe_ct, &wqe->fcp_iread.wqe_com, SLI4_CT_RPI);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* Word 8 - abort_tag is variable */
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* Word 9  - reqtag is variable */
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* Word 10 - dbde, wqes is variable */
13162306a36Sopenharmony_ci	bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0);
13262306a36Sopenharmony_ci	bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ);
13362306a36Sopenharmony_ci	bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, LPFC_WQE_LENLOC_WORD4);
13462306a36Sopenharmony_ci	bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0);
13562306a36Sopenharmony_ci	bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/* Word 11 - pbde is variable */
13862306a36Sopenharmony_ci	bf_set(wqe_cmd_type, &wqe->fcp_iread.wqe_com, COMMAND_DATA_IN);
13962306a36Sopenharmony_ci	bf_set(wqe_cqid, &wqe->fcp_iread.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
14062306a36Sopenharmony_ci	bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 0);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* Word 12 - is zero */
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* Word 13, 14, 15 - PBDE is variable */
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* IWRITE template */
14762306a36Sopenharmony_ci	wqe = &lpfc_iwrite_cmd_template;
14862306a36Sopenharmony_ci	memset(wqe, 0, sizeof(union lpfc_wqe128));
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* Word 0, 1, 2 - BDE is variable */
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/* Word 3 - cmd_buff_len, payload_offset_len is zero */
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* Word 4 - total_xfer_len is variable */
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* Word 5 - initial_xfer_len is variable */
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* Word 6 - ctxt_tag, xri_tag is variable */
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/* Word 7 */
16162306a36Sopenharmony_ci	bf_set(wqe_cmnd, &wqe->fcp_iwrite.wqe_com, CMD_FCP_IWRITE64_WQE);
16262306a36Sopenharmony_ci	bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, PARM_READ_CHECK);
16362306a36Sopenharmony_ci	bf_set(wqe_class, &wqe->fcp_iwrite.wqe_com, CLASS3);
16462306a36Sopenharmony_ci	bf_set(wqe_ct, &wqe->fcp_iwrite.wqe_com, SLI4_CT_RPI);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* Word 8 - abort_tag is variable */
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/* Word 9  - reqtag is variable */
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* Word 10 - dbde, wqes is variable */
17162306a36Sopenharmony_ci	bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0);
17262306a36Sopenharmony_ci	bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE);
17362306a36Sopenharmony_ci	bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_LENLOC_WORD4);
17462306a36Sopenharmony_ci	bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0);
17562306a36Sopenharmony_ci	bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* Word 11 - pbde is variable */
17862306a36Sopenharmony_ci	bf_set(wqe_cmd_type, &wqe->fcp_iwrite.wqe_com, COMMAND_DATA_OUT);
17962306a36Sopenharmony_ci	bf_set(wqe_cqid, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
18062306a36Sopenharmony_ci	bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 0);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* Word 12 - is zero */
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* Word 13, 14, 15 - PBDE is variable */
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	/* ICMND template */
18762306a36Sopenharmony_ci	wqe = &lpfc_icmnd_cmd_template;
18862306a36Sopenharmony_ci	memset(wqe, 0, sizeof(union lpfc_wqe128));
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* Word 0, 1, 2 - BDE is variable */
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/* Word 3 - payload_offset_len is variable */
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	/* Word 4, 5 - is zero */
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* Word 6 - ctxt_tag, xri_tag is variable */
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/* Word 7 */
19962306a36Sopenharmony_ci	bf_set(wqe_cmnd, &wqe->fcp_icmd.wqe_com, CMD_FCP_ICMND64_WQE);
20062306a36Sopenharmony_ci	bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0);
20162306a36Sopenharmony_ci	bf_set(wqe_class, &wqe->fcp_icmd.wqe_com, CLASS3);
20262306a36Sopenharmony_ci	bf_set(wqe_ct, &wqe->fcp_icmd.wqe_com, SLI4_CT_RPI);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* Word 8 - abort_tag is variable */
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* Word 9  - reqtag is variable */
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* Word 10 - dbde, wqes is variable */
20962306a36Sopenharmony_ci	bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1);
21062306a36Sopenharmony_ci	bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_NONE);
21162306a36Sopenharmony_ci	bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, LPFC_WQE_LENLOC_NONE);
21262306a36Sopenharmony_ci	bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0);
21362306a36Sopenharmony_ci	bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* Word 11 */
21662306a36Sopenharmony_ci	bf_set(wqe_cmd_type, &wqe->fcp_icmd.wqe_com, COMMAND_DATA_IN);
21762306a36Sopenharmony_ci	bf_set(wqe_cqid, &wqe->fcp_icmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
21862306a36Sopenharmony_ci	bf_set(wqe_pbde, &wqe->fcp_icmd.wqe_com, 0);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/* Word 12, 13, 14, 15 - is zero */
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci#if defined(CONFIG_64BIT) && defined(__LITTLE_ENDIAN)
22462306a36Sopenharmony_ci/**
22562306a36Sopenharmony_ci * lpfc_sli4_pcimem_bcopy - SLI4 memory copy function
22662306a36Sopenharmony_ci * @srcp: Source memory pointer.
22762306a36Sopenharmony_ci * @destp: Destination memory pointer.
22862306a36Sopenharmony_ci * @cnt: Number of words required to be copied.
22962306a36Sopenharmony_ci *       Must be a multiple of sizeof(uint64_t)
23062306a36Sopenharmony_ci *
23162306a36Sopenharmony_ci * This function is used for copying data between driver memory
23262306a36Sopenharmony_ci * and the SLI WQ. This function also changes the endianness
23362306a36Sopenharmony_ci * of each word if native endianness is different from SLI
23462306a36Sopenharmony_ci * endianness. This function can be called with or without
23562306a36Sopenharmony_ci * lock.
23662306a36Sopenharmony_ci **/
23762306a36Sopenharmony_cistatic void
23862306a36Sopenharmony_cilpfc_sli4_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	uint64_t *src = srcp;
24162306a36Sopenharmony_ci	uint64_t *dest = destp;
24262306a36Sopenharmony_ci	int i;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	for (i = 0; i < (int)cnt; i += sizeof(uint64_t))
24562306a36Sopenharmony_ci		*dest++ = *src++;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci#else
24862306a36Sopenharmony_ci#define lpfc_sli4_pcimem_bcopy(a, b, c) lpfc_sli_pcimem_bcopy(a, b, c)
24962306a36Sopenharmony_ci#endif
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci/**
25262306a36Sopenharmony_ci * lpfc_sli4_wq_put - Put a Work Queue Entry on an Work Queue
25362306a36Sopenharmony_ci * @q: The Work Queue to operate on.
25462306a36Sopenharmony_ci * @wqe: The work Queue Entry to put on the Work queue.
25562306a36Sopenharmony_ci *
25662306a36Sopenharmony_ci * This routine will copy the contents of @wqe to the next available entry on
25762306a36Sopenharmony_ci * the @q. This function will then ring the Work Queue Doorbell to signal the
25862306a36Sopenharmony_ci * HBA to start processing the Work Queue Entry. This function returns 0 if
25962306a36Sopenharmony_ci * successful. If no entries are available on @q then this function will return
26062306a36Sopenharmony_ci * -ENOMEM.
26162306a36Sopenharmony_ci * The caller is expected to hold the hbalock when calling this routine.
26262306a36Sopenharmony_ci **/
26362306a36Sopenharmony_cistatic int
26462306a36Sopenharmony_cilpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	union lpfc_wqe *temp_wqe;
26762306a36Sopenharmony_ci	struct lpfc_register doorbell;
26862306a36Sopenharmony_ci	uint32_t host_index;
26962306a36Sopenharmony_ci	uint32_t idx;
27062306a36Sopenharmony_ci	uint32_t i = 0;
27162306a36Sopenharmony_ci	uint8_t *tmp;
27262306a36Sopenharmony_ci	u32 if_type;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* sanity check on queue memory */
27562306a36Sopenharmony_ci	if (unlikely(!q))
27662306a36Sopenharmony_ci		return -ENOMEM;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	temp_wqe = lpfc_sli4_qe(q, q->host_index);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* If the host has not yet processed the next entry then we are done */
28162306a36Sopenharmony_ci	idx = ((q->host_index + 1) % q->entry_count);
28262306a36Sopenharmony_ci	if (idx == q->hba_index) {
28362306a36Sopenharmony_ci		q->WQ_overflow++;
28462306a36Sopenharmony_ci		return -EBUSY;
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci	q->WQ_posted++;
28762306a36Sopenharmony_ci	/* set consumption flag every once in a while */
28862306a36Sopenharmony_ci	if (!((q->host_index + 1) % q->notify_interval))
28962306a36Sopenharmony_ci		bf_set(wqe_wqec, &wqe->generic.wqe_com, 1);
29062306a36Sopenharmony_ci	else
29162306a36Sopenharmony_ci		bf_set(wqe_wqec, &wqe->generic.wqe_com, 0);
29262306a36Sopenharmony_ci	if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED)
29362306a36Sopenharmony_ci		bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id);
29462306a36Sopenharmony_ci	lpfc_sli4_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
29562306a36Sopenharmony_ci	if (q->dpp_enable && q->phba->cfg_enable_dpp) {
29662306a36Sopenharmony_ci		/* write to DPP aperture taking advatage of Combined Writes */
29762306a36Sopenharmony_ci		tmp = (uint8_t *)temp_wqe;
29862306a36Sopenharmony_ci#ifdef __raw_writeq
29962306a36Sopenharmony_ci		for (i = 0; i < q->entry_size; i += sizeof(uint64_t))
30062306a36Sopenharmony_ci			__raw_writeq(*((uint64_t *)(tmp + i)),
30162306a36Sopenharmony_ci					q->dpp_regaddr + i);
30262306a36Sopenharmony_ci#else
30362306a36Sopenharmony_ci		for (i = 0; i < q->entry_size; i += sizeof(uint32_t))
30462306a36Sopenharmony_ci			__raw_writel(*((uint32_t *)(tmp + i)),
30562306a36Sopenharmony_ci					q->dpp_regaddr + i);
30662306a36Sopenharmony_ci#endif
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci	/* ensure WQE bcopy and DPP flushed before doorbell write */
30962306a36Sopenharmony_ci	wmb();
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/* Update the host index before invoking device */
31262306a36Sopenharmony_ci	host_index = q->host_index;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	q->host_index = idx;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/* Ring Doorbell */
31762306a36Sopenharmony_ci	doorbell.word0 = 0;
31862306a36Sopenharmony_ci	if (q->db_format == LPFC_DB_LIST_FORMAT) {
31962306a36Sopenharmony_ci		if (q->dpp_enable && q->phba->cfg_enable_dpp) {
32062306a36Sopenharmony_ci			bf_set(lpfc_if6_wq_db_list_fm_num_posted, &doorbell, 1);
32162306a36Sopenharmony_ci			bf_set(lpfc_if6_wq_db_list_fm_dpp, &doorbell, 1);
32262306a36Sopenharmony_ci			bf_set(lpfc_if6_wq_db_list_fm_dpp_id, &doorbell,
32362306a36Sopenharmony_ci			    q->dpp_id);
32462306a36Sopenharmony_ci			bf_set(lpfc_if6_wq_db_list_fm_id, &doorbell,
32562306a36Sopenharmony_ci			    q->queue_id);
32662306a36Sopenharmony_ci		} else {
32762306a36Sopenharmony_ci			bf_set(lpfc_wq_db_list_fm_num_posted, &doorbell, 1);
32862306a36Sopenharmony_ci			bf_set(lpfc_wq_db_list_fm_id, &doorbell, q->queue_id);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci			/* Leave bits <23:16> clear for if_type 6 dpp */
33162306a36Sopenharmony_ci			if_type = bf_get(lpfc_sli_intf_if_type,
33262306a36Sopenharmony_ci					 &q->phba->sli4_hba.sli_intf);
33362306a36Sopenharmony_ci			if (if_type != LPFC_SLI_INTF_IF_TYPE_6)
33462306a36Sopenharmony_ci				bf_set(lpfc_wq_db_list_fm_index, &doorbell,
33562306a36Sopenharmony_ci				       host_index);
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci	} else if (q->db_format == LPFC_DB_RING_FORMAT) {
33862306a36Sopenharmony_ci		bf_set(lpfc_wq_db_ring_fm_num_posted, &doorbell, 1);
33962306a36Sopenharmony_ci		bf_set(lpfc_wq_db_ring_fm_id, &doorbell, q->queue_id);
34062306a36Sopenharmony_ci	} else {
34162306a36Sopenharmony_ci		return -EINVAL;
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci	writel(doorbell.word0, q->db_regaddr);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	return 0;
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/**
34962306a36Sopenharmony_ci * lpfc_sli4_wq_release - Updates internal hba index for WQ
35062306a36Sopenharmony_ci * @q: The Work Queue to operate on.
35162306a36Sopenharmony_ci * @index: The index to advance the hba index to.
35262306a36Sopenharmony_ci *
35362306a36Sopenharmony_ci * This routine will update the HBA index of a queue to reflect consumption of
35462306a36Sopenharmony_ci * Work Queue Entries by the HBA. When the HBA indicates that it has consumed
35562306a36Sopenharmony_ci * an entry the host calls this function to update the queue's internal
35662306a36Sopenharmony_ci * pointers.
35762306a36Sopenharmony_ci **/
35862306a36Sopenharmony_cistatic void
35962306a36Sopenharmony_cilpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	/* sanity check on queue memory */
36262306a36Sopenharmony_ci	if (unlikely(!q))
36362306a36Sopenharmony_ci		return;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	q->hba_index = index;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci/**
36962306a36Sopenharmony_ci * lpfc_sli4_mq_put - Put a Mailbox Queue Entry on an Mailbox Queue
37062306a36Sopenharmony_ci * @q: The Mailbox Queue to operate on.
37162306a36Sopenharmony_ci * @mqe: The Mailbox Queue Entry to put on the Work queue.
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * This routine will copy the contents of @mqe to the next available entry on
37462306a36Sopenharmony_ci * the @q. This function will then ring the Work Queue Doorbell to signal the
37562306a36Sopenharmony_ci * HBA to start processing the Work Queue Entry. This function returns 0 if
37662306a36Sopenharmony_ci * successful. If no entries are available on @q then this function will return
37762306a36Sopenharmony_ci * -ENOMEM.
37862306a36Sopenharmony_ci * The caller is expected to hold the hbalock when calling this routine.
37962306a36Sopenharmony_ci **/
38062306a36Sopenharmony_cistatic uint32_t
38162306a36Sopenharmony_cilpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct lpfc_mqe *temp_mqe;
38462306a36Sopenharmony_ci	struct lpfc_register doorbell;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/* sanity check on queue memory */
38762306a36Sopenharmony_ci	if (unlikely(!q))
38862306a36Sopenharmony_ci		return -ENOMEM;
38962306a36Sopenharmony_ci	temp_mqe = lpfc_sli4_qe(q, q->host_index);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* If the host has not yet processed the next entry then we are done */
39262306a36Sopenharmony_ci	if (((q->host_index + 1) % q->entry_count) == q->hba_index)
39362306a36Sopenharmony_ci		return -ENOMEM;
39462306a36Sopenharmony_ci	lpfc_sli4_pcimem_bcopy(mqe, temp_mqe, q->entry_size);
39562306a36Sopenharmony_ci	/* Save off the mailbox pointer for completion */
39662306a36Sopenharmony_ci	q->phba->mbox = (MAILBOX_t *)temp_mqe;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* Update the host index before invoking device */
39962306a36Sopenharmony_ci	q->host_index = ((q->host_index + 1) % q->entry_count);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/* Ring Doorbell */
40262306a36Sopenharmony_ci	doorbell.word0 = 0;
40362306a36Sopenharmony_ci	bf_set(lpfc_mq_doorbell_num_posted, &doorbell, 1);
40462306a36Sopenharmony_ci	bf_set(lpfc_mq_doorbell_id, &doorbell, q->queue_id);
40562306a36Sopenharmony_ci	writel(doorbell.word0, q->phba->sli4_hba.MQDBregaddr);
40662306a36Sopenharmony_ci	return 0;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci/**
41062306a36Sopenharmony_ci * lpfc_sli4_mq_release - Updates internal hba index for MQ
41162306a36Sopenharmony_ci * @q: The Mailbox Queue to operate on.
41262306a36Sopenharmony_ci *
41362306a36Sopenharmony_ci * This routine will update the HBA index of a queue to reflect consumption of
41462306a36Sopenharmony_ci * a Mailbox Queue Entry by the HBA. When the HBA indicates that it has consumed
41562306a36Sopenharmony_ci * an entry the host calls this function to update the queue's internal
41662306a36Sopenharmony_ci * pointers. This routine returns the number of entries that were consumed by
41762306a36Sopenharmony_ci * the HBA.
41862306a36Sopenharmony_ci **/
41962306a36Sopenharmony_cistatic uint32_t
42062306a36Sopenharmony_cilpfc_sli4_mq_release(struct lpfc_queue *q)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	/* sanity check on queue memory */
42362306a36Sopenharmony_ci	if (unlikely(!q))
42462306a36Sopenharmony_ci		return 0;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* Clear the mailbox pointer for completion */
42762306a36Sopenharmony_ci	q->phba->mbox = NULL;
42862306a36Sopenharmony_ci	q->hba_index = ((q->hba_index + 1) % q->entry_count);
42962306a36Sopenharmony_ci	return 1;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci/**
43362306a36Sopenharmony_ci * lpfc_sli4_eq_get - Gets the next valid EQE from a EQ
43462306a36Sopenharmony_ci * @q: The Event Queue to get the first valid EQE from
43562306a36Sopenharmony_ci *
43662306a36Sopenharmony_ci * This routine will get the first valid Event Queue Entry from @q, update
43762306a36Sopenharmony_ci * the queue's internal hba index, and return the EQE. If no valid EQEs are in
43862306a36Sopenharmony_ci * the Queue (no more work to do), or the Queue is full of EQEs that have been
43962306a36Sopenharmony_ci * processed, but not popped back to the HBA then this routine will return NULL.
44062306a36Sopenharmony_ci **/
44162306a36Sopenharmony_cistatic struct lpfc_eqe *
44262306a36Sopenharmony_cilpfc_sli4_eq_get(struct lpfc_queue *q)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct lpfc_eqe *eqe;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/* sanity check on queue memory */
44762306a36Sopenharmony_ci	if (unlikely(!q))
44862306a36Sopenharmony_ci		return NULL;
44962306a36Sopenharmony_ci	eqe = lpfc_sli4_qe(q, q->host_index);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	/* If the next EQE is not valid then we are done */
45262306a36Sopenharmony_ci	if (bf_get_le32(lpfc_eqe_valid, eqe) != q->qe_valid)
45362306a36Sopenharmony_ci		return NULL;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/*
45662306a36Sopenharmony_ci	 * insert barrier for instruction interlock : data from the hardware
45762306a36Sopenharmony_ci	 * must have the valid bit checked before it can be copied and acted
45862306a36Sopenharmony_ci	 * upon. Speculative instructions were allowing a bcopy at the start
45962306a36Sopenharmony_ci	 * of lpfc_sli4_fp_handle_wcqe(), which is called immediately
46062306a36Sopenharmony_ci	 * after our return, to copy data before the valid bit check above
46162306a36Sopenharmony_ci	 * was done. As such, some of the copied data was stale. The barrier
46262306a36Sopenharmony_ci	 * ensures the check is before any data is copied.
46362306a36Sopenharmony_ci	 */
46462306a36Sopenharmony_ci	mb();
46562306a36Sopenharmony_ci	return eqe;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci/**
46962306a36Sopenharmony_ci * lpfc_sli4_eq_clr_intr - Turn off interrupts from this EQ
47062306a36Sopenharmony_ci * @q: The Event Queue to disable interrupts
47162306a36Sopenharmony_ci *
47262306a36Sopenharmony_ci **/
47362306a36Sopenharmony_civoid
47462306a36Sopenharmony_cilpfc_sli4_eq_clr_intr(struct lpfc_queue *q)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	struct lpfc_register doorbell;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	doorbell.word0 = 0;
47962306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1);
48062306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT);
48162306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell,
48262306a36Sopenharmony_ci		(q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT));
48362306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id);
48462306a36Sopenharmony_ci	writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/**
48862306a36Sopenharmony_ci * lpfc_sli4_if6_eq_clr_intr - Turn off interrupts from this EQ
48962306a36Sopenharmony_ci * @q: The Event Queue to disable interrupts
49062306a36Sopenharmony_ci *
49162306a36Sopenharmony_ci **/
49262306a36Sopenharmony_civoid
49362306a36Sopenharmony_cilpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct lpfc_register doorbell;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	doorbell.word0 = 0;
49862306a36Sopenharmony_ci	bf_set(lpfc_if6_eq_doorbell_eqid, &doorbell, q->queue_id);
49962306a36Sopenharmony_ci	writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci/**
50362306a36Sopenharmony_ci * lpfc_sli4_write_eq_db - write EQ DB for eqe's consumed or arm state
50462306a36Sopenharmony_ci * @phba: adapter with EQ
50562306a36Sopenharmony_ci * @q: The Event Queue that the host has completed processing for.
50662306a36Sopenharmony_ci * @count: Number of elements that have been consumed
50762306a36Sopenharmony_ci * @arm: Indicates whether the host wants to arms this CQ.
50862306a36Sopenharmony_ci *
50962306a36Sopenharmony_ci * This routine will notify the HBA, by ringing the doorbell, that count
51062306a36Sopenharmony_ci * number of EQEs have been processed. The @arm parameter indicates whether
51162306a36Sopenharmony_ci * the queue should be rearmed when ringing the doorbell.
51262306a36Sopenharmony_ci **/
51362306a36Sopenharmony_civoid
51462306a36Sopenharmony_cilpfc_sli4_write_eq_db(struct lpfc_hba *phba, struct lpfc_queue *q,
51562306a36Sopenharmony_ci		     uint32_t count, bool arm)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	struct lpfc_register doorbell;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/* sanity check on queue memory */
52062306a36Sopenharmony_ci	if (unlikely(!q || (count == 0 && !arm)))
52162306a36Sopenharmony_ci		return;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* ring doorbell for number popped */
52462306a36Sopenharmony_ci	doorbell.word0 = 0;
52562306a36Sopenharmony_ci	if (arm) {
52662306a36Sopenharmony_ci		bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1);
52762306a36Sopenharmony_ci		bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1);
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, count);
53062306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT);
53162306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell,
53262306a36Sopenharmony_ci			(q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT));
53362306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id);
53462306a36Sopenharmony_ci	writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
53562306a36Sopenharmony_ci	/* PCI read to flush PCI pipeline on re-arming for INTx mode */
53662306a36Sopenharmony_ci	if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM))
53762306a36Sopenharmony_ci		readl(q->phba->sli4_hba.EQDBregaddr);
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci/**
54162306a36Sopenharmony_ci * lpfc_sli4_if6_write_eq_db - write EQ DB for eqe's consumed or arm state
54262306a36Sopenharmony_ci * @phba: adapter with EQ
54362306a36Sopenharmony_ci * @q: The Event Queue that the host has completed processing for.
54462306a36Sopenharmony_ci * @count: Number of elements that have been consumed
54562306a36Sopenharmony_ci * @arm: Indicates whether the host wants to arms this CQ.
54662306a36Sopenharmony_ci *
54762306a36Sopenharmony_ci * This routine will notify the HBA, by ringing the doorbell, that count
54862306a36Sopenharmony_ci * number of EQEs have been processed. The @arm parameter indicates whether
54962306a36Sopenharmony_ci * the queue should be rearmed when ringing the doorbell.
55062306a36Sopenharmony_ci **/
55162306a36Sopenharmony_civoid
55262306a36Sopenharmony_cilpfc_sli4_if6_write_eq_db(struct lpfc_hba *phba, struct lpfc_queue *q,
55362306a36Sopenharmony_ci			  uint32_t count, bool arm)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	struct lpfc_register doorbell;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	/* sanity check on queue memory */
55862306a36Sopenharmony_ci	if (unlikely(!q || (count == 0 && !arm)))
55962306a36Sopenharmony_ci		return;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	/* ring doorbell for number popped */
56262306a36Sopenharmony_ci	doorbell.word0 = 0;
56362306a36Sopenharmony_ci	if (arm)
56462306a36Sopenharmony_ci		bf_set(lpfc_if6_eq_doorbell_arm, &doorbell, 1);
56562306a36Sopenharmony_ci	bf_set(lpfc_if6_eq_doorbell_num_released, &doorbell, count);
56662306a36Sopenharmony_ci	bf_set(lpfc_if6_eq_doorbell_eqid, &doorbell, q->queue_id);
56762306a36Sopenharmony_ci	writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
56862306a36Sopenharmony_ci	/* PCI read to flush PCI pipeline on re-arming for INTx mode */
56962306a36Sopenharmony_ci	if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM))
57062306a36Sopenharmony_ci		readl(q->phba->sli4_hba.EQDBregaddr);
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic void
57462306a36Sopenharmony_ci__lpfc_sli4_consume_eqe(struct lpfc_hba *phba, struct lpfc_queue *eq,
57562306a36Sopenharmony_ci			struct lpfc_eqe *eqe)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	if (!phba->sli4_hba.pc_sli4_params.eqav)
57862306a36Sopenharmony_ci		bf_set_le32(lpfc_eqe_valid, eqe, 0);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	eq->host_index = ((eq->host_index + 1) % eq->entry_count);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* if the index wrapped around, toggle the valid bit */
58362306a36Sopenharmony_ci	if (phba->sli4_hba.pc_sli4_params.eqav && !eq->host_index)
58462306a36Sopenharmony_ci		eq->qe_valid = (eq->qe_valid) ? 0 : 1;
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic void
58862306a36Sopenharmony_cilpfc_sli4_eqcq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct lpfc_eqe *eqe = NULL;
59162306a36Sopenharmony_ci	u32 eq_count = 0, cq_count = 0;
59262306a36Sopenharmony_ci	struct lpfc_cqe *cqe = NULL;
59362306a36Sopenharmony_ci	struct lpfc_queue *cq = NULL, *childq = NULL;
59462306a36Sopenharmony_ci	int cqid = 0;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	/* walk all the EQ entries and drop on the floor */
59762306a36Sopenharmony_ci	eqe = lpfc_sli4_eq_get(eq);
59862306a36Sopenharmony_ci	while (eqe) {
59962306a36Sopenharmony_ci		/* Get the reference to the corresponding CQ */
60062306a36Sopenharmony_ci		cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
60162306a36Sopenharmony_ci		cq = NULL;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci		list_for_each_entry(childq, &eq->child_list, list) {
60462306a36Sopenharmony_ci			if (childq->queue_id == cqid) {
60562306a36Sopenharmony_ci				cq = childq;
60662306a36Sopenharmony_ci				break;
60762306a36Sopenharmony_ci			}
60862306a36Sopenharmony_ci		}
60962306a36Sopenharmony_ci		/* If CQ is valid, iterate through it and drop all the CQEs */
61062306a36Sopenharmony_ci		if (cq) {
61162306a36Sopenharmony_ci			cqe = lpfc_sli4_cq_get(cq);
61262306a36Sopenharmony_ci			while (cqe) {
61362306a36Sopenharmony_ci				__lpfc_sli4_consume_cqe(phba, cq, cqe);
61462306a36Sopenharmony_ci				cq_count++;
61562306a36Sopenharmony_ci				cqe = lpfc_sli4_cq_get(cq);
61662306a36Sopenharmony_ci			}
61762306a36Sopenharmony_ci			/* Clear and re-arm the CQ */
61862306a36Sopenharmony_ci			phba->sli4_hba.sli4_write_cq_db(phba, cq, cq_count,
61962306a36Sopenharmony_ci			    LPFC_QUEUE_REARM);
62062306a36Sopenharmony_ci			cq_count = 0;
62162306a36Sopenharmony_ci		}
62262306a36Sopenharmony_ci		__lpfc_sli4_consume_eqe(phba, eq, eqe);
62362306a36Sopenharmony_ci		eq_count++;
62462306a36Sopenharmony_ci		eqe = lpfc_sli4_eq_get(eq);
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	/* Clear and re-arm the EQ */
62862306a36Sopenharmony_ci	phba->sli4_hba.sli4_write_eq_db(phba, eq, eq_count, LPFC_QUEUE_REARM);
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic int
63262306a36Sopenharmony_cilpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq,
63362306a36Sopenharmony_ci		     u8 rearm, enum lpfc_poll_mode poll_mode)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct lpfc_eqe *eqe;
63662306a36Sopenharmony_ci	int count = 0, consumed = 0;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	if (cmpxchg(&eq->queue_claimed, 0, 1) != 0)
63962306a36Sopenharmony_ci		goto rearm_and_exit;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	eqe = lpfc_sli4_eq_get(eq);
64262306a36Sopenharmony_ci	while (eqe) {
64362306a36Sopenharmony_ci		lpfc_sli4_hba_handle_eqe(phba, eq, eqe, poll_mode);
64462306a36Sopenharmony_ci		__lpfc_sli4_consume_eqe(phba, eq, eqe);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		consumed++;
64762306a36Sopenharmony_ci		if (!(++count % eq->max_proc_limit))
64862306a36Sopenharmony_ci			break;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci		if (!(count % eq->notify_interval)) {
65162306a36Sopenharmony_ci			phba->sli4_hba.sli4_write_eq_db(phba, eq, consumed,
65262306a36Sopenharmony_ci							LPFC_QUEUE_NOARM);
65362306a36Sopenharmony_ci			consumed = 0;
65462306a36Sopenharmony_ci		}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci		eqe = lpfc_sli4_eq_get(eq);
65762306a36Sopenharmony_ci	}
65862306a36Sopenharmony_ci	eq->EQ_processed += count;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	/* Track the max number of EQEs processed in 1 intr */
66162306a36Sopenharmony_ci	if (count > eq->EQ_max_eqe)
66262306a36Sopenharmony_ci		eq->EQ_max_eqe = count;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	xchg(&eq->queue_claimed, 0);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cirearm_and_exit:
66762306a36Sopenharmony_ci	/* Always clear the EQ. */
66862306a36Sopenharmony_ci	phba->sli4_hba.sli4_write_eq_db(phba, eq, consumed, rearm);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	return count;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci/**
67462306a36Sopenharmony_ci * lpfc_sli4_cq_get - Gets the next valid CQE from a CQ
67562306a36Sopenharmony_ci * @q: The Completion Queue to get the first valid CQE from
67662306a36Sopenharmony_ci *
67762306a36Sopenharmony_ci * This routine will get the first valid Completion Queue Entry from @q, update
67862306a36Sopenharmony_ci * the queue's internal hba index, and return the CQE. If no valid CQEs are in
67962306a36Sopenharmony_ci * the Queue (no more work to do), or the Queue is full of CQEs that have been
68062306a36Sopenharmony_ci * processed, but not popped back to the HBA then this routine will return NULL.
68162306a36Sopenharmony_ci **/
68262306a36Sopenharmony_cistatic struct lpfc_cqe *
68362306a36Sopenharmony_cilpfc_sli4_cq_get(struct lpfc_queue *q)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	struct lpfc_cqe *cqe;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	/* sanity check on queue memory */
68862306a36Sopenharmony_ci	if (unlikely(!q))
68962306a36Sopenharmony_ci		return NULL;
69062306a36Sopenharmony_ci	cqe = lpfc_sli4_qe(q, q->host_index);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	/* If the next CQE is not valid then we are done */
69362306a36Sopenharmony_ci	if (bf_get_le32(lpfc_cqe_valid, cqe) != q->qe_valid)
69462306a36Sopenharmony_ci		return NULL;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	/*
69762306a36Sopenharmony_ci	 * insert barrier for instruction interlock : data from the hardware
69862306a36Sopenharmony_ci	 * must have the valid bit checked before it can be copied and acted
69962306a36Sopenharmony_ci	 * upon. Given what was seen in lpfc_sli4_cq_get() of speculative
70062306a36Sopenharmony_ci	 * instructions allowing action on content before valid bit checked,
70162306a36Sopenharmony_ci	 * add barrier here as well. May not be needed as "content" is a
70262306a36Sopenharmony_ci	 * single 32-bit entity here (vs multi word structure for cq's).
70362306a36Sopenharmony_ci	 */
70462306a36Sopenharmony_ci	mb();
70562306a36Sopenharmony_ci	return cqe;
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic void
70962306a36Sopenharmony_ci__lpfc_sli4_consume_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
71062306a36Sopenharmony_ci			struct lpfc_cqe *cqe)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	if (!phba->sli4_hba.pc_sli4_params.cqav)
71362306a36Sopenharmony_ci		bf_set_le32(lpfc_cqe_valid, cqe, 0);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	cq->host_index = ((cq->host_index + 1) % cq->entry_count);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* if the index wrapped around, toggle the valid bit */
71862306a36Sopenharmony_ci	if (phba->sli4_hba.pc_sli4_params.cqav && !cq->host_index)
71962306a36Sopenharmony_ci		cq->qe_valid = (cq->qe_valid) ? 0 : 1;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci/**
72362306a36Sopenharmony_ci * lpfc_sli4_write_cq_db - write cq DB for entries consumed or arm state.
72462306a36Sopenharmony_ci * @phba: the adapter with the CQ
72562306a36Sopenharmony_ci * @q: The Completion Queue that the host has completed processing for.
72662306a36Sopenharmony_ci * @count: the number of elements that were consumed
72762306a36Sopenharmony_ci * @arm: Indicates whether the host wants to arms this CQ.
72862306a36Sopenharmony_ci *
72962306a36Sopenharmony_ci * This routine will notify the HBA, by ringing the doorbell, that the
73062306a36Sopenharmony_ci * CQEs have been processed. The @arm parameter specifies whether the
73162306a36Sopenharmony_ci * queue should be rearmed when ringing the doorbell.
73262306a36Sopenharmony_ci **/
73362306a36Sopenharmony_civoid
73462306a36Sopenharmony_cilpfc_sli4_write_cq_db(struct lpfc_hba *phba, struct lpfc_queue *q,
73562306a36Sopenharmony_ci		     uint32_t count, bool arm)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	struct lpfc_register doorbell;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	/* sanity check on queue memory */
74062306a36Sopenharmony_ci	if (unlikely(!q || (count == 0 && !arm)))
74162306a36Sopenharmony_ci		return;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	/* ring doorbell for number popped */
74462306a36Sopenharmony_ci	doorbell.word0 = 0;
74562306a36Sopenharmony_ci	if (arm)
74662306a36Sopenharmony_ci		bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1);
74762306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, count);
74862306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_COMPLETION);
74962306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_cqid_hi, &doorbell,
75062306a36Sopenharmony_ci			(q->queue_id >> LPFC_CQID_HI_FIELD_SHIFT));
75162306a36Sopenharmony_ci	bf_set(lpfc_eqcq_doorbell_cqid_lo, &doorbell, q->queue_id);
75262306a36Sopenharmony_ci	writel(doorbell.word0, q->phba->sli4_hba.CQDBregaddr);
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci/**
75662306a36Sopenharmony_ci * lpfc_sli4_if6_write_cq_db - write cq DB for entries consumed or arm state.
75762306a36Sopenharmony_ci * @phba: the adapter with the CQ
75862306a36Sopenharmony_ci * @q: The Completion Queue that the host has completed processing for.
75962306a36Sopenharmony_ci * @count: the number of elements that were consumed
76062306a36Sopenharmony_ci * @arm: Indicates whether the host wants to arms this CQ.
76162306a36Sopenharmony_ci *
76262306a36Sopenharmony_ci * This routine will notify the HBA, by ringing the doorbell, that the
76362306a36Sopenharmony_ci * CQEs have been processed. The @arm parameter specifies whether the
76462306a36Sopenharmony_ci * queue should be rearmed when ringing the doorbell.
76562306a36Sopenharmony_ci **/
76662306a36Sopenharmony_civoid
76762306a36Sopenharmony_cilpfc_sli4_if6_write_cq_db(struct lpfc_hba *phba, struct lpfc_queue *q,
76862306a36Sopenharmony_ci			 uint32_t count, bool arm)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	struct lpfc_register doorbell;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	/* sanity check on queue memory */
77362306a36Sopenharmony_ci	if (unlikely(!q || (count == 0 && !arm)))
77462306a36Sopenharmony_ci		return;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	/* ring doorbell for number popped */
77762306a36Sopenharmony_ci	doorbell.word0 = 0;
77862306a36Sopenharmony_ci	if (arm)
77962306a36Sopenharmony_ci		bf_set(lpfc_if6_cq_doorbell_arm, &doorbell, 1);
78062306a36Sopenharmony_ci	bf_set(lpfc_if6_cq_doorbell_num_released, &doorbell, count);
78162306a36Sopenharmony_ci	bf_set(lpfc_if6_cq_doorbell_cqid, &doorbell, q->queue_id);
78262306a36Sopenharmony_ci	writel(doorbell.word0, q->phba->sli4_hba.CQDBregaddr);
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci/*
78662306a36Sopenharmony_ci * lpfc_sli4_rq_put - Put a Receive Buffer Queue Entry on a Receive Queue
78762306a36Sopenharmony_ci *
78862306a36Sopenharmony_ci * This routine will copy the contents of @wqe to the next available entry on
78962306a36Sopenharmony_ci * the @q. This function will then ring the Receive Queue Doorbell to signal the
79062306a36Sopenharmony_ci * HBA to start processing the Receive Queue Entry. This function returns the
79162306a36Sopenharmony_ci * index that the rqe was copied to if successful. If no entries are available
79262306a36Sopenharmony_ci * on @q then this function will return -ENOMEM.
79362306a36Sopenharmony_ci * The caller is expected to hold the hbalock when calling this routine.
79462306a36Sopenharmony_ci **/
79562306a36Sopenharmony_ciint
79662306a36Sopenharmony_cilpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq,
79762306a36Sopenharmony_ci		 struct lpfc_rqe *hrqe, struct lpfc_rqe *drqe)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	struct lpfc_rqe *temp_hrqe;
80062306a36Sopenharmony_ci	struct lpfc_rqe *temp_drqe;
80162306a36Sopenharmony_ci	struct lpfc_register doorbell;
80262306a36Sopenharmony_ci	int hq_put_index;
80362306a36Sopenharmony_ci	int dq_put_index;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	/* sanity check on queue memory */
80662306a36Sopenharmony_ci	if (unlikely(!hq) || unlikely(!dq))
80762306a36Sopenharmony_ci		return -ENOMEM;
80862306a36Sopenharmony_ci	hq_put_index = hq->host_index;
80962306a36Sopenharmony_ci	dq_put_index = dq->host_index;
81062306a36Sopenharmony_ci	temp_hrqe = lpfc_sli4_qe(hq, hq_put_index);
81162306a36Sopenharmony_ci	temp_drqe = lpfc_sli4_qe(dq, dq_put_index);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	if (hq->type != LPFC_HRQ || dq->type != LPFC_DRQ)
81462306a36Sopenharmony_ci		return -EINVAL;
81562306a36Sopenharmony_ci	if (hq_put_index != dq_put_index)
81662306a36Sopenharmony_ci		return -EINVAL;
81762306a36Sopenharmony_ci	/* If the host has not yet processed the next entry then we are done */
81862306a36Sopenharmony_ci	if (((hq_put_index + 1) % hq->entry_count) == hq->hba_index)
81962306a36Sopenharmony_ci		return -EBUSY;
82062306a36Sopenharmony_ci	lpfc_sli4_pcimem_bcopy(hrqe, temp_hrqe, hq->entry_size);
82162306a36Sopenharmony_ci	lpfc_sli4_pcimem_bcopy(drqe, temp_drqe, dq->entry_size);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	/* Update the host index to point to the next slot */
82462306a36Sopenharmony_ci	hq->host_index = ((hq_put_index + 1) % hq->entry_count);
82562306a36Sopenharmony_ci	dq->host_index = ((dq_put_index + 1) % dq->entry_count);
82662306a36Sopenharmony_ci	hq->RQ_buf_posted++;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	/* Ring The Header Receive Queue Doorbell */
82962306a36Sopenharmony_ci	if (!(hq->host_index % hq->notify_interval)) {
83062306a36Sopenharmony_ci		doorbell.word0 = 0;
83162306a36Sopenharmony_ci		if (hq->db_format == LPFC_DB_RING_FORMAT) {
83262306a36Sopenharmony_ci			bf_set(lpfc_rq_db_ring_fm_num_posted, &doorbell,
83362306a36Sopenharmony_ci			       hq->notify_interval);
83462306a36Sopenharmony_ci			bf_set(lpfc_rq_db_ring_fm_id, &doorbell, hq->queue_id);
83562306a36Sopenharmony_ci		} else if (hq->db_format == LPFC_DB_LIST_FORMAT) {
83662306a36Sopenharmony_ci			bf_set(lpfc_rq_db_list_fm_num_posted, &doorbell,
83762306a36Sopenharmony_ci			       hq->notify_interval);
83862306a36Sopenharmony_ci			bf_set(lpfc_rq_db_list_fm_index, &doorbell,
83962306a36Sopenharmony_ci			       hq->host_index);
84062306a36Sopenharmony_ci			bf_set(lpfc_rq_db_list_fm_id, &doorbell, hq->queue_id);
84162306a36Sopenharmony_ci		} else {
84262306a36Sopenharmony_ci			return -EINVAL;
84362306a36Sopenharmony_ci		}
84462306a36Sopenharmony_ci		writel(doorbell.word0, hq->db_regaddr);
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci	return hq_put_index;
84762306a36Sopenharmony_ci}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci/*
85062306a36Sopenharmony_ci * lpfc_sli4_rq_release - Updates internal hba index for RQ
85162306a36Sopenharmony_ci *
85262306a36Sopenharmony_ci * This routine will update the HBA index of a queue to reflect consumption of
85362306a36Sopenharmony_ci * one Receive Queue Entry by the HBA. When the HBA indicates that it has
85462306a36Sopenharmony_ci * consumed an entry the host calls this function to update the queue's
85562306a36Sopenharmony_ci * internal pointers. This routine returns the number of entries that were
85662306a36Sopenharmony_ci * consumed by the HBA.
85762306a36Sopenharmony_ci **/
85862306a36Sopenharmony_cistatic uint32_t
85962306a36Sopenharmony_cilpfc_sli4_rq_release(struct lpfc_queue *hq, struct lpfc_queue *dq)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	/* sanity check on queue memory */
86262306a36Sopenharmony_ci	if (unlikely(!hq) || unlikely(!dq))
86362306a36Sopenharmony_ci		return 0;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	if ((hq->type != LPFC_HRQ) || (dq->type != LPFC_DRQ))
86662306a36Sopenharmony_ci		return 0;
86762306a36Sopenharmony_ci	hq->hba_index = ((hq->hba_index + 1) % hq->entry_count);
86862306a36Sopenharmony_ci	dq->hba_index = ((dq->hba_index + 1) % dq->entry_count);
86962306a36Sopenharmony_ci	return 1;
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci/**
87362306a36Sopenharmony_ci * lpfc_cmd_iocb - Get next command iocb entry in the ring
87462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
87562306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
87662306a36Sopenharmony_ci *
87762306a36Sopenharmony_ci * This function returns pointer to next command iocb entry
87862306a36Sopenharmony_ci * in the command ring. The caller must hold hbalock to prevent
87962306a36Sopenharmony_ci * other threads consume the next command iocb.
88062306a36Sopenharmony_ci * SLI-2/SLI-3 provide different sized iocbs.
88162306a36Sopenharmony_ci **/
88262306a36Sopenharmony_cistatic inline IOCB_t *
88362306a36Sopenharmony_cilpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	return (IOCB_t *) (((char *) pring->sli.sli3.cmdringaddr) +
88662306a36Sopenharmony_ci			   pring->sli.sli3.cmdidx * phba->iocb_cmd_size);
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci/**
89062306a36Sopenharmony_ci * lpfc_resp_iocb - Get next response iocb entry in the ring
89162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
89262306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
89362306a36Sopenharmony_ci *
89462306a36Sopenharmony_ci * This function returns pointer to next response iocb entry
89562306a36Sopenharmony_ci * in the response ring. The caller must hold hbalock to make sure
89662306a36Sopenharmony_ci * that no other thread consume the next response iocb.
89762306a36Sopenharmony_ci * SLI-2/SLI-3 provide different sized iocbs.
89862306a36Sopenharmony_ci **/
89962306a36Sopenharmony_cistatic inline IOCB_t *
90062306a36Sopenharmony_cilpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	return (IOCB_t *) (((char *) pring->sli.sli3.rspringaddr) +
90362306a36Sopenharmony_ci			   pring->sli.sli3.rspidx * phba->iocb_rsp_size);
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci/**
90762306a36Sopenharmony_ci * __lpfc_sli_get_iocbq - Allocates an iocb object from iocb pool
90862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
90962306a36Sopenharmony_ci *
91062306a36Sopenharmony_ci * This function is called with hbalock held. This function
91162306a36Sopenharmony_ci * allocates a new driver iocb object from the iocb pool. If the
91262306a36Sopenharmony_ci * allocation is successful, it returns pointer to the newly
91362306a36Sopenharmony_ci * allocated iocb object else it returns NULL.
91462306a36Sopenharmony_ci **/
91562306a36Sopenharmony_cistruct lpfc_iocbq *
91662306a36Sopenharmony_ci__lpfc_sli_get_iocbq(struct lpfc_hba *phba)
91762306a36Sopenharmony_ci{
91862306a36Sopenharmony_ci	struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
91962306a36Sopenharmony_ci	struct lpfc_iocbq * iocbq = NULL;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list);
92462306a36Sopenharmony_ci	if (iocbq)
92562306a36Sopenharmony_ci		phba->iocb_cnt++;
92662306a36Sopenharmony_ci	if (phba->iocb_cnt > phba->iocb_max)
92762306a36Sopenharmony_ci		phba->iocb_max = phba->iocb_cnt;
92862306a36Sopenharmony_ci	return iocbq;
92962306a36Sopenharmony_ci}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci/**
93262306a36Sopenharmony_ci * __lpfc_clear_active_sglq - Remove the active sglq for this XRI.
93362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
93462306a36Sopenharmony_ci * @xritag: XRI value.
93562306a36Sopenharmony_ci *
93662306a36Sopenharmony_ci * This function clears the sglq pointer from the array of active
93762306a36Sopenharmony_ci * sglq's. The xritag that is passed in is used to index into the
93862306a36Sopenharmony_ci * array. Before the xritag can be used it needs to be adjusted
93962306a36Sopenharmony_ci * by subtracting the xribase.
94062306a36Sopenharmony_ci *
94162306a36Sopenharmony_ci * Returns sglq ponter = success, NULL = Failure.
94262306a36Sopenharmony_ci **/
94362306a36Sopenharmony_cistruct lpfc_sglq *
94462306a36Sopenharmony_ci__lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	struct lpfc_sglq *sglq;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	sglq = phba->sli4_hba.lpfc_sglq_active_list[xritag];
94962306a36Sopenharmony_ci	phba->sli4_hba.lpfc_sglq_active_list[xritag] = NULL;
95062306a36Sopenharmony_ci	return sglq;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci/**
95462306a36Sopenharmony_ci * __lpfc_get_active_sglq - Get the active sglq for this XRI.
95562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
95662306a36Sopenharmony_ci * @xritag: XRI value.
95762306a36Sopenharmony_ci *
95862306a36Sopenharmony_ci * This function returns the sglq pointer from the array of active
95962306a36Sopenharmony_ci * sglq's. The xritag that is passed in is used to index into the
96062306a36Sopenharmony_ci * array. Before the xritag can be used it needs to be adjusted
96162306a36Sopenharmony_ci * by subtracting the xribase.
96262306a36Sopenharmony_ci *
96362306a36Sopenharmony_ci * Returns sglq ponter = success, NULL = Failure.
96462306a36Sopenharmony_ci **/
96562306a36Sopenharmony_cistruct lpfc_sglq *
96662306a36Sopenharmony_ci__lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	struct lpfc_sglq *sglq;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	sglq =  phba->sli4_hba.lpfc_sglq_active_list[xritag];
97162306a36Sopenharmony_ci	return sglq;
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci/**
97562306a36Sopenharmony_ci * lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap.
97662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
97762306a36Sopenharmony_ci * @xritag: xri used in this exchange.
97862306a36Sopenharmony_ci * @rrq: The RRQ to be cleared.
97962306a36Sopenharmony_ci *
98062306a36Sopenharmony_ci **/
98162306a36Sopenharmony_civoid
98262306a36Sopenharmony_cilpfc_clr_rrq_active(struct lpfc_hba *phba,
98362306a36Sopenharmony_ci		    uint16_t xritag,
98462306a36Sopenharmony_ci		    struct lpfc_node_rrq *rrq)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp = NULL;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	/* Lookup did to verify if did is still active on this vport */
98962306a36Sopenharmony_ci	if (rrq->vport)
99062306a36Sopenharmony_ci		ndlp = lpfc_findnode_did(rrq->vport, rrq->nlp_DID);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	if (!ndlp)
99362306a36Sopenharmony_ci		goto out;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	if (test_and_clear_bit(xritag, ndlp->active_rrqs_xri_bitmap)) {
99662306a36Sopenharmony_ci		rrq->send_rrq = 0;
99762306a36Sopenharmony_ci		rrq->xritag = 0;
99862306a36Sopenharmony_ci		rrq->rrq_stop_time = 0;
99962306a36Sopenharmony_ci	}
100062306a36Sopenharmony_ciout:
100162306a36Sopenharmony_ci	mempool_free(rrq, phba->rrq_pool);
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci/**
100562306a36Sopenharmony_ci * lpfc_handle_rrq_active - Checks if RRQ has waithed RATOV.
100662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
100762306a36Sopenharmony_ci *
100862306a36Sopenharmony_ci * This function is called with hbalock held. This function
100962306a36Sopenharmony_ci * Checks if stop_time (ratov from setting rrq active) has
101062306a36Sopenharmony_ci * been reached, if it has and the send_rrq flag is set then
101162306a36Sopenharmony_ci * it will call lpfc_send_rrq. If the send_rrq flag is not set
101262306a36Sopenharmony_ci * then it will just call the routine to clear the rrq and
101362306a36Sopenharmony_ci * free the rrq resource.
101462306a36Sopenharmony_ci * The timer is set to the next rrq that is going to expire before
101562306a36Sopenharmony_ci * leaving the routine.
101662306a36Sopenharmony_ci *
101762306a36Sopenharmony_ci **/
101862306a36Sopenharmony_civoid
101962306a36Sopenharmony_cilpfc_handle_rrq_active(struct lpfc_hba *phba)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	struct lpfc_node_rrq *rrq;
102262306a36Sopenharmony_ci	struct lpfc_node_rrq *nextrrq;
102362306a36Sopenharmony_ci	unsigned long next_time;
102462306a36Sopenharmony_ci	unsigned long iflags;
102562306a36Sopenharmony_ci	LIST_HEAD(send_rrq);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
102862306a36Sopenharmony_ci	phba->hba_flag &= ~HBA_RRQ_ACTIVE;
102962306a36Sopenharmony_ci	next_time = jiffies + msecs_to_jiffies(1000 * (phba->fc_ratov + 1));
103062306a36Sopenharmony_ci	list_for_each_entry_safe(rrq, nextrrq,
103162306a36Sopenharmony_ci				 &phba->active_rrq_list, list) {
103262306a36Sopenharmony_ci		if (time_after(jiffies, rrq->rrq_stop_time))
103362306a36Sopenharmony_ci			list_move(&rrq->list, &send_rrq);
103462306a36Sopenharmony_ci		else if (time_before(rrq->rrq_stop_time, next_time))
103562306a36Sopenharmony_ci			next_time = rrq->rrq_stop_time;
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
103862306a36Sopenharmony_ci	if ((!list_empty(&phba->active_rrq_list)) &&
103962306a36Sopenharmony_ci	    (!(phba->pport->load_flag & FC_UNLOADING)))
104062306a36Sopenharmony_ci		mod_timer(&phba->rrq_tmr, next_time);
104162306a36Sopenharmony_ci	list_for_each_entry_safe(rrq, nextrrq, &send_rrq, list) {
104262306a36Sopenharmony_ci		list_del(&rrq->list);
104362306a36Sopenharmony_ci		if (!rrq->send_rrq) {
104462306a36Sopenharmony_ci			/* this call will free the rrq */
104562306a36Sopenharmony_ci			lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
104662306a36Sopenharmony_ci		} else if (lpfc_send_rrq(phba, rrq)) {
104762306a36Sopenharmony_ci			/* if we send the rrq then the completion handler
104862306a36Sopenharmony_ci			*  will clear the bit in the xribitmap.
104962306a36Sopenharmony_ci			*/
105062306a36Sopenharmony_ci			lpfc_clr_rrq_active(phba, rrq->xritag,
105162306a36Sopenharmony_ci					    rrq);
105262306a36Sopenharmony_ci		}
105362306a36Sopenharmony_ci	}
105462306a36Sopenharmony_ci}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci/**
105762306a36Sopenharmony_ci * lpfc_get_active_rrq - Get the active RRQ for this exchange.
105862306a36Sopenharmony_ci * @vport: Pointer to vport context object.
105962306a36Sopenharmony_ci * @xri: The xri used in the exchange.
106062306a36Sopenharmony_ci * @did: The targets DID for this exchange.
106162306a36Sopenharmony_ci *
106262306a36Sopenharmony_ci * returns NULL = rrq not found in the phba->active_rrq_list.
106362306a36Sopenharmony_ci *         rrq = rrq for this xri and target.
106462306a36Sopenharmony_ci **/
106562306a36Sopenharmony_cistruct lpfc_node_rrq *
106662306a36Sopenharmony_cilpfc_get_active_rrq(struct lpfc_vport *vport, uint16_t xri, uint32_t did)
106762306a36Sopenharmony_ci{
106862306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
106962306a36Sopenharmony_ci	struct lpfc_node_rrq *rrq;
107062306a36Sopenharmony_ci	struct lpfc_node_rrq *nextrrq;
107162306a36Sopenharmony_ci	unsigned long iflags;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	if (phba->sli_rev != LPFC_SLI_REV4)
107462306a36Sopenharmony_ci		return NULL;
107562306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
107662306a36Sopenharmony_ci	list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) {
107762306a36Sopenharmony_ci		if (rrq->vport == vport && rrq->xritag == xri &&
107862306a36Sopenharmony_ci				rrq->nlp_DID == did){
107962306a36Sopenharmony_ci			list_del(&rrq->list);
108062306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflags);
108162306a36Sopenharmony_ci			return rrq;
108262306a36Sopenharmony_ci		}
108362306a36Sopenharmony_ci	}
108462306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
108562306a36Sopenharmony_ci	return NULL;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci/**
108962306a36Sopenharmony_ci * lpfc_cleanup_vports_rrqs - Remove and clear the active RRQ for this vport.
109062306a36Sopenharmony_ci * @vport: Pointer to vport context object.
109162306a36Sopenharmony_ci * @ndlp: Pointer to the lpfc_node_list structure.
109262306a36Sopenharmony_ci * If ndlp is NULL Remove all active RRQs for this vport from the
109362306a36Sopenharmony_ci * phba->active_rrq_list and clear the rrq.
109462306a36Sopenharmony_ci * If ndlp is not NULL then only remove rrqs for this vport & this ndlp.
109562306a36Sopenharmony_ci **/
109662306a36Sopenharmony_civoid
109762306a36Sopenharmony_cilpfc_cleanup_vports_rrqs(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci{
110062306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
110162306a36Sopenharmony_ci	struct lpfc_node_rrq *rrq;
110262306a36Sopenharmony_ci	struct lpfc_node_rrq *nextrrq;
110362306a36Sopenharmony_ci	unsigned long iflags;
110462306a36Sopenharmony_ci	LIST_HEAD(rrq_list);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if (phba->sli_rev != LPFC_SLI_REV4)
110762306a36Sopenharmony_ci		return;
110862306a36Sopenharmony_ci	if (!ndlp) {
110962306a36Sopenharmony_ci		lpfc_sli4_vport_delete_els_xri_aborted(vport);
111062306a36Sopenharmony_ci		lpfc_sli4_vport_delete_fcp_xri_aborted(vport);
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
111362306a36Sopenharmony_ci	list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) {
111462306a36Sopenharmony_ci		if (rrq->vport != vport)
111562306a36Sopenharmony_ci			continue;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci		if (!ndlp || ndlp == lpfc_findnode_did(vport, rrq->nlp_DID))
111862306a36Sopenharmony_ci			list_move(&rrq->list, &rrq_list);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	}
112162306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	list_for_each_entry_safe(rrq, nextrrq, &rrq_list, list) {
112462306a36Sopenharmony_ci		list_del(&rrq->list);
112562306a36Sopenharmony_ci		lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci/**
113062306a36Sopenharmony_ci * lpfc_test_rrq_active - Test RRQ bit in xri_bitmap.
113162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
113262306a36Sopenharmony_ci * @ndlp: Targets nodelist pointer for this exchange.
113362306a36Sopenharmony_ci * @xritag: the xri in the bitmap to test.
113462306a36Sopenharmony_ci *
113562306a36Sopenharmony_ci * This function returns:
113662306a36Sopenharmony_ci * 0 = rrq not active for this xri
113762306a36Sopenharmony_ci * 1 = rrq is valid for this xri.
113862306a36Sopenharmony_ci **/
113962306a36Sopenharmony_ciint
114062306a36Sopenharmony_cilpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
114162306a36Sopenharmony_ci			uint16_t  xritag)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	if (!ndlp)
114462306a36Sopenharmony_ci		return 0;
114562306a36Sopenharmony_ci	if (!ndlp->active_rrqs_xri_bitmap)
114662306a36Sopenharmony_ci		return 0;
114762306a36Sopenharmony_ci	if (test_bit(xritag, ndlp->active_rrqs_xri_bitmap))
114862306a36Sopenharmony_ci		return 1;
114962306a36Sopenharmony_ci	else
115062306a36Sopenharmony_ci		return 0;
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci/**
115462306a36Sopenharmony_ci * lpfc_set_rrq_active - set RRQ active bit in xri_bitmap.
115562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
115662306a36Sopenharmony_ci * @ndlp: nodelist pointer for this target.
115762306a36Sopenharmony_ci * @xritag: xri used in this exchange.
115862306a36Sopenharmony_ci * @rxid: Remote Exchange ID.
115962306a36Sopenharmony_ci * @send_rrq: Flag used to determine if we should send rrq els cmd.
116062306a36Sopenharmony_ci *
116162306a36Sopenharmony_ci * This function takes the hbalock.
116262306a36Sopenharmony_ci * The active bit is always set in the active rrq xri_bitmap even
116362306a36Sopenharmony_ci * if there is no slot avaiable for the other rrq information.
116462306a36Sopenharmony_ci *
116562306a36Sopenharmony_ci * returns 0 rrq actived for this xri
116662306a36Sopenharmony_ci *         < 0 No memory or invalid ndlp.
116762306a36Sopenharmony_ci **/
116862306a36Sopenharmony_ciint
116962306a36Sopenharmony_cilpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
117062306a36Sopenharmony_ci		    uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
117162306a36Sopenharmony_ci{
117262306a36Sopenharmony_ci	unsigned long iflags;
117362306a36Sopenharmony_ci	struct lpfc_node_rrq *rrq;
117462306a36Sopenharmony_ci	int empty;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	if (!ndlp)
117762306a36Sopenharmony_ci		return -EINVAL;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	if (!phba->cfg_enable_rrq)
118062306a36Sopenharmony_ci		return -EINVAL;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
118362306a36Sopenharmony_ci	if (phba->pport->load_flag & FC_UNLOADING) {
118462306a36Sopenharmony_ci		phba->hba_flag &= ~HBA_RRQ_ACTIVE;
118562306a36Sopenharmony_ci		goto out;
118662306a36Sopenharmony_ci	}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING))
118962306a36Sopenharmony_ci		goto out;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	if (!ndlp->active_rrqs_xri_bitmap)
119262306a36Sopenharmony_ci		goto out;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	if (test_and_set_bit(xritag, ndlp->active_rrqs_xri_bitmap))
119562306a36Sopenharmony_ci		goto out;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
119862306a36Sopenharmony_ci	rrq = mempool_alloc(phba->rrq_pool, GFP_ATOMIC);
119962306a36Sopenharmony_ci	if (!rrq) {
120062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
120162306a36Sopenharmony_ci				"3155 Unable to allocate RRQ xri:0x%x rxid:0x%x"
120262306a36Sopenharmony_ci				" DID:0x%x Send:%d\n",
120362306a36Sopenharmony_ci				xritag, rxid, ndlp->nlp_DID, send_rrq);
120462306a36Sopenharmony_ci		return -EINVAL;
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci	if (phba->cfg_enable_rrq == 1)
120762306a36Sopenharmony_ci		rrq->send_rrq = send_rrq;
120862306a36Sopenharmony_ci	else
120962306a36Sopenharmony_ci		rrq->send_rrq = 0;
121062306a36Sopenharmony_ci	rrq->xritag = xritag;
121162306a36Sopenharmony_ci	rrq->rrq_stop_time = jiffies +
121262306a36Sopenharmony_ci				msecs_to_jiffies(1000 * (phba->fc_ratov + 1));
121362306a36Sopenharmony_ci	rrq->nlp_DID = ndlp->nlp_DID;
121462306a36Sopenharmony_ci	rrq->vport = ndlp->vport;
121562306a36Sopenharmony_ci	rrq->rxid = rxid;
121662306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
121762306a36Sopenharmony_ci	empty = list_empty(&phba->active_rrq_list);
121862306a36Sopenharmony_ci	list_add_tail(&rrq->list, &phba->active_rrq_list);
121962306a36Sopenharmony_ci	phba->hba_flag |= HBA_RRQ_ACTIVE;
122062306a36Sopenharmony_ci	if (empty)
122162306a36Sopenharmony_ci		lpfc_worker_wake_up(phba);
122262306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
122362306a36Sopenharmony_ci	return 0;
122462306a36Sopenharmony_ciout:
122562306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
122662306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
122762306a36Sopenharmony_ci			"2921 Can't set rrq active xri:0x%x rxid:0x%x"
122862306a36Sopenharmony_ci			" DID:0x%x Send:%d\n",
122962306a36Sopenharmony_ci			xritag, rxid, ndlp->nlp_DID, send_rrq);
123062306a36Sopenharmony_ci	return -EINVAL;
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci/**
123462306a36Sopenharmony_ci * __lpfc_sli_get_els_sglq - Allocates an iocb object from sgl pool
123562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
123662306a36Sopenharmony_ci * @piocbq: Pointer to the iocbq.
123762306a36Sopenharmony_ci *
123862306a36Sopenharmony_ci * The driver calls this function with either the nvme ls ring lock
123962306a36Sopenharmony_ci * or the fc els ring lock held depending on the iocb usage.  This function
124062306a36Sopenharmony_ci * gets a new driver sglq object from the sglq list. If the list is not empty
124162306a36Sopenharmony_ci * then it is successful, it returns pointer to the newly allocated sglq
124262306a36Sopenharmony_ci * object else it returns NULL.
124362306a36Sopenharmony_ci **/
124462306a36Sopenharmony_cistatic struct lpfc_sglq *
124562306a36Sopenharmony_ci__lpfc_sli_get_els_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	struct list_head *lpfc_els_sgl_list = &phba->sli4_hba.lpfc_els_sgl_list;
124862306a36Sopenharmony_ci	struct lpfc_sglq *sglq = NULL;
124962306a36Sopenharmony_ci	struct lpfc_sglq *start_sglq = NULL;
125062306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_cmd;
125162306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp;
125262306a36Sopenharmony_ci	int found = 0;
125362306a36Sopenharmony_ci	u8 cmnd;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	cmnd = get_job_cmnd(phba, piocbq);
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	if (piocbq->cmd_flag & LPFC_IO_FCP) {
125862306a36Sopenharmony_ci		lpfc_cmd = piocbq->io_buf;
125962306a36Sopenharmony_ci		ndlp = lpfc_cmd->rdata->pnode;
126062306a36Sopenharmony_ci	} else  if ((cmnd == CMD_GEN_REQUEST64_CR) &&
126162306a36Sopenharmony_ci			!(piocbq->cmd_flag & LPFC_IO_LIBDFC)) {
126262306a36Sopenharmony_ci		ndlp = piocbq->ndlp;
126362306a36Sopenharmony_ci	} else  if (piocbq->cmd_flag & LPFC_IO_LIBDFC) {
126462306a36Sopenharmony_ci		if (piocbq->cmd_flag & LPFC_IO_LOOPBACK)
126562306a36Sopenharmony_ci			ndlp = NULL;
126662306a36Sopenharmony_ci		else
126762306a36Sopenharmony_ci			ndlp = piocbq->ndlp;
126862306a36Sopenharmony_ci	} else {
126962306a36Sopenharmony_ci		ndlp = piocbq->ndlp;
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	spin_lock(&phba->sli4_hba.sgl_list_lock);
127362306a36Sopenharmony_ci	list_remove_head(lpfc_els_sgl_list, sglq, struct lpfc_sglq, list);
127462306a36Sopenharmony_ci	start_sglq = sglq;
127562306a36Sopenharmony_ci	while (!found) {
127662306a36Sopenharmony_ci		if (!sglq)
127762306a36Sopenharmony_ci			break;
127862306a36Sopenharmony_ci		if (ndlp && ndlp->active_rrqs_xri_bitmap &&
127962306a36Sopenharmony_ci		    test_bit(sglq->sli4_lxritag,
128062306a36Sopenharmony_ci		    ndlp->active_rrqs_xri_bitmap)) {
128162306a36Sopenharmony_ci			/* This xri has an rrq outstanding for this DID.
128262306a36Sopenharmony_ci			 * put it back in the list and get another xri.
128362306a36Sopenharmony_ci			 */
128462306a36Sopenharmony_ci			list_add_tail(&sglq->list, lpfc_els_sgl_list);
128562306a36Sopenharmony_ci			sglq = NULL;
128662306a36Sopenharmony_ci			list_remove_head(lpfc_els_sgl_list, sglq,
128762306a36Sopenharmony_ci						struct lpfc_sglq, list);
128862306a36Sopenharmony_ci			if (sglq == start_sglq) {
128962306a36Sopenharmony_ci				list_add_tail(&sglq->list, lpfc_els_sgl_list);
129062306a36Sopenharmony_ci				sglq = NULL;
129162306a36Sopenharmony_ci				break;
129262306a36Sopenharmony_ci			} else
129362306a36Sopenharmony_ci				continue;
129462306a36Sopenharmony_ci		}
129562306a36Sopenharmony_ci		sglq->ndlp = ndlp;
129662306a36Sopenharmony_ci		found = 1;
129762306a36Sopenharmony_ci		phba->sli4_hba.lpfc_sglq_active_list[sglq->sli4_lxritag] = sglq;
129862306a36Sopenharmony_ci		sglq->state = SGL_ALLOCATED;
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci	spin_unlock(&phba->sli4_hba.sgl_list_lock);
130162306a36Sopenharmony_ci	return sglq;
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci/**
130562306a36Sopenharmony_ci * __lpfc_sli_get_nvmet_sglq - Allocates an iocb object from sgl pool
130662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
130762306a36Sopenharmony_ci * @piocbq: Pointer to the iocbq.
130862306a36Sopenharmony_ci *
130962306a36Sopenharmony_ci * This function is called with the sgl_list lock held. This function
131062306a36Sopenharmony_ci * gets a new driver sglq object from the sglq list. If the
131162306a36Sopenharmony_ci * list is not empty then it is successful, it returns pointer to the newly
131262306a36Sopenharmony_ci * allocated sglq object else it returns NULL.
131362306a36Sopenharmony_ci **/
131462306a36Sopenharmony_cistruct lpfc_sglq *
131562306a36Sopenharmony_ci__lpfc_sli_get_nvmet_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct list_head *lpfc_nvmet_sgl_list;
131862306a36Sopenharmony_ci	struct lpfc_sglq *sglq = NULL;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	lpfc_nvmet_sgl_list = &phba->sli4_hba.lpfc_nvmet_sgl_list;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	lockdep_assert_held(&phba->sli4_hba.sgl_list_lock);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	list_remove_head(lpfc_nvmet_sgl_list, sglq, struct lpfc_sglq, list);
132562306a36Sopenharmony_ci	if (!sglq)
132662306a36Sopenharmony_ci		return NULL;
132762306a36Sopenharmony_ci	phba->sli4_hba.lpfc_sglq_active_list[sglq->sli4_lxritag] = sglq;
132862306a36Sopenharmony_ci	sglq->state = SGL_ALLOCATED;
132962306a36Sopenharmony_ci	return sglq;
133062306a36Sopenharmony_ci}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci/**
133362306a36Sopenharmony_ci * lpfc_sli_get_iocbq - Allocates an iocb object from iocb pool
133462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
133562306a36Sopenharmony_ci *
133662306a36Sopenharmony_ci * This function is called with no lock held. This function
133762306a36Sopenharmony_ci * allocates a new driver iocb object from the iocb pool. If the
133862306a36Sopenharmony_ci * allocation is successful, it returns pointer to the newly
133962306a36Sopenharmony_ci * allocated iocb object else it returns NULL.
134062306a36Sopenharmony_ci **/
134162306a36Sopenharmony_cistruct lpfc_iocbq *
134262306a36Sopenharmony_cilpfc_sli_get_iocbq(struct lpfc_hba *phba)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	struct lpfc_iocbq * iocbq = NULL;
134562306a36Sopenharmony_ci	unsigned long iflags;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
134862306a36Sopenharmony_ci	iocbq = __lpfc_sli_get_iocbq(phba);
134962306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
135062306a36Sopenharmony_ci	return iocbq;
135162306a36Sopenharmony_ci}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci/**
135462306a36Sopenharmony_ci * __lpfc_sli_release_iocbq_s4 - Release iocb to the iocb pool
135562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
135662306a36Sopenharmony_ci * @iocbq: Pointer to driver iocb object.
135762306a36Sopenharmony_ci *
135862306a36Sopenharmony_ci * This function is called to release the driver iocb object
135962306a36Sopenharmony_ci * to the iocb pool. The iotag in the iocb object
136062306a36Sopenharmony_ci * does not change for each use of the iocb object. This function
136162306a36Sopenharmony_ci * clears all other fields of the iocb object when it is freed.
136262306a36Sopenharmony_ci * The sqlq structure that holds the xritag and phys and virtual
136362306a36Sopenharmony_ci * mappings for the scatter gather list is retrieved from the
136462306a36Sopenharmony_ci * active array of sglq. The get of the sglq pointer also clears
136562306a36Sopenharmony_ci * the entry in the array. If the status of the IO indiactes that
136662306a36Sopenharmony_ci * this IO was aborted then the sglq entry it put on the
136762306a36Sopenharmony_ci * lpfc_abts_els_sgl_list until the CQ_ABORTED_XRI is received. If the
136862306a36Sopenharmony_ci * IO has good status or fails for any other reason then the sglq
136962306a36Sopenharmony_ci * entry is added to the free list (lpfc_els_sgl_list). The hbalock is
137062306a36Sopenharmony_ci *  asserted held in the code path calling this routine.
137162306a36Sopenharmony_ci **/
137262306a36Sopenharmony_cistatic void
137362306a36Sopenharmony_ci__lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
137462306a36Sopenharmony_ci{
137562306a36Sopenharmony_ci	struct lpfc_sglq *sglq;
137662306a36Sopenharmony_ci	unsigned long iflag = 0;
137762306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	if (iocbq->sli4_xritag == NO_XRI)
138062306a36Sopenharmony_ci		sglq = NULL;
138162306a36Sopenharmony_ci	else
138262306a36Sopenharmony_ci		sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_lxritag);
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	if (sglq)  {
138662306a36Sopenharmony_ci		if (iocbq->cmd_flag & LPFC_IO_NVMET) {
138762306a36Sopenharmony_ci			spin_lock_irqsave(&phba->sli4_hba.sgl_list_lock,
138862306a36Sopenharmony_ci					  iflag);
138962306a36Sopenharmony_ci			sglq->state = SGL_FREED;
139062306a36Sopenharmony_ci			sglq->ndlp = NULL;
139162306a36Sopenharmony_ci			list_add_tail(&sglq->list,
139262306a36Sopenharmony_ci				      &phba->sli4_hba.lpfc_nvmet_sgl_list);
139362306a36Sopenharmony_ci			spin_unlock_irqrestore(
139462306a36Sopenharmony_ci				&phba->sli4_hba.sgl_list_lock, iflag);
139562306a36Sopenharmony_ci			goto out;
139662306a36Sopenharmony_ci		}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci		if ((iocbq->cmd_flag & LPFC_EXCHANGE_BUSY) &&
139962306a36Sopenharmony_ci		    (!(unlikely(pci_channel_offline(phba->pcidev)))) &&
140062306a36Sopenharmony_ci		    sglq->state != SGL_XRI_ABORTED) {
140162306a36Sopenharmony_ci			spin_lock_irqsave(&phba->sli4_hba.sgl_list_lock,
140262306a36Sopenharmony_ci					  iflag);
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci			/* Check if we can get a reference on ndlp */
140562306a36Sopenharmony_ci			if (sglq->ndlp && !lpfc_nlp_get(sglq->ndlp))
140662306a36Sopenharmony_ci				sglq->ndlp = NULL;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci			list_add(&sglq->list,
140962306a36Sopenharmony_ci				 &phba->sli4_hba.lpfc_abts_els_sgl_list);
141062306a36Sopenharmony_ci			spin_unlock_irqrestore(
141162306a36Sopenharmony_ci				&phba->sli4_hba.sgl_list_lock, iflag);
141262306a36Sopenharmony_ci		} else {
141362306a36Sopenharmony_ci			spin_lock_irqsave(&phba->sli4_hba.sgl_list_lock,
141462306a36Sopenharmony_ci					  iflag);
141562306a36Sopenharmony_ci			sglq->state = SGL_FREED;
141662306a36Sopenharmony_ci			sglq->ndlp = NULL;
141762306a36Sopenharmony_ci			list_add_tail(&sglq->list,
141862306a36Sopenharmony_ci				      &phba->sli4_hba.lpfc_els_sgl_list);
141962306a36Sopenharmony_ci			spin_unlock_irqrestore(
142062306a36Sopenharmony_ci				&phba->sli4_hba.sgl_list_lock, iflag);
142162306a36Sopenharmony_ci			pring = lpfc_phba_elsring(phba);
142262306a36Sopenharmony_ci			/* Check if TXQ queue needs to be serviced */
142362306a36Sopenharmony_ci			if (pring && (!list_empty(&pring->txq)))
142462306a36Sopenharmony_ci				lpfc_worker_wake_up(phba);
142562306a36Sopenharmony_ci		}
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ciout:
142962306a36Sopenharmony_ci	/*
143062306a36Sopenharmony_ci	 * Clean all volatile data fields, preserve iotag and node struct.
143162306a36Sopenharmony_ci	 */
143262306a36Sopenharmony_ci	memset_startat(iocbq, 0, wqe);
143362306a36Sopenharmony_ci	iocbq->sli4_lxritag = NO_XRI;
143462306a36Sopenharmony_ci	iocbq->sli4_xritag = NO_XRI;
143562306a36Sopenharmony_ci	iocbq->cmd_flag &= ~(LPFC_IO_NVME | LPFC_IO_NVMET | LPFC_IO_CMF |
143662306a36Sopenharmony_ci			      LPFC_IO_NVME_LS);
143762306a36Sopenharmony_ci	list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
143862306a36Sopenharmony_ci}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci/**
144262306a36Sopenharmony_ci * __lpfc_sli_release_iocbq_s3 - Release iocb to the iocb pool
144362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
144462306a36Sopenharmony_ci * @iocbq: Pointer to driver iocb object.
144562306a36Sopenharmony_ci *
144662306a36Sopenharmony_ci * This function is called to release the driver iocb object to the
144762306a36Sopenharmony_ci * iocb pool. The iotag in the iocb object does not change for each
144862306a36Sopenharmony_ci * use of the iocb object. This function clears all other fields of
144962306a36Sopenharmony_ci * the iocb object when it is freed. The hbalock is asserted held in
145062306a36Sopenharmony_ci * the code path calling this routine.
145162306a36Sopenharmony_ci **/
145262306a36Sopenharmony_cistatic void
145362306a36Sopenharmony_ci__lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
145462306a36Sopenharmony_ci{
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	/*
145762306a36Sopenharmony_ci	 * Clean all volatile data fields, preserve iotag and node struct.
145862306a36Sopenharmony_ci	 */
145962306a36Sopenharmony_ci	memset_startat(iocbq, 0, iocb);
146062306a36Sopenharmony_ci	iocbq->sli4_xritag = NO_XRI;
146162306a36Sopenharmony_ci	list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
146262306a36Sopenharmony_ci}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci/**
146562306a36Sopenharmony_ci * __lpfc_sli_release_iocbq - Release iocb to the iocb pool
146662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
146762306a36Sopenharmony_ci * @iocbq: Pointer to driver iocb object.
146862306a36Sopenharmony_ci *
146962306a36Sopenharmony_ci * This function is called with hbalock held to release driver
147062306a36Sopenharmony_ci * iocb object to the iocb pool. The iotag in the iocb object
147162306a36Sopenharmony_ci * does not change for each use of the iocb object. This function
147262306a36Sopenharmony_ci * clears all other fields of the iocb object when it is freed.
147362306a36Sopenharmony_ci **/
147462306a36Sopenharmony_cistatic void
147562306a36Sopenharmony_ci__lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
147662306a36Sopenharmony_ci{
147762306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	phba->__lpfc_sli_release_iocbq(phba, iocbq);
148062306a36Sopenharmony_ci	phba->iocb_cnt--;
148162306a36Sopenharmony_ci}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci/**
148462306a36Sopenharmony_ci * lpfc_sli_release_iocbq - Release iocb to the iocb pool
148562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
148662306a36Sopenharmony_ci * @iocbq: Pointer to driver iocb object.
148762306a36Sopenharmony_ci *
148862306a36Sopenharmony_ci * This function is called with no lock held to release the iocb to
148962306a36Sopenharmony_ci * iocb pool.
149062306a36Sopenharmony_ci **/
149162306a36Sopenharmony_civoid
149262306a36Sopenharmony_cilpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
149362306a36Sopenharmony_ci{
149462306a36Sopenharmony_ci	unsigned long iflags;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	/*
149762306a36Sopenharmony_ci	 * Clean all volatile data fields, preserve iotag and node struct.
149862306a36Sopenharmony_ci	 */
149962306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
150062306a36Sopenharmony_ci	__lpfc_sli_release_iocbq(phba, iocbq);
150162306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci/**
150562306a36Sopenharmony_ci * lpfc_sli_cancel_iocbs - Cancel all iocbs from a list.
150662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
150762306a36Sopenharmony_ci * @iocblist: List of IOCBs.
150862306a36Sopenharmony_ci * @ulpstatus: ULP status in IOCB command field.
150962306a36Sopenharmony_ci * @ulpWord4: ULP word-4 in IOCB command field.
151062306a36Sopenharmony_ci *
151162306a36Sopenharmony_ci * This function is called with a list of IOCBs to cancel. It cancels the IOCB
151262306a36Sopenharmony_ci * on the list by invoking the complete callback function associated with the
151362306a36Sopenharmony_ci * IOCB with the provided @ulpstatus and @ulpword4 set to the IOCB commond
151462306a36Sopenharmony_ci * fields.
151562306a36Sopenharmony_ci **/
151662306a36Sopenharmony_civoid
151762306a36Sopenharmony_cilpfc_sli_cancel_iocbs(struct lpfc_hba *phba, struct list_head *iocblist,
151862306a36Sopenharmony_ci		      uint32_t ulpstatus, uint32_t ulpWord4)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	struct lpfc_iocbq *piocb;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	while (!list_empty(iocblist)) {
152362306a36Sopenharmony_ci		list_remove_head(iocblist, piocb, struct lpfc_iocbq, list);
152462306a36Sopenharmony_ci		if (piocb->cmd_cmpl) {
152562306a36Sopenharmony_ci			if (piocb->cmd_flag & LPFC_IO_NVME) {
152662306a36Sopenharmony_ci				lpfc_nvme_cancel_iocb(phba, piocb,
152762306a36Sopenharmony_ci						      ulpstatus, ulpWord4);
152862306a36Sopenharmony_ci			} else {
152962306a36Sopenharmony_ci				if (phba->sli_rev == LPFC_SLI_REV4) {
153062306a36Sopenharmony_ci					bf_set(lpfc_wcqe_c_status,
153162306a36Sopenharmony_ci					       &piocb->wcqe_cmpl, ulpstatus);
153262306a36Sopenharmony_ci					piocb->wcqe_cmpl.parameter = ulpWord4;
153362306a36Sopenharmony_ci				} else {
153462306a36Sopenharmony_ci					piocb->iocb.ulpStatus = ulpstatus;
153562306a36Sopenharmony_ci					piocb->iocb.un.ulpWord[4] = ulpWord4;
153662306a36Sopenharmony_ci				}
153762306a36Sopenharmony_ci				(piocb->cmd_cmpl) (phba, piocb, piocb);
153862306a36Sopenharmony_ci			}
153962306a36Sopenharmony_ci		} else {
154062306a36Sopenharmony_ci			lpfc_sli_release_iocbq(phba, piocb);
154162306a36Sopenharmony_ci		}
154262306a36Sopenharmony_ci	}
154362306a36Sopenharmony_ci	return;
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci/**
154762306a36Sopenharmony_ci * lpfc_sli_iocb_cmd_type - Get the iocb type
154862306a36Sopenharmony_ci * @iocb_cmnd: iocb command code.
154962306a36Sopenharmony_ci *
155062306a36Sopenharmony_ci * This function is called by ring event handler function to get the iocb type.
155162306a36Sopenharmony_ci * This function translates the iocb command to an iocb command type used to
155262306a36Sopenharmony_ci * decide the final disposition of each completed IOCB.
155362306a36Sopenharmony_ci * The function returns
155462306a36Sopenharmony_ci * LPFC_UNKNOWN_IOCB if it is an unsupported iocb
155562306a36Sopenharmony_ci * LPFC_SOL_IOCB     if it is a solicited iocb completion
155662306a36Sopenharmony_ci * LPFC_ABORT_IOCB   if it is an abort iocb
155762306a36Sopenharmony_ci * LPFC_UNSOL_IOCB   if it is an unsolicited iocb
155862306a36Sopenharmony_ci *
155962306a36Sopenharmony_ci * The caller is not required to hold any lock.
156062306a36Sopenharmony_ci **/
156162306a36Sopenharmony_cistatic lpfc_iocb_type
156262306a36Sopenharmony_cilpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
156362306a36Sopenharmony_ci{
156462306a36Sopenharmony_ci	lpfc_iocb_type type = LPFC_UNKNOWN_IOCB;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	if (iocb_cmnd > CMD_MAX_IOCB_CMD)
156762306a36Sopenharmony_ci		return 0;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	switch (iocb_cmnd) {
157062306a36Sopenharmony_ci	case CMD_XMIT_SEQUENCE_CR:
157162306a36Sopenharmony_ci	case CMD_XMIT_SEQUENCE_CX:
157262306a36Sopenharmony_ci	case CMD_XMIT_BCAST_CN:
157362306a36Sopenharmony_ci	case CMD_XMIT_BCAST_CX:
157462306a36Sopenharmony_ci	case CMD_ELS_REQUEST_CR:
157562306a36Sopenharmony_ci	case CMD_ELS_REQUEST_CX:
157662306a36Sopenharmony_ci	case CMD_CREATE_XRI_CR:
157762306a36Sopenharmony_ci	case CMD_CREATE_XRI_CX:
157862306a36Sopenharmony_ci	case CMD_GET_RPI_CN:
157962306a36Sopenharmony_ci	case CMD_XMIT_ELS_RSP_CX:
158062306a36Sopenharmony_ci	case CMD_GET_RPI_CR:
158162306a36Sopenharmony_ci	case CMD_FCP_IWRITE_CR:
158262306a36Sopenharmony_ci	case CMD_FCP_IWRITE_CX:
158362306a36Sopenharmony_ci	case CMD_FCP_IREAD_CR:
158462306a36Sopenharmony_ci	case CMD_FCP_IREAD_CX:
158562306a36Sopenharmony_ci	case CMD_FCP_ICMND_CR:
158662306a36Sopenharmony_ci	case CMD_FCP_ICMND_CX:
158762306a36Sopenharmony_ci	case CMD_FCP_TSEND_CX:
158862306a36Sopenharmony_ci	case CMD_FCP_TRSP_CX:
158962306a36Sopenharmony_ci	case CMD_FCP_TRECEIVE_CX:
159062306a36Sopenharmony_ci	case CMD_FCP_AUTO_TRSP_CX:
159162306a36Sopenharmony_ci	case CMD_ADAPTER_MSG:
159262306a36Sopenharmony_ci	case CMD_ADAPTER_DUMP:
159362306a36Sopenharmony_ci	case CMD_XMIT_SEQUENCE64_CR:
159462306a36Sopenharmony_ci	case CMD_XMIT_SEQUENCE64_CX:
159562306a36Sopenharmony_ci	case CMD_XMIT_BCAST64_CN:
159662306a36Sopenharmony_ci	case CMD_XMIT_BCAST64_CX:
159762306a36Sopenharmony_ci	case CMD_ELS_REQUEST64_CR:
159862306a36Sopenharmony_ci	case CMD_ELS_REQUEST64_CX:
159962306a36Sopenharmony_ci	case CMD_FCP_IWRITE64_CR:
160062306a36Sopenharmony_ci	case CMD_FCP_IWRITE64_CX:
160162306a36Sopenharmony_ci	case CMD_FCP_IREAD64_CR:
160262306a36Sopenharmony_ci	case CMD_FCP_IREAD64_CX:
160362306a36Sopenharmony_ci	case CMD_FCP_ICMND64_CR:
160462306a36Sopenharmony_ci	case CMD_FCP_ICMND64_CX:
160562306a36Sopenharmony_ci	case CMD_FCP_TSEND64_CX:
160662306a36Sopenharmony_ci	case CMD_FCP_TRSP64_CX:
160762306a36Sopenharmony_ci	case CMD_FCP_TRECEIVE64_CX:
160862306a36Sopenharmony_ci	case CMD_GEN_REQUEST64_CR:
160962306a36Sopenharmony_ci	case CMD_GEN_REQUEST64_CX:
161062306a36Sopenharmony_ci	case CMD_XMIT_ELS_RSP64_CX:
161162306a36Sopenharmony_ci	case DSSCMD_IWRITE64_CR:
161262306a36Sopenharmony_ci	case DSSCMD_IWRITE64_CX:
161362306a36Sopenharmony_ci	case DSSCMD_IREAD64_CR:
161462306a36Sopenharmony_ci	case DSSCMD_IREAD64_CX:
161562306a36Sopenharmony_ci	case CMD_SEND_FRAME:
161662306a36Sopenharmony_ci		type = LPFC_SOL_IOCB;
161762306a36Sopenharmony_ci		break;
161862306a36Sopenharmony_ci	case CMD_ABORT_XRI_CN:
161962306a36Sopenharmony_ci	case CMD_ABORT_XRI_CX:
162062306a36Sopenharmony_ci	case CMD_CLOSE_XRI_CN:
162162306a36Sopenharmony_ci	case CMD_CLOSE_XRI_CX:
162262306a36Sopenharmony_ci	case CMD_XRI_ABORTED_CX:
162362306a36Sopenharmony_ci	case CMD_ABORT_MXRI64_CN:
162462306a36Sopenharmony_ci	case CMD_XMIT_BLS_RSP64_CX:
162562306a36Sopenharmony_ci		type = LPFC_ABORT_IOCB;
162662306a36Sopenharmony_ci		break;
162762306a36Sopenharmony_ci	case CMD_RCV_SEQUENCE_CX:
162862306a36Sopenharmony_ci	case CMD_RCV_ELS_REQ_CX:
162962306a36Sopenharmony_ci	case CMD_RCV_SEQUENCE64_CX:
163062306a36Sopenharmony_ci	case CMD_RCV_ELS_REQ64_CX:
163162306a36Sopenharmony_ci	case CMD_ASYNC_STATUS:
163262306a36Sopenharmony_ci	case CMD_IOCB_RCV_SEQ64_CX:
163362306a36Sopenharmony_ci	case CMD_IOCB_RCV_ELS64_CX:
163462306a36Sopenharmony_ci	case CMD_IOCB_RCV_CONT64_CX:
163562306a36Sopenharmony_ci	case CMD_IOCB_RET_XRI64_CX:
163662306a36Sopenharmony_ci		type = LPFC_UNSOL_IOCB;
163762306a36Sopenharmony_ci		break;
163862306a36Sopenharmony_ci	case CMD_IOCB_XMIT_MSEQ64_CR:
163962306a36Sopenharmony_ci	case CMD_IOCB_XMIT_MSEQ64_CX:
164062306a36Sopenharmony_ci	case CMD_IOCB_RCV_SEQ_LIST64_CX:
164162306a36Sopenharmony_ci	case CMD_IOCB_RCV_ELS_LIST64_CX:
164262306a36Sopenharmony_ci	case CMD_IOCB_CLOSE_EXTENDED_CN:
164362306a36Sopenharmony_ci	case CMD_IOCB_ABORT_EXTENDED_CN:
164462306a36Sopenharmony_ci	case CMD_IOCB_RET_HBQE64_CN:
164562306a36Sopenharmony_ci	case CMD_IOCB_FCP_IBIDIR64_CR:
164662306a36Sopenharmony_ci	case CMD_IOCB_FCP_IBIDIR64_CX:
164762306a36Sopenharmony_ci	case CMD_IOCB_FCP_ITASKMGT64_CX:
164862306a36Sopenharmony_ci	case CMD_IOCB_LOGENTRY_CN:
164962306a36Sopenharmony_ci	case CMD_IOCB_LOGENTRY_ASYNC_CN:
165062306a36Sopenharmony_ci		printk("%s - Unhandled SLI-3 Command x%x\n",
165162306a36Sopenharmony_ci				__func__, iocb_cmnd);
165262306a36Sopenharmony_ci		type = LPFC_UNKNOWN_IOCB;
165362306a36Sopenharmony_ci		break;
165462306a36Sopenharmony_ci	default:
165562306a36Sopenharmony_ci		type = LPFC_UNKNOWN_IOCB;
165662306a36Sopenharmony_ci		break;
165762306a36Sopenharmony_ci	}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	return type;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci/**
166362306a36Sopenharmony_ci * lpfc_sli_ring_map - Issue config_ring mbox for all rings
166462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
166562306a36Sopenharmony_ci *
166662306a36Sopenharmony_ci * This function is called from SLI initialization code
166762306a36Sopenharmony_ci * to configure every ring of the HBA's SLI interface. The
166862306a36Sopenharmony_ci * caller is not required to hold any lock. This function issues
166962306a36Sopenharmony_ci * a config_ring mailbox command for each ring.
167062306a36Sopenharmony_ci * This function returns zero if successful else returns a negative
167162306a36Sopenharmony_ci * error code.
167262306a36Sopenharmony_ci **/
167362306a36Sopenharmony_cistatic int
167462306a36Sopenharmony_cilpfc_sli_ring_map(struct lpfc_hba *phba)
167562306a36Sopenharmony_ci{
167662306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
167762306a36Sopenharmony_ci	LPFC_MBOXQ_t *pmb;
167862306a36Sopenharmony_ci	MAILBOX_t *pmbox;
167962306a36Sopenharmony_ci	int i, rc, ret = 0;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
168262306a36Sopenharmony_ci	if (!pmb)
168362306a36Sopenharmony_ci		return -ENOMEM;
168462306a36Sopenharmony_ci	pmbox = &pmb->u.mb;
168562306a36Sopenharmony_ci	phba->link_state = LPFC_INIT_MBX_CMDS;
168662306a36Sopenharmony_ci	for (i = 0; i < psli->num_rings; i++) {
168762306a36Sopenharmony_ci		lpfc_config_ring(phba, i, pmb);
168862306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
168962306a36Sopenharmony_ci		if (rc != MBX_SUCCESS) {
169062306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
169162306a36Sopenharmony_ci					"0446 Adapter failed to init (%d), "
169262306a36Sopenharmony_ci					"mbxCmd x%x CFG_RING, mbxStatus x%x, "
169362306a36Sopenharmony_ci					"ring %d\n",
169462306a36Sopenharmony_ci					rc, pmbox->mbxCommand,
169562306a36Sopenharmony_ci					pmbox->mbxStatus, i);
169662306a36Sopenharmony_ci			phba->link_state = LPFC_HBA_ERROR;
169762306a36Sopenharmony_ci			ret = -ENXIO;
169862306a36Sopenharmony_ci			break;
169962306a36Sopenharmony_ci		}
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
170262306a36Sopenharmony_ci	return ret;
170362306a36Sopenharmony_ci}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci/**
170662306a36Sopenharmony_ci * lpfc_sli_ringtxcmpl_put - Adds new iocb to the txcmplq
170762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
170862306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
170962306a36Sopenharmony_ci * @piocb: Pointer to the driver iocb object.
171062306a36Sopenharmony_ci *
171162306a36Sopenharmony_ci * The driver calls this function with the hbalock held for SLI3 ports or
171262306a36Sopenharmony_ci * the ring lock held for SLI4 ports. The function adds the
171362306a36Sopenharmony_ci * new iocb to txcmplq of the given ring. This function always returns
171462306a36Sopenharmony_ci * 0. If this function is called for ELS ring, this function checks if
171562306a36Sopenharmony_ci * there is a vport associated with the ELS command. This function also
171662306a36Sopenharmony_ci * starts els_tmofunc timer if this is an ELS command.
171762306a36Sopenharmony_ci **/
171862306a36Sopenharmony_cistatic int
171962306a36Sopenharmony_cilpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
172062306a36Sopenharmony_ci			struct lpfc_iocbq *piocb)
172162306a36Sopenharmony_ci{
172262306a36Sopenharmony_ci	u32 ulp_command = 0;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	BUG_ON(!piocb);
172562306a36Sopenharmony_ci	ulp_command = get_job_cmnd(phba, piocb);
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	list_add_tail(&piocb->list, &pring->txcmplq);
172862306a36Sopenharmony_ci	piocb->cmd_flag |= LPFC_IO_ON_TXCMPLQ;
172962306a36Sopenharmony_ci	pring->txcmplq_cnt++;
173062306a36Sopenharmony_ci	if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
173162306a36Sopenharmony_ci	   (ulp_command != CMD_ABORT_XRI_WQE) &&
173262306a36Sopenharmony_ci	   (ulp_command != CMD_ABORT_XRI_CN) &&
173362306a36Sopenharmony_ci	   (ulp_command != CMD_CLOSE_XRI_CN)) {
173462306a36Sopenharmony_ci		BUG_ON(!piocb->vport);
173562306a36Sopenharmony_ci		if (!(piocb->vport->load_flag & FC_UNLOADING))
173662306a36Sopenharmony_ci			mod_timer(&piocb->vport->els_tmofunc,
173762306a36Sopenharmony_ci				  jiffies +
173862306a36Sopenharmony_ci				  msecs_to_jiffies(1000 * (phba->fc_ratov << 1)));
173962306a36Sopenharmony_ci	}
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	return 0;
174262306a36Sopenharmony_ci}
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci/**
174562306a36Sopenharmony_ci * lpfc_sli_ringtx_get - Get first element of the txq
174662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
174762306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
174862306a36Sopenharmony_ci *
174962306a36Sopenharmony_ci * This function is called with hbalock held to get next
175062306a36Sopenharmony_ci * iocb in txq of the given ring. If there is any iocb in
175162306a36Sopenharmony_ci * the txq, the function returns first iocb in the list after
175262306a36Sopenharmony_ci * removing the iocb from the list, else it returns NULL.
175362306a36Sopenharmony_ci **/
175462306a36Sopenharmony_cistruct lpfc_iocbq *
175562306a36Sopenharmony_cilpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
175662306a36Sopenharmony_ci{
175762306a36Sopenharmony_ci	struct lpfc_iocbq *cmd_iocb;
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list);
176262306a36Sopenharmony_ci	return cmd_iocb;
176362306a36Sopenharmony_ci}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci/**
176662306a36Sopenharmony_ci * lpfc_cmf_sync_cmpl - Process a CMF_SYNC_WQE cmpl
176762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
176862306a36Sopenharmony_ci * @cmdiocb: Pointer to driver command iocb object.
176962306a36Sopenharmony_ci * @rspiocb: Pointer to driver response iocb object.
177062306a36Sopenharmony_ci *
177162306a36Sopenharmony_ci * This routine will inform the driver of any BW adjustments we need
177262306a36Sopenharmony_ci * to make. These changes will be picked up during the next CMF
177362306a36Sopenharmony_ci * timer interrupt. In addition, any BW changes will be logged
177462306a36Sopenharmony_ci * with LOG_CGN_MGMT.
177562306a36Sopenharmony_ci **/
177662306a36Sopenharmony_cistatic void
177762306a36Sopenharmony_cilpfc_cmf_sync_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
177862306a36Sopenharmony_ci		   struct lpfc_iocbq *rspiocb)
177962306a36Sopenharmony_ci{
178062306a36Sopenharmony_ci	union lpfc_wqe128 *wqe;
178162306a36Sopenharmony_ci	uint32_t status, info;
178262306a36Sopenharmony_ci	struct lpfc_wcqe_complete *wcqe = &rspiocb->wcqe_cmpl;
178362306a36Sopenharmony_ci	uint64_t bw, bwdif, slop;
178462306a36Sopenharmony_ci	uint64_t pcent, bwpcent;
178562306a36Sopenharmony_ci	int asig, afpin, sigcnt, fpincnt;
178662306a36Sopenharmony_ci	int wsigmax, wfpinmax, cg, tdp;
178762306a36Sopenharmony_ci	char *s;
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	/* First check for error */
179062306a36Sopenharmony_ci	status = bf_get(lpfc_wcqe_c_status, wcqe);
179162306a36Sopenharmony_ci	if (status) {
179262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
179362306a36Sopenharmony_ci				"6211 CMF_SYNC_WQE Error "
179462306a36Sopenharmony_ci				"req_tag x%x status x%x hwstatus x%x "
179562306a36Sopenharmony_ci				"tdatap x%x parm x%x\n",
179662306a36Sopenharmony_ci				bf_get(lpfc_wcqe_c_request_tag, wcqe),
179762306a36Sopenharmony_ci				bf_get(lpfc_wcqe_c_status, wcqe),
179862306a36Sopenharmony_ci				bf_get(lpfc_wcqe_c_hw_status, wcqe),
179962306a36Sopenharmony_ci				wcqe->total_data_placed,
180062306a36Sopenharmony_ci				wcqe->parameter);
180162306a36Sopenharmony_ci		goto out;
180262306a36Sopenharmony_ci	}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	/* Gather congestion information on a successful cmpl */
180562306a36Sopenharmony_ci	info = wcqe->parameter;
180662306a36Sopenharmony_ci	phba->cmf_active_info = info;
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	/* See if firmware info count is valid or has changed */
180962306a36Sopenharmony_ci	if (info > LPFC_MAX_CMF_INFO || phba->cmf_info_per_interval == info)
181062306a36Sopenharmony_ci		info = 0;
181162306a36Sopenharmony_ci	else
181262306a36Sopenharmony_ci		phba->cmf_info_per_interval = info;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	tdp = bf_get(lpfc_wcqe_c_cmf_bw, wcqe);
181562306a36Sopenharmony_ci	cg = bf_get(lpfc_wcqe_c_cmf_cg, wcqe);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	/* Get BW requirement from firmware */
181862306a36Sopenharmony_ci	bw = (uint64_t)tdp * LPFC_CMF_BLK_SIZE;
181962306a36Sopenharmony_ci	if (!bw) {
182062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
182162306a36Sopenharmony_ci				"6212 CMF_SYNC_WQE x%x: NULL bw\n",
182262306a36Sopenharmony_ci				bf_get(lpfc_wcqe_c_request_tag, wcqe));
182362306a36Sopenharmony_ci		goto out;
182462306a36Sopenharmony_ci	}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	/* Gather information needed for logging if a BW change is required */
182762306a36Sopenharmony_ci	wqe = &cmdiocb->wqe;
182862306a36Sopenharmony_ci	asig = bf_get(cmf_sync_asig, &wqe->cmf_sync);
182962306a36Sopenharmony_ci	afpin = bf_get(cmf_sync_afpin, &wqe->cmf_sync);
183062306a36Sopenharmony_ci	fpincnt = bf_get(cmf_sync_wfpincnt, &wqe->cmf_sync);
183162306a36Sopenharmony_ci	sigcnt = bf_get(cmf_sync_wsigcnt, &wqe->cmf_sync);
183262306a36Sopenharmony_ci	if (phba->cmf_max_bytes_per_interval != bw ||
183362306a36Sopenharmony_ci	    (asig || afpin || sigcnt || fpincnt)) {
183462306a36Sopenharmony_ci		/* Are we increasing or decreasing BW */
183562306a36Sopenharmony_ci		if (phba->cmf_max_bytes_per_interval <  bw) {
183662306a36Sopenharmony_ci			bwdif = bw - phba->cmf_max_bytes_per_interval;
183762306a36Sopenharmony_ci			s = "Increase";
183862306a36Sopenharmony_ci		} else {
183962306a36Sopenharmony_ci			bwdif = phba->cmf_max_bytes_per_interval - bw;
184062306a36Sopenharmony_ci			s = "Decrease";
184162306a36Sopenharmony_ci		}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci		/* What is the change percentage */
184462306a36Sopenharmony_ci		slop = div_u64(phba->cmf_link_byte_count, 200); /*For rounding*/
184562306a36Sopenharmony_ci		pcent = div64_u64(bwdif * 100 + slop,
184662306a36Sopenharmony_ci				  phba->cmf_link_byte_count);
184762306a36Sopenharmony_ci		bwpcent = div64_u64(bw * 100 + slop,
184862306a36Sopenharmony_ci				    phba->cmf_link_byte_count);
184962306a36Sopenharmony_ci		/* Because of bytes adjustment due to shorter timer in
185062306a36Sopenharmony_ci		 * lpfc_cmf_timer() the cmf_link_byte_count can be shorter and
185162306a36Sopenharmony_ci		 * may seem like BW is above 100%.
185262306a36Sopenharmony_ci		 */
185362306a36Sopenharmony_ci		if (bwpcent > 100)
185462306a36Sopenharmony_ci			bwpcent = 100;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci		if (phba->cmf_max_bytes_per_interval < bw &&
185762306a36Sopenharmony_ci		    bwpcent > 95)
185862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
185962306a36Sopenharmony_ci					"6208 Congestion bandwidth "
186062306a36Sopenharmony_ci					"limits removed\n");
186162306a36Sopenharmony_ci		else if ((phba->cmf_max_bytes_per_interval > bw) &&
186262306a36Sopenharmony_ci			 ((bwpcent + pcent) <= 100) && ((bwpcent + pcent) > 95))
186362306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
186462306a36Sopenharmony_ci					"6209 Congestion bandwidth "
186562306a36Sopenharmony_ci					"limits in effect\n");
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci		if (asig) {
186862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
186962306a36Sopenharmony_ci					"6237 BW Threshold %lld%% (%lld): "
187062306a36Sopenharmony_ci					"%lld%% %s: Signal Alarm: cg:%d "
187162306a36Sopenharmony_ci					"Info:%u\n",
187262306a36Sopenharmony_ci					bwpcent, bw, pcent, s, cg,
187362306a36Sopenharmony_ci					phba->cmf_active_info);
187462306a36Sopenharmony_ci		} else if (afpin) {
187562306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
187662306a36Sopenharmony_ci					"6238 BW Threshold %lld%% (%lld): "
187762306a36Sopenharmony_ci					"%lld%% %s: FPIN Alarm: cg:%d "
187862306a36Sopenharmony_ci					"Info:%u\n",
187962306a36Sopenharmony_ci					bwpcent, bw, pcent, s, cg,
188062306a36Sopenharmony_ci					phba->cmf_active_info);
188162306a36Sopenharmony_ci		} else if (sigcnt) {
188262306a36Sopenharmony_ci			wsigmax = bf_get(cmf_sync_wsigmax, &wqe->cmf_sync);
188362306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
188462306a36Sopenharmony_ci					"6239 BW Threshold %lld%% (%lld): "
188562306a36Sopenharmony_ci					"%lld%% %s: Signal Warning: "
188662306a36Sopenharmony_ci					"Cnt %d Max %d: cg:%d Info:%u\n",
188762306a36Sopenharmony_ci					bwpcent, bw, pcent, s, sigcnt,
188862306a36Sopenharmony_ci					wsigmax, cg, phba->cmf_active_info);
188962306a36Sopenharmony_ci		} else if (fpincnt) {
189062306a36Sopenharmony_ci			wfpinmax = bf_get(cmf_sync_wfpinmax, &wqe->cmf_sync);
189162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
189262306a36Sopenharmony_ci					"6240 BW Threshold %lld%% (%lld): "
189362306a36Sopenharmony_ci					"%lld%% %s: FPIN Warning: "
189462306a36Sopenharmony_ci					"Cnt %d Max %d: cg:%d Info:%u\n",
189562306a36Sopenharmony_ci					bwpcent, bw, pcent, s, fpincnt,
189662306a36Sopenharmony_ci					wfpinmax, cg, phba->cmf_active_info);
189762306a36Sopenharmony_ci		} else {
189862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
189962306a36Sopenharmony_ci					"6241 BW Threshold %lld%% (%lld): "
190062306a36Sopenharmony_ci					"CMF %lld%% %s: cg:%d Info:%u\n",
190162306a36Sopenharmony_ci					bwpcent, bw, pcent, s, cg,
190262306a36Sopenharmony_ci					phba->cmf_active_info);
190362306a36Sopenharmony_ci		}
190462306a36Sopenharmony_ci	} else if (info) {
190562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
190662306a36Sopenharmony_ci				"6246 Info Threshold %u\n", info);
190762306a36Sopenharmony_ci	}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	/* Save BW change to be picked up during next timer interrupt */
191062306a36Sopenharmony_ci	phba->cmf_last_sync_bw = bw;
191162306a36Sopenharmony_ciout:
191262306a36Sopenharmony_ci	lpfc_sli_release_iocbq(phba, cmdiocb);
191362306a36Sopenharmony_ci}
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci/**
191662306a36Sopenharmony_ci * lpfc_issue_cmf_sync_wqe - Issue a CMF_SYNC_WQE
191762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
191862306a36Sopenharmony_ci * @ms:   ms to set in WQE interval, 0 means use init op
191962306a36Sopenharmony_ci * @total: Total rcv bytes for this interval
192062306a36Sopenharmony_ci *
192162306a36Sopenharmony_ci * This routine is called every CMF timer interrupt. Its purpose is
192262306a36Sopenharmony_ci * to issue a CMF_SYNC_WQE to the firmware to inform it of any events
192362306a36Sopenharmony_ci * that may indicate we have congestion (FPINs or Signals). Upon
192462306a36Sopenharmony_ci * completion, the firmware will indicate any BW restrictions the
192562306a36Sopenharmony_ci * driver may need to take.
192662306a36Sopenharmony_ci **/
192762306a36Sopenharmony_ciint
192862306a36Sopenharmony_cilpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	union lpfc_wqe128 *wqe;
193162306a36Sopenharmony_ci	struct lpfc_iocbq *sync_buf;
193262306a36Sopenharmony_ci	unsigned long iflags;
193362306a36Sopenharmony_ci	u32 ret_val;
193462306a36Sopenharmony_ci	u32 atot, wtot, max;
193562306a36Sopenharmony_ci	u8 warn_sync_period = 0;
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	/* First address any alarm / warning activity */
193862306a36Sopenharmony_ci	atot = atomic_xchg(&phba->cgn_sync_alarm_cnt, 0);
193962306a36Sopenharmony_ci	wtot = atomic_xchg(&phba->cgn_sync_warn_cnt, 0);
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	/* ONLY Managed mode will send the CMF_SYNC_WQE to the HBA */
194262306a36Sopenharmony_ci	if (phba->cmf_active_mode != LPFC_CFG_MANAGED ||
194362306a36Sopenharmony_ci	    phba->link_state == LPFC_LINK_DOWN)
194462306a36Sopenharmony_ci		return 0;
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
194762306a36Sopenharmony_ci	sync_buf = __lpfc_sli_get_iocbq(phba);
194862306a36Sopenharmony_ci	if (!sync_buf) {
194962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT,
195062306a36Sopenharmony_ci				"6244 No available WQEs for CMF_SYNC_WQE\n");
195162306a36Sopenharmony_ci		ret_val = ENOMEM;
195262306a36Sopenharmony_ci		goto out_unlock;
195362306a36Sopenharmony_ci	}
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	wqe = &sync_buf->wqe;
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	/* WQEs are reused.  Clear stale data and set key fields to zero */
195862306a36Sopenharmony_ci	memset(wqe, 0, sizeof(*wqe));
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	/* If this is the very first CMF_SYNC_WQE, issue an init operation */
196162306a36Sopenharmony_ci	if (!ms) {
196262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
196362306a36Sopenharmony_ci				"6441 CMF Init %d - CMF_SYNC_WQE\n",
196462306a36Sopenharmony_ci				phba->fc_eventTag);
196562306a36Sopenharmony_ci		bf_set(cmf_sync_op, &wqe->cmf_sync, 1); /* 1=init */
196662306a36Sopenharmony_ci		bf_set(cmf_sync_interval, &wqe->cmf_sync, LPFC_CMF_INTERVAL);
196762306a36Sopenharmony_ci		goto initpath;
196862306a36Sopenharmony_ci	}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	bf_set(cmf_sync_op, &wqe->cmf_sync, 0); /* 0=recalc */
197162306a36Sopenharmony_ci	bf_set(cmf_sync_interval, &wqe->cmf_sync, ms);
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	/* Check for alarms / warnings */
197462306a36Sopenharmony_ci	if (atot) {
197562306a36Sopenharmony_ci		if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) {
197662306a36Sopenharmony_ci			/* We hit an Signal alarm condition */
197762306a36Sopenharmony_ci			bf_set(cmf_sync_asig, &wqe->cmf_sync, 1);
197862306a36Sopenharmony_ci		} else {
197962306a36Sopenharmony_ci			/* We hit a FPIN alarm condition */
198062306a36Sopenharmony_ci			bf_set(cmf_sync_afpin, &wqe->cmf_sync, 1);
198162306a36Sopenharmony_ci		}
198262306a36Sopenharmony_ci	} else if (wtot) {
198362306a36Sopenharmony_ci		if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY ||
198462306a36Sopenharmony_ci		    phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) {
198562306a36Sopenharmony_ci			/* We hit an Signal warning condition */
198662306a36Sopenharmony_ci			max = LPFC_SEC_TO_MSEC / lpfc_fabric_cgn_frequency *
198762306a36Sopenharmony_ci				lpfc_acqe_cgn_frequency;
198862306a36Sopenharmony_ci			bf_set(cmf_sync_wsigmax, &wqe->cmf_sync, max);
198962306a36Sopenharmony_ci			bf_set(cmf_sync_wsigcnt, &wqe->cmf_sync, wtot);
199062306a36Sopenharmony_ci			warn_sync_period = lpfc_acqe_cgn_frequency;
199162306a36Sopenharmony_ci		} else {
199262306a36Sopenharmony_ci			/* We hit a FPIN warning condition */
199362306a36Sopenharmony_ci			bf_set(cmf_sync_wfpinmax, &wqe->cmf_sync, 1);
199462306a36Sopenharmony_ci			bf_set(cmf_sync_wfpincnt, &wqe->cmf_sync, 1);
199562306a36Sopenharmony_ci			if (phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ)
199662306a36Sopenharmony_ci				warn_sync_period =
199762306a36Sopenharmony_ci				LPFC_MSECS_TO_SECS(phba->cgn_fpin_frequency);
199862306a36Sopenharmony_ci		}
199962306a36Sopenharmony_ci	}
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	/* Update total read blocks during previous timer interval */
200262306a36Sopenharmony_ci	wqe->cmf_sync.read_bytes = (u32)(total / LPFC_CMF_BLK_SIZE);
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ciinitpath:
200562306a36Sopenharmony_ci	bf_set(cmf_sync_ver, &wqe->cmf_sync, LPFC_CMF_SYNC_VER);
200662306a36Sopenharmony_ci	wqe->cmf_sync.event_tag = phba->fc_eventTag;
200762306a36Sopenharmony_ci	bf_set(cmf_sync_cmnd, &wqe->cmf_sync, CMD_CMF_SYNC_WQE);
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	/* Setup reqtag to match the wqe completion. */
201062306a36Sopenharmony_ci	bf_set(cmf_sync_reqtag, &wqe->cmf_sync, sync_buf->iotag);
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	bf_set(cmf_sync_qosd, &wqe->cmf_sync, 1);
201362306a36Sopenharmony_ci	bf_set(cmf_sync_period, &wqe->cmf_sync, warn_sync_period);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	bf_set(cmf_sync_cmd_type, &wqe->cmf_sync, CMF_SYNC_COMMAND);
201662306a36Sopenharmony_ci	bf_set(cmf_sync_wqec, &wqe->cmf_sync, 1);
201762306a36Sopenharmony_ci	bf_set(cmf_sync_cqid, &wqe->cmf_sync, LPFC_WQE_CQ_ID_DEFAULT);
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	sync_buf->vport = phba->pport;
202062306a36Sopenharmony_ci	sync_buf->cmd_cmpl = lpfc_cmf_sync_cmpl;
202162306a36Sopenharmony_ci	sync_buf->cmd_dmabuf = NULL;
202262306a36Sopenharmony_ci	sync_buf->rsp_dmabuf = NULL;
202362306a36Sopenharmony_ci	sync_buf->bpl_dmabuf = NULL;
202462306a36Sopenharmony_ci	sync_buf->sli4_xritag = NO_XRI;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	sync_buf->cmd_flag |= LPFC_IO_CMF;
202762306a36Sopenharmony_ci	ret_val = lpfc_sli4_issue_wqe(phba, &phba->sli4_hba.hdwq[0], sync_buf);
202862306a36Sopenharmony_ci	if (ret_val) {
202962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
203062306a36Sopenharmony_ci				"6214 Cannot issue CMF_SYNC_WQE: x%x\n",
203162306a36Sopenharmony_ci				ret_val);
203262306a36Sopenharmony_ci		__lpfc_sli_release_iocbq(phba, sync_buf);
203362306a36Sopenharmony_ci	}
203462306a36Sopenharmony_ciout_unlock:
203562306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
203662306a36Sopenharmony_ci	return ret_val;
203762306a36Sopenharmony_ci}
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci/**
204062306a36Sopenharmony_ci * lpfc_sli_next_iocb_slot - Get next iocb slot in the ring
204162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
204262306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
204362306a36Sopenharmony_ci *
204462306a36Sopenharmony_ci * This function is called with hbalock held and the caller must post the
204562306a36Sopenharmony_ci * iocb without releasing the lock. If the caller releases the lock,
204662306a36Sopenharmony_ci * iocb slot returned by the function is not guaranteed to be available.
204762306a36Sopenharmony_ci * The function returns pointer to the next available iocb slot if there
204862306a36Sopenharmony_ci * is available slot in the ring, else it returns NULL.
204962306a36Sopenharmony_ci * If the get index of the ring is ahead of the put index, the function
205062306a36Sopenharmony_ci * will post an error attention event to the worker thread to take the
205162306a36Sopenharmony_ci * HBA to offline state.
205262306a36Sopenharmony_ci **/
205362306a36Sopenharmony_cistatic IOCB_t *
205462306a36Sopenharmony_cilpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
205562306a36Sopenharmony_ci{
205662306a36Sopenharmony_ci	struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno];
205762306a36Sopenharmony_ci	uint32_t  max_cmd_idx = pring->sli.sli3.numCiocb;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	if ((pring->sli.sli3.next_cmdidx == pring->sli.sli3.cmdidx) &&
206262306a36Sopenharmony_ci	   (++pring->sli.sli3.next_cmdidx >= max_cmd_idx))
206362306a36Sopenharmony_ci		pring->sli.sli3.next_cmdidx = 0;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	if (unlikely(pring->sli.sli3.local_getidx ==
206662306a36Sopenharmony_ci		pring->sli.sli3.next_cmdidx)) {
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci		pring->sli.sli3.local_getidx = le32_to_cpu(pgp->cmdGetInx);
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci		if (unlikely(pring->sli.sli3.local_getidx >= max_cmd_idx)) {
207162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
207262306a36Sopenharmony_ci					"0315 Ring %d issue: portCmdGet %d "
207362306a36Sopenharmony_ci					"is bigger than cmd ring %d\n",
207462306a36Sopenharmony_ci					pring->ringno,
207562306a36Sopenharmony_ci					pring->sli.sli3.local_getidx,
207662306a36Sopenharmony_ci					max_cmd_idx);
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci			phba->link_state = LPFC_HBA_ERROR;
207962306a36Sopenharmony_ci			/*
208062306a36Sopenharmony_ci			 * All error attention handlers are posted to
208162306a36Sopenharmony_ci			 * worker thread
208262306a36Sopenharmony_ci			 */
208362306a36Sopenharmony_ci			phba->work_ha |= HA_ERATT;
208462306a36Sopenharmony_ci			phba->work_hs = HS_FFER3;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci			lpfc_worker_wake_up(phba);
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci			return NULL;
208962306a36Sopenharmony_ci		}
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci		if (pring->sli.sli3.local_getidx == pring->sli.sli3.next_cmdidx)
209262306a36Sopenharmony_ci			return NULL;
209362306a36Sopenharmony_ci	}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	return lpfc_cmd_iocb(phba, pring);
209662306a36Sopenharmony_ci}
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci/**
209962306a36Sopenharmony_ci * lpfc_sli_next_iotag - Get an iotag for the iocb
210062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
210162306a36Sopenharmony_ci * @iocbq: Pointer to driver iocb object.
210262306a36Sopenharmony_ci *
210362306a36Sopenharmony_ci * This function gets an iotag for the iocb. If there is no unused iotag and
210462306a36Sopenharmony_ci * the iocbq_lookup_len < 0xffff, this function allocates a bigger iotag_lookup
210562306a36Sopenharmony_ci * array and assigns a new iotag.
210662306a36Sopenharmony_ci * The function returns the allocated iotag if successful, else returns zero.
210762306a36Sopenharmony_ci * Zero is not a valid iotag.
210862306a36Sopenharmony_ci * The caller is not required to hold any lock.
210962306a36Sopenharmony_ci **/
211062306a36Sopenharmony_ciuint16_t
211162306a36Sopenharmony_cilpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
211262306a36Sopenharmony_ci{
211362306a36Sopenharmony_ci	struct lpfc_iocbq **new_arr;
211462306a36Sopenharmony_ci	struct lpfc_iocbq **old_arr;
211562306a36Sopenharmony_ci	size_t new_len;
211662306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
211762306a36Sopenharmony_ci	uint16_t iotag;
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
212062306a36Sopenharmony_ci	iotag = psli->last_iotag;
212162306a36Sopenharmony_ci	if(++iotag < psli->iocbq_lookup_len) {
212262306a36Sopenharmony_ci		psli->last_iotag = iotag;
212362306a36Sopenharmony_ci		psli->iocbq_lookup[iotag] = iocbq;
212462306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
212562306a36Sopenharmony_ci		iocbq->iotag = iotag;
212662306a36Sopenharmony_ci		return iotag;
212762306a36Sopenharmony_ci	} else if (psli->iocbq_lookup_len < (0xffff
212862306a36Sopenharmony_ci					   - LPFC_IOCBQ_LOOKUP_INCREMENT)) {
212962306a36Sopenharmony_ci		new_len = psli->iocbq_lookup_len + LPFC_IOCBQ_LOOKUP_INCREMENT;
213062306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
213162306a36Sopenharmony_ci		new_arr = kcalloc(new_len, sizeof(struct lpfc_iocbq *),
213262306a36Sopenharmony_ci				  GFP_KERNEL);
213362306a36Sopenharmony_ci		if (new_arr) {
213462306a36Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
213562306a36Sopenharmony_ci			old_arr = psli->iocbq_lookup;
213662306a36Sopenharmony_ci			if (new_len <= psli->iocbq_lookup_len) {
213762306a36Sopenharmony_ci				/* highly unprobable case */
213862306a36Sopenharmony_ci				kfree(new_arr);
213962306a36Sopenharmony_ci				iotag = psli->last_iotag;
214062306a36Sopenharmony_ci				if(++iotag < psli->iocbq_lookup_len) {
214162306a36Sopenharmony_ci					psli->last_iotag = iotag;
214262306a36Sopenharmony_ci					psli->iocbq_lookup[iotag] = iocbq;
214362306a36Sopenharmony_ci					spin_unlock_irq(&phba->hbalock);
214462306a36Sopenharmony_ci					iocbq->iotag = iotag;
214562306a36Sopenharmony_ci					return iotag;
214662306a36Sopenharmony_ci				}
214762306a36Sopenharmony_ci				spin_unlock_irq(&phba->hbalock);
214862306a36Sopenharmony_ci				return 0;
214962306a36Sopenharmony_ci			}
215062306a36Sopenharmony_ci			if (psli->iocbq_lookup)
215162306a36Sopenharmony_ci				memcpy(new_arr, old_arr,
215262306a36Sopenharmony_ci				       ((psli->last_iotag  + 1) *
215362306a36Sopenharmony_ci					sizeof (struct lpfc_iocbq *)));
215462306a36Sopenharmony_ci			psli->iocbq_lookup = new_arr;
215562306a36Sopenharmony_ci			psli->iocbq_lookup_len = new_len;
215662306a36Sopenharmony_ci			psli->last_iotag = iotag;
215762306a36Sopenharmony_ci			psli->iocbq_lookup[iotag] = iocbq;
215862306a36Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
215962306a36Sopenharmony_ci			iocbq->iotag = iotag;
216062306a36Sopenharmony_ci			kfree(old_arr);
216162306a36Sopenharmony_ci			return iotag;
216262306a36Sopenharmony_ci		}
216362306a36Sopenharmony_ci	} else
216462306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
216762306a36Sopenharmony_ci			"0318 Failed to allocate IOTAG.last IOTAG is %d\n",
216862306a36Sopenharmony_ci			psli->last_iotag);
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	return 0;
217162306a36Sopenharmony_ci}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci/**
217462306a36Sopenharmony_ci * lpfc_sli_submit_iocb - Submit an iocb to the firmware
217562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
217662306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
217762306a36Sopenharmony_ci * @iocb: Pointer to iocb slot in the ring.
217862306a36Sopenharmony_ci * @nextiocb: Pointer to driver iocb object which need to be
217962306a36Sopenharmony_ci *            posted to firmware.
218062306a36Sopenharmony_ci *
218162306a36Sopenharmony_ci * This function is called to post a new iocb to the firmware. This
218262306a36Sopenharmony_ci * function copies the new iocb to ring iocb slot and updates the
218362306a36Sopenharmony_ci * ring pointers. It adds the new iocb to txcmplq if there is
218462306a36Sopenharmony_ci * a completion call back for this iocb else the function will free the
218562306a36Sopenharmony_ci * iocb object.  The hbalock is asserted held in the code path calling
218662306a36Sopenharmony_ci * this routine.
218762306a36Sopenharmony_ci **/
218862306a36Sopenharmony_cistatic void
218962306a36Sopenharmony_cilpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
219062306a36Sopenharmony_ci		IOCB_t *iocb, struct lpfc_iocbq *nextiocb)
219162306a36Sopenharmony_ci{
219262306a36Sopenharmony_ci	/*
219362306a36Sopenharmony_ci	 * Set up an iotag
219462306a36Sopenharmony_ci	 */
219562306a36Sopenharmony_ci	nextiocb->iocb.ulpIoTag = (nextiocb->cmd_cmpl) ? nextiocb->iotag : 0;
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci	if (pring->ringno == LPFC_ELS_RING) {
219962306a36Sopenharmony_ci		lpfc_debugfs_slow_ring_trc(phba,
220062306a36Sopenharmony_ci			"IOCB cmd ring:   wd4:x%08x wd6:x%08x wd7:x%08x",
220162306a36Sopenharmony_ci			*(((uint32_t *) &nextiocb->iocb) + 4),
220262306a36Sopenharmony_ci			*(((uint32_t *) &nextiocb->iocb) + 6),
220362306a36Sopenharmony_ci			*(((uint32_t *) &nextiocb->iocb) + 7));
220462306a36Sopenharmony_ci	}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	/*
220762306a36Sopenharmony_ci	 * Issue iocb command to adapter
220862306a36Sopenharmony_ci	 */
220962306a36Sopenharmony_ci	lpfc_sli_pcimem_bcopy(&nextiocb->iocb, iocb, phba->iocb_cmd_size);
221062306a36Sopenharmony_ci	wmb();
221162306a36Sopenharmony_ci	pring->stats.iocb_cmd++;
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	/*
221462306a36Sopenharmony_ci	 * If there is no completion routine to call, we can release the
221562306a36Sopenharmony_ci	 * IOCB buffer back right now. For IOCBs, like QUE_RING_BUF,
221662306a36Sopenharmony_ci	 * that have no rsp ring completion, cmd_cmpl MUST be NULL.
221762306a36Sopenharmony_ci	 */
221862306a36Sopenharmony_ci	if (nextiocb->cmd_cmpl)
221962306a36Sopenharmony_ci		lpfc_sli_ringtxcmpl_put(phba, pring, nextiocb);
222062306a36Sopenharmony_ci	else
222162306a36Sopenharmony_ci		__lpfc_sli_release_iocbq(phba, nextiocb);
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	/*
222462306a36Sopenharmony_ci	 * Let the HBA know what IOCB slot will be the next one the
222562306a36Sopenharmony_ci	 * driver will put a command into.
222662306a36Sopenharmony_ci	 */
222762306a36Sopenharmony_ci	pring->sli.sli3.cmdidx = pring->sli.sli3.next_cmdidx;
222862306a36Sopenharmony_ci	writel(pring->sli.sli3.cmdidx, &phba->host_gp[pring->ringno].cmdPutInx);
222962306a36Sopenharmony_ci}
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci/**
223262306a36Sopenharmony_ci * lpfc_sli_update_full_ring - Update the chip attention register
223362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
223462306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
223562306a36Sopenharmony_ci *
223662306a36Sopenharmony_ci * The caller is not required to hold any lock for calling this function.
223762306a36Sopenharmony_ci * This function updates the chip attention bits for the ring to inform firmware
223862306a36Sopenharmony_ci * that there are pending work to be done for this ring and requests an
223962306a36Sopenharmony_ci * interrupt when there is space available in the ring. This function is
224062306a36Sopenharmony_ci * called when the driver is unable to post more iocbs to the ring due
224162306a36Sopenharmony_ci * to unavailability of space in the ring.
224262306a36Sopenharmony_ci **/
224362306a36Sopenharmony_cistatic void
224462306a36Sopenharmony_cilpfc_sli_update_full_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
224562306a36Sopenharmony_ci{
224662306a36Sopenharmony_ci	int ringno = pring->ringno;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	pring->flag |= LPFC_CALL_RING_AVAILABLE;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	wmb();
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	/*
225362306a36Sopenharmony_ci	 * Set ring 'ringno' to SET R0CE_REQ in Chip Att register.
225462306a36Sopenharmony_ci	 * The HBA will tell us when an IOCB entry is available.
225562306a36Sopenharmony_ci	 */
225662306a36Sopenharmony_ci	writel((CA_R0ATT|CA_R0CE_REQ) << (ringno*4), phba->CAregaddr);
225762306a36Sopenharmony_ci	readl(phba->CAregaddr); /* flush */
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	pring->stats.iocb_cmd_full++;
226062306a36Sopenharmony_ci}
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci/**
226362306a36Sopenharmony_ci * lpfc_sli_update_ring - Update chip attention register
226462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
226562306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
226662306a36Sopenharmony_ci *
226762306a36Sopenharmony_ci * This function updates the chip attention register bit for the
226862306a36Sopenharmony_ci * given ring to inform HBA that there is more work to be done
226962306a36Sopenharmony_ci * in this ring. The caller is not required to hold any lock.
227062306a36Sopenharmony_ci **/
227162306a36Sopenharmony_cistatic void
227262306a36Sopenharmony_cilpfc_sli_update_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
227362306a36Sopenharmony_ci{
227462306a36Sopenharmony_ci	int ringno = pring->ringno;
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci	/*
227762306a36Sopenharmony_ci	 * Tell the HBA that there is work to do in this ring.
227862306a36Sopenharmony_ci	 */
227962306a36Sopenharmony_ci	if (!(phba->sli3_options & LPFC_SLI3_CRP_ENABLED)) {
228062306a36Sopenharmony_ci		wmb();
228162306a36Sopenharmony_ci		writel(CA_R0ATT << (ringno * 4), phba->CAregaddr);
228262306a36Sopenharmony_ci		readl(phba->CAregaddr); /* flush */
228362306a36Sopenharmony_ci	}
228462306a36Sopenharmony_ci}
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci/**
228762306a36Sopenharmony_ci * lpfc_sli_resume_iocb - Process iocbs in the txq
228862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
228962306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
229062306a36Sopenharmony_ci *
229162306a36Sopenharmony_ci * This function is called with hbalock held to post pending iocbs
229262306a36Sopenharmony_ci * in the txq to the firmware. This function is called when driver
229362306a36Sopenharmony_ci * detects space available in the ring.
229462306a36Sopenharmony_ci **/
229562306a36Sopenharmony_cistatic void
229662306a36Sopenharmony_cilpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
229762306a36Sopenharmony_ci{
229862306a36Sopenharmony_ci	IOCB_t *iocb;
229962306a36Sopenharmony_ci	struct lpfc_iocbq *nextiocb;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	/*
230462306a36Sopenharmony_ci	 * Check to see if:
230562306a36Sopenharmony_ci	 *  (a) there is anything on the txq to send
230662306a36Sopenharmony_ci	 *  (b) link is up
230762306a36Sopenharmony_ci	 *  (c) link attention events can be processed (fcp ring only)
230862306a36Sopenharmony_ci	 *  (d) IOCB processing is not blocked by the outstanding mbox command.
230962306a36Sopenharmony_ci	 */
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	if (lpfc_is_link_up(phba) &&
231262306a36Sopenharmony_ci	    (!list_empty(&pring->txq)) &&
231362306a36Sopenharmony_ci	    (pring->ringno != LPFC_FCP_RING ||
231462306a36Sopenharmony_ci	     phba->sli.sli_flag & LPFC_PROCESS_LA)) {
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci		while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
231762306a36Sopenharmony_ci		       (nextiocb = lpfc_sli_ringtx_get(phba, pring)))
231862306a36Sopenharmony_ci			lpfc_sli_submit_iocb(phba, pring, iocb, nextiocb);
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci		if (iocb)
232162306a36Sopenharmony_ci			lpfc_sli_update_ring(phba, pring);
232262306a36Sopenharmony_ci		else
232362306a36Sopenharmony_ci			lpfc_sli_update_full_ring(phba, pring);
232462306a36Sopenharmony_ci	}
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	return;
232762306a36Sopenharmony_ci}
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci/**
233062306a36Sopenharmony_ci * lpfc_sli_next_hbq_slot - Get next hbq entry for the HBQ
233162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
233262306a36Sopenharmony_ci * @hbqno: HBQ number.
233362306a36Sopenharmony_ci *
233462306a36Sopenharmony_ci * This function is called with hbalock held to get the next
233562306a36Sopenharmony_ci * available slot for the given HBQ. If there is free slot
233662306a36Sopenharmony_ci * available for the HBQ it will return pointer to the next available
233762306a36Sopenharmony_ci * HBQ entry else it will return NULL.
233862306a36Sopenharmony_ci **/
233962306a36Sopenharmony_cistatic struct lpfc_hbq_entry *
234062306a36Sopenharmony_cilpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
234162306a36Sopenharmony_ci{
234262306a36Sopenharmony_ci	struct hbq_s *hbqp = &phba->hbqs[hbqno];
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	if (hbqp->next_hbqPutIdx == hbqp->hbqPutIdx &&
234762306a36Sopenharmony_ci	    ++hbqp->next_hbqPutIdx >= hbqp->entry_count)
234862306a36Sopenharmony_ci		hbqp->next_hbqPutIdx = 0;
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	if (unlikely(hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)) {
235162306a36Sopenharmony_ci		uint32_t raw_index = phba->hbq_get[hbqno];
235262306a36Sopenharmony_ci		uint32_t getidx = le32_to_cpu(raw_index);
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci		hbqp->local_hbqGetIdx = getidx;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci		if (unlikely(hbqp->local_hbqGetIdx >= hbqp->entry_count)) {
235762306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
235862306a36Sopenharmony_ci					"1802 HBQ %d: local_hbqGetIdx "
235962306a36Sopenharmony_ci					"%u is > than hbqp->entry_count %u\n",
236062306a36Sopenharmony_ci					hbqno, hbqp->local_hbqGetIdx,
236162306a36Sopenharmony_ci					hbqp->entry_count);
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci			phba->link_state = LPFC_HBA_ERROR;
236462306a36Sopenharmony_ci			return NULL;
236562306a36Sopenharmony_ci		}
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci		if (hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)
236862306a36Sopenharmony_ci			return NULL;
236962306a36Sopenharmony_ci	}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	return (struct lpfc_hbq_entry *) phba->hbqs[hbqno].hbq_virt +
237262306a36Sopenharmony_ci			hbqp->hbqPutIdx;
237362306a36Sopenharmony_ci}
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci/**
237662306a36Sopenharmony_ci * lpfc_sli_hbqbuf_free_all - Free all the hbq buffers
237762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
237862306a36Sopenharmony_ci *
237962306a36Sopenharmony_ci * This function is called with no lock held to free all the
238062306a36Sopenharmony_ci * hbq buffers while uninitializing the SLI interface. It also
238162306a36Sopenharmony_ci * frees the HBQ buffers returned by the firmware but not yet
238262306a36Sopenharmony_ci * processed by the upper layers.
238362306a36Sopenharmony_ci **/
238462306a36Sopenharmony_civoid
238562306a36Sopenharmony_cilpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
238662306a36Sopenharmony_ci{
238762306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf, *next_dmabuf;
238862306a36Sopenharmony_ci	struct hbq_dmabuf *hbq_buf;
238962306a36Sopenharmony_ci	unsigned long flags;
239062306a36Sopenharmony_ci	int i, hbq_count;
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	hbq_count = lpfc_sli_hbq_count();
239362306a36Sopenharmony_ci	/* Return all memory used by all HBQs */
239462306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, flags);
239562306a36Sopenharmony_ci	for (i = 0; i < hbq_count; ++i) {
239662306a36Sopenharmony_ci		list_for_each_entry_safe(dmabuf, next_dmabuf,
239762306a36Sopenharmony_ci				&phba->hbqs[i].hbq_buffer_list, list) {
239862306a36Sopenharmony_ci			hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
239962306a36Sopenharmony_ci			list_del(&hbq_buf->dbuf.list);
240062306a36Sopenharmony_ci			(phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf);
240162306a36Sopenharmony_ci		}
240262306a36Sopenharmony_ci		phba->hbqs[i].buffer_count = 0;
240362306a36Sopenharmony_ci	}
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	/* Mark the HBQs not in use */
240662306a36Sopenharmony_ci	phba->hbq_in_use = 0;
240762306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, flags);
240862306a36Sopenharmony_ci}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci/**
241162306a36Sopenharmony_ci * lpfc_sli_hbq_to_firmware - Post the hbq buffer to firmware
241262306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
241362306a36Sopenharmony_ci * @hbqno: HBQ number.
241462306a36Sopenharmony_ci * @hbq_buf: Pointer to HBQ buffer.
241562306a36Sopenharmony_ci *
241662306a36Sopenharmony_ci * This function is called with the hbalock held to post a
241762306a36Sopenharmony_ci * hbq buffer to the firmware. If the function finds an empty
241862306a36Sopenharmony_ci * slot in the HBQ, it will post the buffer. The function will return
241962306a36Sopenharmony_ci * pointer to the hbq entry if it successfully post the buffer
242062306a36Sopenharmony_ci * else it will return NULL.
242162306a36Sopenharmony_ci **/
242262306a36Sopenharmony_cistatic int
242362306a36Sopenharmony_cilpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
242462306a36Sopenharmony_ci			 struct hbq_dmabuf *hbq_buf)
242562306a36Sopenharmony_ci{
242662306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
242762306a36Sopenharmony_ci	return phba->lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buf);
242862306a36Sopenharmony_ci}
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci/**
243162306a36Sopenharmony_ci * lpfc_sli_hbq_to_firmware_s3 - Post the hbq buffer to SLI3 firmware
243262306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
243362306a36Sopenharmony_ci * @hbqno: HBQ number.
243462306a36Sopenharmony_ci * @hbq_buf: Pointer to HBQ buffer.
243562306a36Sopenharmony_ci *
243662306a36Sopenharmony_ci * This function is called with the hbalock held to post a hbq buffer to the
243762306a36Sopenharmony_ci * firmware. If the function finds an empty slot in the HBQ, it will post the
243862306a36Sopenharmony_ci * buffer and place it on the hbq_buffer_list. The function will return zero if
243962306a36Sopenharmony_ci * it successfully post the buffer else it will return an error.
244062306a36Sopenharmony_ci **/
244162306a36Sopenharmony_cistatic int
244262306a36Sopenharmony_cilpfc_sli_hbq_to_firmware_s3(struct lpfc_hba *phba, uint32_t hbqno,
244362306a36Sopenharmony_ci			    struct hbq_dmabuf *hbq_buf)
244462306a36Sopenharmony_ci{
244562306a36Sopenharmony_ci	struct lpfc_hbq_entry *hbqe;
244662306a36Sopenharmony_ci	dma_addr_t physaddr = hbq_buf->dbuf.phys;
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
244962306a36Sopenharmony_ci	/* Get next HBQ entry slot to use */
245062306a36Sopenharmony_ci	hbqe = lpfc_sli_next_hbq_slot(phba, hbqno);
245162306a36Sopenharmony_ci	if (hbqe) {
245262306a36Sopenharmony_ci		struct hbq_s *hbqp = &phba->hbqs[hbqno];
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci		hbqe->bde.addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
245562306a36Sopenharmony_ci		hbqe->bde.addrLow  = le32_to_cpu(putPaddrLow(physaddr));
245662306a36Sopenharmony_ci		hbqe->bde.tus.f.bdeSize = hbq_buf->total_size;
245762306a36Sopenharmony_ci		hbqe->bde.tus.f.bdeFlags = 0;
245862306a36Sopenharmony_ci		hbqe->bde.tus.w = le32_to_cpu(hbqe->bde.tus.w);
245962306a36Sopenharmony_ci		hbqe->buffer_tag = le32_to_cpu(hbq_buf->tag);
246062306a36Sopenharmony_ci				/* Sync SLIM */
246162306a36Sopenharmony_ci		hbqp->hbqPutIdx = hbqp->next_hbqPutIdx;
246262306a36Sopenharmony_ci		writel(hbqp->hbqPutIdx, phba->hbq_put + hbqno);
246362306a36Sopenharmony_ci				/* flush */
246462306a36Sopenharmony_ci		readl(phba->hbq_put + hbqno);
246562306a36Sopenharmony_ci		list_add_tail(&hbq_buf->dbuf.list, &hbqp->hbq_buffer_list);
246662306a36Sopenharmony_ci		return 0;
246762306a36Sopenharmony_ci	} else
246862306a36Sopenharmony_ci		return -ENOMEM;
246962306a36Sopenharmony_ci}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci/**
247262306a36Sopenharmony_ci * lpfc_sli_hbq_to_firmware_s4 - Post the hbq buffer to SLI4 firmware
247362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
247462306a36Sopenharmony_ci * @hbqno: HBQ number.
247562306a36Sopenharmony_ci * @hbq_buf: Pointer to HBQ buffer.
247662306a36Sopenharmony_ci *
247762306a36Sopenharmony_ci * This function is called with the hbalock held to post an RQE to the SLI4
247862306a36Sopenharmony_ci * firmware. If able to post the RQE to the RQ it will queue the hbq entry to
247962306a36Sopenharmony_ci * the hbq_buffer_list and return zero, otherwise it will return an error.
248062306a36Sopenharmony_ci **/
248162306a36Sopenharmony_cistatic int
248262306a36Sopenharmony_cilpfc_sli_hbq_to_firmware_s4(struct lpfc_hba *phba, uint32_t hbqno,
248362306a36Sopenharmony_ci			    struct hbq_dmabuf *hbq_buf)
248462306a36Sopenharmony_ci{
248562306a36Sopenharmony_ci	int rc;
248662306a36Sopenharmony_ci	struct lpfc_rqe hrqe;
248762306a36Sopenharmony_ci	struct lpfc_rqe drqe;
248862306a36Sopenharmony_ci	struct lpfc_queue *hrq;
248962306a36Sopenharmony_ci	struct lpfc_queue *drq;
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	if (hbqno != LPFC_ELS_HBQ)
249262306a36Sopenharmony_ci		return 1;
249362306a36Sopenharmony_ci	hrq = phba->sli4_hba.hdr_rq;
249462306a36Sopenharmony_ci	drq = phba->sli4_hba.dat_rq;
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
249762306a36Sopenharmony_ci	hrqe.address_lo = putPaddrLow(hbq_buf->hbuf.phys);
249862306a36Sopenharmony_ci	hrqe.address_hi = putPaddrHigh(hbq_buf->hbuf.phys);
249962306a36Sopenharmony_ci	drqe.address_lo = putPaddrLow(hbq_buf->dbuf.phys);
250062306a36Sopenharmony_ci	drqe.address_hi = putPaddrHigh(hbq_buf->dbuf.phys);
250162306a36Sopenharmony_ci	rc = lpfc_sli4_rq_put(hrq, drq, &hrqe, &drqe);
250262306a36Sopenharmony_ci	if (rc < 0)
250362306a36Sopenharmony_ci		return rc;
250462306a36Sopenharmony_ci	hbq_buf->tag = (rc | (hbqno << 16));
250562306a36Sopenharmony_ci	list_add_tail(&hbq_buf->dbuf.list, &phba->hbqs[hbqno].hbq_buffer_list);
250662306a36Sopenharmony_ci	return 0;
250762306a36Sopenharmony_ci}
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci/* HBQ for ELS and CT traffic. */
251062306a36Sopenharmony_cistatic struct lpfc_hbq_init lpfc_els_hbq = {
251162306a36Sopenharmony_ci	.rn = 1,
251262306a36Sopenharmony_ci	.entry_count = 256,
251362306a36Sopenharmony_ci	.mask_count = 0,
251462306a36Sopenharmony_ci	.profile = 0,
251562306a36Sopenharmony_ci	.ring_mask = (1 << LPFC_ELS_RING),
251662306a36Sopenharmony_ci	.buffer_count = 0,
251762306a36Sopenharmony_ci	.init_count = 40,
251862306a36Sopenharmony_ci	.add_count = 40,
251962306a36Sopenharmony_ci};
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci/* Array of HBQs */
252262306a36Sopenharmony_cistruct lpfc_hbq_init *lpfc_hbq_defs[] = {
252362306a36Sopenharmony_ci	&lpfc_els_hbq,
252462306a36Sopenharmony_ci};
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci/**
252762306a36Sopenharmony_ci * lpfc_sli_hbqbuf_fill_hbqs - Post more hbq buffers to HBQ
252862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
252962306a36Sopenharmony_ci * @hbqno: HBQ number.
253062306a36Sopenharmony_ci * @count: Number of HBQ buffers to be posted.
253162306a36Sopenharmony_ci *
253262306a36Sopenharmony_ci * This function is called with no lock held to post more hbq buffers to the
253362306a36Sopenharmony_ci * given HBQ. The function returns the number of HBQ buffers successfully
253462306a36Sopenharmony_ci * posted.
253562306a36Sopenharmony_ci **/
253662306a36Sopenharmony_cistatic int
253762306a36Sopenharmony_cilpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
253862306a36Sopenharmony_ci{
253962306a36Sopenharmony_ci	uint32_t i, posted = 0;
254062306a36Sopenharmony_ci	unsigned long flags;
254162306a36Sopenharmony_ci	struct hbq_dmabuf *hbq_buffer;
254262306a36Sopenharmony_ci	LIST_HEAD(hbq_buf_list);
254362306a36Sopenharmony_ci	if (!phba->hbqs[hbqno].hbq_alloc_buffer)
254462306a36Sopenharmony_ci		return 0;
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci	if ((phba->hbqs[hbqno].buffer_count + count) >
254762306a36Sopenharmony_ci	    lpfc_hbq_defs[hbqno]->entry_count)
254862306a36Sopenharmony_ci		count = lpfc_hbq_defs[hbqno]->entry_count -
254962306a36Sopenharmony_ci					phba->hbqs[hbqno].buffer_count;
255062306a36Sopenharmony_ci	if (!count)
255162306a36Sopenharmony_ci		return 0;
255262306a36Sopenharmony_ci	/* Allocate HBQ entries */
255362306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
255462306a36Sopenharmony_ci		hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
255562306a36Sopenharmony_ci		if (!hbq_buffer)
255662306a36Sopenharmony_ci			break;
255762306a36Sopenharmony_ci		list_add_tail(&hbq_buffer->dbuf.list, &hbq_buf_list);
255862306a36Sopenharmony_ci	}
255962306a36Sopenharmony_ci	/* Check whether HBQ is still in use */
256062306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, flags);
256162306a36Sopenharmony_ci	if (!phba->hbq_in_use)
256262306a36Sopenharmony_ci		goto err;
256362306a36Sopenharmony_ci	while (!list_empty(&hbq_buf_list)) {
256462306a36Sopenharmony_ci		list_remove_head(&hbq_buf_list, hbq_buffer, struct hbq_dmabuf,
256562306a36Sopenharmony_ci				 dbuf.list);
256662306a36Sopenharmony_ci		hbq_buffer->tag = (phba->hbqs[hbqno].buffer_count |
256762306a36Sopenharmony_ci				      (hbqno << 16));
256862306a36Sopenharmony_ci		if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) {
256962306a36Sopenharmony_ci			phba->hbqs[hbqno].buffer_count++;
257062306a36Sopenharmony_ci			posted++;
257162306a36Sopenharmony_ci		} else
257262306a36Sopenharmony_ci			(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
257362306a36Sopenharmony_ci	}
257462306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, flags);
257562306a36Sopenharmony_ci	return posted;
257662306a36Sopenharmony_cierr:
257762306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, flags);
257862306a36Sopenharmony_ci	while (!list_empty(&hbq_buf_list)) {
257962306a36Sopenharmony_ci		list_remove_head(&hbq_buf_list, hbq_buffer, struct hbq_dmabuf,
258062306a36Sopenharmony_ci				 dbuf.list);
258162306a36Sopenharmony_ci		(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
258262306a36Sopenharmony_ci	}
258362306a36Sopenharmony_ci	return 0;
258462306a36Sopenharmony_ci}
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci/**
258762306a36Sopenharmony_ci * lpfc_sli_hbqbuf_add_hbqs - Post more HBQ buffers to firmware
258862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
258962306a36Sopenharmony_ci * @qno: HBQ number.
259062306a36Sopenharmony_ci *
259162306a36Sopenharmony_ci * This function posts more buffers to the HBQ. This function
259262306a36Sopenharmony_ci * is called with no lock held. The function returns the number of HBQ entries
259362306a36Sopenharmony_ci * successfully allocated.
259462306a36Sopenharmony_ci **/
259562306a36Sopenharmony_ciint
259662306a36Sopenharmony_cilpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno)
259762306a36Sopenharmony_ci{
259862306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
259962306a36Sopenharmony_ci		return 0;
260062306a36Sopenharmony_ci	else
260162306a36Sopenharmony_ci		return lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
260262306a36Sopenharmony_ci					 lpfc_hbq_defs[qno]->add_count);
260362306a36Sopenharmony_ci}
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci/**
260662306a36Sopenharmony_ci * lpfc_sli_hbqbuf_init_hbqs - Post initial buffers to the HBQ
260762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
260862306a36Sopenharmony_ci * @qno:  HBQ queue number.
260962306a36Sopenharmony_ci *
261062306a36Sopenharmony_ci * This function is called from SLI initialization code path with
261162306a36Sopenharmony_ci * no lock held to post initial HBQ buffers to firmware. The
261262306a36Sopenharmony_ci * function returns the number of HBQ entries successfully allocated.
261362306a36Sopenharmony_ci **/
261462306a36Sopenharmony_cistatic int
261562306a36Sopenharmony_cilpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno)
261662306a36Sopenharmony_ci{
261762306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
261862306a36Sopenharmony_ci		return lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
261962306a36Sopenharmony_ci					lpfc_hbq_defs[qno]->entry_count);
262062306a36Sopenharmony_ci	else
262162306a36Sopenharmony_ci		return lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
262262306a36Sopenharmony_ci					 lpfc_hbq_defs[qno]->init_count);
262362306a36Sopenharmony_ci}
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci/*
262662306a36Sopenharmony_ci * lpfc_sli_hbqbuf_get - Remove the first hbq off of an hbq list
262762306a36Sopenharmony_ci *
262862306a36Sopenharmony_ci * This function removes the first hbq buffer on an hbq list and returns a
262962306a36Sopenharmony_ci * pointer to that buffer. If it finds no buffers on the list it returns NULL.
263062306a36Sopenharmony_ci **/
263162306a36Sopenharmony_cistatic struct hbq_dmabuf *
263262306a36Sopenharmony_cilpfc_sli_hbqbuf_get(struct list_head *rb_list)
263362306a36Sopenharmony_ci{
263462306a36Sopenharmony_ci	struct lpfc_dmabuf *d_buf;
263562306a36Sopenharmony_ci
263662306a36Sopenharmony_ci	list_remove_head(rb_list, d_buf, struct lpfc_dmabuf, list);
263762306a36Sopenharmony_ci	if (!d_buf)
263862306a36Sopenharmony_ci		return NULL;
263962306a36Sopenharmony_ci	return container_of(d_buf, struct hbq_dmabuf, dbuf);
264062306a36Sopenharmony_ci}
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_ci/**
264362306a36Sopenharmony_ci * lpfc_sli_rqbuf_get - Remove the first dma buffer off of an RQ list
264462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
264562306a36Sopenharmony_ci * @hrq: HBQ number.
264662306a36Sopenharmony_ci *
264762306a36Sopenharmony_ci * This function removes the first RQ buffer on an RQ buffer list and returns a
264862306a36Sopenharmony_ci * pointer to that buffer. If it finds no buffers on the list it returns NULL.
264962306a36Sopenharmony_ci **/
265062306a36Sopenharmony_cistatic struct rqb_dmabuf *
265162306a36Sopenharmony_cilpfc_sli_rqbuf_get(struct lpfc_hba *phba, struct lpfc_queue *hrq)
265262306a36Sopenharmony_ci{
265362306a36Sopenharmony_ci	struct lpfc_dmabuf *h_buf;
265462306a36Sopenharmony_ci	struct lpfc_rqb *rqbp;
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci	rqbp = hrq->rqbp;
265762306a36Sopenharmony_ci	list_remove_head(&rqbp->rqb_buffer_list, h_buf,
265862306a36Sopenharmony_ci			 struct lpfc_dmabuf, list);
265962306a36Sopenharmony_ci	if (!h_buf)
266062306a36Sopenharmony_ci		return NULL;
266162306a36Sopenharmony_ci	rqbp->buffer_count--;
266262306a36Sopenharmony_ci	return container_of(h_buf, struct rqb_dmabuf, hbuf);
266362306a36Sopenharmony_ci}
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci/**
266662306a36Sopenharmony_ci * lpfc_sli_hbqbuf_find - Find the hbq buffer associated with a tag
266762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
266862306a36Sopenharmony_ci * @tag: Tag of the hbq buffer.
266962306a36Sopenharmony_ci *
267062306a36Sopenharmony_ci * This function searches for the hbq buffer associated with the given tag in
267162306a36Sopenharmony_ci * the hbq buffer list. If it finds the hbq buffer, it returns the hbq_buffer
267262306a36Sopenharmony_ci * otherwise it returns NULL.
267362306a36Sopenharmony_ci **/
267462306a36Sopenharmony_cistatic struct hbq_dmabuf *
267562306a36Sopenharmony_cilpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
267662306a36Sopenharmony_ci{
267762306a36Sopenharmony_ci	struct lpfc_dmabuf *d_buf;
267862306a36Sopenharmony_ci	struct hbq_dmabuf *hbq_buf;
267962306a36Sopenharmony_ci	uint32_t hbqno;
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	hbqno = tag >> 16;
268262306a36Sopenharmony_ci	if (hbqno >= LPFC_MAX_HBQS)
268362306a36Sopenharmony_ci		return NULL;
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
268662306a36Sopenharmony_ci	list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) {
268762306a36Sopenharmony_ci		hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
268862306a36Sopenharmony_ci		if (hbq_buf->tag == tag) {
268962306a36Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
269062306a36Sopenharmony_ci			return hbq_buf;
269162306a36Sopenharmony_ci		}
269262306a36Sopenharmony_ci	}
269362306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
269462306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
269562306a36Sopenharmony_ci			"1803 Bad hbq tag. Data: x%x x%x\n",
269662306a36Sopenharmony_ci			tag, phba->hbqs[tag >> 16].buffer_count);
269762306a36Sopenharmony_ci	return NULL;
269862306a36Sopenharmony_ci}
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci/**
270162306a36Sopenharmony_ci * lpfc_sli_free_hbq - Give back the hbq buffer to firmware
270262306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
270362306a36Sopenharmony_ci * @hbq_buffer: Pointer to HBQ buffer.
270462306a36Sopenharmony_ci *
270562306a36Sopenharmony_ci * This function is called with hbalock. This function gives back
270662306a36Sopenharmony_ci * the hbq buffer to firmware. If the HBQ does not have space to
270762306a36Sopenharmony_ci * post the buffer, it will free the buffer.
270862306a36Sopenharmony_ci **/
270962306a36Sopenharmony_civoid
271062306a36Sopenharmony_cilpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *hbq_buffer)
271162306a36Sopenharmony_ci{
271262306a36Sopenharmony_ci	uint32_t hbqno;
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	if (hbq_buffer) {
271562306a36Sopenharmony_ci		hbqno = hbq_buffer->tag >> 16;
271662306a36Sopenharmony_ci		if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
271762306a36Sopenharmony_ci			(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
271862306a36Sopenharmony_ci	}
271962306a36Sopenharmony_ci}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci/**
272262306a36Sopenharmony_ci * lpfc_sli_chk_mbx_command - Check if the mailbox is a legitimate mailbox
272362306a36Sopenharmony_ci * @mbxCommand: mailbox command code.
272462306a36Sopenharmony_ci *
272562306a36Sopenharmony_ci * This function is called by the mailbox event handler function to verify
272662306a36Sopenharmony_ci * that the completed mailbox command is a legitimate mailbox command. If the
272762306a36Sopenharmony_ci * completed mailbox is not known to the function, it will return MBX_SHUTDOWN
272862306a36Sopenharmony_ci * and the mailbox event handler will take the HBA offline.
272962306a36Sopenharmony_ci **/
273062306a36Sopenharmony_cistatic int
273162306a36Sopenharmony_cilpfc_sli_chk_mbx_command(uint8_t mbxCommand)
273262306a36Sopenharmony_ci{
273362306a36Sopenharmony_ci	uint8_t ret;
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	switch (mbxCommand) {
273662306a36Sopenharmony_ci	case MBX_LOAD_SM:
273762306a36Sopenharmony_ci	case MBX_READ_NV:
273862306a36Sopenharmony_ci	case MBX_WRITE_NV:
273962306a36Sopenharmony_ci	case MBX_WRITE_VPARMS:
274062306a36Sopenharmony_ci	case MBX_RUN_BIU_DIAG:
274162306a36Sopenharmony_ci	case MBX_INIT_LINK:
274262306a36Sopenharmony_ci	case MBX_DOWN_LINK:
274362306a36Sopenharmony_ci	case MBX_CONFIG_LINK:
274462306a36Sopenharmony_ci	case MBX_CONFIG_RING:
274562306a36Sopenharmony_ci	case MBX_RESET_RING:
274662306a36Sopenharmony_ci	case MBX_READ_CONFIG:
274762306a36Sopenharmony_ci	case MBX_READ_RCONFIG:
274862306a36Sopenharmony_ci	case MBX_READ_SPARM:
274962306a36Sopenharmony_ci	case MBX_READ_STATUS:
275062306a36Sopenharmony_ci	case MBX_READ_RPI:
275162306a36Sopenharmony_ci	case MBX_READ_XRI:
275262306a36Sopenharmony_ci	case MBX_READ_REV:
275362306a36Sopenharmony_ci	case MBX_READ_LNK_STAT:
275462306a36Sopenharmony_ci	case MBX_REG_LOGIN:
275562306a36Sopenharmony_ci	case MBX_UNREG_LOGIN:
275662306a36Sopenharmony_ci	case MBX_CLEAR_LA:
275762306a36Sopenharmony_ci	case MBX_DUMP_MEMORY:
275862306a36Sopenharmony_ci	case MBX_DUMP_CONTEXT:
275962306a36Sopenharmony_ci	case MBX_RUN_DIAGS:
276062306a36Sopenharmony_ci	case MBX_RESTART:
276162306a36Sopenharmony_ci	case MBX_UPDATE_CFG:
276262306a36Sopenharmony_ci	case MBX_DOWN_LOAD:
276362306a36Sopenharmony_ci	case MBX_DEL_LD_ENTRY:
276462306a36Sopenharmony_ci	case MBX_RUN_PROGRAM:
276562306a36Sopenharmony_ci	case MBX_SET_MASK:
276662306a36Sopenharmony_ci	case MBX_SET_VARIABLE:
276762306a36Sopenharmony_ci	case MBX_UNREG_D_ID:
276862306a36Sopenharmony_ci	case MBX_KILL_BOARD:
276962306a36Sopenharmony_ci	case MBX_CONFIG_FARP:
277062306a36Sopenharmony_ci	case MBX_BEACON:
277162306a36Sopenharmony_ci	case MBX_LOAD_AREA:
277262306a36Sopenharmony_ci	case MBX_RUN_BIU_DIAG64:
277362306a36Sopenharmony_ci	case MBX_CONFIG_PORT:
277462306a36Sopenharmony_ci	case MBX_READ_SPARM64:
277562306a36Sopenharmony_ci	case MBX_READ_RPI64:
277662306a36Sopenharmony_ci	case MBX_REG_LOGIN64:
277762306a36Sopenharmony_ci	case MBX_READ_TOPOLOGY:
277862306a36Sopenharmony_ci	case MBX_WRITE_WWN:
277962306a36Sopenharmony_ci	case MBX_SET_DEBUG:
278062306a36Sopenharmony_ci	case MBX_LOAD_EXP_ROM:
278162306a36Sopenharmony_ci	case MBX_ASYNCEVT_ENABLE:
278262306a36Sopenharmony_ci	case MBX_REG_VPI:
278362306a36Sopenharmony_ci	case MBX_UNREG_VPI:
278462306a36Sopenharmony_ci	case MBX_HEARTBEAT:
278562306a36Sopenharmony_ci	case MBX_PORT_CAPABILITIES:
278662306a36Sopenharmony_ci	case MBX_PORT_IOV_CONTROL:
278762306a36Sopenharmony_ci	case MBX_SLI4_CONFIG:
278862306a36Sopenharmony_ci	case MBX_SLI4_REQ_FTRS:
278962306a36Sopenharmony_ci	case MBX_REG_FCFI:
279062306a36Sopenharmony_ci	case MBX_UNREG_FCFI:
279162306a36Sopenharmony_ci	case MBX_REG_VFI:
279262306a36Sopenharmony_ci	case MBX_UNREG_VFI:
279362306a36Sopenharmony_ci	case MBX_INIT_VPI:
279462306a36Sopenharmony_ci	case MBX_INIT_VFI:
279562306a36Sopenharmony_ci	case MBX_RESUME_RPI:
279662306a36Sopenharmony_ci	case MBX_READ_EVENT_LOG_STATUS:
279762306a36Sopenharmony_ci	case MBX_READ_EVENT_LOG:
279862306a36Sopenharmony_ci	case MBX_SECURITY_MGMT:
279962306a36Sopenharmony_ci	case MBX_AUTH_PORT:
280062306a36Sopenharmony_ci	case MBX_ACCESS_VDATA:
280162306a36Sopenharmony_ci		ret = mbxCommand;
280262306a36Sopenharmony_ci		break;
280362306a36Sopenharmony_ci	default:
280462306a36Sopenharmony_ci		ret = MBX_SHUTDOWN;
280562306a36Sopenharmony_ci		break;
280662306a36Sopenharmony_ci	}
280762306a36Sopenharmony_ci	return ret;
280862306a36Sopenharmony_ci}
280962306a36Sopenharmony_ci
281062306a36Sopenharmony_ci/**
281162306a36Sopenharmony_ci * lpfc_sli_wake_mbox_wait - lpfc_sli_issue_mbox_wait mbox completion handler
281262306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
281362306a36Sopenharmony_ci * @pmboxq: Pointer to mailbox command.
281462306a36Sopenharmony_ci *
281562306a36Sopenharmony_ci * This is completion handler function for mailbox commands issued from
281662306a36Sopenharmony_ci * lpfc_sli_issue_mbox_wait function. This function is called by the
281762306a36Sopenharmony_ci * mailbox event handler function with no lock held. This function
281862306a36Sopenharmony_ci * will wake up thread waiting on the wait queue pointed by context1
281962306a36Sopenharmony_ci * of the mailbox.
282062306a36Sopenharmony_ci **/
282162306a36Sopenharmony_civoid
282262306a36Sopenharmony_cilpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
282362306a36Sopenharmony_ci{
282462306a36Sopenharmony_ci	unsigned long drvr_flag;
282562306a36Sopenharmony_ci	struct completion *pmbox_done;
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci	/*
282862306a36Sopenharmony_ci	 * If pmbox_done is empty, the driver thread gave up waiting and
282962306a36Sopenharmony_ci	 * continued running.
283062306a36Sopenharmony_ci	 */
283162306a36Sopenharmony_ci	pmboxq->mbox_flag |= LPFC_MBX_WAKE;
283262306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, drvr_flag);
283362306a36Sopenharmony_ci	pmbox_done = (struct completion *)pmboxq->context3;
283462306a36Sopenharmony_ci	if (pmbox_done)
283562306a36Sopenharmony_ci		complete(pmbox_done);
283662306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
283762306a36Sopenharmony_ci	return;
283862306a36Sopenharmony_ci}
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_cistatic void
284162306a36Sopenharmony_ci__lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
284262306a36Sopenharmony_ci{
284362306a36Sopenharmony_ci	unsigned long iflags;
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	if (ndlp->nlp_flag & NLP_RELEASE_RPI) {
284662306a36Sopenharmony_ci		lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi);
284762306a36Sopenharmony_ci		spin_lock_irqsave(&ndlp->lock, iflags);
284862306a36Sopenharmony_ci		ndlp->nlp_flag &= ~NLP_RELEASE_RPI;
284962306a36Sopenharmony_ci		ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
285062306a36Sopenharmony_ci		spin_unlock_irqrestore(&ndlp->lock, iflags);
285162306a36Sopenharmony_ci	}
285262306a36Sopenharmony_ci	ndlp->nlp_flag &= ~NLP_UNREG_INP;
285362306a36Sopenharmony_ci}
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_civoid
285662306a36Sopenharmony_cilpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
285762306a36Sopenharmony_ci{
285862306a36Sopenharmony_ci	__lpfc_sli_rpi_release(vport, ndlp);
285962306a36Sopenharmony_ci}
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci/**
286262306a36Sopenharmony_ci * lpfc_sli_def_mbox_cmpl - Default mailbox completion handler
286362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
286462306a36Sopenharmony_ci * @pmb: Pointer to mailbox object.
286562306a36Sopenharmony_ci *
286662306a36Sopenharmony_ci * This function is the default mailbox completion handler. It
286762306a36Sopenharmony_ci * frees the memory resources associated with the completed mailbox
286862306a36Sopenharmony_ci * command. If the completed command is a REG_LOGIN mailbox command,
286962306a36Sopenharmony_ci * this function will issue a UREG_LOGIN to re-claim the RPI.
287062306a36Sopenharmony_ci **/
287162306a36Sopenharmony_civoid
287262306a36Sopenharmony_cilpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
287362306a36Sopenharmony_ci{
287462306a36Sopenharmony_ci	struct lpfc_vport  *vport = pmb->vport;
287562306a36Sopenharmony_ci	struct lpfc_dmabuf *mp;
287662306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp;
287762306a36Sopenharmony_ci	struct Scsi_Host *shost;
287862306a36Sopenharmony_ci	uint16_t rpi, vpi;
287962306a36Sopenharmony_ci	int rc;
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci	/*
288262306a36Sopenharmony_ci	 * If a REG_LOGIN succeeded  after node is destroyed or node
288362306a36Sopenharmony_ci	 * is in re-discovery driver need to cleanup the RPI.
288462306a36Sopenharmony_ci	 */
288562306a36Sopenharmony_ci	if (!(phba->pport->load_flag & FC_UNLOADING) &&
288662306a36Sopenharmony_ci	    pmb->u.mb.mbxCommand == MBX_REG_LOGIN64 &&
288762306a36Sopenharmony_ci	    !pmb->u.mb.mbxStatus) {
288862306a36Sopenharmony_ci		mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
288962306a36Sopenharmony_ci		if (mp) {
289062306a36Sopenharmony_ci			pmb->ctx_buf = NULL;
289162306a36Sopenharmony_ci			lpfc_mbuf_free(phba, mp->virt, mp->phys);
289262306a36Sopenharmony_ci			kfree(mp);
289362306a36Sopenharmony_ci		}
289462306a36Sopenharmony_ci		rpi = pmb->u.mb.un.varWords[0];
289562306a36Sopenharmony_ci		vpi = pmb->u.mb.un.varRegLogin.vpi;
289662306a36Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4)
289762306a36Sopenharmony_ci			vpi -= phba->sli4_hba.max_cfg_param.vpi_base;
289862306a36Sopenharmony_ci		lpfc_unreg_login(phba, vpi, rpi, pmb);
289962306a36Sopenharmony_ci		pmb->vport = vport;
290062306a36Sopenharmony_ci		pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
290162306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
290262306a36Sopenharmony_ci		if (rc != MBX_NOT_FINISHED)
290362306a36Sopenharmony_ci			return;
290462306a36Sopenharmony_ci	}
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	if ((pmb->u.mb.mbxCommand == MBX_REG_VPI) &&
290762306a36Sopenharmony_ci		!(phba->pport->load_flag & FC_UNLOADING) &&
290862306a36Sopenharmony_ci		!pmb->u.mb.mbxStatus) {
290962306a36Sopenharmony_ci		shost = lpfc_shost_from_vport(vport);
291062306a36Sopenharmony_ci		spin_lock_irq(shost->host_lock);
291162306a36Sopenharmony_ci		vport->vpi_state |= LPFC_VPI_REGISTERED;
291262306a36Sopenharmony_ci		vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
291362306a36Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
291462306a36Sopenharmony_ci	}
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci	if (pmb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
291762306a36Sopenharmony_ci		ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
291862306a36Sopenharmony_ci		lpfc_nlp_put(ndlp);
291962306a36Sopenharmony_ci	}
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci	if (pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) {
292262306a36Sopenharmony_ci		ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci		/* Check to see if there are any deferred events to process */
292562306a36Sopenharmony_ci		if (ndlp) {
292662306a36Sopenharmony_ci			lpfc_printf_vlog(
292762306a36Sopenharmony_ci				vport,
292862306a36Sopenharmony_ci				KERN_INFO, LOG_MBOX | LOG_DISCOVERY,
292962306a36Sopenharmony_ci				"1438 UNREG cmpl deferred mbox x%x "
293062306a36Sopenharmony_ci				"on NPort x%x Data: x%x x%x x%px x%x x%x\n",
293162306a36Sopenharmony_ci				ndlp->nlp_rpi, ndlp->nlp_DID,
293262306a36Sopenharmony_ci				ndlp->nlp_flag, ndlp->nlp_defer_did,
293362306a36Sopenharmony_ci				ndlp, vport->load_flag, kref_read(&ndlp->kref));
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci			if ((ndlp->nlp_flag & NLP_UNREG_INP) &&
293662306a36Sopenharmony_ci			    (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) {
293762306a36Sopenharmony_ci				ndlp->nlp_flag &= ~NLP_UNREG_INP;
293862306a36Sopenharmony_ci				ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING;
293962306a36Sopenharmony_ci				lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
294062306a36Sopenharmony_ci			} else {
294162306a36Sopenharmony_ci				__lpfc_sli_rpi_release(vport, ndlp);
294262306a36Sopenharmony_ci			}
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ci			/* The unreg_login mailbox is complete and had a
294562306a36Sopenharmony_ci			 * reference that has to be released.  The PLOGI
294662306a36Sopenharmony_ci			 * got its own ref.
294762306a36Sopenharmony_ci			 */
294862306a36Sopenharmony_ci			lpfc_nlp_put(ndlp);
294962306a36Sopenharmony_ci			pmb->ctx_ndlp = NULL;
295062306a36Sopenharmony_ci		}
295162306a36Sopenharmony_ci	}
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	/* This nlp_put pairs with lpfc_sli4_resume_rpi */
295462306a36Sopenharmony_ci	if (pmb->u.mb.mbxCommand == MBX_RESUME_RPI) {
295562306a36Sopenharmony_ci		ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
295662306a36Sopenharmony_ci		lpfc_nlp_put(ndlp);
295762306a36Sopenharmony_ci	}
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci	/* Check security permission status on INIT_LINK mailbox command */
296062306a36Sopenharmony_ci	if ((pmb->u.mb.mbxCommand == MBX_INIT_LINK) &&
296162306a36Sopenharmony_ci	    (pmb->u.mb.mbxStatus == MBXERR_SEC_NO_PERMISSION))
296262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
296362306a36Sopenharmony_ci				"2860 SLI authentication is required "
296462306a36Sopenharmony_ci				"for INIT_LINK but has not done yet\n");
296562306a36Sopenharmony_ci
296662306a36Sopenharmony_ci	if (bf_get(lpfc_mqe_command, &pmb->u.mqe) == MBX_SLI4_CONFIG)
296762306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, pmb);
296862306a36Sopenharmony_ci	else
296962306a36Sopenharmony_ci		lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
297062306a36Sopenharmony_ci}
297162306a36Sopenharmony_ci /**
297262306a36Sopenharmony_ci * lpfc_sli4_unreg_rpi_cmpl_clr - mailbox completion handler
297362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
297462306a36Sopenharmony_ci * @pmb: Pointer to mailbox object.
297562306a36Sopenharmony_ci *
297662306a36Sopenharmony_ci * This function is the unreg rpi mailbox completion handler. It
297762306a36Sopenharmony_ci * frees the memory resources associated with the completed mailbox
297862306a36Sopenharmony_ci * command. An additional reference is put on the ndlp to prevent
297962306a36Sopenharmony_ci * lpfc_nlp_release from freeing the rpi bit in the bitmask before
298062306a36Sopenharmony_ci * the unreg mailbox command completes, this routine puts the
298162306a36Sopenharmony_ci * reference back.
298262306a36Sopenharmony_ci *
298362306a36Sopenharmony_ci **/
298462306a36Sopenharmony_civoid
298562306a36Sopenharmony_cilpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
298662306a36Sopenharmony_ci{
298762306a36Sopenharmony_ci	struct lpfc_vport  *vport = pmb->vport;
298862306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp;
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci	ndlp = pmb->ctx_ndlp;
299162306a36Sopenharmony_ci	if (pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) {
299262306a36Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4 &&
299362306a36Sopenharmony_ci		    (bf_get(lpfc_sli_intf_if_type,
299462306a36Sopenharmony_ci		     &phba->sli4_hba.sli_intf) >=
299562306a36Sopenharmony_ci		     LPFC_SLI_INTF_IF_TYPE_2)) {
299662306a36Sopenharmony_ci			if (ndlp) {
299762306a36Sopenharmony_ci				lpfc_printf_vlog(
299862306a36Sopenharmony_ci					 vport, KERN_INFO, LOG_MBOX | LOG_SLI,
299962306a36Sopenharmony_ci					 "0010 UNREG_LOGIN vpi:%x "
300062306a36Sopenharmony_ci					 "rpi:%x DID:%x defer x%x flg x%x "
300162306a36Sopenharmony_ci					 "x%px\n",
300262306a36Sopenharmony_ci					 vport->vpi, ndlp->nlp_rpi,
300362306a36Sopenharmony_ci					 ndlp->nlp_DID, ndlp->nlp_defer_did,
300462306a36Sopenharmony_ci					 ndlp->nlp_flag,
300562306a36Sopenharmony_ci					 ndlp);
300662306a36Sopenharmony_ci				ndlp->nlp_flag &= ~NLP_LOGO_ACC;
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci				/* Check to see if there are any deferred
300962306a36Sopenharmony_ci				 * events to process
301062306a36Sopenharmony_ci				 */
301162306a36Sopenharmony_ci				if ((ndlp->nlp_flag & NLP_UNREG_INP) &&
301262306a36Sopenharmony_ci				    (ndlp->nlp_defer_did !=
301362306a36Sopenharmony_ci				    NLP_EVT_NOTHING_PENDING)) {
301462306a36Sopenharmony_ci					lpfc_printf_vlog(
301562306a36Sopenharmony_ci						vport, KERN_INFO, LOG_DISCOVERY,
301662306a36Sopenharmony_ci						"4111 UNREG cmpl deferred "
301762306a36Sopenharmony_ci						"clr x%x on "
301862306a36Sopenharmony_ci						"NPort x%x Data: x%x x%px\n",
301962306a36Sopenharmony_ci						ndlp->nlp_rpi, ndlp->nlp_DID,
302062306a36Sopenharmony_ci						ndlp->nlp_defer_did, ndlp);
302162306a36Sopenharmony_ci					ndlp->nlp_flag &= ~NLP_UNREG_INP;
302262306a36Sopenharmony_ci					ndlp->nlp_defer_did =
302362306a36Sopenharmony_ci						NLP_EVT_NOTHING_PENDING;
302462306a36Sopenharmony_ci					lpfc_issue_els_plogi(
302562306a36Sopenharmony_ci						vport, ndlp->nlp_DID, 0);
302662306a36Sopenharmony_ci				} else {
302762306a36Sopenharmony_ci					__lpfc_sli_rpi_release(vport, ndlp);
302862306a36Sopenharmony_ci				}
302962306a36Sopenharmony_ci				lpfc_nlp_put(ndlp);
303062306a36Sopenharmony_ci			}
303162306a36Sopenharmony_ci		}
303262306a36Sopenharmony_ci	}
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
303562306a36Sopenharmony_ci}
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci/**
303862306a36Sopenharmony_ci * lpfc_sli_handle_mb_event - Handle mailbox completions from firmware
303962306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
304062306a36Sopenharmony_ci *
304162306a36Sopenharmony_ci * This function is called with no lock held. This function processes all
304262306a36Sopenharmony_ci * the completed mailbox commands and gives it to upper layers. The interrupt
304362306a36Sopenharmony_ci * service routine processes mailbox completion interrupt and adds completed
304462306a36Sopenharmony_ci * mailbox commands to the mboxq_cmpl queue and signals the worker thread.
304562306a36Sopenharmony_ci * Worker thread call lpfc_sli_handle_mb_event, which will return the
304662306a36Sopenharmony_ci * completed mailbox commands in mboxq_cmpl queue to the upper layers. This
304762306a36Sopenharmony_ci * function returns the mailbox commands to the upper layer by calling the
304862306a36Sopenharmony_ci * completion handler function of each mailbox.
304962306a36Sopenharmony_ci **/
305062306a36Sopenharmony_ciint
305162306a36Sopenharmony_cilpfc_sli_handle_mb_event(struct lpfc_hba *phba)
305262306a36Sopenharmony_ci{
305362306a36Sopenharmony_ci	MAILBOX_t *pmbox;
305462306a36Sopenharmony_ci	LPFC_MBOXQ_t *pmb;
305562306a36Sopenharmony_ci	int rc;
305662306a36Sopenharmony_ci	LIST_HEAD(cmplq);
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	phba->sli.slistat.mbox_event++;
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_ci	/* Get all completed mailboxe buffers into the cmplq */
306162306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
306262306a36Sopenharmony_ci	list_splice_init(&phba->sli.mboxq_cmpl, &cmplq);
306362306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	/* Get a Mailbox buffer to setup mailbox commands for callback */
306662306a36Sopenharmony_ci	do {
306762306a36Sopenharmony_ci		list_remove_head(&cmplq, pmb, LPFC_MBOXQ_t, list);
306862306a36Sopenharmony_ci		if (pmb == NULL)
306962306a36Sopenharmony_ci			break;
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci		pmbox = &pmb->u.mb;
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci		if (pmbox->mbxCommand != MBX_HEARTBEAT) {
307462306a36Sopenharmony_ci			if (pmb->vport) {
307562306a36Sopenharmony_ci				lpfc_debugfs_disc_trc(pmb->vport,
307662306a36Sopenharmony_ci					LPFC_DISC_TRC_MBOX_VPORT,
307762306a36Sopenharmony_ci					"MBOX cmpl vport: cmd:x%x mb:x%x x%x",
307862306a36Sopenharmony_ci					(uint32_t)pmbox->mbxCommand,
307962306a36Sopenharmony_ci					pmbox->un.varWords[0],
308062306a36Sopenharmony_ci					pmbox->un.varWords[1]);
308162306a36Sopenharmony_ci			}
308262306a36Sopenharmony_ci			else {
308362306a36Sopenharmony_ci				lpfc_debugfs_disc_trc(phba->pport,
308462306a36Sopenharmony_ci					LPFC_DISC_TRC_MBOX,
308562306a36Sopenharmony_ci					"MBOX cmpl:       cmd:x%x mb:x%x x%x",
308662306a36Sopenharmony_ci					(uint32_t)pmbox->mbxCommand,
308762306a36Sopenharmony_ci					pmbox->un.varWords[0],
308862306a36Sopenharmony_ci					pmbox->un.varWords[1]);
308962306a36Sopenharmony_ci			}
309062306a36Sopenharmony_ci		}
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci		/*
309362306a36Sopenharmony_ci		 * It is a fatal error if unknown mbox command completion.
309462306a36Sopenharmony_ci		 */
309562306a36Sopenharmony_ci		if (lpfc_sli_chk_mbx_command(pmbox->mbxCommand) ==
309662306a36Sopenharmony_ci		    MBX_SHUTDOWN) {
309762306a36Sopenharmony_ci			/* Unknown mailbox command compl */
309862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
309962306a36Sopenharmony_ci					"(%d):0323 Unknown Mailbox command "
310062306a36Sopenharmony_ci					"x%x (x%x/x%x) Cmpl\n",
310162306a36Sopenharmony_ci					pmb->vport ? pmb->vport->vpi :
310262306a36Sopenharmony_ci					LPFC_VPORT_UNKNOWN,
310362306a36Sopenharmony_ci					pmbox->mbxCommand,
310462306a36Sopenharmony_ci					lpfc_sli_config_mbox_subsys_get(phba,
310562306a36Sopenharmony_ci									pmb),
310662306a36Sopenharmony_ci					lpfc_sli_config_mbox_opcode_get(phba,
310762306a36Sopenharmony_ci									pmb));
310862306a36Sopenharmony_ci			phba->link_state = LPFC_HBA_ERROR;
310962306a36Sopenharmony_ci			phba->work_hs = HS_FFER3;
311062306a36Sopenharmony_ci			lpfc_handle_eratt(phba);
311162306a36Sopenharmony_ci			continue;
311262306a36Sopenharmony_ci		}
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci		if (pmbox->mbxStatus) {
311562306a36Sopenharmony_ci			phba->sli.slistat.mbox_stat_err++;
311662306a36Sopenharmony_ci			if (pmbox->mbxStatus == MBXERR_NO_RESOURCES) {
311762306a36Sopenharmony_ci				/* Mbox cmd cmpl error - RETRYing */
311862306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO,
311962306a36Sopenharmony_ci					LOG_MBOX | LOG_SLI,
312062306a36Sopenharmony_ci					"(%d):0305 Mbox cmd cmpl "
312162306a36Sopenharmony_ci					"error - RETRYing Data: x%x "
312262306a36Sopenharmony_ci					"(x%x/x%x) x%x x%x x%x\n",
312362306a36Sopenharmony_ci					pmb->vport ? pmb->vport->vpi :
312462306a36Sopenharmony_ci					LPFC_VPORT_UNKNOWN,
312562306a36Sopenharmony_ci					pmbox->mbxCommand,
312662306a36Sopenharmony_ci					lpfc_sli_config_mbox_subsys_get(phba,
312762306a36Sopenharmony_ci									pmb),
312862306a36Sopenharmony_ci					lpfc_sli_config_mbox_opcode_get(phba,
312962306a36Sopenharmony_ci									pmb),
313062306a36Sopenharmony_ci					pmbox->mbxStatus,
313162306a36Sopenharmony_ci					pmbox->un.varWords[0],
313262306a36Sopenharmony_ci					pmb->vport ? pmb->vport->port_state :
313362306a36Sopenharmony_ci					LPFC_VPORT_UNKNOWN);
313462306a36Sopenharmony_ci				pmbox->mbxStatus = 0;
313562306a36Sopenharmony_ci				pmbox->mbxOwner = OWN_HOST;
313662306a36Sopenharmony_ci				rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
313762306a36Sopenharmony_ci				if (rc != MBX_NOT_FINISHED)
313862306a36Sopenharmony_ci					continue;
313962306a36Sopenharmony_ci			}
314062306a36Sopenharmony_ci		}
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_ci		/* Mailbox cmd <cmd> Cmpl <cmpl> */
314362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
314462306a36Sopenharmony_ci				"(%d):0307 Mailbox cmd x%x (x%x/x%x) Cmpl %ps "
314562306a36Sopenharmony_ci				"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x "
314662306a36Sopenharmony_ci				"x%x x%x x%x\n",
314762306a36Sopenharmony_ci				pmb->vport ? pmb->vport->vpi : 0,
314862306a36Sopenharmony_ci				pmbox->mbxCommand,
314962306a36Sopenharmony_ci				lpfc_sli_config_mbox_subsys_get(phba, pmb),
315062306a36Sopenharmony_ci				lpfc_sli_config_mbox_opcode_get(phba, pmb),
315162306a36Sopenharmony_ci				pmb->mbox_cmpl,
315262306a36Sopenharmony_ci				*((uint32_t *) pmbox),
315362306a36Sopenharmony_ci				pmbox->un.varWords[0],
315462306a36Sopenharmony_ci				pmbox->un.varWords[1],
315562306a36Sopenharmony_ci				pmbox->un.varWords[2],
315662306a36Sopenharmony_ci				pmbox->un.varWords[3],
315762306a36Sopenharmony_ci				pmbox->un.varWords[4],
315862306a36Sopenharmony_ci				pmbox->un.varWords[5],
315962306a36Sopenharmony_ci				pmbox->un.varWords[6],
316062306a36Sopenharmony_ci				pmbox->un.varWords[7],
316162306a36Sopenharmony_ci				pmbox->un.varWords[8],
316262306a36Sopenharmony_ci				pmbox->un.varWords[9],
316362306a36Sopenharmony_ci				pmbox->un.varWords[10]);
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_ci		if (pmb->mbox_cmpl)
316662306a36Sopenharmony_ci			pmb->mbox_cmpl(phba,pmb);
316762306a36Sopenharmony_ci	} while (1);
316862306a36Sopenharmony_ci	return 0;
316962306a36Sopenharmony_ci}
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci/**
317262306a36Sopenharmony_ci * lpfc_sli_get_buff - Get the buffer associated with the buffer tag
317362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
317462306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
317562306a36Sopenharmony_ci * @tag: buffer tag.
317662306a36Sopenharmony_ci *
317762306a36Sopenharmony_ci * This function is called with no lock held. When QUE_BUFTAG_BIT bit
317862306a36Sopenharmony_ci * is set in the tag the buffer is posted for a particular exchange,
317962306a36Sopenharmony_ci * the function will return the buffer without replacing the buffer.
318062306a36Sopenharmony_ci * If the buffer is for unsolicited ELS or CT traffic, this function
318162306a36Sopenharmony_ci * returns the buffer and also posts another buffer to the firmware.
318262306a36Sopenharmony_ci **/
318362306a36Sopenharmony_cistatic struct lpfc_dmabuf *
318462306a36Sopenharmony_cilpfc_sli_get_buff(struct lpfc_hba *phba,
318562306a36Sopenharmony_ci		  struct lpfc_sli_ring *pring,
318662306a36Sopenharmony_ci		  uint32_t tag)
318762306a36Sopenharmony_ci{
318862306a36Sopenharmony_ci	struct hbq_dmabuf *hbq_entry;
318962306a36Sopenharmony_ci
319062306a36Sopenharmony_ci	if (tag & QUE_BUFTAG_BIT)
319162306a36Sopenharmony_ci		return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
319262306a36Sopenharmony_ci	hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
319362306a36Sopenharmony_ci	if (!hbq_entry)
319462306a36Sopenharmony_ci		return NULL;
319562306a36Sopenharmony_ci	return &hbq_entry->dbuf;
319662306a36Sopenharmony_ci}
319762306a36Sopenharmony_ci
319862306a36Sopenharmony_ci/**
319962306a36Sopenharmony_ci * lpfc_nvme_unsol_ls_handler - Process an unsolicited event data buffer
320062306a36Sopenharmony_ci *                              containing a NVME LS request.
320162306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
320262306a36Sopenharmony_ci * @piocb: pointer to the iocbq struct representing the sequence starting
320362306a36Sopenharmony_ci *        frame.
320462306a36Sopenharmony_ci *
320562306a36Sopenharmony_ci * This routine initially validates the NVME LS, validates there is a login
320662306a36Sopenharmony_ci * with the port that sent the LS, and then calls the appropriate nvme host
320762306a36Sopenharmony_ci * or target LS request handler.
320862306a36Sopenharmony_ci **/
320962306a36Sopenharmony_cistatic void
321062306a36Sopenharmony_cilpfc_nvme_unsol_ls_handler(struct lpfc_hba *phba, struct lpfc_iocbq *piocb)
321162306a36Sopenharmony_ci{
321262306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp;
321362306a36Sopenharmony_ci	struct lpfc_dmabuf *d_buf;
321462306a36Sopenharmony_ci	struct hbq_dmabuf *nvmebuf;
321562306a36Sopenharmony_ci	struct fc_frame_header *fc_hdr;
321662306a36Sopenharmony_ci	struct lpfc_async_xchg_ctx *axchg = NULL;
321762306a36Sopenharmony_ci	char *failwhy = NULL;
321862306a36Sopenharmony_ci	uint32_t oxid, sid, did, fctl, size;
321962306a36Sopenharmony_ci	int ret = 1;
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	d_buf = piocb->cmd_dmabuf;
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci	nvmebuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
322462306a36Sopenharmony_ci	fc_hdr = nvmebuf->hbuf.virt;
322562306a36Sopenharmony_ci	oxid = be16_to_cpu(fc_hdr->fh_ox_id);
322662306a36Sopenharmony_ci	sid = sli4_sid_from_fc_hdr(fc_hdr);
322762306a36Sopenharmony_ci	did = sli4_did_from_fc_hdr(fc_hdr);
322862306a36Sopenharmony_ci	fctl = (fc_hdr->fh_f_ctl[0] << 16 |
322962306a36Sopenharmony_ci		fc_hdr->fh_f_ctl[1] << 8 |
323062306a36Sopenharmony_ci		fc_hdr->fh_f_ctl[2]);
323162306a36Sopenharmony_ci	size = bf_get(lpfc_rcqe_length, &nvmebuf->cq_event.cqe.rcqe_cmpl);
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci	lpfc_nvmeio_data(phba, "NVME LS    RCV: xri x%x sz %d from %06x\n",
323462306a36Sopenharmony_ci			 oxid, size, sid);
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci	if (phba->pport->load_flag & FC_UNLOADING) {
323762306a36Sopenharmony_ci		failwhy = "Driver Unloading";
323862306a36Sopenharmony_ci	} else if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) {
323962306a36Sopenharmony_ci		failwhy = "NVME FC4 Disabled";
324062306a36Sopenharmony_ci	} else if (!phba->nvmet_support && !phba->pport->localport) {
324162306a36Sopenharmony_ci		failwhy = "No Localport";
324262306a36Sopenharmony_ci	} else if (phba->nvmet_support && !phba->targetport) {
324362306a36Sopenharmony_ci		failwhy = "No Targetport";
324462306a36Sopenharmony_ci	} else if (unlikely(fc_hdr->fh_r_ctl != FC_RCTL_ELS4_REQ)) {
324562306a36Sopenharmony_ci		failwhy = "Bad NVME LS R_CTL";
324662306a36Sopenharmony_ci	} else if (unlikely((fctl & 0x00FF0000) !=
324762306a36Sopenharmony_ci			(FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT))) {
324862306a36Sopenharmony_ci		failwhy = "Bad NVME LS F_CTL";
324962306a36Sopenharmony_ci	} else {
325062306a36Sopenharmony_ci		axchg = kzalloc(sizeof(*axchg), GFP_ATOMIC);
325162306a36Sopenharmony_ci		if (!axchg)
325262306a36Sopenharmony_ci			failwhy = "No CTX memory";
325362306a36Sopenharmony_ci	}
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	if (unlikely(failwhy)) {
325662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
325762306a36Sopenharmony_ci				"6154 Drop NVME LS: SID %06X OXID x%X: %s\n",
325862306a36Sopenharmony_ci				sid, oxid, failwhy);
325962306a36Sopenharmony_ci		goto out_fail;
326062306a36Sopenharmony_ci	}
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci	/* validate the source of the LS is logged in */
326362306a36Sopenharmony_ci	ndlp = lpfc_findnode_did(phba->pport, sid);
326462306a36Sopenharmony_ci	if (!ndlp ||
326562306a36Sopenharmony_ci	    ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
326662306a36Sopenharmony_ci	     (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) {
326762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC,
326862306a36Sopenharmony_ci				"6216 NVME Unsol rcv: No ndlp: "
326962306a36Sopenharmony_ci				"NPort_ID x%x oxid x%x\n",
327062306a36Sopenharmony_ci				sid, oxid);
327162306a36Sopenharmony_ci		goto out_fail;
327262306a36Sopenharmony_ci	}
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci	axchg->phba = phba;
327562306a36Sopenharmony_ci	axchg->ndlp = ndlp;
327662306a36Sopenharmony_ci	axchg->size = size;
327762306a36Sopenharmony_ci	axchg->oxid = oxid;
327862306a36Sopenharmony_ci	axchg->sid = sid;
327962306a36Sopenharmony_ci	axchg->wqeq = NULL;
328062306a36Sopenharmony_ci	axchg->state = LPFC_NVME_STE_LS_RCV;
328162306a36Sopenharmony_ci	axchg->entry_cnt = 1;
328262306a36Sopenharmony_ci	axchg->rqb_buffer = (void *)nvmebuf;
328362306a36Sopenharmony_ci	axchg->hdwq = &phba->sli4_hba.hdwq[0];
328462306a36Sopenharmony_ci	axchg->payload = nvmebuf->dbuf.virt;
328562306a36Sopenharmony_ci	INIT_LIST_HEAD(&axchg->list);
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_ci	if (phba->nvmet_support) {
328862306a36Sopenharmony_ci		ret = lpfc_nvmet_handle_lsreq(phba, axchg);
328962306a36Sopenharmony_ci		spin_lock_irq(&ndlp->lock);
329062306a36Sopenharmony_ci		if (!ret && !(ndlp->fc4_xpt_flags & NLP_XPT_HAS_HH)) {
329162306a36Sopenharmony_ci			ndlp->fc4_xpt_flags |= NLP_XPT_HAS_HH;
329262306a36Sopenharmony_ci			spin_unlock_irq(&ndlp->lock);
329362306a36Sopenharmony_ci
329462306a36Sopenharmony_ci			/* This reference is a single occurrence to hold the
329562306a36Sopenharmony_ci			 * node valid until the nvmet transport calls
329662306a36Sopenharmony_ci			 * host_release.
329762306a36Sopenharmony_ci			 */
329862306a36Sopenharmony_ci			if (!lpfc_nlp_get(ndlp))
329962306a36Sopenharmony_ci				goto out_fail;
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_NODE,
330262306a36Sopenharmony_ci					"6206 NVMET unsol ls_req ndlp x%px "
330362306a36Sopenharmony_ci					"DID x%x xflags x%x refcnt %d\n",
330462306a36Sopenharmony_ci					ndlp, ndlp->nlp_DID,
330562306a36Sopenharmony_ci					ndlp->fc4_xpt_flags,
330662306a36Sopenharmony_ci					kref_read(&ndlp->kref));
330762306a36Sopenharmony_ci		} else {
330862306a36Sopenharmony_ci			spin_unlock_irq(&ndlp->lock);
330962306a36Sopenharmony_ci		}
331062306a36Sopenharmony_ci	} else {
331162306a36Sopenharmony_ci		ret = lpfc_nvme_handle_lsreq(phba, axchg);
331262306a36Sopenharmony_ci	}
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci	/* if zero, LS was successfully handled. If non-zero, LS not handled */
331562306a36Sopenharmony_ci	if (!ret)
331662306a36Sopenharmony_ci		return;
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ciout_fail:
331962306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
332062306a36Sopenharmony_ci			"6155 Drop NVME LS from DID %06X: SID %06X OXID x%X "
332162306a36Sopenharmony_ci			"NVMe%s handler failed %d\n",
332262306a36Sopenharmony_ci			did, sid, oxid,
332362306a36Sopenharmony_ci			(phba->nvmet_support) ? "T" : "I", ret);
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	/* recycle receive buffer */
332662306a36Sopenharmony_ci	lpfc_in_buf_free(phba, &nvmebuf->dbuf);
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_ci	/* If start of new exchange, abort it */
332962306a36Sopenharmony_ci	if (axchg && (fctl & FC_FC_FIRST_SEQ && !(fctl & FC_FC_EX_CTX)))
333062306a36Sopenharmony_ci		ret = lpfc_nvme_unsol_ls_issue_abort(phba, axchg, sid, oxid);
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci	if (ret)
333362306a36Sopenharmony_ci		kfree(axchg);
333462306a36Sopenharmony_ci}
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci/**
333762306a36Sopenharmony_ci * lpfc_complete_unsol_iocb - Complete an unsolicited sequence
333862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
333962306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
334062306a36Sopenharmony_ci * @saveq: Pointer to the iocbq struct representing the sequence starting frame.
334162306a36Sopenharmony_ci * @fch_r_ctl: the r_ctl for the first frame of the sequence.
334262306a36Sopenharmony_ci * @fch_type: the type for the first frame of the sequence.
334362306a36Sopenharmony_ci *
334462306a36Sopenharmony_ci * This function is called with no lock held. This function uses the r_ctl and
334562306a36Sopenharmony_ci * type of the received sequence to find the correct callback function to call
334662306a36Sopenharmony_ci * to process the sequence.
334762306a36Sopenharmony_ci **/
334862306a36Sopenharmony_cistatic int
334962306a36Sopenharmony_cilpfc_complete_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
335062306a36Sopenharmony_ci			 struct lpfc_iocbq *saveq, uint32_t fch_r_ctl,
335162306a36Sopenharmony_ci			 uint32_t fch_type)
335262306a36Sopenharmony_ci{
335362306a36Sopenharmony_ci	int i;
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci	switch (fch_type) {
335662306a36Sopenharmony_ci	case FC_TYPE_NVME:
335762306a36Sopenharmony_ci		lpfc_nvme_unsol_ls_handler(phba, saveq);
335862306a36Sopenharmony_ci		return 1;
335962306a36Sopenharmony_ci	default:
336062306a36Sopenharmony_ci		break;
336162306a36Sopenharmony_ci	}
336262306a36Sopenharmony_ci
336362306a36Sopenharmony_ci	/* unSolicited Responses */
336462306a36Sopenharmony_ci	if (pring->prt[0].profile) {
336562306a36Sopenharmony_ci		if (pring->prt[0].lpfc_sli_rcv_unsol_event)
336662306a36Sopenharmony_ci			(pring->prt[0].lpfc_sli_rcv_unsol_event) (phba, pring,
336762306a36Sopenharmony_ci									saveq);
336862306a36Sopenharmony_ci		return 1;
336962306a36Sopenharmony_ci	}
337062306a36Sopenharmony_ci	/* We must search, based on rctl / type
337162306a36Sopenharmony_ci	   for the right routine */
337262306a36Sopenharmony_ci	for (i = 0; i < pring->num_mask; i++) {
337362306a36Sopenharmony_ci		if ((pring->prt[i].rctl == fch_r_ctl) &&
337462306a36Sopenharmony_ci		    (pring->prt[i].type == fch_type)) {
337562306a36Sopenharmony_ci			if (pring->prt[i].lpfc_sli_rcv_unsol_event)
337662306a36Sopenharmony_ci				(pring->prt[i].lpfc_sli_rcv_unsol_event)
337762306a36Sopenharmony_ci						(phba, pring, saveq);
337862306a36Sopenharmony_ci			return 1;
337962306a36Sopenharmony_ci		}
338062306a36Sopenharmony_ci	}
338162306a36Sopenharmony_ci	return 0;
338262306a36Sopenharmony_ci}
338362306a36Sopenharmony_ci
338462306a36Sopenharmony_cistatic void
338562306a36Sopenharmony_cilpfc_sli_prep_unsol_wqe(struct lpfc_hba *phba,
338662306a36Sopenharmony_ci			struct lpfc_iocbq *saveq)
338762306a36Sopenharmony_ci{
338862306a36Sopenharmony_ci	IOCB_t *irsp;
338962306a36Sopenharmony_ci	union lpfc_wqe128 *wqe;
339062306a36Sopenharmony_ci	u16 i = 0;
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_ci	irsp = &saveq->iocb;
339362306a36Sopenharmony_ci	wqe = &saveq->wqe;
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ci	/* Fill wcqe with the IOCB status fields */
339662306a36Sopenharmony_ci	bf_set(lpfc_wcqe_c_status, &saveq->wcqe_cmpl, irsp->ulpStatus);
339762306a36Sopenharmony_ci	saveq->wcqe_cmpl.word3 = irsp->ulpBdeCount;
339862306a36Sopenharmony_ci	saveq->wcqe_cmpl.parameter = irsp->un.ulpWord[4];
339962306a36Sopenharmony_ci	saveq->wcqe_cmpl.total_data_placed = irsp->unsli3.rcvsli3.acc_len;
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci	/* Source ID */
340262306a36Sopenharmony_ci	bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, irsp->un.rcvels.parmRo);
340362306a36Sopenharmony_ci
340462306a36Sopenharmony_ci	/* rx-id of the response frame */
340562306a36Sopenharmony_ci	bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, irsp->ulpContext);
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ci	/* ox-id of the frame */
340862306a36Sopenharmony_ci	bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com,
340962306a36Sopenharmony_ci	       irsp->unsli3.rcvsli3.ox_id);
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_ci	/* DID */
341262306a36Sopenharmony_ci	bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest,
341362306a36Sopenharmony_ci	       irsp->un.rcvels.remoteID);
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	/* unsol data len */
341662306a36Sopenharmony_ci	for (i = 0; i < irsp->ulpBdeCount; i++) {
341762306a36Sopenharmony_ci		struct lpfc_hbq_entry *hbqe = NULL;
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ci		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
342062306a36Sopenharmony_ci			if (i == 0) {
342162306a36Sopenharmony_ci				hbqe = (struct lpfc_hbq_entry *)
342262306a36Sopenharmony_ci					&irsp->un.ulpWord[0];
342362306a36Sopenharmony_ci				saveq->wqe.gen_req.bde.tus.f.bdeSize =
342462306a36Sopenharmony_ci					hbqe->bde.tus.f.bdeSize;
342562306a36Sopenharmony_ci			} else if (i == 1) {
342662306a36Sopenharmony_ci				hbqe = (struct lpfc_hbq_entry *)
342762306a36Sopenharmony_ci					&irsp->unsli3.sli3Words[4];
342862306a36Sopenharmony_ci				saveq->unsol_rcv_len = hbqe->bde.tus.f.bdeSize;
342962306a36Sopenharmony_ci			}
343062306a36Sopenharmony_ci		}
343162306a36Sopenharmony_ci	}
343262306a36Sopenharmony_ci}
343362306a36Sopenharmony_ci
343462306a36Sopenharmony_ci/**
343562306a36Sopenharmony_ci * lpfc_sli_process_unsol_iocb - Unsolicited iocb handler
343662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
343762306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
343862306a36Sopenharmony_ci * @saveq: Pointer to the unsolicited iocb.
343962306a36Sopenharmony_ci *
344062306a36Sopenharmony_ci * This function is called with no lock held by the ring event handler
344162306a36Sopenharmony_ci * when there is an unsolicited iocb posted to the response ring by the
344262306a36Sopenharmony_ci * firmware. This function gets the buffer associated with the iocbs
344362306a36Sopenharmony_ci * and calls the event handler for the ring. This function handles both
344462306a36Sopenharmony_ci * qring buffers and hbq buffers.
344562306a36Sopenharmony_ci * When the function returns 1 the caller can free the iocb object otherwise
344662306a36Sopenharmony_ci * upper layer functions will free the iocb objects.
344762306a36Sopenharmony_ci **/
344862306a36Sopenharmony_cistatic int
344962306a36Sopenharmony_cilpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
345062306a36Sopenharmony_ci			    struct lpfc_iocbq *saveq)
345162306a36Sopenharmony_ci{
345262306a36Sopenharmony_ci	IOCB_t           * irsp;
345362306a36Sopenharmony_ci	WORD5            * w5p;
345462306a36Sopenharmony_ci	dma_addr_t	 paddr;
345562306a36Sopenharmony_ci	uint32_t           Rctl, Type;
345662306a36Sopenharmony_ci	struct lpfc_iocbq *iocbq;
345762306a36Sopenharmony_ci	struct lpfc_dmabuf *dmzbuf;
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci	irsp = &saveq->iocb;
346062306a36Sopenharmony_ci	saveq->vport = phba->pport;
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_ci	if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
346362306a36Sopenharmony_ci		if (pring->lpfc_sli_rcv_async_status)
346462306a36Sopenharmony_ci			pring->lpfc_sli_rcv_async_status(phba, pring, saveq);
346562306a36Sopenharmony_ci		else
346662306a36Sopenharmony_ci			lpfc_printf_log(phba,
346762306a36Sopenharmony_ci					KERN_WARNING,
346862306a36Sopenharmony_ci					LOG_SLI,
346962306a36Sopenharmony_ci					"0316 Ring %d handler: unexpected "
347062306a36Sopenharmony_ci					"ASYNC_STATUS iocb received evt_code "
347162306a36Sopenharmony_ci					"0x%x\n",
347262306a36Sopenharmony_ci					pring->ringno,
347362306a36Sopenharmony_ci					irsp->un.asyncstat.evt_code);
347462306a36Sopenharmony_ci		return 1;
347562306a36Sopenharmony_ci	}
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci	if ((irsp->ulpCommand == CMD_IOCB_RET_XRI64_CX) &&
347862306a36Sopenharmony_ci	    (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) {
347962306a36Sopenharmony_ci		if (irsp->ulpBdeCount > 0) {
348062306a36Sopenharmony_ci			dmzbuf = lpfc_sli_get_buff(phba, pring,
348162306a36Sopenharmony_ci						   irsp->un.ulpWord[3]);
348262306a36Sopenharmony_ci			lpfc_in_buf_free(phba, dmzbuf);
348362306a36Sopenharmony_ci		}
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci		if (irsp->ulpBdeCount > 1) {
348662306a36Sopenharmony_ci			dmzbuf = lpfc_sli_get_buff(phba, pring,
348762306a36Sopenharmony_ci						   irsp->unsli3.sli3Words[3]);
348862306a36Sopenharmony_ci			lpfc_in_buf_free(phba, dmzbuf);
348962306a36Sopenharmony_ci		}
349062306a36Sopenharmony_ci
349162306a36Sopenharmony_ci		if (irsp->ulpBdeCount > 2) {
349262306a36Sopenharmony_ci			dmzbuf = lpfc_sli_get_buff(phba, pring,
349362306a36Sopenharmony_ci						   irsp->unsli3.sli3Words[7]);
349462306a36Sopenharmony_ci			lpfc_in_buf_free(phba, dmzbuf);
349562306a36Sopenharmony_ci		}
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci		return 1;
349862306a36Sopenharmony_ci	}
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
350162306a36Sopenharmony_ci		if (irsp->ulpBdeCount != 0) {
350262306a36Sopenharmony_ci			saveq->cmd_dmabuf = lpfc_sli_get_buff(phba, pring,
350362306a36Sopenharmony_ci						irsp->un.ulpWord[3]);
350462306a36Sopenharmony_ci			if (!saveq->cmd_dmabuf)
350562306a36Sopenharmony_ci				lpfc_printf_log(phba,
350662306a36Sopenharmony_ci					KERN_ERR,
350762306a36Sopenharmony_ci					LOG_SLI,
350862306a36Sopenharmony_ci					"0341 Ring %d Cannot find buffer for "
350962306a36Sopenharmony_ci					"an unsolicited iocb. tag 0x%x\n",
351062306a36Sopenharmony_ci					pring->ringno,
351162306a36Sopenharmony_ci					irsp->un.ulpWord[3]);
351262306a36Sopenharmony_ci		}
351362306a36Sopenharmony_ci		if (irsp->ulpBdeCount == 2) {
351462306a36Sopenharmony_ci			saveq->bpl_dmabuf = lpfc_sli_get_buff(phba, pring,
351562306a36Sopenharmony_ci						irsp->unsli3.sli3Words[7]);
351662306a36Sopenharmony_ci			if (!saveq->bpl_dmabuf)
351762306a36Sopenharmony_ci				lpfc_printf_log(phba,
351862306a36Sopenharmony_ci					KERN_ERR,
351962306a36Sopenharmony_ci					LOG_SLI,
352062306a36Sopenharmony_ci					"0342 Ring %d Cannot find buffer for an"
352162306a36Sopenharmony_ci					" unsolicited iocb. tag 0x%x\n",
352262306a36Sopenharmony_ci					pring->ringno,
352362306a36Sopenharmony_ci					irsp->unsli3.sli3Words[7]);
352462306a36Sopenharmony_ci		}
352562306a36Sopenharmony_ci		list_for_each_entry(iocbq, &saveq->list, list) {
352662306a36Sopenharmony_ci			irsp = &iocbq->iocb;
352762306a36Sopenharmony_ci			if (irsp->ulpBdeCount != 0) {
352862306a36Sopenharmony_ci				iocbq->cmd_dmabuf = lpfc_sli_get_buff(phba,
352962306a36Sopenharmony_ci							pring,
353062306a36Sopenharmony_ci							irsp->un.ulpWord[3]);
353162306a36Sopenharmony_ci				if (!iocbq->cmd_dmabuf)
353262306a36Sopenharmony_ci					lpfc_printf_log(phba,
353362306a36Sopenharmony_ci						KERN_ERR,
353462306a36Sopenharmony_ci						LOG_SLI,
353562306a36Sopenharmony_ci						"0343 Ring %d Cannot find "
353662306a36Sopenharmony_ci						"buffer for an unsolicited iocb"
353762306a36Sopenharmony_ci						". tag 0x%x\n", pring->ringno,
353862306a36Sopenharmony_ci						irsp->un.ulpWord[3]);
353962306a36Sopenharmony_ci			}
354062306a36Sopenharmony_ci			if (irsp->ulpBdeCount == 2) {
354162306a36Sopenharmony_ci				iocbq->bpl_dmabuf = lpfc_sli_get_buff(phba,
354262306a36Sopenharmony_ci						pring,
354362306a36Sopenharmony_ci						irsp->unsli3.sli3Words[7]);
354462306a36Sopenharmony_ci				if (!iocbq->bpl_dmabuf)
354562306a36Sopenharmony_ci					lpfc_printf_log(phba,
354662306a36Sopenharmony_ci						KERN_ERR,
354762306a36Sopenharmony_ci						LOG_SLI,
354862306a36Sopenharmony_ci						"0344 Ring %d Cannot find "
354962306a36Sopenharmony_ci						"buffer for an unsolicited "
355062306a36Sopenharmony_ci						"iocb. tag 0x%x\n",
355162306a36Sopenharmony_ci						pring->ringno,
355262306a36Sopenharmony_ci						irsp->unsli3.sli3Words[7]);
355362306a36Sopenharmony_ci			}
355462306a36Sopenharmony_ci		}
355562306a36Sopenharmony_ci	} else {
355662306a36Sopenharmony_ci		paddr = getPaddr(irsp->un.cont64[0].addrHigh,
355762306a36Sopenharmony_ci				 irsp->un.cont64[0].addrLow);
355862306a36Sopenharmony_ci		saveq->cmd_dmabuf = lpfc_sli_ringpostbuf_get(phba, pring,
355962306a36Sopenharmony_ci							     paddr);
356062306a36Sopenharmony_ci		if (irsp->ulpBdeCount == 2) {
356162306a36Sopenharmony_ci			paddr = getPaddr(irsp->un.cont64[1].addrHigh,
356262306a36Sopenharmony_ci					 irsp->un.cont64[1].addrLow);
356362306a36Sopenharmony_ci			saveq->bpl_dmabuf = lpfc_sli_ringpostbuf_get(phba,
356462306a36Sopenharmony_ci								   pring,
356562306a36Sopenharmony_ci								   paddr);
356662306a36Sopenharmony_ci		}
356762306a36Sopenharmony_ci	}
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ci	if (irsp->ulpBdeCount != 0 &&
357062306a36Sopenharmony_ci	    (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX ||
357162306a36Sopenharmony_ci	     irsp->ulpStatus == IOSTAT_INTERMED_RSP)) {
357262306a36Sopenharmony_ci		int found = 0;
357362306a36Sopenharmony_ci
357462306a36Sopenharmony_ci		/* search continue save q for same XRI */
357562306a36Sopenharmony_ci		list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) {
357662306a36Sopenharmony_ci			if (iocbq->iocb.unsli3.rcvsli3.ox_id ==
357762306a36Sopenharmony_ci				saveq->iocb.unsli3.rcvsli3.ox_id) {
357862306a36Sopenharmony_ci				list_add_tail(&saveq->list, &iocbq->list);
357962306a36Sopenharmony_ci				found = 1;
358062306a36Sopenharmony_ci				break;
358162306a36Sopenharmony_ci			}
358262306a36Sopenharmony_ci		}
358362306a36Sopenharmony_ci		if (!found)
358462306a36Sopenharmony_ci			list_add_tail(&saveq->clist,
358562306a36Sopenharmony_ci				      &pring->iocb_continue_saveq);
358662306a36Sopenharmony_ci
358762306a36Sopenharmony_ci		if (saveq->iocb.ulpStatus != IOSTAT_INTERMED_RSP) {
358862306a36Sopenharmony_ci			list_del_init(&iocbq->clist);
358962306a36Sopenharmony_ci			saveq = iocbq;
359062306a36Sopenharmony_ci			irsp = &saveq->iocb;
359162306a36Sopenharmony_ci		} else {
359262306a36Sopenharmony_ci			return 0;
359362306a36Sopenharmony_ci		}
359462306a36Sopenharmony_ci	}
359562306a36Sopenharmony_ci	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) ||
359662306a36Sopenharmony_ci	    (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) ||
359762306a36Sopenharmony_ci	    (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)) {
359862306a36Sopenharmony_ci		Rctl = FC_RCTL_ELS_REQ;
359962306a36Sopenharmony_ci		Type = FC_TYPE_ELS;
360062306a36Sopenharmony_ci	} else {
360162306a36Sopenharmony_ci		w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]);
360262306a36Sopenharmony_ci		Rctl = w5p->hcsw.Rctl;
360362306a36Sopenharmony_ci		Type = w5p->hcsw.Type;
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci		/* Firmware Workaround */
360662306a36Sopenharmony_ci		if ((Rctl == 0) && (pring->ringno == LPFC_ELS_RING) &&
360762306a36Sopenharmony_ci			(irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX ||
360862306a36Sopenharmony_ci			 irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
360962306a36Sopenharmony_ci			Rctl = FC_RCTL_ELS_REQ;
361062306a36Sopenharmony_ci			Type = FC_TYPE_ELS;
361162306a36Sopenharmony_ci			w5p->hcsw.Rctl = Rctl;
361262306a36Sopenharmony_ci			w5p->hcsw.Type = Type;
361362306a36Sopenharmony_ci		}
361462306a36Sopenharmony_ci	}
361562306a36Sopenharmony_ci
361662306a36Sopenharmony_ci	if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
361762306a36Sopenharmony_ci	    (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX ||
361862306a36Sopenharmony_ci	    irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
361962306a36Sopenharmony_ci		if (irsp->unsli3.rcvsli3.vpi == 0xffff)
362062306a36Sopenharmony_ci			saveq->vport = phba->pport;
362162306a36Sopenharmony_ci		else
362262306a36Sopenharmony_ci			saveq->vport = lpfc_find_vport_by_vpid(phba,
362362306a36Sopenharmony_ci					       irsp->unsli3.rcvsli3.vpi);
362462306a36Sopenharmony_ci	}
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci	/* Prepare WQE with Unsol frame */
362762306a36Sopenharmony_ci	lpfc_sli_prep_unsol_wqe(phba, saveq);
362862306a36Sopenharmony_ci
362962306a36Sopenharmony_ci	if (!lpfc_complete_unsol_iocb(phba, pring, saveq, Rctl, Type))
363062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
363162306a36Sopenharmony_ci				"0313 Ring %d handler: unexpected Rctl x%x "
363262306a36Sopenharmony_ci				"Type x%x received\n",
363362306a36Sopenharmony_ci				pring->ringno, Rctl, Type);
363462306a36Sopenharmony_ci
363562306a36Sopenharmony_ci	return 1;
363662306a36Sopenharmony_ci}
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci/**
363962306a36Sopenharmony_ci * lpfc_sli_iocbq_lookup - Find command iocb for the given response iocb
364062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
364162306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
364262306a36Sopenharmony_ci * @prspiocb: Pointer to response iocb object.
364362306a36Sopenharmony_ci *
364462306a36Sopenharmony_ci * This function looks up the iocb_lookup table to get the command iocb
364562306a36Sopenharmony_ci * corresponding to the given response iocb using the iotag of the
364662306a36Sopenharmony_ci * response iocb. The driver calls this function with the hbalock held
364762306a36Sopenharmony_ci * for SLI3 ports or the ring lock held for SLI4 ports.
364862306a36Sopenharmony_ci * This function returns the command iocb object if it finds the command
364962306a36Sopenharmony_ci * iocb else returns NULL.
365062306a36Sopenharmony_ci **/
365162306a36Sopenharmony_cistatic struct lpfc_iocbq *
365262306a36Sopenharmony_cilpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
365362306a36Sopenharmony_ci		      struct lpfc_sli_ring *pring,
365462306a36Sopenharmony_ci		      struct lpfc_iocbq *prspiocb)
365562306a36Sopenharmony_ci{
365662306a36Sopenharmony_ci	struct lpfc_iocbq *cmd_iocb = NULL;
365762306a36Sopenharmony_ci	u16 iotag;
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
366062306a36Sopenharmony_ci		iotag = get_wqe_reqtag(prspiocb);
366162306a36Sopenharmony_ci	else
366262306a36Sopenharmony_ci		iotag = prspiocb->iocb.ulpIoTag;
366362306a36Sopenharmony_ci
366462306a36Sopenharmony_ci	if (iotag != 0 && iotag <= phba->sli.last_iotag) {
366562306a36Sopenharmony_ci		cmd_iocb = phba->sli.iocbq_lookup[iotag];
366662306a36Sopenharmony_ci		if (cmd_iocb->cmd_flag & LPFC_IO_ON_TXCMPLQ) {
366762306a36Sopenharmony_ci			/* remove from txcmpl queue list */
366862306a36Sopenharmony_ci			list_del_init(&cmd_iocb->list);
366962306a36Sopenharmony_ci			cmd_iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ;
367062306a36Sopenharmony_ci			pring->txcmplq_cnt--;
367162306a36Sopenharmony_ci			return cmd_iocb;
367262306a36Sopenharmony_ci		}
367362306a36Sopenharmony_ci	}
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
367662306a36Sopenharmony_ci			"0317 iotag x%x is out of "
367762306a36Sopenharmony_ci			"range: max iotag x%x\n",
367862306a36Sopenharmony_ci			iotag, phba->sli.last_iotag);
367962306a36Sopenharmony_ci	return NULL;
368062306a36Sopenharmony_ci}
368162306a36Sopenharmony_ci
368262306a36Sopenharmony_ci/**
368362306a36Sopenharmony_ci * lpfc_sli_iocbq_lookup_by_tag - Find command iocb for the iotag
368462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
368562306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
368662306a36Sopenharmony_ci * @iotag: IOCB tag.
368762306a36Sopenharmony_ci *
368862306a36Sopenharmony_ci * This function looks up the iocb_lookup table to get the command iocb
368962306a36Sopenharmony_ci * corresponding to the given iotag. The driver calls this function with
369062306a36Sopenharmony_ci * the ring lock held because this function is an SLI4 port only helper.
369162306a36Sopenharmony_ci * This function returns the command iocb object if it finds the command
369262306a36Sopenharmony_ci * iocb else returns NULL.
369362306a36Sopenharmony_ci **/
369462306a36Sopenharmony_cistatic struct lpfc_iocbq *
369562306a36Sopenharmony_cilpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
369662306a36Sopenharmony_ci			     struct lpfc_sli_ring *pring, uint16_t iotag)
369762306a36Sopenharmony_ci{
369862306a36Sopenharmony_ci	struct lpfc_iocbq *cmd_iocb = NULL;
369962306a36Sopenharmony_ci
370062306a36Sopenharmony_ci	if (iotag != 0 && iotag <= phba->sli.last_iotag) {
370162306a36Sopenharmony_ci		cmd_iocb = phba->sli.iocbq_lookup[iotag];
370262306a36Sopenharmony_ci		if (cmd_iocb->cmd_flag & LPFC_IO_ON_TXCMPLQ) {
370362306a36Sopenharmony_ci			/* remove from txcmpl queue list */
370462306a36Sopenharmony_ci			list_del_init(&cmd_iocb->list);
370562306a36Sopenharmony_ci			cmd_iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ;
370662306a36Sopenharmony_ci			pring->txcmplq_cnt--;
370762306a36Sopenharmony_ci			return cmd_iocb;
370862306a36Sopenharmony_ci		}
370962306a36Sopenharmony_ci	}
371062306a36Sopenharmony_ci
371162306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
371262306a36Sopenharmony_ci			"0372 iotag x%x lookup error: max iotag (x%x) "
371362306a36Sopenharmony_ci			"cmd_flag x%x\n",
371462306a36Sopenharmony_ci			iotag, phba->sli.last_iotag,
371562306a36Sopenharmony_ci			cmd_iocb ? cmd_iocb->cmd_flag : 0xffff);
371662306a36Sopenharmony_ci	return NULL;
371762306a36Sopenharmony_ci}
371862306a36Sopenharmony_ci
371962306a36Sopenharmony_ci/**
372062306a36Sopenharmony_ci * lpfc_sli_process_sol_iocb - process solicited iocb completion
372162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
372262306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
372362306a36Sopenharmony_ci * @saveq: Pointer to the response iocb to be processed.
372462306a36Sopenharmony_ci *
372562306a36Sopenharmony_ci * This function is called by the ring event handler for non-fcp
372662306a36Sopenharmony_ci * rings when there is a new response iocb in the response ring.
372762306a36Sopenharmony_ci * The caller is not required to hold any locks. This function
372862306a36Sopenharmony_ci * gets the command iocb associated with the response iocb and
372962306a36Sopenharmony_ci * calls the completion handler for the command iocb. If there
373062306a36Sopenharmony_ci * is no completion handler, the function will free the resources
373162306a36Sopenharmony_ci * associated with command iocb. If the response iocb is for
373262306a36Sopenharmony_ci * an already aborted command iocb, the status of the completion
373362306a36Sopenharmony_ci * is changed to IOSTAT_LOCAL_REJECT/IOERR_SLI_ABORTED.
373462306a36Sopenharmony_ci * This function always returns 1.
373562306a36Sopenharmony_ci **/
373662306a36Sopenharmony_cistatic int
373762306a36Sopenharmony_cilpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
373862306a36Sopenharmony_ci			  struct lpfc_iocbq *saveq)
373962306a36Sopenharmony_ci{
374062306a36Sopenharmony_ci	struct lpfc_iocbq *cmdiocbp;
374162306a36Sopenharmony_ci	unsigned long iflag;
374262306a36Sopenharmony_ci	u32 ulp_command, ulp_status, ulp_word4, ulp_context, iotag;
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
374562306a36Sopenharmony_ci		spin_lock_irqsave(&pring->ring_lock, iflag);
374662306a36Sopenharmony_ci	else
374762306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflag);
374862306a36Sopenharmony_ci	cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq);
374962306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
375062306a36Sopenharmony_ci		spin_unlock_irqrestore(&pring->ring_lock, iflag);
375162306a36Sopenharmony_ci	else
375262306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
375362306a36Sopenharmony_ci
375462306a36Sopenharmony_ci	ulp_command = get_job_cmnd(phba, saveq);
375562306a36Sopenharmony_ci	ulp_status = get_job_ulpstatus(phba, saveq);
375662306a36Sopenharmony_ci	ulp_word4 = get_job_word4(phba, saveq);
375762306a36Sopenharmony_ci	ulp_context = get_job_ulpcontext(phba, saveq);
375862306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
375962306a36Sopenharmony_ci		iotag = get_wqe_reqtag(saveq);
376062306a36Sopenharmony_ci	else
376162306a36Sopenharmony_ci		iotag = saveq->iocb.ulpIoTag;
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_ci	if (cmdiocbp) {
376462306a36Sopenharmony_ci		ulp_command = get_job_cmnd(phba, cmdiocbp);
376562306a36Sopenharmony_ci		if (cmdiocbp->cmd_cmpl) {
376662306a36Sopenharmony_ci			/*
376762306a36Sopenharmony_ci			 * If an ELS command failed send an event to mgmt
376862306a36Sopenharmony_ci			 * application.
376962306a36Sopenharmony_ci			 */
377062306a36Sopenharmony_ci			if (ulp_status &&
377162306a36Sopenharmony_ci			     (pring->ringno == LPFC_ELS_RING) &&
377262306a36Sopenharmony_ci			     (ulp_command == CMD_ELS_REQUEST64_CR))
377362306a36Sopenharmony_ci				lpfc_send_els_failure_event(phba,
377462306a36Sopenharmony_ci					cmdiocbp, saveq);
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci			/*
377762306a36Sopenharmony_ci			 * Post all ELS completions to the worker thread.
377862306a36Sopenharmony_ci			 * All other are passed to the completion callback.
377962306a36Sopenharmony_ci			 */
378062306a36Sopenharmony_ci			if (pring->ringno == LPFC_ELS_RING) {
378162306a36Sopenharmony_ci				if ((phba->sli_rev < LPFC_SLI_REV4) &&
378262306a36Sopenharmony_ci				    (cmdiocbp->cmd_flag &
378362306a36Sopenharmony_ci							LPFC_DRIVER_ABORTED)) {
378462306a36Sopenharmony_ci					spin_lock_irqsave(&phba->hbalock,
378562306a36Sopenharmony_ci							  iflag);
378662306a36Sopenharmony_ci					cmdiocbp->cmd_flag &=
378762306a36Sopenharmony_ci						~LPFC_DRIVER_ABORTED;
378862306a36Sopenharmony_ci					spin_unlock_irqrestore(&phba->hbalock,
378962306a36Sopenharmony_ci							       iflag);
379062306a36Sopenharmony_ci					saveq->iocb.ulpStatus =
379162306a36Sopenharmony_ci						IOSTAT_LOCAL_REJECT;
379262306a36Sopenharmony_ci					saveq->iocb.un.ulpWord[4] =
379362306a36Sopenharmony_ci						IOERR_SLI_ABORTED;
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci					/* Firmware could still be in progress
379662306a36Sopenharmony_ci					 * of DMAing payload, so don't free data
379762306a36Sopenharmony_ci					 * buffer till after a hbeat.
379862306a36Sopenharmony_ci					 */
379962306a36Sopenharmony_ci					spin_lock_irqsave(&phba->hbalock,
380062306a36Sopenharmony_ci							  iflag);
380162306a36Sopenharmony_ci					saveq->cmd_flag |= LPFC_DELAY_MEM_FREE;
380262306a36Sopenharmony_ci					spin_unlock_irqrestore(&phba->hbalock,
380362306a36Sopenharmony_ci							       iflag);
380462306a36Sopenharmony_ci				}
380562306a36Sopenharmony_ci				if (phba->sli_rev == LPFC_SLI_REV4) {
380662306a36Sopenharmony_ci					if (saveq->cmd_flag &
380762306a36Sopenharmony_ci					    LPFC_EXCHANGE_BUSY) {
380862306a36Sopenharmony_ci						/* Set cmdiocb flag for the
380962306a36Sopenharmony_ci						 * exchange busy so sgl (xri)
381062306a36Sopenharmony_ci						 * will not be released until
381162306a36Sopenharmony_ci						 * the abort xri is received
381262306a36Sopenharmony_ci						 * from hba.
381362306a36Sopenharmony_ci						 */
381462306a36Sopenharmony_ci						spin_lock_irqsave(
381562306a36Sopenharmony_ci							&phba->hbalock, iflag);
381662306a36Sopenharmony_ci						cmdiocbp->cmd_flag |=
381762306a36Sopenharmony_ci							LPFC_EXCHANGE_BUSY;
381862306a36Sopenharmony_ci						spin_unlock_irqrestore(
381962306a36Sopenharmony_ci							&phba->hbalock, iflag);
382062306a36Sopenharmony_ci					}
382162306a36Sopenharmony_ci					if (cmdiocbp->cmd_flag &
382262306a36Sopenharmony_ci					    LPFC_DRIVER_ABORTED) {
382362306a36Sopenharmony_ci						/*
382462306a36Sopenharmony_ci						 * Clear LPFC_DRIVER_ABORTED
382562306a36Sopenharmony_ci						 * bit in case it was driver
382662306a36Sopenharmony_ci						 * initiated abort.
382762306a36Sopenharmony_ci						 */
382862306a36Sopenharmony_ci						spin_lock_irqsave(
382962306a36Sopenharmony_ci							&phba->hbalock, iflag);
383062306a36Sopenharmony_ci						cmdiocbp->cmd_flag &=
383162306a36Sopenharmony_ci							~LPFC_DRIVER_ABORTED;
383262306a36Sopenharmony_ci						spin_unlock_irqrestore(
383362306a36Sopenharmony_ci							&phba->hbalock, iflag);
383462306a36Sopenharmony_ci						set_job_ulpstatus(cmdiocbp,
383562306a36Sopenharmony_ci								  IOSTAT_LOCAL_REJECT);
383662306a36Sopenharmony_ci						set_job_ulpword4(cmdiocbp,
383762306a36Sopenharmony_ci								 IOERR_ABORT_REQUESTED);
383862306a36Sopenharmony_ci						/*
383962306a36Sopenharmony_ci						 * For SLI4, irspiocb contains
384062306a36Sopenharmony_ci						 * NO_XRI in sli_xritag, it
384162306a36Sopenharmony_ci						 * shall not affect releasing
384262306a36Sopenharmony_ci						 * sgl (xri) process.
384362306a36Sopenharmony_ci						 */
384462306a36Sopenharmony_ci						set_job_ulpstatus(saveq,
384562306a36Sopenharmony_ci								  IOSTAT_LOCAL_REJECT);
384662306a36Sopenharmony_ci						set_job_ulpword4(saveq,
384762306a36Sopenharmony_ci								 IOERR_SLI_ABORTED);
384862306a36Sopenharmony_ci						spin_lock_irqsave(
384962306a36Sopenharmony_ci							&phba->hbalock, iflag);
385062306a36Sopenharmony_ci						saveq->cmd_flag |=
385162306a36Sopenharmony_ci							LPFC_DELAY_MEM_FREE;
385262306a36Sopenharmony_ci						spin_unlock_irqrestore(
385362306a36Sopenharmony_ci							&phba->hbalock, iflag);
385462306a36Sopenharmony_ci					}
385562306a36Sopenharmony_ci				}
385662306a36Sopenharmony_ci			}
385762306a36Sopenharmony_ci			cmdiocbp->cmd_cmpl(phba, cmdiocbp, saveq);
385862306a36Sopenharmony_ci		} else
385962306a36Sopenharmony_ci			lpfc_sli_release_iocbq(phba, cmdiocbp);
386062306a36Sopenharmony_ci	} else {
386162306a36Sopenharmony_ci		/*
386262306a36Sopenharmony_ci		 * Unknown initiating command based on the response iotag.
386362306a36Sopenharmony_ci		 * This could be the case on the ELS ring because of
386462306a36Sopenharmony_ci		 * lpfc_els_abort().
386562306a36Sopenharmony_ci		 */
386662306a36Sopenharmony_ci		if (pring->ringno != LPFC_ELS_RING) {
386762306a36Sopenharmony_ci			/*
386862306a36Sopenharmony_ci			 * Ring <ringno> handler: unexpected completion IoTag
386962306a36Sopenharmony_ci			 * <IoTag>
387062306a36Sopenharmony_ci			 */
387162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
387262306a36Sopenharmony_ci					 "0322 Ring %d handler: "
387362306a36Sopenharmony_ci					 "unexpected completion IoTag x%x "
387462306a36Sopenharmony_ci					 "Data: x%x x%x x%x x%x\n",
387562306a36Sopenharmony_ci					 pring->ringno, iotag, ulp_status,
387662306a36Sopenharmony_ci					 ulp_word4, ulp_command, ulp_context);
387762306a36Sopenharmony_ci		}
387862306a36Sopenharmony_ci	}
387962306a36Sopenharmony_ci
388062306a36Sopenharmony_ci	return 1;
388162306a36Sopenharmony_ci}
388262306a36Sopenharmony_ci
388362306a36Sopenharmony_ci/**
388462306a36Sopenharmony_ci * lpfc_sli_rsp_pointers_error - Response ring pointer error handler
388562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
388662306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
388762306a36Sopenharmony_ci *
388862306a36Sopenharmony_ci * This function is called from the iocb ring event handlers when
388962306a36Sopenharmony_ci * put pointer is ahead of the get pointer for a ring. This function signal
389062306a36Sopenharmony_ci * an error attention condition to the worker thread and the worker
389162306a36Sopenharmony_ci * thread will transition the HBA to offline state.
389262306a36Sopenharmony_ci **/
389362306a36Sopenharmony_cistatic void
389462306a36Sopenharmony_cilpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
389562306a36Sopenharmony_ci{
389662306a36Sopenharmony_ci	struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno];
389762306a36Sopenharmony_ci	/*
389862306a36Sopenharmony_ci	 * Ring <ringno> handler: portRspPut <portRspPut> is bigger than
389962306a36Sopenharmony_ci	 * rsp ring <portRspMax>
390062306a36Sopenharmony_ci	 */
390162306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
390262306a36Sopenharmony_ci			"0312 Ring %d handler: portRspPut %d "
390362306a36Sopenharmony_ci			"is bigger than rsp ring %d\n",
390462306a36Sopenharmony_ci			pring->ringno, le32_to_cpu(pgp->rspPutInx),
390562306a36Sopenharmony_ci			pring->sli.sli3.numRiocb);
390662306a36Sopenharmony_ci
390762306a36Sopenharmony_ci	phba->link_state = LPFC_HBA_ERROR;
390862306a36Sopenharmony_ci
390962306a36Sopenharmony_ci	/*
391062306a36Sopenharmony_ci	 * All error attention handlers are posted to
391162306a36Sopenharmony_ci	 * worker thread
391262306a36Sopenharmony_ci	 */
391362306a36Sopenharmony_ci	phba->work_ha |= HA_ERATT;
391462306a36Sopenharmony_ci	phba->work_hs = HS_FFER3;
391562306a36Sopenharmony_ci
391662306a36Sopenharmony_ci	lpfc_worker_wake_up(phba);
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci	return;
391962306a36Sopenharmony_ci}
392062306a36Sopenharmony_ci
392162306a36Sopenharmony_ci/**
392262306a36Sopenharmony_ci * lpfc_poll_eratt - Error attention polling timer timeout handler
392362306a36Sopenharmony_ci * @t: Context to fetch pointer to address of HBA context object from.
392462306a36Sopenharmony_ci *
392562306a36Sopenharmony_ci * This function is invoked by the Error Attention polling timer when the
392662306a36Sopenharmony_ci * timer times out. It will check the SLI Error Attention register for
392762306a36Sopenharmony_ci * possible attention events. If so, it will post an Error Attention event
392862306a36Sopenharmony_ci * and wake up worker thread to process it. Otherwise, it will set up the
392962306a36Sopenharmony_ci * Error Attention polling timer for the next poll.
393062306a36Sopenharmony_ci **/
393162306a36Sopenharmony_civoid lpfc_poll_eratt(struct timer_list *t)
393262306a36Sopenharmony_ci{
393362306a36Sopenharmony_ci	struct lpfc_hba *phba;
393462306a36Sopenharmony_ci	uint32_t eratt = 0;
393562306a36Sopenharmony_ci	uint64_t sli_intr, cnt;
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_ci	phba = from_timer(phba, t, eratt_poll);
393862306a36Sopenharmony_ci	if (!(phba->hba_flag & HBA_SETUP))
393962306a36Sopenharmony_ci		return;
394062306a36Sopenharmony_ci
394162306a36Sopenharmony_ci	/* Here we will also keep track of interrupts per sec of the hba */
394262306a36Sopenharmony_ci	sli_intr = phba->sli.slistat.sli_intr;
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci	if (phba->sli.slistat.sli_prev_intr > sli_intr)
394562306a36Sopenharmony_ci		cnt = (((uint64_t)(-1) - phba->sli.slistat.sli_prev_intr) +
394662306a36Sopenharmony_ci			sli_intr);
394762306a36Sopenharmony_ci	else
394862306a36Sopenharmony_ci		cnt = (sli_intr - phba->sli.slistat.sli_prev_intr);
394962306a36Sopenharmony_ci
395062306a36Sopenharmony_ci	/* 64-bit integer division not supported on 32-bit x86 - use do_div */
395162306a36Sopenharmony_ci	do_div(cnt, phba->eratt_poll_interval);
395262306a36Sopenharmony_ci	phba->sli.slistat.sli_ips = cnt;
395362306a36Sopenharmony_ci
395462306a36Sopenharmony_ci	phba->sli.slistat.sli_prev_intr = sli_intr;
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	/* Check chip HA register for error event */
395762306a36Sopenharmony_ci	eratt = lpfc_sli_check_eratt(phba);
395862306a36Sopenharmony_ci
395962306a36Sopenharmony_ci	if (eratt)
396062306a36Sopenharmony_ci		/* Tell the worker thread there is work to do */
396162306a36Sopenharmony_ci		lpfc_worker_wake_up(phba);
396262306a36Sopenharmony_ci	else
396362306a36Sopenharmony_ci		/* Restart the timer for next eratt poll */
396462306a36Sopenharmony_ci		mod_timer(&phba->eratt_poll,
396562306a36Sopenharmony_ci			  jiffies +
396662306a36Sopenharmony_ci			  msecs_to_jiffies(1000 * phba->eratt_poll_interval));
396762306a36Sopenharmony_ci	return;
396862306a36Sopenharmony_ci}
396962306a36Sopenharmony_ci
397062306a36Sopenharmony_ci
397162306a36Sopenharmony_ci/**
397262306a36Sopenharmony_ci * lpfc_sli_handle_fast_ring_event - Handle ring events on FCP ring
397362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
397462306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
397562306a36Sopenharmony_ci * @mask: Host attention register mask for this ring.
397662306a36Sopenharmony_ci *
397762306a36Sopenharmony_ci * This function is called from the interrupt context when there is a ring
397862306a36Sopenharmony_ci * event for the fcp ring. The caller does not hold any lock.
397962306a36Sopenharmony_ci * The function processes each response iocb in the response ring until it
398062306a36Sopenharmony_ci * finds an iocb with LE bit set and chains all the iocbs up to the iocb with
398162306a36Sopenharmony_ci * LE bit set. The function will call the completion handler of the command iocb
398262306a36Sopenharmony_ci * if the response iocb indicates a completion for a command iocb or it is
398362306a36Sopenharmony_ci * an abort completion. The function will call lpfc_sli_process_unsol_iocb
398462306a36Sopenharmony_ci * function if this is an unsolicited iocb.
398562306a36Sopenharmony_ci * This routine presumes LPFC_FCP_RING handling and doesn't bother
398662306a36Sopenharmony_ci * to check it explicitly.
398762306a36Sopenharmony_ci */
398862306a36Sopenharmony_ciint
398962306a36Sopenharmony_cilpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
399062306a36Sopenharmony_ci				struct lpfc_sli_ring *pring, uint32_t mask)
399162306a36Sopenharmony_ci{
399262306a36Sopenharmony_ci	struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno];
399362306a36Sopenharmony_ci	IOCB_t *irsp = NULL;
399462306a36Sopenharmony_ci	IOCB_t *entry = NULL;
399562306a36Sopenharmony_ci	struct lpfc_iocbq *cmdiocbq = NULL;
399662306a36Sopenharmony_ci	struct lpfc_iocbq rspiocbq;
399762306a36Sopenharmony_ci	uint32_t status;
399862306a36Sopenharmony_ci	uint32_t portRspPut, portRspMax;
399962306a36Sopenharmony_ci	int rc = 1;
400062306a36Sopenharmony_ci	lpfc_iocb_type type;
400162306a36Sopenharmony_ci	unsigned long iflag;
400262306a36Sopenharmony_ci	uint32_t rsp_cmpl = 0;
400362306a36Sopenharmony_ci
400462306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflag);
400562306a36Sopenharmony_ci	pring->stats.iocb_event++;
400662306a36Sopenharmony_ci
400762306a36Sopenharmony_ci	/*
400862306a36Sopenharmony_ci	 * The next available response entry should never exceed the maximum
400962306a36Sopenharmony_ci	 * entries.  If it does, treat it as an adapter hardware error.
401062306a36Sopenharmony_ci	 */
401162306a36Sopenharmony_ci	portRspMax = pring->sli.sli3.numRiocb;
401262306a36Sopenharmony_ci	portRspPut = le32_to_cpu(pgp->rspPutInx);
401362306a36Sopenharmony_ci	if (unlikely(portRspPut >= portRspMax)) {
401462306a36Sopenharmony_ci		lpfc_sli_rsp_pointers_error(phba, pring);
401562306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
401662306a36Sopenharmony_ci		return 1;
401762306a36Sopenharmony_ci	}
401862306a36Sopenharmony_ci	if (phba->fcp_ring_in_use) {
401962306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
402062306a36Sopenharmony_ci		return 1;
402162306a36Sopenharmony_ci	} else
402262306a36Sopenharmony_ci		phba->fcp_ring_in_use = 1;
402362306a36Sopenharmony_ci
402462306a36Sopenharmony_ci	rmb();
402562306a36Sopenharmony_ci	while (pring->sli.sli3.rspidx != portRspPut) {
402662306a36Sopenharmony_ci		/*
402762306a36Sopenharmony_ci		 * Fetch an entry off the ring and copy it into a local data
402862306a36Sopenharmony_ci		 * structure.  The copy involves a byte-swap since the
402962306a36Sopenharmony_ci		 * network byte order and pci byte orders are different.
403062306a36Sopenharmony_ci		 */
403162306a36Sopenharmony_ci		entry = lpfc_resp_iocb(phba, pring);
403262306a36Sopenharmony_ci		phba->last_completion_time = jiffies;
403362306a36Sopenharmony_ci
403462306a36Sopenharmony_ci		if (++pring->sli.sli3.rspidx >= portRspMax)
403562306a36Sopenharmony_ci			pring->sli.sli3.rspidx = 0;
403662306a36Sopenharmony_ci
403762306a36Sopenharmony_ci		lpfc_sli_pcimem_bcopy((uint32_t *) entry,
403862306a36Sopenharmony_ci				      (uint32_t *) &rspiocbq.iocb,
403962306a36Sopenharmony_ci				      phba->iocb_rsp_size);
404062306a36Sopenharmony_ci		INIT_LIST_HEAD(&(rspiocbq.list));
404162306a36Sopenharmony_ci		irsp = &rspiocbq.iocb;
404262306a36Sopenharmony_ci
404362306a36Sopenharmony_ci		type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK);
404462306a36Sopenharmony_ci		pring->stats.iocb_rsp++;
404562306a36Sopenharmony_ci		rsp_cmpl++;
404662306a36Sopenharmony_ci
404762306a36Sopenharmony_ci		if (unlikely(irsp->ulpStatus)) {
404862306a36Sopenharmony_ci			/*
404962306a36Sopenharmony_ci			 * If resource errors reported from HBA, reduce
405062306a36Sopenharmony_ci			 * queuedepths of the SCSI device.
405162306a36Sopenharmony_ci			 */
405262306a36Sopenharmony_ci			if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
405362306a36Sopenharmony_ci			    ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) ==
405462306a36Sopenharmony_ci			     IOERR_NO_RESOURCES)) {
405562306a36Sopenharmony_ci				spin_unlock_irqrestore(&phba->hbalock, iflag);
405662306a36Sopenharmony_ci				phba->lpfc_rampdown_queue_depth(phba);
405762306a36Sopenharmony_ci				spin_lock_irqsave(&phba->hbalock, iflag);
405862306a36Sopenharmony_ci			}
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_ci			/* Rsp ring <ringno> error: IOCB */
406162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
406262306a36Sopenharmony_ci					"0336 Rsp Ring %d error: IOCB Data: "
406362306a36Sopenharmony_ci					"x%x x%x x%x x%x x%x x%x x%x x%x\n",
406462306a36Sopenharmony_ci					pring->ringno,
406562306a36Sopenharmony_ci					irsp->un.ulpWord[0],
406662306a36Sopenharmony_ci					irsp->un.ulpWord[1],
406762306a36Sopenharmony_ci					irsp->un.ulpWord[2],
406862306a36Sopenharmony_ci					irsp->un.ulpWord[3],
406962306a36Sopenharmony_ci					irsp->un.ulpWord[4],
407062306a36Sopenharmony_ci					irsp->un.ulpWord[5],
407162306a36Sopenharmony_ci					*(uint32_t *)&irsp->un1,
407262306a36Sopenharmony_ci					*((uint32_t *)&irsp->un1 + 1));
407362306a36Sopenharmony_ci		}
407462306a36Sopenharmony_ci
407562306a36Sopenharmony_ci		switch (type) {
407662306a36Sopenharmony_ci		case LPFC_ABORT_IOCB:
407762306a36Sopenharmony_ci		case LPFC_SOL_IOCB:
407862306a36Sopenharmony_ci			/*
407962306a36Sopenharmony_ci			 * Idle exchange closed via ABTS from port.  No iocb
408062306a36Sopenharmony_ci			 * resources need to be recovered.
408162306a36Sopenharmony_ci			 */
408262306a36Sopenharmony_ci			if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
408362306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
408462306a36Sopenharmony_ci						"0333 IOCB cmd 0x%x"
408562306a36Sopenharmony_ci						" processed. Skipping"
408662306a36Sopenharmony_ci						" completion\n",
408762306a36Sopenharmony_ci						irsp->ulpCommand);
408862306a36Sopenharmony_ci				break;
408962306a36Sopenharmony_ci			}
409062306a36Sopenharmony_ci
409162306a36Sopenharmony_ci			cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring,
409262306a36Sopenharmony_ci							 &rspiocbq);
409362306a36Sopenharmony_ci			if (unlikely(!cmdiocbq))
409462306a36Sopenharmony_ci				break;
409562306a36Sopenharmony_ci			if (cmdiocbq->cmd_flag & LPFC_DRIVER_ABORTED)
409662306a36Sopenharmony_ci				cmdiocbq->cmd_flag &= ~LPFC_DRIVER_ABORTED;
409762306a36Sopenharmony_ci			if (cmdiocbq->cmd_cmpl) {
409862306a36Sopenharmony_ci				spin_unlock_irqrestore(&phba->hbalock, iflag);
409962306a36Sopenharmony_ci				cmdiocbq->cmd_cmpl(phba, cmdiocbq, &rspiocbq);
410062306a36Sopenharmony_ci				spin_lock_irqsave(&phba->hbalock, iflag);
410162306a36Sopenharmony_ci			}
410262306a36Sopenharmony_ci			break;
410362306a36Sopenharmony_ci		case LPFC_UNSOL_IOCB:
410462306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflag);
410562306a36Sopenharmony_ci			lpfc_sli_process_unsol_iocb(phba, pring, &rspiocbq);
410662306a36Sopenharmony_ci			spin_lock_irqsave(&phba->hbalock, iflag);
410762306a36Sopenharmony_ci			break;
410862306a36Sopenharmony_ci		default:
410962306a36Sopenharmony_ci			if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
411062306a36Sopenharmony_ci				char adaptermsg[LPFC_MAX_ADPTMSG];
411162306a36Sopenharmony_ci				memset(adaptermsg, 0, LPFC_MAX_ADPTMSG);
411262306a36Sopenharmony_ci				memcpy(&adaptermsg[0], (uint8_t *) irsp,
411362306a36Sopenharmony_ci				       MAX_MSG_DATA);
411462306a36Sopenharmony_ci				dev_warn(&((phba->pcidev)->dev),
411562306a36Sopenharmony_ci					 "lpfc%d: %s\n",
411662306a36Sopenharmony_ci					 phba->brd_no, adaptermsg);
411762306a36Sopenharmony_ci			} else {
411862306a36Sopenharmony_ci				/* Unknown IOCB command */
411962306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
412062306a36Sopenharmony_ci						"0334 Unknown IOCB command "
412162306a36Sopenharmony_ci						"Data: x%x, x%x x%x x%x x%x\n",
412262306a36Sopenharmony_ci						type, irsp->ulpCommand,
412362306a36Sopenharmony_ci						irsp->ulpStatus,
412462306a36Sopenharmony_ci						irsp->ulpIoTag,
412562306a36Sopenharmony_ci						irsp->ulpContext);
412662306a36Sopenharmony_ci			}
412762306a36Sopenharmony_ci			break;
412862306a36Sopenharmony_ci		}
412962306a36Sopenharmony_ci
413062306a36Sopenharmony_ci		/*
413162306a36Sopenharmony_ci		 * The response IOCB has been processed.  Update the ring
413262306a36Sopenharmony_ci		 * pointer in SLIM.  If the port response put pointer has not
413362306a36Sopenharmony_ci		 * been updated, sync the pgp->rspPutInx and fetch the new port
413462306a36Sopenharmony_ci		 * response put pointer.
413562306a36Sopenharmony_ci		 */
413662306a36Sopenharmony_ci		writel(pring->sli.sli3.rspidx,
413762306a36Sopenharmony_ci			&phba->host_gp[pring->ringno].rspGetInx);
413862306a36Sopenharmony_ci
413962306a36Sopenharmony_ci		if (pring->sli.sli3.rspidx == portRspPut)
414062306a36Sopenharmony_ci			portRspPut = le32_to_cpu(pgp->rspPutInx);
414162306a36Sopenharmony_ci	}
414262306a36Sopenharmony_ci
414362306a36Sopenharmony_ci	if ((rsp_cmpl > 0) && (mask & HA_R0RE_REQ)) {
414462306a36Sopenharmony_ci		pring->stats.iocb_rsp_full++;
414562306a36Sopenharmony_ci		status = ((CA_R0ATT | CA_R0RE_RSP) << (pring->ringno * 4));
414662306a36Sopenharmony_ci		writel(status, phba->CAregaddr);
414762306a36Sopenharmony_ci		readl(phba->CAregaddr);
414862306a36Sopenharmony_ci	}
414962306a36Sopenharmony_ci	if ((mask & HA_R0CE_RSP) && (pring->flag & LPFC_CALL_RING_AVAILABLE)) {
415062306a36Sopenharmony_ci		pring->flag &= ~LPFC_CALL_RING_AVAILABLE;
415162306a36Sopenharmony_ci		pring->stats.iocb_cmd_empty++;
415262306a36Sopenharmony_ci
415362306a36Sopenharmony_ci		/* Force update of the local copy of cmdGetInx */
415462306a36Sopenharmony_ci		pring->sli.sli3.local_getidx = le32_to_cpu(pgp->cmdGetInx);
415562306a36Sopenharmony_ci		lpfc_sli_resume_iocb(phba, pring);
415662306a36Sopenharmony_ci
415762306a36Sopenharmony_ci		if ((pring->lpfc_sli_cmd_available))
415862306a36Sopenharmony_ci			(pring->lpfc_sli_cmd_available) (phba, pring);
415962306a36Sopenharmony_ci
416062306a36Sopenharmony_ci	}
416162306a36Sopenharmony_ci
416262306a36Sopenharmony_ci	phba->fcp_ring_in_use = 0;
416362306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflag);
416462306a36Sopenharmony_ci	return rc;
416562306a36Sopenharmony_ci}
416662306a36Sopenharmony_ci
416762306a36Sopenharmony_ci/**
416862306a36Sopenharmony_ci * lpfc_sli_sp_handle_rspiocb - Handle slow-path response iocb
416962306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
417062306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
417162306a36Sopenharmony_ci * @rspiocbp: Pointer to driver response IOCB object.
417262306a36Sopenharmony_ci *
417362306a36Sopenharmony_ci * This function is called from the worker thread when there is a slow-path
417462306a36Sopenharmony_ci * response IOCB to process. This function chains all the response iocbs until
417562306a36Sopenharmony_ci * seeing the iocb with the LE bit set. The function will call
417662306a36Sopenharmony_ci * lpfc_sli_process_sol_iocb function if the response iocb indicates a
417762306a36Sopenharmony_ci * completion of a command iocb. The function will call the
417862306a36Sopenharmony_ci * lpfc_sli_process_unsol_iocb function if this is an unsolicited iocb.
417962306a36Sopenharmony_ci * The function frees the resources or calls the completion handler if this
418062306a36Sopenharmony_ci * iocb is an abort completion. The function returns NULL when the response
418162306a36Sopenharmony_ci * iocb has the LE bit set and all the chained iocbs are processed, otherwise
418262306a36Sopenharmony_ci * this function shall chain the iocb on to the iocb_continueq and return the
418362306a36Sopenharmony_ci * response iocb passed in.
418462306a36Sopenharmony_ci **/
418562306a36Sopenharmony_cistatic struct lpfc_iocbq *
418662306a36Sopenharmony_cilpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
418762306a36Sopenharmony_ci			struct lpfc_iocbq *rspiocbp)
418862306a36Sopenharmony_ci{
418962306a36Sopenharmony_ci	struct lpfc_iocbq *saveq;
419062306a36Sopenharmony_ci	struct lpfc_iocbq *cmdiocb;
419162306a36Sopenharmony_ci	struct lpfc_iocbq *next_iocb;
419262306a36Sopenharmony_ci	IOCB_t *irsp;
419362306a36Sopenharmony_ci	uint32_t free_saveq;
419462306a36Sopenharmony_ci	u8 cmd_type;
419562306a36Sopenharmony_ci	lpfc_iocb_type type;
419662306a36Sopenharmony_ci	unsigned long iflag;
419762306a36Sopenharmony_ci	u32 ulp_status = get_job_ulpstatus(phba, rspiocbp);
419862306a36Sopenharmony_ci	u32 ulp_word4 = get_job_word4(phba, rspiocbp);
419962306a36Sopenharmony_ci	u32 ulp_command = get_job_cmnd(phba, rspiocbp);
420062306a36Sopenharmony_ci	int rc;
420162306a36Sopenharmony_ci
420262306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflag);
420362306a36Sopenharmony_ci	/* First add the response iocb to the countinueq list */
420462306a36Sopenharmony_ci	list_add_tail(&rspiocbp->list, &pring->iocb_continueq);
420562306a36Sopenharmony_ci	pring->iocb_continueq_cnt++;
420662306a36Sopenharmony_ci
420762306a36Sopenharmony_ci	/*
420862306a36Sopenharmony_ci	 * By default, the driver expects to free all resources
420962306a36Sopenharmony_ci	 * associated with this iocb completion.
421062306a36Sopenharmony_ci	 */
421162306a36Sopenharmony_ci	free_saveq = 1;
421262306a36Sopenharmony_ci	saveq = list_get_first(&pring->iocb_continueq,
421362306a36Sopenharmony_ci			       struct lpfc_iocbq, list);
421462306a36Sopenharmony_ci	list_del_init(&pring->iocb_continueq);
421562306a36Sopenharmony_ci	pring->iocb_continueq_cnt = 0;
421662306a36Sopenharmony_ci
421762306a36Sopenharmony_ci	pring->stats.iocb_rsp++;
421862306a36Sopenharmony_ci
421962306a36Sopenharmony_ci	/*
422062306a36Sopenharmony_ci	 * If resource errors reported from HBA, reduce
422162306a36Sopenharmony_ci	 * queuedepths of the SCSI device.
422262306a36Sopenharmony_ci	 */
422362306a36Sopenharmony_ci	if (ulp_status == IOSTAT_LOCAL_REJECT &&
422462306a36Sopenharmony_ci	    ((ulp_word4 & IOERR_PARAM_MASK) ==
422562306a36Sopenharmony_ci	     IOERR_NO_RESOURCES)) {
422662306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
422762306a36Sopenharmony_ci		phba->lpfc_rampdown_queue_depth(phba);
422862306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflag);
422962306a36Sopenharmony_ci	}
423062306a36Sopenharmony_ci
423162306a36Sopenharmony_ci	if (ulp_status) {
423262306a36Sopenharmony_ci		/* Rsp ring <ringno> error: IOCB */
423362306a36Sopenharmony_ci		if (phba->sli_rev < LPFC_SLI_REV4) {
423462306a36Sopenharmony_ci			irsp = &rspiocbp->iocb;
423562306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
423662306a36Sopenharmony_ci					"0328 Rsp Ring %d error: ulp_status x%x "
423762306a36Sopenharmony_ci					"IOCB Data: "
423862306a36Sopenharmony_ci					"x%08x x%08x x%08x x%08x "
423962306a36Sopenharmony_ci					"x%08x x%08x x%08x x%08x "
424062306a36Sopenharmony_ci					"x%08x x%08x x%08x x%08x "
424162306a36Sopenharmony_ci					"x%08x x%08x x%08x x%08x\n",
424262306a36Sopenharmony_ci					pring->ringno, ulp_status,
424362306a36Sopenharmony_ci					get_job_ulpword(rspiocbp, 0),
424462306a36Sopenharmony_ci					get_job_ulpword(rspiocbp, 1),
424562306a36Sopenharmony_ci					get_job_ulpword(rspiocbp, 2),
424662306a36Sopenharmony_ci					get_job_ulpword(rspiocbp, 3),
424762306a36Sopenharmony_ci					get_job_ulpword(rspiocbp, 4),
424862306a36Sopenharmony_ci					get_job_ulpword(rspiocbp, 5),
424962306a36Sopenharmony_ci					*(((uint32_t *)irsp) + 6),
425062306a36Sopenharmony_ci					*(((uint32_t *)irsp) + 7),
425162306a36Sopenharmony_ci					*(((uint32_t *)irsp) + 8),
425262306a36Sopenharmony_ci					*(((uint32_t *)irsp) + 9),
425362306a36Sopenharmony_ci					*(((uint32_t *)irsp) + 10),
425462306a36Sopenharmony_ci					*(((uint32_t *)irsp) + 11),
425562306a36Sopenharmony_ci					*(((uint32_t *)irsp) + 12),
425662306a36Sopenharmony_ci					*(((uint32_t *)irsp) + 13),
425762306a36Sopenharmony_ci					*(((uint32_t *)irsp) + 14),
425862306a36Sopenharmony_ci					*(((uint32_t *)irsp) + 15));
425962306a36Sopenharmony_ci		} else {
426062306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
426162306a36Sopenharmony_ci					"0321 Rsp Ring %d error: "
426262306a36Sopenharmony_ci					"IOCB Data: "
426362306a36Sopenharmony_ci					"x%x x%x x%x x%x\n",
426462306a36Sopenharmony_ci					pring->ringno,
426562306a36Sopenharmony_ci					rspiocbp->wcqe_cmpl.word0,
426662306a36Sopenharmony_ci					rspiocbp->wcqe_cmpl.total_data_placed,
426762306a36Sopenharmony_ci					rspiocbp->wcqe_cmpl.parameter,
426862306a36Sopenharmony_ci					rspiocbp->wcqe_cmpl.word3);
426962306a36Sopenharmony_ci		}
427062306a36Sopenharmony_ci	}
427162306a36Sopenharmony_ci
427262306a36Sopenharmony_ci
427362306a36Sopenharmony_ci	/*
427462306a36Sopenharmony_ci	 * Fetch the iocb command type and call the correct completion
427562306a36Sopenharmony_ci	 * routine. Solicited and Unsolicited IOCBs on the ELS ring
427662306a36Sopenharmony_ci	 * get freed back to the lpfc_iocb_list by the discovery
427762306a36Sopenharmony_ci	 * kernel thread.
427862306a36Sopenharmony_ci	 */
427962306a36Sopenharmony_ci	cmd_type = ulp_command & CMD_IOCB_MASK;
428062306a36Sopenharmony_ci	type = lpfc_sli_iocb_cmd_type(cmd_type);
428162306a36Sopenharmony_ci	switch (type) {
428262306a36Sopenharmony_ci	case LPFC_SOL_IOCB:
428362306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
428462306a36Sopenharmony_ci		rc = lpfc_sli_process_sol_iocb(phba, pring, saveq);
428562306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflag);
428662306a36Sopenharmony_ci		break;
428762306a36Sopenharmony_ci	case LPFC_UNSOL_IOCB:
428862306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
428962306a36Sopenharmony_ci		rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq);
429062306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflag);
429162306a36Sopenharmony_ci		if (!rc)
429262306a36Sopenharmony_ci			free_saveq = 0;
429362306a36Sopenharmony_ci		break;
429462306a36Sopenharmony_ci	case LPFC_ABORT_IOCB:
429562306a36Sopenharmony_ci		cmdiocb = NULL;
429662306a36Sopenharmony_ci		if (ulp_command != CMD_XRI_ABORTED_CX)
429762306a36Sopenharmony_ci			cmdiocb = lpfc_sli_iocbq_lookup(phba, pring,
429862306a36Sopenharmony_ci							saveq);
429962306a36Sopenharmony_ci		if (cmdiocb) {
430062306a36Sopenharmony_ci			/* Call the specified completion routine */
430162306a36Sopenharmony_ci			if (cmdiocb->cmd_cmpl) {
430262306a36Sopenharmony_ci				spin_unlock_irqrestore(&phba->hbalock, iflag);
430362306a36Sopenharmony_ci				cmdiocb->cmd_cmpl(phba, cmdiocb, saveq);
430462306a36Sopenharmony_ci				spin_lock_irqsave(&phba->hbalock, iflag);
430562306a36Sopenharmony_ci			} else {
430662306a36Sopenharmony_ci				__lpfc_sli_release_iocbq(phba, cmdiocb);
430762306a36Sopenharmony_ci			}
430862306a36Sopenharmony_ci		}
430962306a36Sopenharmony_ci		break;
431062306a36Sopenharmony_ci	case LPFC_UNKNOWN_IOCB:
431162306a36Sopenharmony_ci		if (ulp_command == CMD_ADAPTER_MSG) {
431262306a36Sopenharmony_ci			char adaptermsg[LPFC_MAX_ADPTMSG];
431362306a36Sopenharmony_ci
431462306a36Sopenharmony_ci			memset(adaptermsg, 0, LPFC_MAX_ADPTMSG);
431562306a36Sopenharmony_ci			memcpy(&adaptermsg[0], (uint8_t *)&rspiocbp->wqe,
431662306a36Sopenharmony_ci			       MAX_MSG_DATA);
431762306a36Sopenharmony_ci			dev_warn(&((phba->pcidev)->dev),
431862306a36Sopenharmony_ci				 "lpfc%d: %s\n",
431962306a36Sopenharmony_ci				 phba->brd_no, adaptermsg);
432062306a36Sopenharmony_ci		} else {
432162306a36Sopenharmony_ci			/* Unknown command */
432262306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
432362306a36Sopenharmony_ci					"0335 Unknown IOCB "
432462306a36Sopenharmony_ci					"command Data: x%x "
432562306a36Sopenharmony_ci					"x%x x%x x%x\n",
432662306a36Sopenharmony_ci					ulp_command,
432762306a36Sopenharmony_ci					ulp_status,
432862306a36Sopenharmony_ci					get_wqe_reqtag(rspiocbp),
432962306a36Sopenharmony_ci					get_job_ulpcontext(phba, rspiocbp));
433062306a36Sopenharmony_ci		}
433162306a36Sopenharmony_ci		break;
433262306a36Sopenharmony_ci	}
433362306a36Sopenharmony_ci
433462306a36Sopenharmony_ci	if (free_saveq) {
433562306a36Sopenharmony_ci		list_for_each_entry_safe(rspiocbp, next_iocb,
433662306a36Sopenharmony_ci					 &saveq->list, list) {
433762306a36Sopenharmony_ci			list_del_init(&rspiocbp->list);
433862306a36Sopenharmony_ci			__lpfc_sli_release_iocbq(phba, rspiocbp);
433962306a36Sopenharmony_ci		}
434062306a36Sopenharmony_ci		__lpfc_sli_release_iocbq(phba, saveq);
434162306a36Sopenharmony_ci	}
434262306a36Sopenharmony_ci	rspiocbp = NULL;
434362306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflag);
434462306a36Sopenharmony_ci	return rspiocbp;
434562306a36Sopenharmony_ci}
434662306a36Sopenharmony_ci
434762306a36Sopenharmony_ci/**
434862306a36Sopenharmony_ci * lpfc_sli_handle_slow_ring_event - Wrapper func for handling slow-path iocbs
434962306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
435062306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
435162306a36Sopenharmony_ci * @mask: Host attention register mask for this ring.
435262306a36Sopenharmony_ci *
435362306a36Sopenharmony_ci * This routine wraps the actual slow_ring event process routine from the
435462306a36Sopenharmony_ci * API jump table function pointer from the lpfc_hba struct.
435562306a36Sopenharmony_ci **/
435662306a36Sopenharmony_civoid
435762306a36Sopenharmony_cilpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
435862306a36Sopenharmony_ci				struct lpfc_sli_ring *pring, uint32_t mask)
435962306a36Sopenharmony_ci{
436062306a36Sopenharmony_ci	phba->lpfc_sli_handle_slow_ring_event(phba, pring, mask);
436162306a36Sopenharmony_ci}
436262306a36Sopenharmony_ci
436362306a36Sopenharmony_ci/**
436462306a36Sopenharmony_ci * lpfc_sli_handle_slow_ring_event_s3 - Handle SLI3 ring event for non-FCP rings
436562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
436662306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
436762306a36Sopenharmony_ci * @mask: Host attention register mask for this ring.
436862306a36Sopenharmony_ci *
436962306a36Sopenharmony_ci * This function is called from the worker thread when there is a ring event
437062306a36Sopenharmony_ci * for non-fcp rings. The caller does not hold any lock. The function will
437162306a36Sopenharmony_ci * remove each response iocb in the response ring and calls the handle
437262306a36Sopenharmony_ci * response iocb routine (lpfc_sli_sp_handle_rspiocb) to process it.
437362306a36Sopenharmony_ci **/
437462306a36Sopenharmony_cistatic void
437562306a36Sopenharmony_cilpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba,
437662306a36Sopenharmony_ci				   struct lpfc_sli_ring *pring, uint32_t mask)
437762306a36Sopenharmony_ci{
437862306a36Sopenharmony_ci	struct lpfc_pgp *pgp;
437962306a36Sopenharmony_ci	IOCB_t *entry;
438062306a36Sopenharmony_ci	IOCB_t *irsp = NULL;
438162306a36Sopenharmony_ci	struct lpfc_iocbq *rspiocbp = NULL;
438262306a36Sopenharmony_ci	uint32_t portRspPut, portRspMax;
438362306a36Sopenharmony_ci	unsigned long iflag;
438462306a36Sopenharmony_ci	uint32_t status;
438562306a36Sopenharmony_ci
438662306a36Sopenharmony_ci	pgp = &phba->port_gp[pring->ringno];
438762306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflag);
438862306a36Sopenharmony_ci	pring->stats.iocb_event++;
438962306a36Sopenharmony_ci
439062306a36Sopenharmony_ci	/*
439162306a36Sopenharmony_ci	 * The next available response entry should never exceed the maximum
439262306a36Sopenharmony_ci	 * entries.  If it does, treat it as an adapter hardware error.
439362306a36Sopenharmony_ci	 */
439462306a36Sopenharmony_ci	portRspMax = pring->sli.sli3.numRiocb;
439562306a36Sopenharmony_ci	portRspPut = le32_to_cpu(pgp->rspPutInx);
439662306a36Sopenharmony_ci	if (portRspPut >= portRspMax) {
439762306a36Sopenharmony_ci		/*
439862306a36Sopenharmony_ci		 * Ring <ringno> handler: portRspPut <portRspPut> is bigger than
439962306a36Sopenharmony_ci		 * rsp ring <portRspMax>
440062306a36Sopenharmony_ci		 */
440162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
440262306a36Sopenharmony_ci				"0303 Ring %d handler: portRspPut %d "
440362306a36Sopenharmony_ci				"is bigger than rsp ring %d\n",
440462306a36Sopenharmony_ci				pring->ringno, portRspPut, portRspMax);
440562306a36Sopenharmony_ci
440662306a36Sopenharmony_ci		phba->link_state = LPFC_HBA_ERROR;
440762306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
440862306a36Sopenharmony_ci
440962306a36Sopenharmony_ci		phba->work_hs = HS_FFER3;
441062306a36Sopenharmony_ci		lpfc_handle_eratt(phba);
441162306a36Sopenharmony_ci
441262306a36Sopenharmony_ci		return;
441362306a36Sopenharmony_ci	}
441462306a36Sopenharmony_ci
441562306a36Sopenharmony_ci	rmb();
441662306a36Sopenharmony_ci	while (pring->sli.sli3.rspidx != portRspPut) {
441762306a36Sopenharmony_ci		/*
441862306a36Sopenharmony_ci		 * Build a completion list and call the appropriate handler.
441962306a36Sopenharmony_ci		 * The process is to get the next available response iocb, get
442062306a36Sopenharmony_ci		 * a free iocb from the list, copy the response data into the
442162306a36Sopenharmony_ci		 * free iocb, insert to the continuation list, and update the
442262306a36Sopenharmony_ci		 * next response index to slim.  This process makes response
442362306a36Sopenharmony_ci		 * iocb's in the ring available to DMA as fast as possible but
442462306a36Sopenharmony_ci		 * pays a penalty for a copy operation.  Since the iocb is
442562306a36Sopenharmony_ci		 * only 32 bytes, this penalty is considered small relative to
442662306a36Sopenharmony_ci		 * the PCI reads for register values and a slim write.  When
442762306a36Sopenharmony_ci		 * the ulpLe field is set, the entire Command has been
442862306a36Sopenharmony_ci		 * received.
442962306a36Sopenharmony_ci		 */
443062306a36Sopenharmony_ci		entry = lpfc_resp_iocb(phba, pring);
443162306a36Sopenharmony_ci
443262306a36Sopenharmony_ci		phba->last_completion_time = jiffies;
443362306a36Sopenharmony_ci		rspiocbp = __lpfc_sli_get_iocbq(phba);
443462306a36Sopenharmony_ci		if (rspiocbp == NULL) {
443562306a36Sopenharmony_ci			printk(KERN_ERR "%s: out of buffers! Failing "
443662306a36Sopenharmony_ci			       "completion.\n", __func__);
443762306a36Sopenharmony_ci			break;
443862306a36Sopenharmony_ci		}
443962306a36Sopenharmony_ci
444062306a36Sopenharmony_ci		lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb,
444162306a36Sopenharmony_ci				      phba->iocb_rsp_size);
444262306a36Sopenharmony_ci		irsp = &rspiocbp->iocb;
444362306a36Sopenharmony_ci
444462306a36Sopenharmony_ci		if (++pring->sli.sli3.rspidx >= portRspMax)
444562306a36Sopenharmony_ci			pring->sli.sli3.rspidx = 0;
444662306a36Sopenharmony_ci
444762306a36Sopenharmony_ci		if (pring->ringno == LPFC_ELS_RING) {
444862306a36Sopenharmony_ci			lpfc_debugfs_slow_ring_trc(phba,
444962306a36Sopenharmony_ci			"IOCB rsp ring:   wd4:x%08x wd6:x%08x wd7:x%08x",
445062306a36Sopenharmony_ci				*(((uint32_t *) irsp) + 4),
445162306a36Sopenharmony_ci				*(((uint32_t *) irsp) + 6),
445262306a36Sopenharmony_ci				*(((uint32_t *) irsp) + 7));
445362306a36Sopenharmony_ci		}
445462306a36Sopenharmony_ci
445562306a36Sopenharmony_ci		writel(pring->sli.sli3.rspidx,
445662306a36Sopenharmony_ci			&phba->host_gp[pring->ringno].rspGetInx);
445762306a36Sopenharmony_ci
445862306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
445962306a36Sopenharmony_ci		/* Handle the response IOCB */
446062306a36Sopenharmony_ci		rspiocbp = lpfc_sli_sp_handle_rspiocb(phba, pring, rspiocbp);
446162306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflag);
446262306a36Sopenharmony_ci
446362306a36Sopenharmony_ci		/*
446462306a36Sopenharmony_ci		 * If the port response put pointer has not been updated, sync
446562306a36Sopenharmony_ci		 * the pgp->rspPutInx in the MAILBOX_tand fetch the new port
446662306a36Sopenharmony_ci		 * response put pointer.
446762306a36Sopenharmony_ci		 */
446862306a36Sopenharmony_ci		if (pring->sli.sli3.rspidx == portRspPut) {
446962306a36Sopenharmony_ci			portRspPut = le32_to_cpu(pgp->rspPutInx);
447062306a36Sopenharmony_ci		}
447162306a36Sopenharmony_ci	} /* while (pring->sli.sli3.rspidx != portRspPut) */
447262306a36Sopenharmony_ci
447362306a36Sopenharmony_ci	if ((rspiocbp != NULL) && (mask & HA_R0RE_REQ)) {
447462306a36Sopenharmony_ci		/* At least one response entry has been freed */
447562306a36Sopenharmony_ci		pring->stats.iocb_rsp_full++;
447662306a36Sopenharmony_ci		/* SET RxRE_RSP in Chip Att register */
447762306a36Sopenharmony_ci		status = ((CA_R0ATT | CA_R0RE_RSP) << (pring->ringno * 4));
447862306a36Sopenharmony_ci		writel(status, phba->CAregaddr);
447962306a36Sopenharmony_ci		readl(phba->CAregaddr); /* flush */
448062306a36Sopenharmony_ci	}
448162306a36Sopenharmony_ci	if ((mask & HA_R0CE_RSP) && (pring->flag & LPFC_CALL_RING_AVAILABLE)) {
448262306a36Sopenharmony_ci		pring->flag &= ~LPFC_CALL_RING_AVAILABLE;
448362306a36Sopenharmony_ci		pring->stats.iocb_cmd_empty++;
448462306a36Sopenharmony_ci
448562306a36Sopenharmony_ci		/* Force update of the local copy of cmdGetInx */
448662306a36Sopenharmony_ci		pring->sli.sli3.local_getidx = le32_to_cpu(pgp->cmdGetInx);
448762306a36Sopenharmony_ci		lpfc_sli_resume_iocb(phba, pring);
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci		if ((pring->lpfc_sli_cmd_available))
449062306a36Sopenharmony_ci			(pring->lpfc_sli_cmd_available) (phba, pring);
449162306a36Sopenharmony_ci
449262306a36Sopenharmony_ci	}
449362306a36Sopenharmony_ci
449462306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflag);
449562306a36Sopenharmony_ci	return;
449662306a36Sopenharmony_ci}
449762306a36Sopenharmony_ci
449862306a36Sopenharmony_ci/**
449962306a36Sopenharmony_ci * lpfc_sli_handle_slow_ring_event_s4 - Handle SLI4 slow-path els events
450062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
450162306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
450262306a36Sopenharmony_ci * @mask: Host attention register mask for this ring.
450362306a36Sopenharmony_ci *
450462306a36Sopenharmony_ci * This function is called from the worker thread when there is a pending
450562306a36Sopenharmony_ci * ELS response iocb on the driver internal slow-path response iocb worker
450662306a36Sopenharmony_ci * queue. The caller does not hold any lock. The function will remove each
450762306a36Sopenharmony_ci * response iocb from the response worker queue and calls the handle
450862306a36Sopenharmony_ci * response iocb routine (lpfc_sli_sp_handle_rspiocb) to process it.
450962306a36Sopenharmony_ci **/
451062306a36Sopenharmony_cistatic void
451162306a36Sopenharmony_cilpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba,
451262306a36Sopenharmony_ci				   struct lpfc_sli_ring *pring, uint32_t mask)
451362306a36Sopenharmony_ci{
451462306a36Sopenharmony_ci	struct lpfc_iocbq *irspiocbq;
451562306a36Sopenharmony_ci	struct hbq_dmabuf *dmabuf;
451662306a36Sopenharmony_ci	struct lpfc_cq_event *cq_event;
451762306a36Sopenharmony_ci	unsigned long iflag;
451862306a36Sopenharmony_ci	int count = 0;
451962306a36Sopenharmony_ci
452062306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflag);
452162306a36Sopenharmony_ci	phba->hba_flag &= ~HBA_SP_QUEUE_EVT;
452262306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflag);
452362306a36Sopenharmony_ci	while (!list_empty(&phba->sli4_hba.sp_queue_event)) {
452462306a36Sopenharmony_ci		/* Get the response iocb from the head of work queue */
452562306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflag);
452662306a36Sopenharmony_ci		list_remove_head(&phba->sli4_hba.sp_queue_event,
452762306a36Sopenharmony_ci				 cq_event, struct lpfc_cq_event, list);
452862306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
452962306a36Sopenharmony_ci
453062306a36Sopenharmony_ci		switch (bf_get(lpfc_wcqe_c_code, &cq_event->cqe.wcqe_cmpl)) {
453162306a36Sopenharmony_ci		case CQE_CODE_COMPL_WQE:
453262306a36Sopenharmony_ci			irspiocbq = container_of(cq_event, struct lpfc_iocbq,
453362306a36Sopenharmony_ci						 cq_event);
453462306a36Sopenharmony_ci			/* Translate ELS WCQE to response IOCBQ */
453562306a36Sopenharmony_ci			irspiocbq = lpfc_sli4_els_preprocess_rspiocbq(phba,
453662306a36Sopenharmony_ci								      irspiocbq);
453762306a36Sopenharmony_ci			if (irspiocbq)
453862306a36Sopenharmony_ci				lpfc_sli_sp_handle_rspiocb(phba, pring,
453962306a36Sopenharmony_ci							   irspiocbq);
454062306a36Sopenharmony_ci			count++;
454162306a36Sopenharmony_ci			break;
454262306a36Sopenharmony_ci		case CQE_CODE_RECEIVE:
454362306a36Sopenharmony_ci		case CQE_CODE_RECEIVE_V1:
454462306a36Sopenharmony_ci			dmabuf = container_of(cq_event, struct hbq_dmabuf,
454562306a36Sopenharmony_ci					      cq_event);
454662306a36Sopenharmony_ci			lpfc_sli4_handle_received_buffer(phba, dmabuf);
454762306a36Sopenharmony_ci			count++;
454862306a36Sopenharmony_ci			break;
454962306a36Sopenharmony_ci		default:
455062306a36Sopenharmony_ci			break;
455162306a36Sopenharmony_ci		}
455262306a36Sopenharmony_ci
455362306a36Sopenharmony_ci		/* Limit the number of events to 64 to avoid soft lockups */
455462306a36Sopenharmony_ci		if (count == 64)
455562306a36Sopenharmony_ci			break;
455662306a36Sopenharmony_ci	}
455762306a36Sopenharmony_ci}
455862306a36Sopenharmony_ci
455962306a36Sopenharmony_ci/**
456062306a36Sopenharmony_ci * lpfc_sli_abort_iocb_ring - Abort all iocbs in the ring
456162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
456262306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
456362306a36Sopenharmony_ci *
456462306a36Sopenharmony_ci * This function aborts all iocbs in the given ring and frees all the iocb
456562306a36Sopenharmony_ci * objects in txq. This function issues an abort iocb for all the iocb commands
456662306a36Sopenharmony_ci * in txcmplq. The iocbs in the txcmplq is not guaranteed to complete before
456762306a36Sopenharmony_ci * the return of this function. The caller is not required to hold any locks.
456862306a36Sopenharmony_ci **/
456962306a36Sopenharmony_civoid
457062306a36Sopenharmony_cilpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
457162306a36Sopenharmony_ci{
457262306a36Sopenharmony_ci	LIST_HEAD(tx_completions);
457362306a36Sopenharmony_ci	LIST_HEAD(txcmplq_completions);
457462306a36Sopenharmony_ci	struct lpfc_iocbq *iocb, *next_iocb;
457562306a36Sopenharmony_ci	int offline;
457662306a36Sopenharmony_ci
457762306a36Sopenharmony_ci	if (pring->ringno == LPFC_ELS_RING) {
457862306a36Sopenharmony_ci		lpfc_fabric_abort_hba(phba);
457962306a36Sopenharmony_ci	}
458062306a36Sopenharmony_ci	offline = pci_channel_offline(phba->pcidev);
458162306a36Sopenharmony_ci
458262306a36Sopenharmony_ci	/* Error everything on txq and txcmplq
458362306a36Sopenharmony_ci	 * First do the txq.
458462306a36Sopenharmony_ci	 */
458562306a36Sopenharmony_ci	if (phba->sli_rev >= LPFC_SLI_REV4) {
458662306a36Sopenharmony_ci		spin_lock_irq(&pring->ring_lock);
458762306a36Sopenharmony_ci		list_splice_init(&pring->txq, &tx_completions);
458862306a36Sopenharmony_ci		pring->txq_cnt = 0;
458962306a36Sopenharmony_ci
459062306a36Sopenharmony_ci		if (offline) {
459162306a36Sopenharmony_ci			list_splice_init(&pring->txcmplq,
459262306a36Sopenharmony_ci					 &txcmplq_completions);
459362306a36Sopenharmony_ci		} else {
459462306a36Sopenharmony_ci			/* Next issue ABTS for everything on the txcmplq */
459562306a36Sopenharmony_ci			list_for_each_entry_safe(iocb, next_iocb,
459662306a36Sopenharmony_ci						 &pring->txcmplq, list)
459762306a36Sopenharmony_ci				lpfc_sli_issue_abort_iotag(phba, pring,
459862306a36Sopenharmony_ci							   iocb, NULL);
459962306a36Sopenharmony_ci		}
460062306a36Sopenharmony_ci		spin_unlock_irq(&pring->ring_lock);
460162306a36Sopenharmony_ci	} else {
460262306a36Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
460362306a36Sopenharmony_ci		list_splice_init(&pring->txq, &tx_completions);
460462306a36Sopenharmony_ci		pring->txq_cnt = 0;
460562306a36Sopenharmony_ci
460662306a36Sopenharmony_ci		if (offline) {
460762306a36Sopenharmony_ci			list_splice_init(&pring->txcmplq, &txcmplq_completions);
460862306a36Sopenharmony_ci		} else {
460962306a36Sopenharmony_ci			/* Next issue ABTS for everything on the txcmplq */
461062306a36Sopenharmony_ci			list_for_each_entry_safe(iocb, next_iocb,
461162306a36Sopenharmony_ci						 &pring->txcmplq, list)
461262306a36Sopenharmony_ci				lpfc_sli_issue_abort_iotag(phba, pring,
461362306a36Sopenharmony_ci							   iocb, NULL);
461462306a36Sopenharmony_ci		}
461562306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
461662306a36Sopenharmony_ci	}
461762306a36Sopenharmony_ci
461862306a36Sopenharmony_ci	if (offline) {
461962306a36Sopenharmony_ci		/* Cancel all the IOCBs from the completions list */
462062306a36Sopenharmony_ci		lpfc_sli_cancel_iocbs(phba, &txcmplq_completions,
462162306a36Sopenharmony_ci				      IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
462262306a36Sopenharmony_ci	} else {
462362306a36Sopenharmony_ci		/* Make sure HBA is alive */
462462306a36Sopenharmony_ci		lpfc_issue_hb_tmo(phba);
462562306a36Sopenharmony_ci	}
462662306a36Sopenharmony_ci	/* Cancel all the IOCBs from the completions list */
462762306a36Sopenharmony_ci	lpfc_sli_cancel_iocbs(phba, &tx_completions, IOSTAT_LOCAL_REJECT,
462862306a36Sopenharmony_ci			      IOERR_SLI_ABORTED);
462962306a36Sopenharmony_ci}
463062306a36Sopenharmony_ci
463162306a36Sopenharmony_ci/**
463262306a36Sopenharmony_ci * lpfc_sli_abort_fcp_rings - Abort all iocbs in all FCP rings
463362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
463462306a36Sopenharmony_ci *
463562306a36Sopenharmony_ci * This function aborts all iocbs in FCP rings and frees all the iocb
463662306a36Sopenharmony_ci * objects in txq. This function issues an abort iocb for all the iocb commands
463762306a36Sopenharmony_ci * in txcmplq. The iocbs in the txcmplq is not guaranteed to complete before
463862306a36Sopenharmony_ci * the return of this function. The caller is not required to hold any locks.
463962306a36Sopenharmony_ci **/
464062306a36Sopenharmony_civoid
464162306a36Sopenharmony_cilpfc_sli_abort_fcp_rings(struct lpfc_hba *phba)
464262306a36Sopenharmony_ci{
464362306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
464462306a36Sopenharmony_ci	struct lpfc_sli_ring  *pring;
464562306a36Sopenharmony_ci	uint32_t i;
464662306a36Sopenharmony_ci
464762306a36Sopenharmony_ci	/* Look on all the FCP Rings for the iotag */
464862306a36Sopenharmony_ci	if (phba->sli_rev >= LPFC_SLI_REV4) {
464962306a36Sopenharmony_ci		for (i = 0; i < phba->cfg_hdw_queue; i++) {
465062306a36Sopenharmony_ci			pring = phba->sli4_hba.hdwq[i].io_wq->pring;
465162306a36Sopenharmony_ci			lpfc_sli_abort_iocb_ring(phba, pring);
465262306a36Sopenharmony_ci		}
465362306a36Sopenharmony_ci	} else {
465462306a36Sopenharmony_ci		pring = &psli->sli3_ring[LPFC_FCP_RING];
465562306a36Sopenharmony_ci		lpfc_sli_abort_iocb_ring(phba, pring);
465662306a36Sopenharmony_ci	}
465762306a36Sopenharmony_ci}
465862306a36Sopenharmony_ci
465962306a36Sopenharmony_ci/**
466062306a36Sopenharmony_ci * lpfc_sli_flush_io_rings - flush all iocbs in the IO ring
466162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
466262306a36Sopenharmony_ci *
466362306a36Sopenharmony_ci * This function flushes all iocbs in the IO ring and frees all the iocb
466462306a36Sopenharmony_ci * objects in txq and txcmplq. This function will not issue abort iocbs
466562306a36Sopenharmony_ci * for all the iocb commands in txcmplq, they will just be returned with
466662306a36Sopenharmony_ci * IOERR_SLI_DOWN. This function is invoked with EEH when device's PCI
466762306a36Sopenharmony_ci * slot has been permanently disabled.
466862306a36Sopenharmony_ci **/
466962306a36Sopenharmony_civoid
467062306a36Sopenharmony_cilpfc_sli_flush_io_rings(struct lpfc_hba *phba)
467162306a36Sopenharmony_ci{
467262306a36Sopenharmony_ci	LIST_HEAD(txq);
467362306a36Sopenharmony_ci	LIST_HEAD(txcmplq);
467462306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
467562306a36Sopenharmony_ci	struct lpfc_sli_ring  *pring;
467662306a36Sopenharmony_ci	uint32_t i;
467762306a36Sopenharmony_ci	struct lpfc_iocbq *piocb, *next_iocb;
467862306a36Sopenharmony_ci
467962306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
468062306a36Sopenharmony_ci	/* Indicate the I/O queues are flushed */
468162306a36Sopenharmony_ci	phba->hba_flag |= HBA_IOQ_FLUSH;
468262306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
468362306a36Sopenharmony_ci
468462306a36Sopenharmony_ci	/* Look on all the FCP Rings for the iotag */
468562306a36Sopenharmony_ci	if (phba->sli_rev >= LPFC_SLI_REV4) {
468662306a36Sopenharmony_ci		for (i = 0; i < phba->cfg_hdw_queue; i++) {
468762306a36Sopenharmony_ci			pring = phba->sli4_hba.hdwq[i].io_wq->pring;
468862306a36Sopenharmony_ci
468962306a36Sopenharmony_ci			spin_lock_irq(&pring->ring_lock);
469062306a36Sopenharmony_ci			/* Retrieve everything on txq */
469162306a36Sopenharmony_ci			list_splice_init(&pring->txq, &txq);
469262306a36Sopenharmony_ci			list_for_each_entry_safe(piocb, next_iocb,
469362306a36Sopenharmony_ci						 &pring->txcmplq, list)
469462306a36Sopenharmony_ci				piocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ;
469562306a36Sopenharmony_ci			/* Retrieve everything on the txcmplq */
469662306a36Sopenharmony_ci			list_splice_init(&pring->txcmplq, &txcmplq);
469762306a36Sopenharmony_ci			pring->txq_cnt = 0;
469862306a36Sopenharmony_ci			pring->txcmplq_cnt = 0;
469962306a36Sopenharmony_ci			spin_unlock_irq(&pring->ring_lock);
470062306a36Sopenharmony_ci
470162306a36Sopenharmony_ci			/* Flush the txq */
470262306a36Sopenharmony_ci			lpfc_sli_cancel_iocbs(phba, &txq,
470362306a36Sopenharmony_ci					      IOSTAT_LOCAL_REJECT,
470462306a36Sopenharmony_ci					      IOERR_SLI_DOWN);
470562306a36Sopenharmony_ci			/* Flush the txcmplq */
470662306a36Sopenharmony_ci			lpfc_sli_cancel_iocbs(phba, &txcmplq,
470762306a36Sopenharmony_ci					      IOSTAT_LOCAL_REJECT,
470862306a36Sopenharmony_ci					      IOERR_SLI_DOWN);
470962306a36Sopenharmony_ci			if (unlikely(pci_channel_offline(phba->pcidev)))
471062306a36Sopenharmony_ci				lpfc_sli4_io_xri_aborted(phba, NULL, 0);
471162306a36Sopenharmony_ci		}
471262306a36Sopenharmony_ci	} else {
471362306a36Sopenharmony_ci		pring = &psli->sli3_ring[LPFC_FCP_RING];
471462306a36Sopenharmony_ci
471562306a36Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
471662306a36Sopenharmony_ci		/* Retrieve everything on txq */
471762306a36Sopenharmony_ci		list_splice_init(&pring->txq, &txq);
471862306a36Sopenharmony_ci		list_for_each_entry_safe(piocb, next_iocb,
471962306a36Sopenharmony_ci					 &pring->txcmplq, list)
472062306a36Sopenharmony_ci			piocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ;
472162306a36Sopenharmony_ci		/* Retrieve everything on the txcmplq */
472262306a36Sopenharmony_ci		list_splice_init(&pring->txcmplq, &txcmplq);
472362306a36Sopenharmony_ci		pring->txq_cnt = 0;
472462306a36Sopenharmony_ci		pring->txcmplq_cnt = 0;
472562306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
472662306a36Sopenharmony_ci
472762306a36Sopenharmony_ci		/* Flush the txq */
472862306a36Sopenharmony_ci		lpfc_sli_cancel_iocbs(phba, &txq, IOSTAT_LOCAL_REJECT,
472962306a36Sopenharmony_ci				      IOERR_SLI_DOWN);
473062306a36Sopenharmony_ci		/* Flush the txcmpq */
473162306a36Sopenharmony_ci		lpfc_sli_cancel_iocbs(phba, &txcmplq, IOSTAT_LOCAL_REJECT,
473262306a36Sopenharmony_ci				      IOERR_SLI_DOWN);
473362306a36Sopenharmony_ci	}
473462306a36Sopenharmony_ci}
473562306a36Sopenharmony_ci
473662306a36Sopenharmony_ci/**
473762306a36Sopenharmony_ci * lpfc_sli_brdready_s3 - Check for sli3 host ready status
473862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
473962306a36Sopenharmony_ci * @mask: Bit mask to be checked.
474062306a36Sopenharmony_ci *
474162306a36Sopenharmony_ci * This function reads the host status register and compares
474262306a36Sopenharmony_ci * with the provided bit mask to check if HBA completed
474362306a36Sopenharmony_ci * the restart. This function will wait in a loop for the
474462306a36Sopenharmony_ci * HBA to complete restart. If the HBA does not restart within
474562306a36Sopenharmony_ci * 15 iterations, the function will reset the HBA again. The
474662306a36Sopenharmony_ci * function returns 1 when HBA fail to restart otherwise returns
474762306a36Sopenharmony_ci * zero.
474862306a36Sopenharmony_ci **/
474962306a36Sopenharmony_cistatic int
475062306a36Sopenharmony_cilpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask)
475162306a36Sopenharmony_ci{
475262306a36Sopenharmony_ci	uint32_t status;
475362306a36Sopenharmony_ci	int i = 0;
475462306a36Sopenharmony_ci	int retval = 0;
475562306a36Sopenharmony_ci
475662306a36Sopenharmony_ci	/* Read the HBA Host Status Register */
475762306a36Sopenharmony_ci	if (lpfc_readl(phba->HSregaddr, &status))
475862306a36Sopenharmony_ci		return 1;
475962306a36Sopenharmony_ci
476062306a36Sopenharmony_ci	phba->hba_flag |= HBA_NEEDS_CFG_PORT;
476162306a36Sopenharmony_ci
476262306a36Sopenharmony_ci	/*
476362306a36Sopenharmony_ci	 * Check status register every 100ms for 5 retries, then every
476462306a36Sopenharmony_ci	 * 500ms for 5, then every 2.5 sec for 5, then reset board and
476562306a36Sopenharmony_ci	 * every 2.5 sec for 4.
476662306a36Sopenharmony_ci	 * Break our of the loop if errors occurred during init.
476762306a36Sopenharmony_ci	 */
476862306a36Sopenharmony_ci	while (((status & mask) != mask) &&
476962306a36Sopenharmony_ci	       !(status & HS_FFERM) &&
477062306a36Sopenharmony_ci	       i++ < 20) {
477162306a36Sopenharmony_ci
477262306a36Sopenharmony_ci		if (i <= 5)
477362306a36Sopenharmony_ci			msleep(10);
477462306a36Sopenharmony_ci		else if (i <= 10)
477562306a36Sopenharmony_ci			msleep(500);
477662306a36Sopenharmony_ci		else
477762306a36Sopenharmony_ci			msleep(2500);
477862306a36Sopenharmony_ci
477962306a36Sopenharmony_ci		if (i == 15) {
478062306a36Sopenharmony_ci				/* Do post */
478162306a36Sopenharmony_ci			phba->pport->port_state = LPFC_VPORT_UNKNOWN;
478262306a36Sopenharmony_ci			lpfc_sli_brdrestart(phba);
478362306a36Sopenharmony_ci		}
478462306a36Sopenharmony_ci		/* Read the HBA Host Status Register */
478562306a36Sopenharmony_ci		if (lpfc_readl(phba->HSregaddr, &status)) {
478662306a36Sopenharmony_ci			retval = 1;
478762306a36Sopenharmony_ci			break;
478862306a36Sopenharmony_ci		}
478962306a36Sopenharmony_ci	}
479062306a36Sopenharmony_ci
479162306a36Sopenharmony_ci	/* Check to see if any errors occurred during init */
479262306a36Sopenharmony_ci	if ((status & HS_FFERM) || (i >= 20)) {
479362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
479462306a36Sopenharmony_ci				"2751 Adapter failed to restart, "
479562306a36Sopenharmony_ci				"status reg x%x, FW Data: A8 x%x AC x%x\n",
479662306a36Sopenharmony_ci				status,
479762306a36Sopenharmony_ci				readl(phba->MBslimaddr + 0xa8),
479862306a36Sopenharmony_ci				readl(phba->MBslimaddr + 0xac));
479962306a36Sopenharmony_ci		phba->link_state = LPFC_HBA_ERROR;
480062306a36Sopenharmony_ci		retval = 1;
480162306a36Sopenharmony_ci	}
480262306a36Sopenharmony_ci
480362306a36Sopenharmony_ci	return retval;
480462306a36Sopenharmony_ci}
480562306a36Sopenharmony_ci
480662306a36Sopenharmony_ci/**
480762306a36Sopenharmony_ci * lpfc_sli_brdready_s4 - Check for sli4 host ready status
480862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
480962306a36Sopenharmony_ci * @mask: Bit mask to be checked.
481062306a36Sopenharmony_ci *
481162306a36Sopenharmony_ci * This function checks the host status register to check if HBA is
481262306a36Sopenharmony_ci * ready. This function will wait in a loop for the HBA to be ready
481362306a36Sopenharmony_ci * If the HBA is not ready , the function will will reset the HBA PCI
481462306a36Sopenharmony_ci * function again. The function returns 1 when HBA fail to be ready
481562306a36Sopenharmony_ci * otherwise returns zero.
481662306a36Sopenharmony_ci **/
481762306a36Sopenharmony_cistatic int
481862306a36Sopenharmony_cilpfc_sli_brdready_s4(struct lpfc_hba *phba, uint32_t mask)
481962306a36Sopenharmony_ci{
482062306a36Sopenharmony_ci	uint32_t status;
482162306a36Sopenharmony_ci	int retval = 0;
482262306a36Sopenharmony_ci
482362306a36Sopenharmony_ci	/* Read the HBA Host Status Register */
482462306a36Sopenharmony_ci	status = lpfc_sli4_post_status_check(phba);
482562306a36Sopenharmony_ci
482662306a36Sopenharmony_ci	if (status) {
482762306a36Sopenharmony_ci		phba->pport->port_state = LPFC_VPORT_UNKNOWN;
482862306a36Sopenharmony_ci		lpfc_sli_brdrestart(phba);
482962306a36Sopenharmony_ci		status = lpfc_sli4_post_status_check(phba);
483062306a36Sopenharmony_ci	}
483162306a36Sopenharmony_ci
483262306a36Sopenharmony_ci	/* Check to see if any errors occurred during init */
483362306a36Sopenharmony_ci	if (status) {
483462306a36Sopenharmony_ci		phba->link_state = LPFC_HBA_ERROR;
483562306a36Sopenharmony_ci		retval = 1;
483662306a36Sopenharmony_ci	} else
483762306a36Sopenharmony_ci		phba->sli4_hba.intr_enable = 0;
483862306a36Sopenharmony_ci
483962306a36Sopenharmony_ci	phba->hba_flag &= ~HBA_SETUP;
484062306a36Sopenharmony_ci	return retval;
484162306a36Sopenharmony_ci}
484262306a36Sopenharmony_ci
484362306a36Sopenharmony_ci/**
484462306a36Sopenharmony_ci * lpfc_sli_brdready - Wrapper func for checking the hba readyness
484562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
484662306a36Sopenharmony_ci * @mask: Bit mask to be checked.
484762306a36Sopenharmony_ci *
484862306a36Sopenharmony_ci * This routine wraps the actual SLI3 or SLI4 hba readyness check routine
484962306a36Sopenharmony_ci * from the API jump table function pointer from the lpfc_hba struct.
485062306a36Sopenharmony_ci **/
485162306a36Sopenharmony_ciint
485262306a36Sopenharmony_cilpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask)
485362306a36Sopenharmony_ci{
485462306a36Sopenharmony_ci	return phba->lpfc_sli_brdready(phba, mask);
485562306a36Sopenharmony_ci}
485662306a36Sopenharmony_ci
485762306a36Sopenharmony_ci#define BARRIER_TEST_PATTERN (0xdeadbeef)
485862306a36Sopenharmony_ci
485962306a36Sopenharmony_ci/**
486062306a36Sopenharmony_ci * lpfc_reset_barrier - Make HBA ready for HBA reset
486162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
486262306a36Sopenharmony_ci *
486362306a36Sopenharmony_ci * This function is called before resetting an HBA. This function is called
486462306a36Sopenharmony_ci * with hbalock held and requests HBA to quiesce DMAs before a reset.
486562306a36Sopenharmony_ci **/
486662306a36Sopenharmony_civoid lpfc_reset_barrier(struct lpfc_hba *phba)
486762306a36Sopenharmony_ci{
486862306a36Sopenharmony_ci	uint32_t __iomem *resp_buf;
486962306a36Sopenharmony_ci	uint32_t __iomem *mbox_buf;
487062306a36Sopenharmony_ci	volatile struct MAILBOX_word0 mbox;
487162306a36Sopenharmony_ci	uint32_t hc_copy, ha_copy, resp_data;
487262306a36Sopenharmony_ci	int  i;
487362306a36Sopenharmony_ci	uint8_t hdrtype;
487462306a36Sopenharmony_ci
487562306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
487662306a36Sopenharmony_ci
487762306a36Sopenharmony_ci	pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype);
487862306a36Sopenharmony_ci	if (hdrtype != 0x80 ||
487962306a36Sopenharmony_ci	    (FC_JEDEC_ID(phba->vpd.rev.biuRev) != HELIOS_JEDEC_ID &&
488062306a36Sopenharmony_ci	     FC_JEDEC_ID(phba->vpd.rev.biuRev) != THOR_JEDEC_ID))
488162306a36Sopenharmony_ci		return;
488262306a36Sopenharmony_ci
488362306a36Sopenharmony_ci	/*
488462306a36Sopenharmony_ci	 * Tell the other part of the chip to suspend temporarily all
488562306a36Sopenharmony_ci	 * its DMA activity.
488662306a36Sopenharmony_ci	 */
488762306a36Sopenharmony_ci	resp_buf = phba->MBslimaddr;
488862306a36Sopenharmony_ci
488962306a36Sopenharmony_ci	/* Disable the error attention */
489062306a36Sopenharmony_ci	if (lpfc_readl(phba->HCregaddr, &hc_copy))
489162306a36Sopenharmony_ci		return;
489262306a36Sopenharmony_ci	writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr);
489362306a36Sopenharmony_ci	readl(phba->HCregaddr); /* flush */
489462306a36Sopenharmony_ci	phba->link_flag |= LS_IGNORE_ERATT;
489562306a36Sopenharmony_ci
489662306a36Sopenharmony_ci	if (lpfc_readl(phba->HAregaddr, &ha_copy))
489762306a36Sopenharmony_ci		return;
489862306a36Sopenharmony_ci	if (ha_copy & HA_ERATT) {
489962306a36Sopenharmony_ci		/* Clear Chip error bit */
490062306a36Sopenharmony_ci		writel(HA_ERATT, phba->HAregaddr);
490162306a36Sopenharmony_ci		phba->pport->stopped = 1;
490262306a36Sopenharmony_ci	}
490362306a36Sopenharmony_ci
490462306a36Sopenharmony_ci	mbox.word0 = 0;
490562306a36Sopenharmony_ci	mbox.mbxCommand = MBX_KILL_BOARD;
490662306a36Sopenharmony_ci	mbox.mbxOwner = OWN_CHIP;
490762306a36Sopenharmony_ci
490862306a36Sopenharmony_ci	writel(BARRIER_TEST_PATTERN, (resp_buf + 1));
490962306a36Sopenharmony_ci	mbox_buf = phba->MBslimaddr;
491062306a36Sopenharmony_ci	writel(mbox.word0, mbox_buf);
491162306a36Sopenharmony_ci
491262306a36Sopenharmony_ci	for (i = 0; i < 50; i++) {
491362306a36Sopenharmony_ci		if (lpfc_readl((resp_buf + 1), &resp_data))
491462306a36Sopenharmony_ci			return;
491562306a36Sopenharmony_ci		if (resp_data != ~(BARRIER_TEST_PATTERN))
491662306a36Sopenharmony_ci			mdelay(1);
491762306a36Sopenharmony_ci		else
491862306a36Sopenharmony_ci			break;
491962306a36Sopenharmony_ci	}
492062306a36Sopenharmony_ci	resp_data = 0;
492162306a36Sopenharmony_ci	if (lpfc_readl((resp_buf + 1), &resp_data))
492262306a36Sopenharmony_ci		return;
492362306a36Sopenharmony_ci	if (resp_data  != ~(BARRIER_TEST_PATTERN)) {
492462306a36Sopenharmony_ci		if (phba->sli.sli_flag & LPFC_SLI_ACTIVE ||
492562306a36Sopenharmony_ci		    phba->pport->stopped)
492662306a36Sopenharmony_ci			goto restore_hc;
492762306a36Sopenharmony_ci		else
492862306a36Sopenharmony_ci			goto clear_errat;
492962306a36Sopenharmony_ci	}
493062306a36Sopenharmony_ci
493162306a36Sopenharmony_ci	mbox.mbxOwner = OWN_HOST;
493262306a36Sopenharmony_ci	resp_data = 0;
493362306a36Sopenharmony_ci	for (i = 0; i < 500; i++) {
493462306a36Sopenharmony_ci		if (lpfc_readl(resp_buf, &resp_data))
493562306a36Sopenharmony_ci			return;
493662306a36Sopenharmony_ci		if (resp_data != mbox.word0)
493762306a36Sopenharmony_ci			mdelay(1);
493862306a36Sopenharmony_ci		else
493962306a36Sopenharmony_ci			break;
494062306a36Sopenharmony_ci	}
494162306a36Sopenharmony_ci
494262306a36Sopenharmony_ciclear_errat:
494362306a36Sopenharmony_ci
494462306a36Sopenharmony_ci	while (++i < 500) {
494562306a36Sopenharmony_ci		if (lpfc_readl(phba->HAregaddr, &ha_copy))
494662306a36Sopenharmony_ci			return;
494762306a36Sopenharmony_ci		if (!(ha_copy & HA_ERATT))
494862306a36Sopenharmony_ci			mdelay(1);
494962306a36Sopenharmony_ci		else
495062306a36Sopenharmony_ci			break;
495162306a36Sopenharmony_ci	}
495262306a36Sopenharmony_ci
495362306a36Sopenharmony_ci	if (readl(phba->HAregaddr) & HA_ERATT) {
495462306a36Sopenharmony_ci		writel(HA_ERATT, phba->HAregaddr);
495562306a36Sopenharmony_ci		phba->pport->stopped = 1;
495662306a36Sopenharmony_ci	}
495762306a36Sopenharmony_ci
495862306a36Sopenharmony_cirestore_hc:
495962306a36Sopenharmony_ci	phba->link_flag &= ~LS_IGNORE_ERATT;
496062306a36Sopenharmony_ci	writel(hc_copy, phba->HCregaddr);
496162306a36Sopenharmony_ci	readl(phba->HCregaddr); /* flush */
496262306a36Sopenharmony_ci}
496362306a36Sopenharmony_ci
496462306a36Sopenharmony_ci/**
496562306a36Sopenharmony_ci * lpfc_sli_brdkill - Issue a kill_board mailbox command
496662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
496762306a36Sopenharmony_ci *
496862306a36Sopenharmony_ci * This function issues a kill_board mailbox command and waits for
496962306a36Sopenharmony_ci * the error attention interrupt. This function is called for stopping
497062306a36Sopenharmony_ci * the firmware processing. The caller is not required to hold any
497162306a36Sopenharmony_ci * locks. This function calls lpfc_hba_down_post function to free
497262306a36Sopenharmony_ci * any pending commands after the kill. The function will return 1 when it
497362306a36Sopenharmony_ci * fails to kill the board else will return 0.
497462306a36Sopenharmony_ci **/
497562306a36Sopenharmony_ciint
497662306a36Sopenharmony_cilpfc_sli_brdkill(struct lpfc_hba *phba)
497762306a36Sopenharmony_ci{
497862306a36Sopenharmony_ci	struct lpfc_sli *psli;
497962306a36Sopenharmony_ci	LPFC_MBOXQ_t *pmb;
498062306a36Sopenharmony_ci	uint32_t status;
498162306a36Sopenharmony_ci	uint32_t ha_copy;
498262306a36Sopenharmony_ci	int retval;
498362306a36Sopenharmony_ci	int i = 0;
498462306a36Sopenharmony_ci
498562306a36Sopenharmony_ci	psli = &phba->sli;
498662306a36Sopenharmony_ci
498762306a36Sopenharmony_ci	/* Kill HBA */
498862306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
498962306a36Sopenharmony_ci			"0329 Kill HBA Data: x%x x%x\n",
499062306a36Sopenharmony_ci			phba->pport->port_state, psli->sli_flag);
499162306a36Sopenharmony_ci
499262306a36Sopenharmony_ci	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
499362306a36Sopenharmony_ci	if (!pmb)
499462306a36Sopenharmony_ci		return 1;
499562306a36Sopenharmony_ci
499662306a36Sopenharmony_ci	/* Disable the error attention */
499762306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
499862306a36Sopenharmony_ci	if (lpfc_readl(phba->HCregaddr, &status)) {
499962306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
500062306a36Sopenharmony_ci		mempool_free(pmb, phba->mbox_mem_pool);
500162306a36Sopenharmony_ci		return 1;
500262306a36Sopenharmony_ci	}
500362306a36Sopenharmony_ci	status &= ~HC_ERINT_ENA;
500462306a36Sopenharmony_ci	writel(status, phba->HCregaddr);
500562306a36Sopenharmony_ci	readl(phba->HCregaddr); /* flush */
500662306a36Sopenharmony_ci	phba->link_flag |= LS_IGNORE_ERATT;
500762306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
500862306a36Sopenharmony_ci
500962306a36Sopenharmony_ci	lpfc_kill_board(phba, pmb);
501062306a36Sopenharmony_ci	pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
501162306a36Sopenharmony_ci	retval = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
501262306a36Sopenharmony_ci
501362306a36Sopenharmony_ci	if (retval != MBX_SUCCESS) {
501462306a36Sopenharmony_ci		if (retval != MBX_BUSY)
501562306a36Sopenharmony_ci			mempool_free(pmb, phba->mbox_mem_pool);
501662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
501762306a36Sopenharmony_ci				"2752 KILL_BOARD command failed retval %d\n",
501862306a36Sopenharmony_ci				retval);
501962306a36Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
502062306a36Sopenharmony_ci		phba->link_flag &= ~LS_IGNORE_ERATT;
502162306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
502262306a36Sopenharmony_ci		return 1;
502362306a36Sopenharmony_ci	}
502462306a36Sopenharmony_ci
502562306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
502662306a36Sopenharmony_ci	psli->sli_flag &= ~LPFC_SLI_ACTIVE;
502762306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
502862306a36Sopenharmony_ci
502962306a36Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
503062306a36Sopenharmony_ci
503162306a36Sopenharmony_ci	/* There is no completion for a KILL_BOARD mbox cmd. Check for an error
503262306a36Sopenharmony_ci	 * attention every 100ms for 3 seconds. If we don't get ERATT after
503362306a36Sopenharmony_ci	 * 3 seconds we still set HBA_ERROR state because the status of the
503462306a36Sopenharmony_ci	 * board is now undefined.
503562306a36Sopenharmony_ci	 */
503662306a36Sopenharmony_ci	if (lpfc_readl(phba->HAregaddr, &ha_copy))
503762306a36Sopenharmony_ci		return 1;
503862306a36Sopenharmony_ci	while ((i++ < 30) && !(ha_copy & HA_ERATT)) {
503962306a36Sopenharmony_ci		mdelay(100);
504062306a36Sopenharmony_ci		if (lpfc_readl(phba->HAregaddr, &ha_copy))
504162306a36Sopenharmony_ci			return 1;
504262306a36Sopenharmony_ci	}
504362306a36Sopenharmony_ci
504462306a36Sopenharmony_ci	del_timer_sync(&psli->mbox_tmo);
504562306a36Sopenharmony_ci	if (ha_copy & HA_ERATT) {
504662306a36Sopenharmony_ci		writel(HA_ERATT, phba->HAregaddr);
504762306a36Sopenharmony_ci		phba->pport->stopped = 1;
504862306a36Sopenharmony_ci	}
504962306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
505062306a36Sopenharmony_ci	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
505162306a36Sopenharmony_ci	psli->mbox_active = NULL;
505262306a36Sopenharmony_ci	phba->link_flag &= ~LS_IGNORE_ERATT;
505362306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
505462306a36Sopenharmony_ci
505562306a36Sopenharmony_ci	lpfc_hba_down_post(phba);
505662306a36Sopenharmony_ci	phba->link_state = LPFC_HBA_ERROR;
505762306a36Sopenharmony_ci
505862306a36Sopenharmony_ci	return ha_copy & HA_ERATT ? 0 : 1;
505962306a36Sopenharmony_ci}
506062306a36Sopenharmony_ci
506162306a36Sopenharmony_ci/**
506262306a36Sopenharmony_ci * lpfc_sli_brdreset - Reset a sli-2 or sli-3 HBA
506362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
506462306a36Sopenharmony_ci *
506562306a36Sopenharmony_ci * This function resets the HBA by writing HC_INITFF to the control
506662306a36Sopenharmony_ci * register. After the HBA resets, this function resets all the iocb ring
506762306a36Sopenharmony_ci * indices. This function disables PCI layer parity checking during
506862306a36Sopenharmony_ci * the reset.
506962306a36Sopenharmony_ci * This function returns 0 always.
507062306a36Sopenharmony_ci * The caller is not required to hold any locks.
507162306a36Sopenharmony_ci **/
507262306a36Sopenharmony_ciint
507362306a36Sopenharmony_cilpfc_sli_brdreset(struct lpfc_hba *phba)
507462306a36Sopenharmony_ci{
507562306a36Sopenharmony_ci	struct lpfc_sli *psli;
507662306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
507762306a36Sopenharmony_ci	uint16_t cfg_value;
507862306a36Sopenharmony_ci	int i;
507962306a36Sopenharmony_ci
508062306a36Sopenharmony_ci	psli = &phba->sli;
508162306a36Sopenharmony_ci
508262306a36Sopenharmony_ci	/* Reset HBA */
508362306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
508462306a36Sopenharmony_ci			"0325 Reset HBA Data: x%x x%x\n",
508562306a36Sopenharmony_ci			(phba->pport) ? phba->pport->port_state : 0,
508662306a36Sopenharmony_ci			psli->sli_flag);
508762306a36Sopenharmony_ci
508862306a36Sopenharmony_ci	/* perform board reset */
508962306a36Sopenharmony_ci	phba->fc_eventTag = 0;
509062306a36Sopenharmony_ci	phba->link_events = 0;
509162306a36Sopenharmony_ci	phba->hba_flag |= HBA_NEEDS_CFG_PORT;
509262306a36Sopenharmony_ci	if (phba->pport) {
509362306a36Sopenharmony_ci		phba->pport->fc_myDID = 0;
509462306a36Sopenharmony_ci		phba->pport->fc_prevDID = 0;
509562306a36Sopenharmony_ci	}
509662306a36Sopenharmony_ci
509762306a36Sopenharmony_ci	/* Turn off parity checking and serr during the physical reset */
509862306a36Sopenharmony_ci	if (pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value))
509962306a36Sopenharmony_ci		return -EIO;
510062306a36Sopenharmony_ci
510162306a36Sopenharmony_ci	pci_write_config_word(phba->pcidev, PCI_COMMAND,
510262306a36Sopenharmony_ci			      (cfg_value &
510362306a36Sopenharmony_ci			       ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
510462306a36Sopenharmony_ci
510562306a36Sopenharmony_ci	psli->sli_flag &= ~(LPFC_SLI_ACTIVE | LPFC_PROCESS_LA);
510662306a36Sopenharmony_ci
510762306a36Sopenharmony_ci	/* Now toggle INITFF bit in the Host Control Register */
510862306a36Sopenharmony_ci	writel(HC_INITFF, phba->HCregaddr);
510962306a36Sopenharmony_ci	mdelay(1);
511062306a36Sopenharmony_ci	readl(phba->HCregaddr); /* flush */
511162306a36Sopenharmony_ci	writel(0, phba->HCregaddr);
511262306a36Sopenharmony_ci	readl(phba->HCregaddr); /* flush */
511362306a36Sopenharmony_ci
511462306a36Sopenharmony_ci	/* Restore PCI cmd register */
511562306a36Sopenharmony_ci	pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value);
511662306a36Sopenharmony_ci
511762306a36Sopenharmony_ci	/* Initialize relevant SLI info */
511862306a36Sopenharmony_ci	for (i = 0; i < psli->num_rings; i++) {
511962306a36Sopenharmony_ci		pring = &psli->sli3_ring[i];
512062306a36Sopenharmony_ci		pring->flag = 0;
512162306a36Sopenharmony_ci		pring->sli.sli3.rspidx = 0;
512262306a36Sopenharmony_ci		pring->sli.sli3.next_cmdidx  = 0;
512362306a36Sopenharmony_ci		pring->sli.sli3.local_getidx = 0;
512462306a36Sopenharmony_ci		pring->sli.sli3.cmdidx = 0;
512562306a36Sopenharmony_ci		pring->missbufcnt = 0;
512662306a36Sopenharmony_ci	}
512762306a36Sopenharmony_ci
512862306a36Sopenharmony_ci	phba->link_state = LPFC_WARM_START;
512962306a36Sopenharmony_ci	return 0;
513062306a36Sopenharmony_ci}
513162306a36Sopenharmony_ci
513262306a36Sopenharmony_ci/**
513362306a36Sopenharmony_ci * lpfc_sli4_brdreset - Reset a sli-4 HBA
513462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
513562306a36Sopenharmony_ci *
513662306a36Sopenharmony_ci * This function resets a SLI4 HBA. This function disables PCI layer parity
513762306a36Sopenharmony_ci * checking during resets the device. The caller is not required to hold
513862306a36Sopenharmony_ci * any locks.
513962306a36Sopenharmony_ci *
514062306a36Sopenharmony_ci * This function returns 0 on success else returns negative error code.
514162306a36Sopenharmony_ci **/
514262306a36Sopenharmony_ciint
514362306a36Sopenharmony_cilpfc_sli4_brdreset(struct lpfc_hba *phba)
514462306a36Sopenharmony_ci{
514562306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
514662306a36Sopenharmony_ci	uint16_t cfg_value;
514762306a36Sopenharmony_ci	int rc = 0;
514862306a36Sopenharmony_ci
514962306a36Sopenharmony_ci	/* Reset HBA */
515062306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
515162306a36Sopenharmony_ci			"0295 Reset HBA Data: x%x x%x x%x\n",
515262306a36Sopenharmony_ci			phba->pport->port_state, psli->sli_flag,
515362306a36Sopenharmony_ci			phba->hba_flag);
515462306a36Sopenharmony_ci
515562306a36Sopenharmony_ci	/* perform board reset */
515662306a36Sopenharmony_ci	phba->fc_eventTag = 0;
515762306a36Sopenharmony_ci	phba->link_events = 0;
515862306a36Sopenharmony_ci	phba->pport->fc_myDID = 0;
515962306a36Sopenharmony_ci	phba->pport->fc_prevDID = 0;
516062306a36Sopenharmony_ci	phba->hba_flag &= ~HBA_SETUP;
516162306a36Sopenharmony_ci
516262306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
516362306a36Sopenharmony_ci	psli->sli_flag &= ~(LPFC_PROCESS_LA);
516462306a36Sopenharmony_ci	phba->fcf.fcf_flag = 0;
516562306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
516662306a36Sopenharmony_ci
516762306a36Sopenharmony_ci	/* Now physically reset the device */
516862306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
516962306a36Sopenharmony_ci			"0389 Performing PCI function reset!\n");
517062306a36Sopenharmony_ci
517162306a36Sopenharmony_ci	/* Turn off parity checking and serr during the physical reset */
517262306a36Sopenharmony_ci	if (pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value)) {
517362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
517462306a36Sopenharmony_ci				"3205 PCI read Config failed\n");
517562306a36Sopenharmony_ci		return -EIO;
517662306a36Sopenharmony_ci	}
517762306a36Sopenharmony_ci
517862306a36Sopenharmony_ci	pci_write_config_word(phba->pcidev, PCI_COMMAND, (cfg_value &
517962306a36Sopenharmony_ci			      ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
518062306a36Sopenharmony_ci
518162306a36Sopenharmony_ci	/* Perform FCoE PCI function reset before freeing queue memory */
518262306a36Sopenharmony_ci	rc = lpfc_pci_function_reset(phba);
518362306a36Sopenharmony_ci
518462306a36Sopenharmony_ci	/* Restore PCI cmd register */
518562306a36Sopenharmony_ci	pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value);
518662306a36Sopenharmony_ci
518762306a36Sopenharmony_ci	return rc;
518862306a36Sopenharmony_ci}
518962306a36Sopenharmony_ci
519062306a36Sopenharmony_ci/**
519162306a36Sopenharmony_ci * lpfc_sli_brdrestart_s3 - Restart a sli-3 hba
519262306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
519362306a36Sopenharmony_ci *
519462306a36Sopenharmony_ci * This function is called in the SLI initialization code path to
519562306a36Sopenharmony_ci * restart the HBA. The caller is not required to hold any lock.
519662306a36Sopenharmony_ci * This function writes MBX_RESTART mailbox command to the SLIM and
519762306a36Sopenharmony_ci * resets the HBA. At the end of the function, it calls lpfc_hba_down_post
519862306a36Sopenharmony_ci * function to free any pending commands. The function enables
519962306a36Sopenharmony_ci * POST only during the first initialization. The function returns zero.
520062306a36Sopenharmony_ci * The function does not guarantee completion of MBX_RESTART mailbox
520162306a36Sopenharmony_ci * command before the return of this function.
520262306a36Sopenharmony_ci **/
520362306a36Sopenharmony_cistatic int
520462306a36Sopenharmony_cilpfc_sli_brdrestart_s3(struct lpfc_hba *phba)
520562306a36Sopenharmony_ci{
520662306a36Sopenharmony_ci	volatile struct MAILBOX_word0 mb;
520762306a36Sopenharmony_ci	struct lpfc_sli *psli;
520862306a36Sopenharmony_ci	void __iomem *to_slim;
520962306a36Sopenharmony_ci
521062306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
521162306a36Sopenharmony_ci
521262306a36Sopenharmony_ci	psli = &phba->sli;
521362306a36Sopenharmony_ci
521462306a36Sopenharmony_ci	/* Restart HBA */
521562306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
521662306a36Sopenharmony_ci			"0337 Restart HBA Data: x%x x%x\n",
521762306a36Sopenharmony_ci			(phba->pport) ? phba->pport->port_state : 0,
521862306a36Sopenharmony_ci			psli->sli_flag);
521962306a36Sopenharmony_ci
522062306a36Sopenharmony_ci	mb.word0 = 0;
522162306a36Sopenharmony_ci	mb.mbxCommand = MBX_RESTART;
522262306a36Sopenharmony_ci	mb.mbxHc = 1;
522362306a36Sopenharmony_ci
522462306a36Sopenharmony_ci	lpfc_reset_barrier(phba);
522562306a36Sopenharmony_ci
522662306a36Sopenharmony_ci	to_slim = phba->MBslimaddr;
522762306a36Sopenharmony_ci	writel(mb.word0, to_slim);
522862306a36Sopenharmony_ci	readl(to_slim); /* flush */
522962306a36Sopenharmony_ci
523062306a36Sopenharmony_ci	/* Only skip post after fc_ffinit is completed */
523162306a36Sopenharmony_ci	if (phba->pport && phba->pport->port_state)
523262306a36Sopenharmony_ci		mb.word0 = 1;	/* This is really setting up word1 */
523362306a36Sopenharmony_ci	else
523462306a36Sopenharmony_ci		mb.word0 = 0;	/* This is really setting up word1 */
523562306a36Sopenharmony_ci	to_slim = phba->MBslimaddr + sizeof (uint32_t);
523662306a36Sopenharmony_ci	writel(mb.word0, to_slim);
523762306a36Sopenharmony_ci	readl(to_slim); /* flush */
523862306a36Sopenharmony_ci
523962306a36Sopenharmony_ci	lpfc_sli_brdreset(phba);
524062306a36Sopenharmony_ci	if (phba->pport)
524162306a36Sopenharmony_ci		phba->pport->stopped = 0;
524262306a36Sopenharmony_ci	phba->link_state = LPFC_INIT_START;
524362306a36Sopenharmony_ci	phba->hba_flag = 0;
524462306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
524562306a36Sopenharmony_ci
524662306a36Sopenharmony_ci	memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
524762306a36Sopenharmony_ci	psli->stats_start = ktime_get_seconds();
524862306a36Sopenharmony_ci
524962306a36Sopenharmony_ci	/* Give the INITFF and Post time to settle. */
525062306a36Sopenharmony_ci	mdelay(100);
525162306a36Sopenharmony_ci
525262306a36Sopenharmony_ci	lpfc_hba_down_post(phba);
525362306a36Sopenharmony_ci
525462306a36Sopenharmony_ci	return 0;
525562306a36Sopenharmony_ci}
525662306a36Sopenharmony_ci
525762306a36Sopenharmony_ci/**
525862306a36Sopenharmony_ci * lpfc_sli_brdrestart_s4 - Restart the sli-4 hba
525962306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
526062306a36Sopenharmony_ci *
526162306a36Sopenharmony_ci * This function is called in the SLI initialization code path to restart
526262306a36Sopenharmony_ci * a SLI4 HBA. The caller is not required to hold any lock.
526362306a36Sopenharmony_ci * At the end of the function, it calls lpfc_hba_down_post function to
526462306a36Sopenharmony_ci * free any pending commands.
526562306a36Sopenharmony_ci **/
526662306a36Sopenharmony_cistatic int
526762306a36Sopenharmony_cilpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
526862306a36Sopenharmony_ci{
526962306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
527062306a36Sopenharmony_ci	int rc;
527162306a36Sopenharmony_ci
527262306a36Sopenharmony_ci	/* Restart HBA */
527362306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
527462306a36Sopenharmony_ci			"0296 Restart HBA Data: x%x x%x\n",
527562306a36Sopenharmony_ci			phba->pport->port_state, psli->sli_flag);
527662306a36Sopenharmony_ci
527762306a36Sopenharmony_ci	rc = lpfc_sli4_brdreset(phba);
527862306a36Sopenharmony_ci	if (rc) {
527962306a36Sopenharmony_ci		phba->link_state = LPFC_HBA_ERROR;
528062306a36Sopenharmony_ci		goto hba_down_queue;
528162306a36Sopenharmony_ci	}
528262306a36Sopenharmony_ci
528362306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
528462306a36Sopenharmony_ci	phba->pport->stopped = 0;
528562306a36Sopenharmony_ci	phba->link_state = LPFC_INIT_START;
528662306a36Sopenharmony_ci	phba->hba_flag = 0;
528762306a36Sopenharmony_ci	/* Preserve FA-PWWN expectation */
528862306a36Sopenharmony_ci	phba->sli4_hba.fawwpn_flag &= LPFC_FAWWPN_FABRIC;
528962306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
529062306a36Sopenharmony_ci
529162306a36Sopenharmony_ci	memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
529262306a36Sopenharmony_ci	psli->stats_start = ktime_get_seconds();
529362306a36Sopenharmony_ci
529462306a36Sopenharmony_cihba_down_queue:
529562306a36Sopenharmony_ci	lpfc_hba_down_post(phba);
529662306a36Sopenharmony_ci	lpfc_sli4_queue_destroy(phba);
529762306a36Sopenharmony_ci
529862306a36Sopenharmony_ci	return rc;
529962306a36Sopenharmony_ci}
530062306a36Sopenharmony_ci
530162306a36Sopenharmony_ci/**
530262306a36Sopenharmony_ci * lpfc_sli_brdrestart - Wrapper func for restarting hba
530362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
530462306a36Sopenharmony_ci *
530562306a36Sopenharmony_ci * This routine wraps the actual SLI3 or SLI4 hba restart routine from the
530662306a36Sopenharmony_ci * API jump table function pointer from the lpfc_hba struct.
530762306a36Sopenharmony_ci**/
530862306a36Sopenharmony_ciint
530962306a36Sopenharmony_cilpfc_sli_brdrestart(struct lpfc_hba *phba)
531062306a36Sopenharmony_ci{
531162306a36Sopenharmony_ci	return phba->lpfc_sli_brdrestart(phba);
531262306a36Sopenharmony_ci}
531362306a36Sopenharmony_ci
531462306a36Sopenharmony_ci/**
531562306a36Sopenharmony_ci * lpfc_sli_chipset_init - Wait for the restart of the HBA after a restart
531662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
531762306a36Sopenharmony_ci *
531862306a36Sopenharmony_ci * This function is called after a HBA restart to wait for successful
531962306a36Sopenharmony_ci * restart of the HBA. Successful restart of the HBA is indicated by
532062306a36Sopenharmony_ci * HS_FFRDY and HS_MBRDY bits. If the HBA fails to restart even after 15
532162306a36Sopenharmony_ci * iteration, the function will restart the HBA again. The function returns
532262306a36Sopenharmony_ci * zero if HBA successfully restarted else returns negative error code.
532362306a36Sopenharmony_ci **/
532462306a36Sopenharmony_ciint
532562306a36Sopenharmony_cilpfc_sli_chipset_init(struct lpfc_hba *phba)
532662306a36Sopenharmony_ci{
532762306a36Sopenharmony_ci	uint32_t status, i = 0;
532862306a36Sopenharmony_ci
532962306a36Sopenharmony_ci	/* Read the HBA Host Status Register */
533062306a36Sopenharmony_ci	if (lpfc_readl(phba->HSregaddr, &status))
533162306a36Sopenharmony_ci		return -EIO;
533262306a36Sopenharmony_ci
533362306a36Sopenharmony_ci	/* Check status register to see what current state is */
533462306a36Sopenharmony_ci	i = 0;
533562306a36Sopenharmony_ci	while ((status & (HS_FFRDY | HS_MBRDY)) != (HS_FFRDY | HS_MBRDY)) {
533662306a36Sopenharmony_ci
533762306a36Sopenharmony_ci		/* Check every 10ms for 10 retries, then every 100ms for 90
533862306a36Sopenharmony_ci		 * retries, then every 1 sec for 50 retires for a total of
533962306a36Sopenharmony_ci		 * ~60 seconds before reset the board again and check every
534062306a36Sopenharmony_ci		 * 1 sec for 50 retries. The up to 60 seconds before the
534162306a36Sopenharmony_ci		 * board ready is required by the Falcon FIPS zeroization
534262306a36Sopenharmony_ci		 * complete, and any reset the board in between shall cause
534362306a36Sopenharmony_ci		 * restart of zeroization, further delay the board ready.
534462306a36Sopenharmony_ci		 */
534562306a36Sopenharmony_ci		if (i++ >= 200) {
534662306a36Sopenharmony_ci			/* Adapter failed to init, timeout, status reg
534762306a36Sopenharmony_ci			   <status> */
534862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
534962306a36Sopenharmony_ci					"0436 Adapter failed to init, "
535062306a36Sopenharmony_ci					"timeout, status reg x%x, "
535162306a36Sopenharmony_ci					"FW Data: A8 x%x AC x%x\n", status,
535262306a36Sopenharmony_ci					readl(phba->MBslimaddr + 0xa8),
535362306a36Sopenharmony_ci					readl(phba->MBslimaddr + 0xac));
535462306a36Sopenharmony_ci			phba->link_state = LPFC_HBA_ERROR;
535562306a36Sopenharmony_ci			return -ETIMEDOUT;
535662306a36Sopenharmony_ci		}
535762306a36Sopenharmony_ci
535862306a36Sopenharmony_ci		/* Check to see if any errors occurred during init */
535962306a36Sopenharmony_ci		if (status & HS_FFERM) {
536062306a36Sopenharmony_ci			/* ERROR: During chipset initialization */
536162306a36Sopenharmony_ci			/* Adapter failed to init, chipset, status reg
536262306a36Sopenharmony_ci			   <status> */
536362306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
536462306a36Sopenharmony_ci					"0437 Adapter failed to init, "
536562306a36Sopenharmony_ci					"chipset, status reg x%x, "
536662306a36Sopenharmony_ci					"FW Data: A8 x%x AC x%x\n", status,
536762306a36Sopenharmony_ci					readl(phba->MBslimaddr + 0xa8),
536862306a36Sopenharmony_ci					readl(phba->MBslimaddr + 0xac));
536962306a36Sopenharmony_ci			phba->link_state = LPFC_HBA_ERROR;
537062306a36Sopenharmony_ci			return -EIO;
537162306a36Sopenharmony_ci		}
537262306a36Sopenharmony_ci
537362306a36Sopenharmony_ci		if (i <= 10)
537462306a36Sopenharmony_ci			msleep(10);
537562306a36Sopenharmony_ci		else if (i <= 100)
537662306a36Sopenharmony_ci			msleep(100);
537762306a36Sopenharmony_ci		else
537862306a36Sopenharmony_ci			msleep(1000);
537962306a36Sopenharmony_ci
538062306a36Sopenharmony_ci		if (i == 150) {
538162306a36Sopenharmony_ci			/* Do post */
538262306a36Sopenharmony_ci			phba->pport->port_state = LPFC_VPORT_UNKNOWN;
538362306a36Sopenharmony_ci			lpfc_sli_brdrestart(phba);
538462306a36Sopenharmony_ci		}
538562306a36Sopenharmony_ci		/* Read the HBA Host Status Register */
538662306a36Sopenharmony_ci		if (lpfc_readl(phba->HSregaddr, &status))
538762306a36Sopenharmony_ci			return -EIO;
538862306a36Sopenharmony_ci	}
538962306a36Sopenharmony_ci
539062306a36Sopenharmony_ci	/* Check to see if any errors occurred during init */
539162306a36Sopenharmony_ci	if (status & HS_FFERM) {
539262306a36Sopenharmony_ci		/* ERROR: During chipset initialization */
539362306a36Sopenharmony_ci		/* Adapter failed to init, chipset, status reg <status> */
539462306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
539562306a36Sopenharmony_ci				"0438 Adapter failed to init, chipset, "
539662306a36Sopenharmony_ci				"status reg x%x, "
539762306a36Sopenharmony_ci				"FW Data: A8 x%x AC x%x\n", status,
539862306a36Sopenharmony_ci				readl(phba->MBslimaddr + 0xa8),
539962306a36Sopenharmony_ci				readl(phba->MBslimaddr + 0xac));
540062306a36Sopenharmony_ci		phba->link_state = LPFC_HBA_ERROR;
540162306a36Sopenharmony_ci		return -EIO;
540262306a36Sopenharmony_ci	}
540362306a36Sopenharmony_ci
540462306a36Sopenharmony_ci	phba->hba_flag |= HBA_NEEDS_CFG_PORT;
540562306a36Sopenharmony_ci
540662306a36Sopenharmony_ci	/* Clear all interrupt enable conditions */
540762306a36Sopenharmony_ci	writel(0, phba->HCregaddr);
540862306a36Sopenharmony_ci	readl(phba->HCregaddr); /* flush */
540962306a36Sopenharmony_ci
541062306a36Sopenharmony_ci	/* setup host attn register */
541162306a36Sopenharmony_ci	writel(0xffffffff, phba->HAregaddr);
541262306a36Sopenharmony_ci	readl(phba->HAregaddr); /* flush */
541362306a36Sopenharmony_ci	return 0;
541462306a36Sopenharmony_ci}
541562306a36Sopenharmony_ci
541662306a36Sopenharmony_ci/**
541762306a36Sopenharmony_ci * lpfc_sli_hbq_count - Get the number of HBQs to be configured
541862306a36Sopenharmony_ci *
541962306a36Sopenharmony_ci * This function calculates and returns the number of HBQs required to be
542062306a36Sopenharmony_ci * configured.
542162306a36Sopenharmony_ci **/
542262306a36Sopenharmony_ciint
542362306a36Sopenharmony_cilpfc_sli_hbq_count(void)
542462306a36Sopenharmony_ci{
542562306a36Sopenharmony_ci	return ARRAY_SIZE(lpfc_hbq_defs);
542662306a36Sopenharmony_ci}
542762306a36Sopenharmony_ci
542862306a36Sopenharmony_ci/**
542962306a36Sopenharmony_ci * lpfc_sli_hbq_entry_count - Calculate total number of hbq entries
543062306a36Sopenharmony_ci *
543162306a36Sopenharmony_ci * This function adds the number of hbq entries in every HBQ to get
543262306a36Sopenharmony_ci * the total number of hbq entries required for the HBA and returns
543362306a36Sopenharmony_ci * the total count.
543462306a36Sopenharmony_ci **/
543562306a36Sopenharmony_cistatic int
543662306a36Sopenharmony_cilpfc_sli_hbq_entry_count(void)
543762306a36Sopenharmony_ci{
543862306a36Sopenharmony_ci	int  hbq_count = lpfc_sli_hbq_count();
543962306a36Sopenharmony_ci	int  count = 0;
544062306a36Sopenharmony_ci	int  i;
544162306a36Sopenharmony_ci
544262306a36Sopenharmony_ci	for (i = 0; i < hbq_count; ++i)
544362306a36Sopenharmony_ci		count += lpfc_hbq_defs[i]->entry_count;
544462306a36Sopenharmony_ci	return count;
544562306a36Sopenharmony_ci}
544662306a36Sopenharmony_ci
544762306a36Sopenharmony_ci/**
544862306a36Sopenharmony_ci * lpfc_sli_hbq_size - Calculate memory required for all hbq entries
544962306a36Sopenharmony_ci *
545062306a36Sopenharmony_ci * This function calculates amount of memory required for all hbq entries
545162306a36Sopenharmony_ci * to be configured and returns the total memory required.
545262306a36Sopenharmony_ci **/
545362306a36Sopenharmony_ciint
545462306a36Sopenharmony_cilpfc_sli_hbq_size(void)
545562306a36Sopenharmony_ci{
545662306a36Sopenharmony_ci	return lpfc_sli_hbq_entry_count() * sizeof(struct lpfc_hbq_entry);
545762306a36Sopenharmony_ci}
545862306a36Sopenharmony_ci
545962306a36Sopenharmony_ci/**
546062306a36Sopenharmony_ci * lpfc_sli_hbq_setup - configure and initialize HBQs
546162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
546262306a36Sopenharmony_ci *
546362306a36Sopenharmony_ci * This function is called during the SLI initialization to configure
546462306a36Sopenharmony_ci * all the HBQs and post buffers to the HBQ. The caller is not
546562306a36Sopenharmony_ci * required to hold any locks. This function will return zero if successful
546662306a36Sopenharmony_ci * else it will return negative error code.
546762306a36Sopenharmony_ci **/
546862306a36Sopenharmony_cistatic int
546962306a36Sopenharmony_cilpfc_sli_hbq_setup(struct lpfc_hba *phba)
547062306a36Sopenharmony_ci{
547162306a36Sopenharmony_ci	int  hbq_count = lpfc_sli_hbq_count();
547262306a36Sopenharmony_ci	LPFC_MBOXQ_t *pmb;
547362306a36Sopenharmony_ci	MAILBOX_t *pmbox;
547462306a36Sopenharmony_ci	uint32_t hbqno;
547562306a36Sopenharmony_ci	uint32_t hbq_entry_index;
547662306a36Sopenharmony_ci
547762306a36Sopenharmony_ci				/* Get a Mailbox buffer to setup mailbox
547862306a36Sopenharmony_ci				 * commands for HBA initialization
547962306a36Sopenharmony_ci				 */
548062306a36Sopenharmony_ci	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
548162306a36Sopenharmony_ci
548262306a36Sopenharmony_ci	if (!pmb)
548362306a36Sopenharmony_ci		return -ENOMEM;
548462306a36Sopenharmony_ci
548562306a36Sopenharmony_ci	pmbox = &pmb->u.mb;
548662306a36Sopenharmony_ci
548762306a36Sopenharmony_ci	/* Initialize the struct lpfc_sli_hbq structure for each hbq */
548862306a36Sopenharmony_ci	phba->link_state = LPFC_INIT_MBX_CMDS;
548962306a36Sopenharmony_ci	phba->hbq_in_use = 1;
549062306a36Sopenharmony_ci
549162306a36Sopenharmony_ci	hbq_entry_index = 0;
549262306a36Sopenharmony_ci	for (hbqno = 0; hbqno < hbq_count; ++hbqno) {
549362306a36Sopenharmony_ci		phba->hbqs[hbqno].next_hbqPutIdx = 0;
549462306a36Sopenharmony_ci		phba->hbqs[hbqno].hbqPutIdx      = 0;
549562306a36Sopenharmony_ci		phba->hbqs[hbqno].local_hbqGetIdx   = 0;
549662306a36Sopenharmony_ci		phba->hbqs[hbqno].entry_count =
549762306a36Sopenharmony_ci			lpfc_hbq_defs[hbqno]->entry_count;
549862306a36Sopenharmony_ci		lpfc_config_hbq(phba, hbqno, lpfc_hbq_defs[hbqno],
549962306a36Sopenharmony_ci			hbq_entry_index, pmb);
550062306a36Sopenharmony_ci		hbq_entry_index += phba->hbqs[hbqno].entry_count;
550162306a36Sopenharmony_ci
550262306a36Sopenharmony_ci		if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
550362306a36Sopenharmony_ci			/* Adapter failed to init, mbxCmd <cmd> CFG_RING,
550462306a36Sopenharmony_ci			   mbxStatus <status>, ring <num> */
550562306a36Sopenharmony_ci
550662306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR,
550762306a36Sopenharmony_ci					LOG_SLI | LOG_VPORT,
550862306a36Sopenharmony_ci					"1805 Adapter failed to init. "
550962306a36Sopenharmony_ci					"Data: x%x x%x x%x\n",
551062306a36Sopenharmony_ci					pmbox->mbxCommand,
551162306a36Sopenharmony_ci					pmbox->mbxStatus, hbqno);
551262306a36Sopenharmony_ci
551362306a36Sopenharmony_ci			phba->link_state = LPFC_HBA_ERROR;
551462306a36Sopenharmony_ci			mempool_free(pmb, phba->mbox_mem_pool);
551562306a36Sopenharmony_ci			return -ENXIO;
551662306a36Sopenharmony_ci		}
551762306a36Sopenharmony_ci	}
551862306a36Sopenharmony_ci	phba->hbq_count = hbq_count;
551962306a36Sopenharmony_ci
552062306a36Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
552162306a36Sopenharmony_ci
552262306a36Sopenharmony_ci	/* Initially populate or replenish the HBQs */
552362306a36Sopenharmony_ci	for (hbqno = 0; hbqno < hbq_count; ++hbqno)
552462306a36Sopenharmony_ci		lpfc_sli_hbqbuf_init_hbqs(phba, hbqno);
552562306a36Sopenharmony_ci	return 0;
552662306a36Sopenharmony_ci}
552762306a36Sopenharmony_ci
552862306a36Sopenharmony_ci/**
552962306a36Sopenharmony_ci * lpfc_sli4_rb_setup - Initialize and post RBs to HBA
553062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
553162306a36Sopenharmony_ci *
553262306a36Sopenharmony_ci * This function is called during the SLI initialization to configure
553362306a36Sopenharmony_ci * all the HBQs and post buffers to the HBQ. The caller is not
553462306a36Sopenharmony_ci * required to hold any locks. This function will return zero if successful
553562306a36Sopenharmony_ci * else it will return negative error code.
553662306a36Sopenharmony_ci **/
553762306a36Sopenharmony_cistatic int
553862306a36Sopenharmony_cilpfc_sli4_rb_setup(struct lpfc_hba *phba)
553962306a36Sopenharmony_ci{
554062306a36Sopenharmony_ci	phba->hbq_in_use = 1;
554162306a36Sopenharmony_ci	/**
554262306a36Sopenharmony_ci	 * Specific case when the MDS diagnostics is enabled and supported.
554362306a36Sopenharmony_ci	 * The receive buffer count is truncated to manage the incoming
554462306a36Sopenharmony_ci	 * traffic.
554562306a36Sopenharmony_ci	 **/
554662306a36Sopenharmony_ci	if (phba->cfg_enable_mds_diags && phba->mds_diags_support)
554762306a36Sopenharmony_ci		phba->hbqs[LPFC_ELS_HBQ].entry_count =
554862306a36Sopenharmony_ci			lpfc_hbq_defs[LPFC_ELS_HBQ]->entry_count >> 1;
554962306a36Sopenharmony_ci	else
555062306a36Sopenharmony_ci		phba->hbqs[LPFC_ELS_HBQ].entry_count =
555162306a36Sopenharmony_ci			lpfc_hbq_defs[LPFC_ELS_HBQ]->entry_count;
555262306a36Sopenharmony_ci	phba->hbq_count = 1;
555362306a36Sopenharmony_ci	lpfc_sli_hbqbuf_init_hbqs(phba, LPFC_ELS_HBQ);
555462306a36Sopenharmony_ci	/* Initially populate or replenish the HBQs */
555562306a36Sopenharmony_ci	return 0;
555662306a36Sopenharmony_ci}
555762306a36Sopenharmony_ci
555862306a36Sopenharmony_ci/**
555962306a36Sopenharmony_ci * lpfc_sli_config_port - Issue config port mailbox command
556062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
556162306a36Sopenharmony_ci * @sli_mode: sli mode - 2/3
556262306a36Sopenharmony_ci *
556362306a36Sopenharmony_ci * This function is called by the sli initialization code path
556462306a36Sopenharmony_ci * to issue config_port mailbox command. This function restarts the
556562306a36Sopenharmony_ci * HBA firmware and issues a config_port mailbox command to configure
556662306a36Sopenharmony_ci * the SLI interface in the sli mode specified by sli_mode
556762306a36Sopenharmony_ci * variable. The caller is not required to hold any locks.
556862306a36Sopenharmony_ci * The function returns 0 if successful, else returns negative error
556962306a36Sopenharmony_ci * code.
557062306a36Sopenharmony_ci **/
557162306a36Sopenharmony_ciint
557262306a36Sopenharmony_cilpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
557362306a36Sopenharmony_ci{
557462306a36Sopenharmony_ci	LPFC_MBOXQ_t *pmb;
557562306a36Sopenharmony_ci	uint32_t resetcount = 0, rc = 0, done = 0;
557662306a36Sopenharmony_ci
557762306a36Sopenharmony_ci	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
557862306a36Sopenharmony_ci	if (!pmb) {
557962306a36Sopenharmony_ci		phba->link_state = LPFC_HBA_ERROR;
558062306a36Sopenharmony_ci		return -ENOMEM;
558162306a36Sopenharmony_ci	}
558262306a36Sopenharmony_ci
558362306a36Sopenharmony_ci	phba->sli_rev = sli_mode;
558462306a36Sopenharmony_ci	while (resetcount < 2 && !done) {
558562306a36Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
558662306a36Sopenharmony_ci		phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE;
558762306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
558862306a36Sopenharmony_ci		phba->pport->port_state = LPFC_VPORT_UNKNOWN;
558962306a36Sopenharmony_ci		lpfc_sli_brdrestart(phba);
559062306a36Sopenharmony_ci		rc = lpfc_sli_chipset_init(phba);
559162306a36Sopenharmony_ci		if (rc)
559262306a36Sopenharmony_ci			break;
559362306a36Sopenharmony_ci
559462306a36Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
559562306a36Sopenharmony_ci		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
559662306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
559762306a36Sopenharmony_ci		resetcount++;
559862306a36Sopenharmony_ci
559962306a36Sopenharmony_ci		/* Call pre CONFIG_PORT mailbox command initialization.  A
560062306a36Sopenharmony_ci		 * value of 0 means the call was successful.  Any other
560162306a36Sopenharmony_ci		 * nonzero value is a failure, but if ERESTART is returned,
560262306a36Sopenharmony_ci		 * the driver may reset the HBA and try again.
560362306a36Sopenharmony_ci		 */
560462306a36Sopenharmony_ci		rc = lpfc_config_port_prep(phba);
560562306a36Sopenharmony_ci		if (rc == -ERESTART) {
560662306a36Sopenharmony_ci			phba->link_state = LPFC_LINK_UNKNOWN;
560762306a36Sopenharmony_ci			continue;
560862306a36Sopenharmony_ci		} else if (rc)
560962306a36Sopenharmony_ci			break;
561062306a36Sopenharmony_ci
561162306a36Sopenharmony_ci		phba->link_state = LPFC_INIT_MBX_CMDS;
561262306a36Sopenharmony_ci		lpfc_config_port(phba, pmb);
561362306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
561462306a36Sopenharmony_ci		phba->sli3_options &= ~(LPFC_SLI3_NPIV_ENABLED |
561562306a36Sopenharmony_ci					LPFC_SLI3_HBQ_ENABLED |
561662306a36Sopenharmony_ci					LPFC_SLI3_CRP_ENABLED |
561762306a36Sopenharmony_ci					LPFC_SLI3_DSS_ENABLED);
561862306a36Sopenharmony_ci		if (rc != MBX_SUCCESS) {
561962306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
562062306a36Sopenharmony_ci				"0442 Adapter failed to init, mbxCmd x%x "
562162306a36Sopenharmony_ci				"CONFIG_PORT, mbxStatus x%x Data: x%x\n",
562262306a36Sopenharmony_ci				pmb->u.mb.mbxCommand, pmb->u.mb.mbxStatus, 0);
562362306a36Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
562462306a36Sopenharmony_ci			phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE;
562562306a36Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
562662306a36Sopenharmony_ci			rc = -ENXIO;
562762306a36Sopenharmony_ci		} else {
562862306a36Sopenharmony_ci			/* Allow asynchronous mailbox command to go through */
562962306a36Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
563062306a36Sopenharmony_ci			phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK;
563162306a36Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
563262306a36Sopenharmony_ci			done = 1;
563362306a36Sopenharmony_ci
563462306a36Sopenharmony_ci			if ((pmb->u.mb.un.varCfgPort.casabt == 1) &&
563562306a36Sopenharmony_ci			    (pmb->u.mb.un.varCfgPort.gasabt == 0))
563662306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
563762306a36Sopenharmony_ci					"3110 Port did not grant ASABT\n");
563862306a36Sopenharmony_ci		}
563962306a36Sopenharmony_ci	}
564062306a36Sopenharmony_ci	if (!done) {
564162306a36Sopenharmony_ci		rc = -EINVAL;
564262306a36Sopenharmony_ci		goto do_prep_failed;
564362306a36Sopenharmony_ci	}
564462306a36Sopenharmony_ci	if (pmb->u.mb.un.varCfgPort.sli_mode == 3) {
564562306a36Sopenharmony_ci		if (!pmb->u.mb.un.varCfgPort.cMA) {
564662306a36Sopenharmony_ci			rc = -ENXIO;
564762306a36Sopenharmony_ci			goto do_prep_failed;
564862306a36Sopenharmony_ci		}
564962306a36Sopenharmony_ci		if (phba->max_vpi && pmb->u.mb.un.varCfgPort.gmv) {
565062306a36Sopenharmony_ci			phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
565162306a36Sopenharmony_ci			phba->max_vpi = pmb->u.mb.un.varCfgPort.max_vpi;
565262306a36Sopenharmony_ci			phba->max_vports = (phba->max_vpi > phba->max_vports) ?
565362306a36Sopenharmony_ci				phba->max_vpi : phba->max_vports;
565462306a36Sopenharmony_ci
565562306a36Sopenharmony_ci		} else
565662306a36Sopenharmony_ci			phba->max_vpi = 0;
565762306a36Sopenharmony_ci		if (pmb->u.mb.un.varCfgPort.gerbm)
565862306a36Sopenharmony_ci			phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
565962306a36Sopenharmony_ci		if (pmb->u.mb.un.varCfgPort.gcrp)
566062306a36Sopenharmony_ci			phba->sli3_options |= LPFC_SLI3_CRP_ENABLED;
566162306a36Sopenharmony_ci
566262306a36Sopenharmony_ci		phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
566362306a36Sopenharmony_ci		phba->port_gp = phba->mbox->us.s3_pgp.port;
566462306a36Sopenharmony_ci
566562306a36Sopenharmony_ci		if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
566662306a36Sopenharmony_ci			if (pmb->u.mb.un.varCfgPort.gbg == 0) {
566762306a36Sopenharmony_ci				phba->cfg_enable_bg = 0;
566862306a36Sopenharmony_ci				phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED;
566962306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
567062306a36Sopenharmony_ci						"0443 Adapter did not grant "
567162306a36Sopenharmony_ci						"BlockGuard\n");
567262306a36Sopenharmony_ci			}
567362306a36Sopenharmony_ci		}
567462306a36Sopenharmony_ci	} else {
567562306a36Sopenharmony_ci		phba->hbq_get = NULL;
567662306a36Sopenharmony_ci		phba->port_gp = phba->mbox->us.s2.port;
567762306a36Sopenharmony_ci		phba->max_vpi = 0;
567862306a36Sopenharmony_ci	}
567962306a36Sopenharmony_cido_prep_failed:
568062306a36Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
568162306a36Sopenharmony_ci	return rc;
568262306a36Sopenharmony_ci}
568362306a36Sopenharmony_ci
568462306a36Sopenharmony_ci
568562306a36Sopenharmony_ci/**
568662306a36Sopenharmony_ci * lpfc_sli_hba_setup - SLI initialization function
568762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
568862306a36Sopenharmony_ci *
568962306a36Sopenharmony_ci * This function is the main SLI initialization function. This function
569062306a36Sopenharmony_ci * is called by the HBA initialization code, HBA reset code and HBA
569162306a36Sopenharmony_ci * error attention handler code. Caller is not required to hold any
569262306a36Sopenharmony_ci * locks. This function issues config_port mailbox command to configure
569362306a36Sopenharmony_ci * the SLI, setup iocb rings and HBQ rings. In the end the function
569462306a36Sopenharmony_ci * calls the config_port_post function to issue init_link mailbox
569562306a36Sopenharmony_ci * command and to start the discovery. The function will return zero
569662306a36Sopenharmony_ci * if successful, else it will return negative error code.
569762306a36Sopenharmony_ci **/
569862306a36Sopenharmony_ciint
569962306a36Sopenharmony_cilpfc_sli_hba_setup(struct lpfc_hba *phba)
570062306a36Sopenharmony_ci{
570162306a36Sopenharmony_ci	uint32_t rc;
570262306a36Sopenharmony_ci	int  i;
570362306a36Sopenharmony_ci	int longs;
570462306a36Sopenharmony_ci
570562306a36Sopenharmony_ci	/* Enable ISR already does config_port because of config_msi mbx */
570662306a36Sopenharmony_ci	if (phba->hba_flag & HBA_NEEDS_CFG_PORT) {
570762306a36Sopenharmony_ci		rc = lpfc_sli_config_port(phba, LPFC_SLI_REV3);
570862306a36Sopenharmony_ci		if (rc)
570962306a36Sopenharmony_ci			return -EIO;
571062306a36Sopenharmony_ci		phba->hba_flag &= ~HBA_NEEDS_CFG_PORT;
571162306a36Sopenharmony_ci	}
571262306a36Sopenharmony_ci	phba->fcp_embed_io = 0;	/* SLI4 FC support only */
571362306a36Sopenharmony_ci
571462306a36Sopenharmony_ci	if (phba->sli_rev == 3) {
571562306a36Sopenharmony_ci		phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE;
571662306a36Sopenharmony_ci		phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE;
571762306a36Sopenharmony_ci	} else {
571862306a36Sopenharmony_ci		phba->iocb_cmd_size = SLI2_IOCB_CMD_SIZE;
571962306a36Sopenharmony_ci		phba->iocb_rsp_size = SLI2_IOCB_RSP_SIZE;
572062306a36Sopenharmony_ci		phba->sli3_options = 0;
572162306a36Sopenharmony_ci	}
572262306a36Sopenharmony_ci
572362306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
572462306a36Sopenharmony_ci			"0444 Firmware in SLI %x mode. Max_vpi %d\n",
572562306a36Sopenharmony_ci			phba->sli_rev, phba->max_vpi);
572662306a36Sopenharmony_ci	rc = lpfc_sli_ring_map(phba);
572762306a36Sopenharmony_ci
572862306a36Sopenharmony_ci	if (rc)
572962306a36Sopenharmony_ci		goto lpfc_sli_hba_setup_error;
573062306a36Sopenharmony_ci
573162306a36Sopenharmony_ci	/* Initialize VPIs. */
573262306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV3) {
573362306a36Sopenharmony_ci		/*
573462306a36Sopenharmony_ci		 * The VPI bitmask and physical ID array are allocated
573562306a36Sopenharmony_ci		 * and initialized once only - at driver load.  A port
573662306a36Sopenharmony_ci		 * reset doesn't need to reinitialize this memory.
573762306a36Sopenharmony_ci		 */
573862306a36Sopenharmony_ci		if ((phba->vpi_bmask == NULL) && (phba->vpi_ids == NULL)) {
573962306a36Sopenharmony_ci			longs = (phba->max_vpi + BITS_PER_LONG) / BITS_PER_LONG;
574062306a36Sopenharmony_ci			phba->vpi_bmask = kcalloc(longs,
574162306a36Sopenharmony_ci						  sizeof(unsigned long),
574262306a36Sopenharmony_ci						  GFP_KERNEL);
574362306a36Sopenharmony_ci			if (!phba->vpi_bmask) {
574462306a36Sopenharmony_ci				rc = -ENOMEM;
574562306a36Sopenharmony_ci				goto lpfc_sli_hba_setup_error;
574662306a36Sopenharmony_ci			}
574762306a36Sopenharmony_ci
574862306a36Sopenharmony_ci			phba->vpi_ids = kcalloc(phba->max_vpi + 1,
574962306a36Sopenharmony_ci						sizeof(uint16_t),
575062306a36Sopenharmony_ci						GFP_KERNEL);
575162306a36Sopenharmony_ci			if (!phba->vpi_ids) {
575262306a36Sopenharmony_ci				kfree(phba->vpi_bmask);
575362306a36Sopenharmony_ci				rc = -ENOMEM;
575462306a36Sopenharmony_ci				goto lpfc_sli_hba_setup_error;
575562306a36Sopenharmony_ci			}
575662306a36Sopenharmony_ci			for (i = 0; i < phba->max_vpi; i++)
575762306a36Sopenharmony_ci				phba->vpi_ids[i] = i;
575862306a36Sopenharmony_ci		}
575962306a36Sopenharmony_ci	}
576062306a36Sopenharmony_ci
576162306a36Sopenharmony_ci	/* Init HBQs */
576262306a36Sopenharmony_ci	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
576362306a36Sopenharmony_ci		rc = lpfc_sli_hbq_setup(phba);
576462306a36Sopenharmony_ci		if (rc)
576562306a36Sopenharmony_ci			goto lpfc_sli_hba_setup_error;
576662306a36Sopenharmony_ci	}
576762306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
576862306a36Sopenharmony_ci	phba->sli.sli_flag |= LPFC_PROCESS_LA;
576962306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
577062306a36Sopenharmony_ci
577162306a36Sopenharmony_ci	rc = lpfc_config_port_post(phba);
577262306a36Sopenharmony_ci	if (rc)
577362306a36Sopenharmony_ci		goto lpfc_sli_hba_setup_error;
577462306a36Sopenharmony_ci
577562306a36Sopenharmony_ci	return rc;
577662306a36Sopenharmony_ci
577762306a36Sopenharmony_cilpfc_sli_hba_setup_error:
577862306a36Sopenharmony_ci	phba->link_state = LPFC_HBA_ERROR;
577962306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
578062306a36Sopenharmony_ci			"0445 Firmware initialization failed\n");
578162306a36Sopenharmony_ci	return rc;
578262306a36Sopenharmony_ci}
578362306a36Sopenharmony_ci
578462306a36Sopenharmony_ci/**
578562306a36Sopenharmony_ci * lpfc_sli4_read_fcoe_params - Read fcoe params from conf region
578662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
578762306a36Sopenharmony_ci *
578862306a36Sopenharmony_ci * This function issue a dump mailbox command to read config region
578962306a36Sopenharmony_ci * 23 and parse the records in the region and populate driver
579062306a36Sopenharmony_ci * data structure.
579162306a36Sopenharmony_ci **/
579262306a36Sopenharmony_cistatic int
579362306a36Sopenharmony_cilpfc_sli4_read_fcoe_params(struct lpfc_hba *phba)
579462306a36Sopenharmony_ci{
579562306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
579662306a36Sopenharmony_ci	struct lpfc_dmabuf *mp;
579762306a36Sopenharmony_ci	struct lpfc_mqe *mqe;
579862306a36Sopenharmony_ci	uint32_t data_length;
579962306a36Sopenharmony_ci	int rc;
580062306a36Sopenharmony_ci
580162306a36Sopenharmony_ci	/* Program the default value of vlan_id and fc_map */
580262306a36Sopenharmony_ci	phba->valid_vlan = 0;
580362306a36Sopenharmony_ci	phba->fc_map[0] = LPFC_FCOE_FCF_MAP0;
580462306a36Sopenharmony_ci	phba->fc_map[1] = LPFC_FCOE_FCF_MAP1;
580562306a36Sopenharmony_ci	phba->fc_map[2] = LPFC_FCOE_FCF_MAP2;
580662306a36Sopenharmony_ci
580762306a36Sopenharmony_ci	mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
580862306a36Sopenharmony_ci	if (!mboxq)
580962306a36Sopenharmony_ci		return -ENOMEM;
581062306a36Sopenharmony_ci
581162306a36Sopenharmony_ci	mqe = &mboxq->u.mqe;
581262306a36Sopenharmony_ci	if (lpfc_sli4_dump_cfg_rg23(phba, mboxq)) {
581362306a36Sopenharmony_ci		rc = -ENOMEM;
581462306a36Sopenharmony_ci		goto out_free_mboxq;
581562306a36Sopenharmony_ci	}
581662306a36Sopenharmony_ci
581762306a36Sopenharmony_ci	mp = (struct lpfc_dmabuf *)mboxq->ctx_buf;
581862306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
581962306a36Sopenharmony_ci
582062306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
582162306a36Sopenharmony_ci			"(%d):2571 Mailbox cmd x%x Status x%x "
582262306a36Sopenharmony_ci			"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x "
582362306a36Sopenharmony_ci			"x%x x%x x%x x%x x%x x%x x%x x%x x%x "
582462306a36Sopenharmony_ci			"CQ: x%x x%x x%x x%x\n",
582562306a36Sopenharmony_ci			mboxq->vport ? mboxq->vport->vpi : 0,
582662306a36Sopenharmony_ci			bf_get(lpfc_mqe_command, mqe),
582762306a36Sopenharmony_ci			bf_get(lpfc_mqe_status, mqe),
582862306a36Sopenharmony_ci			mqe->un.mb_words[0], mqe->un.mb_words[1],
582962306a36Sopenharmony_ci			mqe->un.mb_words[2], mqe->un.mb_words[3],
583062306a36Sopenharmony_ci			mqe->un.mb_words[4], mqe->un.mb_words[5],
583162306a36Sopenharmony_ci			mqe->un.mb_words[6], mqe->un.mb_words[7],
583262306a36Sopenharmony_ci			mqe->un.mb_words[8], mqe->un.mb_words[9],
583362306a36Sopenharmony_ci			mqe->un.mb_words[10], mqe->un.mb_words[11],
583462306a36Sopenharmony_ci			mqe->un.mb_words[12], mqe->un.mb_words[13],
583562306a36Sopenharmony_ci			mqe->un.mb_words[14], mqe->un.mb_words[15],
583662306a36Sopenharmony_ci			mqe->un.mb_words[16], mqe->un.mb_words[50],
583762306a36Sopenharmony_ci			mboxq->mcqe.word0,
583862306a36Sopenharmony_ci			mboxq->mcqe.mcqe_tag0, 	mboxq->mcqe.mcqe_tag1,
583962306a36Sopenharmony_ci			mboxq->mcqe.trailer);
584062306a36Sopenharmony_ci
584162306a36Sopenharmony_ci	if (rc) {
584262306a36Sopenharmony_ci		rc = -EIO;
584362306a36Sopenharmony_ci		goto out_free_mboxq;
584462306a36Sopenharmony_ci	}
584562306a36Sopenharmony_ci	data_length = mqe->un.mb_words[5];
584662306a36Sopenharmony_ci	if (data_length > DMP_RGN23_SIZE) {
584762306a36Sopenharmony_ci		rc = -EIO;
584862306a36Sopenharmony_ci		goto out_free_mboxq;
584962306a36Sopenharmony_ci	}
585062306a36Sopenharmony_ci
585162306a36Sopenharmony_ci	lpfc_parse_fcoe_conf(phba, mp->virt, data_length);
585262306a36Sopenharmony_ci	rc = 0;
585362306a36Sopenharmony_ci
585462306a36Sopenharmony_ciout_free_mboxq:
585562306a36Sopenharmony_ci	lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED);
585662306a36Sopenharmony_ci	return rc;
585762306a36Sopenharmony_ci}
585862306a36Sopenharmony_ci
585962306a36Sopenharmony_ci/**
586062306a36Sopenharmony_ci * lpfc_sli4_read_rev - Issue READ_REV and collect vpd data
586162306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
586262306a36Sopenharmony_ci * @mboxq: pointer to the LPFC_MBOXQ_t structure.
586362306a36Sopenharmony_ci * @vpd: pointer to the memory to hold resulting port vpd data.
586462306a36Sopenharmony_ci * @vpd_size: On input, the number of bytes allocated to @vpd.
586562306a36Sopenharmony_ci *	      On output, the number of data bytes in @vpd.
586662306a36Sopenharmony_ci *
586762306a36Sopenharmony_ci * This routine executes a READ_REV SLI4 mailbox command.  In
586862306a36Sopenharmony_ci * addition, this routine gets the port vpd data.
586962306a36Sopenharmony_ci *
587062306a36Sopenharmony_ci * Return codes
587162306a36Sopenharmony_ci * 	0 - successful
587262306a36Sopenharmony_ci * 	-ENOMEM - could not allocated memory.
587362306a36Sopenharmony_ci **/
587462306a36Sopenharmony_cistatic int
587562306a36Sopenharmony_cilpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
587662306a36Sopenharmony_ci		    uint8_t *vpd, uint32_t *vpd_size)
587762306a36Sopenharmony_ci{
587862306a36Sopenharmony_ci	int rc = 0;
587962306a36Sopenharmony_ci	uint32_t dma_size;
588062306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
588162306a36Sopenharmony_ci	struct lpfc_mqe *mqe;
588262306a36Sopenharmony_ci
588362306a36Sopenharmony_ci	dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
588462306a36Sopenharmony_ci	if (!dmabuf)
588562306a36Sopenharmony_ci		return -ENOMEM;
588662306a36Sopenharmony_ci
588762306a36Sopenharmony_ci	/*
588862306a36Sopenharmony_ci	 * Get a DMA buffer for the vpd data resulting from the READ_REV
588962306a36Sopenharmony_ci	 * mailbox command.
589062306a36Sopenharmony_ci	 */
589162306a36Sopenharmony_ci	dma_size = *vpd_size;
589262306a36Sopenharmony_ci	dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, dma_size,
589362306a36Sopenharmony_ci					  &dmabuf->phys, GFP_KERNEL);
589462306a36Sopenharmony_ci	if (!dmabuf->virt) {
589562306a36Sopenharmony_ci		kfree(dmabuf);
589662306a36Sopenharmony_ci		return -ENOMEM;
589762306a36Sopenharmony_ci	}
589862306a36Sopenharmony_ci
589962306a36Sopenharmony_ci	/*
590062306a36Sopenharmony_ci	 * The SLI4 implementation of READ_REV conflicts at word1,
590162306a36Sopenharmony_ci	 * bits 31:16 and SLI4 adds vpd functionality not present
590262306a36Sopenharmony_ci	 * in SLI3.  This code corrects the conflicts.
590362306a36Sopenharmony_ci	 */
590462306a36Sopenharmony_ci	lpfc_read_rev(phba, mboxq);
590562306a36Sopenharmony_ci	mqe = &mboxq->u.mqe;
590662306a36Sopenharmony_ci	mqe->un.read_rev.vpd_paddr_high = putPaddrHigh(dmabuf->phys);
590762306a36Sopenharmony_ci	mqe->un.read_rev.vpd_paddr_low = putPaddrLow(dmabuf->phys);
590862306a36Sopenharmony_ci	mqe->un.read_rev.word1 &= 0x0000FFFF;
590962306a36Sopenharmony_ci	bf_set(lpfc_mbx_rd_rev_vpd, &mqe->un.read_rev, 1);
591062306a36Sopenharmony_ci	bf_set(lpfc_mbx_rd_rev_avail_len, &mqe->un.read_rev, dma_size);
591162306a36Sopenharmony_ci
591262306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
591362306a36Sopenharmony_ci	if (rc) {
591462306a36Sopenharmony_ci		dma_free_coherent(&phba->pcidev->dev, dma_size,
591562306a36Sopenharmony_ci				  dmabuf->virt, dmabuf->phys);
591662306a36Sopenharmony_ci		kfree(dmabuf);
591762306a36Sopenharmony_ci		return -EIO;
591862306a36Sopenharmony_ci	}
591962306a36Sopenharmony_ci
592062306a36Sopenharmony_ci	/*
592162306a36Sopenharmony_ci	 * The available vpd length cannot be bigger than the
592262306a36Sopenharmony_ci	 * DMA buffer passed to the port.  Catch the less than
592362306a36Sopenharmony_ci	 * case and update the caller's size.
592462306a36Sopenharmony_ci	 */
592562306a36Sopenharmony_ci	if (mqe->un.read_rev.avail_vpd_len < *vpd_size)
592662306a36Sopenharmony_ci		*vpd_size = mqe->un.read_rev.avail_vpd_len;
592762306a36Sopenharmony_ci
592862306a36Sopenharmony_ci	memcpy(vpd, dmabuf->virt, *vpd_size);
592962306a36Sopenharmony_ci
593062306a36Sopenharmony_ci	dma_free_coherent(&phba->pcidev->dev, dma_size,
593162306a36Sopenharmony_ci			  dmabuf->virt, dmabuf->phys);
593262306a36Sopenharmony_ci	kfree(dmabuf);
593362306a36Sopenharmony_ci	return 0;
593462306a36Sopenharmony_ci}
593562306a36Sopenharmony_ci
593662306a36Sopenharmony_ci/**
593762306a36Sopenharmony_ci * lpfc_sli4_get_ctl_attr - Retrieve SLI4 device controller attributes
593862306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
593962306a36Sopenharmony_ci *
594062306a36Sopenharmony_ci * This routine retrieves SLI4 device physical port name this PCI function
594162306a36Sopenharmony_ci * is attached to.
594262306a36Sopenharmony_ci *
594362306a36Sopenharmony_ci * Return codes
594462306a36Sopenharmony_ci *      0 - successful
594562306a36Sopenharmony_ci *      otherwise - failed to retrieve controller attributes
594662306a36Sopenharmony_ci **/
594762306a36Sopenharmony_cistatic int
594862306a36Sopenharmony_cilpfc_sli4_get_ctl_attr(struct lpfc_hba *phba)
594962306a36Sopenharmony_ci{
595062306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
595162306a36Sopenharmony_ci	struct lpfc_mbx_get_cntl_attributes *mbx_cntl_attr;
595262306a36Sopenharmony_ci	struct lpfc_controller_attribute *cntl_attr;
595362306a36Sopenharmony_ci	void *virtaddr = NULL;
595462306a36Sopenharmony_ci	uint32_t alloclen, reqlen;
595562306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
595662306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
595762306a36Sopenharmony_ci	int rc;
595862306a36Sopenharmony_ci
595962306a36Sopenharmony_ci	mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
596062306a36Sopenharmony_ci	if (!mboxq)
596162306a36Sopenharmony_ci		return -ENOMEM;
596262306a36Sopenharmony_ci
596362306a36Sopenharmony_ci	/* Send COMMON_GET_CNTL_ATTRIBUTES mbox cmd */
596462306a36Sopenharmony_ci	reqlen = sizeof(struct lpfc_mbx_get_cntl_attributes);
596562306a36Sopenharmony_ci	alloclen = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
596662306a36Sopenharmony_ci			LPFC_MBOX_OPCODE_GET_CNTL_ATTRIBUTES, reqlen,
596762306a36Sopenharmony_ci			LPFC_SLI4_MBX_NEMBED);
596862306a36Sopenharmony_ci
596962306a36Sopenharmony_ci	if (alloclen < reqlen) {
597062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
597162306a36Sopenharmony_ci				"3084 Allocated DMA memory size (%d) is "
597262306a36Sopenharmony_ci				"less than the requested DMA memory size "
597362306a36Sopenharmony_ci				"(%d)\n", alloclen, reqlen);
597462306a36Sopenharmony_ci		rc = -ENOMEM;
597562306a36Sopenharmony_ci		goto out_free_mboxq;
597662306a36Sopenharmony_ci	}
597762306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
597862306a36Sopenharmony_ci	virtaddr = mboxq->sge_array->addr[0];
597962306a36Sopenharmony_ci	mbx_cntl_attr = (struct lpfc_mbx_get_cntl_attributes *)virtaddr;
598062306a36Sopenharmony_ci	shdr = &mbx_cntl_attr->cfg_shdr;
598162306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
598262306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
598362306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
598462306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
598562306a36Sopenharmony_ci				"3085 Mailbox x%x (x%x/x%x) failed, "
598662306a36Sopenharmony_ci				"rc:x%x, status:x%x, add_status:x%x\n",
598762306a36Sopenharmony_ci				bf_get(lpfc_mqe_command, &mboxq->u.mqe),
598862306a36Sopenharmony_ci				lpfc_sli_config_mbox_subsys_get(phba, mboxq),
598962306a36Sopenharmony_ci				lpfc_sli_config_mbox_opcode_get(phba, mboxq),
599062306a36Sopenharmony_ci				rc, shdr_status, shdr_add_status);
599162306a36Sopenharmony_ci		rc = -ENXIO;
599262306a36Sopenharmony_ci		goto out_free_mboxq;
599362306a36Sopenharmony_ci	}
599462306a36Sopenharmony_ci
599562306a36Sopenharmony_ci	cntl_attr = &mbx_cntl_attr->cntl_attr;
599662306a36Sopenharmony_ci	phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_VAL;
599762306a36Sopenharmony_ci	phba->sli4_hba.lnk_info.lnk_tp =
599862306a36Sopenharmony_ci		bf_get(lpfc_cntl_attr_lnk_type, cntl_attr);
599962306a36Sopenharmony_ci	phba->sli4_hba.lnk_info.lnk_no =
600062306a36Sopenharmony_ci		bf_get(lpfc_cntl_attr_lnk_numb, cntl_attr);
600162306a36Sopenharmony_ci	phba->sli4_hba.flash_id = bf_get(lpfc_cntl_attr_flash_id, cntl_attr);
600262306a36Sopenharmony_ci	phba->sli4_hba.asic_rev = bf_get(lpfc_cntl_attr_asic_rev, cntl_attr);
600362306a36Sopenharmony_ci
600462306a36Sopenharmony_ci	memset(phba->BIOSVersion, 0, sizeof(phba->BIOSVersion));
600562306a36Sopenharmony_ci	strlcat(phba->BIOSVersion, (char *)cntl_attr->bios_ver_str,
600662306a36Sopenharmony_ci		sizeof(phba->BIOSVersion));
600762306a36Sopenharmony_ci
600862306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
600962306a36Sopenharmony_ci			"3086 lnk_type:%d, lnk_numb:%d, bios_ver:%s, "
601062306a36Sopenharmony_ci			"flash_id: x%02x, asic_rev: x%02x\n",
601162306a36Sopenharmony_ci			phba->sli4_hba.lnk_info.lnk_tp,
601262306a36Sopenharmony_ci			phba->sli4_hba.lnk_info.lnk_no,
601362306a36Sopenharmony_ci			phba->BIOSVersion, phba->sli4_hba.flash_id,
601462306a36Sopenharmony_ci			phba->sli4_hba.asic_rev);
601562306a36Sopenharmony_ciout_free_mboxq:
601662306a36Sopenharmony_ci	if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG)
601762306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mboxq);
601862306a36Sopenharmony_ci	else
601962306a36Sopenharmony_ci		mempool_free(mboxq, phba->mbox_mem_pool);
602062306a36Sopenharmony_ci	return rc;
602162306a36Sopenharmony_ci}
602262306a36Sopenharmony_ci
602362306a36Sopenharmony_ci/**
602462306a36Sopenharmony_ci * lpfc_sli4_retrieve_pport_name - Retrieve SLI4 device physical port name
602562306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
602662306a36Sopenharmony_ci *
602762306a36Sopenharmony_ci * This routine retrieves SLI4 device physical port name this PCI function
602862306a36Sopenharmony_ci * is attached to.
602962306a36Sopenharmony_ci *
603062306a36Sopenharmony_ci * Return codes
603162306a36Sopenharmony_ci *      0 - successful
603262306a36Sopenharmony_ci *      otherwise - failed to retrieve physical port name
603362306a36Sopenharmony_ci **/
603462306a36Sopenharmony_cistatic int
603562306a36Sopenharmony_cilpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba)
603662306a36Sopenharmony_ci{
603762306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
603862306a36Sopenharmony_ci	struct lpfc_mbx_get_port_name *get_port_name;
603962306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
604062306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
604162306a36Sopenharmony_ci	char cport_name = 0;
604262306a36Sopenharmony_ci	int rc;
604362306a36Sopenharmony_ci
604462306a36Sopenharmony_ci	/* We assume nothing at this point */
604562306a36Sopenharmony_ci	phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL;
604662306a36Sopenharmony_ci	phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_NON;
604762306a36Sopenharmony_ci
604862306a36Sopenharmony_ci	mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
604962306a36Sopenharmony_ci	if (!mboxq)
605062306a36Sopenharmony_ci		return -ENOMEM;
605162306a36Sopenharmony_ci	/* obtain link type and link number via READ_CONFIG */
605262306a36Sopenharmony_ci	phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL;
605362306a36Sopenharmony_ci	lpfc_sli4_read_config(phba);
605462306a36Sopenharmony_ci
605562306a36Sopenharmony_ci	if (phba->sli4_hba.fawwpn_flag & LPFC_FAWWPN_CONFIG)
605662306a36Sopenharmony_ci		phba->sli4_hba.fawwpn_flag |= LPFC_FAWWPN_FABRIC;
605762306a36Sopenharmony_ci
605862306a36Sopenharmony_ci	if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL)
605962306a36Sopenharmony_ci		goto retrieve_ppname;
606062306a36Sopenharmony_ci
606162306a36Sopenharmony_ci	/* obtain link type and link number via COMMON_GET_CNTL_ATTRIBUTES */
606262306a36Sopenharmony_ci	rc = lpfc_sli4_get_ctl_attr(phba);
606362306a36Sopenharmony_ci	if (rc)
606462306a36Sopenharmony_ci		goto out_free_mboxq;
606562306a36Sopenharmony_ci
606662306a36Sopenharmony_ciretrieve_ppname:
606762306a36Sopenharmony_ci	lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
606862306a36Sopenharmony_ci		LPFC_MBOX_OPCODE_GET_PORT_NAME,
606962306a36Sopenharmony_ci		sizeof(struct lpfc_mbx_get_port_name) -
607062306a36Sopenharmony_ci		sizeof(struct lpfc_sli4_cfg_mhdr),
607162306a36Sopenharmony_ci		LPFC_SLI4_MBX_EMBED);
607262306a36Sopenharmony_ci	get_port_name = &mboxq->u.mqe.un.get_port_name;
607362306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)&get_port_name->header.cfg_shdr;
607462306a36Sopenharmony_ci	bf_set(lpfc_mbox_hdr_version, &shdr->request, LPFC_OPCODE_VERSION_1);
607562306a36Sopenharmony_ci	bf_set(lpfc_mbx_get_port_name_lnk_type, &get_port_name->u.request,
607662306a36Sopenharmony_ci		phba->sli4_hba.lnk_info.lnk_tp);
607762306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
607862306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
607962306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
608062306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
608162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
608262306a36Sopenharmony_ci				"3087 Mailbox x%x (x%x/x%x) failed: "
608362306a36Sopenharmony_ci				"rc:x%x, status:x%x, add_status:x%x\n",
608462306a36Sopenharmony_ci				bf_get(lpfc_mqe_command, &mboxq->u.mqe),
608562306a36Sopenharmony_ci				lpfc_sli_config_mbox_subsys_get(phba, mboxq),
608662306a36Sopenharmony_ci				lpfc_sli_config_mbox_opcode_get(phba, mboxq),
608762306a36Sopenharmony_ci				rc, shdr_status, shdr_add_status);
608862306a36Sopenharmony_ci		rc = -ENXIO;
608962306a36Sopenharmony_ci		goto out_free_mboxq;
609062306a36Sopenharmony_ci	}
609162306a36Sopenharmony_ci	switch (phba->sli4_hba.lnk_info.lnk_no) {
609262306a36Sopenharmony_ci	case LPFC_LINK_NUMBER_0:
609362306a36Sopenharmony_ci		cport_name = bf_get(lpfc_mbx_get_port_name_name0,
609462306a36Sopenharmony_ci				&get_port_name->u.response);
609562306a36Sopenharmony_ci		phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_GET;
609662306a36Sopenharmony_ci		break;
609762306a36Sopenharmony_ci	case LPFC_LINK_NUMBER_1:
609862306a36Sopenharmony_ci		cport_name = bf_get(lpfc_mbx_get_port_name_name1,
609962306a36Sopenharmony_ci				&get_port_name->u.response);
610062306a36Sopenharmony_ci		phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_GET;
610162306a36Sopenharmony_ci		break;
610262306a36Sopenharmony_ci	case LPFC_LINK_NUMBER_2:
610362306a36Sopenharmony_ci		cport_name = bf_get(lpfc_mbx_get_port_name_name2,
610462306a36Sopenharmony_ci				&get_port_name->u.response);
610562306a36Sopenharmony_ci		phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_GET;
610662306a36Sopenharmony_ci		break;
610762306a36Sopenharmony_ci	case LPFC_LINK_NUMBER_3:
610862306a36Sopenharmony_ci		cport_name = bf_get(lpfc_mbx_get_port_name_name3,
610962306a36Sopenharmony_ci				&get_port_name->u.response);
611062306a36Sopenharmony_ci		phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_GET;
611162306a36Sopenharmony_ci		break;
611262306a36Sopenharmony_ci	default:
611362306a36Sopenharmony_ci		break;
611462306a36Sopenharmony_ci	}
611562306a36Sopenharmony_ci
611662306a36Sopenharmony_ci	if (phba->sli4_hba.pport_name_sta == LPFC_SLI4_PPNAME_GET) {
611762306a36Sopenharmony_ci		phba->Port[0] = cport_name;
611862306a36Sopenharmony_ci		phba->Port[1] = '\0';
611962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
612062306a36Sopenharmony_ci				"3091 SLI get port name: %s\n", phba->Port);
612162306a36Sopenharmony_ci	}
612262306a36Sopenharmony_ci
612362306a36Sopenharmony_ciout_free_mboxq:
612462306a36Sopenharmony_ci	if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG)
612562306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mboxq);
612662306a36Sopenharmony_ci	else
612762306a36Sopenharmony_ci		mempool_free(mboxq, phba->mbox_mem_pool);
612862306a36Sopenharmony_ci	return rc;
612962306a36Sopenharmony_ci}
613062306a36Sopenharmony_ci
613162306a36Sopenharmony_ci/**
613262306a36Sopenharmony_ci * lpfc_sli4_arm_cqeq_intr - Arm sli-4 device completion and event queues
613362306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
613462306a36Sopenharmony_ci *
613562306a36Sopenharmony_ci * This routine is called to explicitly arm the SLI4 device's completion and
613662306a36Sopenharmony_ci * event queues
613762306a36Sopenharmony_ci **/
613862306a36Sopenharmony_cistatic void
613962306a36Sopenharmony_cilpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
614062306a36Sopenharmony_ci{
614162306a36Sopenharmony_ci	int qidx;
614262306a36Sopenharmony_ci	struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
614362306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *qp;
614462306a36Sopenharmony_ci	struct lpfc_queue *eq;
614562306a36Sopenharmony_ci
614662306a36Sopenharmony_ci	sli4_hba->sli4_write_cq_db(phba, sli4_hba->mbx_cq, 0, LPFC_QUEUE_REARM);
614762306a36Sopenharmony_ci	sli4_hba->sli4_write_cq_db(phba, sli4_hba->els_cq, 0, LPFC_QUEUE_REARM);
614862306a36Sopenharmony_ci	if (sli4_hba->nvmels_cq)
614962306a36Sopenharmony_ci		sli4_hba->sli4_write_cq_db(phba, sli4_hba->nvmels_cq, 0,
615062306a36Sopenharmony_ci					   LPFC_QUEUE_REARM);
615162306a36Sopenharmony_ci
615262306a36Sopenharmony_ci	if (sli4_hba->hdwq) {
615362306a36Sopenharmony_ci		/* Loop thru all Hardware Queues */
615462306a36Sopenharmony_ci		for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
615562306a36Sopenharmony_ci			qp = &sli4_hba->hdwq[qidx];
615662306a36Sopenharmony_ci			/* ARM the corresponding CQ */
615762306a36Sopenharmony_ci			sli4_hba->sli4_write_cq_db(phba, qp->io_cq, 0,
615862306a36Sopenharmony_ci						LPFC_QUEUE_REARM);
615962306a36Sopenharmony_ci		}
616062306a36Sopenharmony_ci
616162306a36Sopenharmony_ci		/* Loop thru all IRQ vectors */
616262306a36Sopenharmony_ci		for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
616362306a36Sopenharmony_ci			eq = sli4_hba->hba_eq_hdl[qidx].eq;
616462306a36Sopenharmony_ci			/* ARM the corresponding EQ */
616562306a36Sopenharmony_ci			sli4_hba->sli4_write_eq_db(phba, eq,
616662306a36Sopenharmony_ci						   0, LPFC_QUEUE_REARM);
616762306a36Sopenharmony_ci		}
616862306a36Sopenharmony_ci	}
616962306a36Sopenharmony_ci
617062306a36Sopenharmony_ci	if (phba->nvmet_support) {
617162306a36Sopenharmony_ci		for (qidx = 0; qidx < phba->cfg_nvmet_mrq; qidx++) {
617262306a36Sopenharmony_ci			sli4_hba->sli4_write_cq_db(phba,
617362306a36Sopenharmony_ci				sli4_hba->nvmet_cqset[qidx], 0,
617462306a36Sopenharmony_ci				LPFC_QUEUE_REARM);
617562306a36Sopenharmony_ci		}
617662306a36Sopenharmony_ci	}
617762306a36Sopenharmony_ci}
617862306a36Sopenharmony_ci
617962306a36Sopenharmony_ci/**
618062306a36Sopenharmony_ci * lpfc_sli4_get_avail_extnt_rsrc - Get available resource extent count.
618162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
618262306a36Sopenharmony_ci * @type: The resource extent type.
618362306a36Sopenharmony_ci * @extnt_count: buffer to hold port available extent count.
618462306a36Sopenharmony_ci * @extnt_size: buffer to hold element count per extent.
618562306a36Sopenharmony_ci *
618662306a36Sopenharmony_ci * This function calls the port and retrievs the number of available
618762306a36Sopenharmony_ci * extents and their size for a particular extent type.
618862306a36Sopenharmony_ci *
618962306a36Sopenharmony_ci * Returns: 0 if successful.  Nonzero otherwise.
619062306a36Sopenharmony_ci **/
619162306a36Sopenharmony_ciint
619262306a36Sopenharmony_cilpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type,
619362306a36Sopenharmony_ci			       uint16_t *extnt_count, uint16_t *extnt_size)
619462306a36Sopenharmony_ci{
619562306a36Sopenharmony_ci	int rc = 0;
619662306a36Sopenharmony_ci	uint32_t length;
619762306a36Sopenharmony_ci	uint32_t mbox_tmo;
619862306a36Sopenharmony_ci	struct lpfc_mbx_get_rsrc_extent_info *rsrc_info;
619962306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
620062306a36Sopenharmony_ci
620162306a36Sopenharmony_ci	*extnt_count = 0;
620262306a36Sopenharmony_ci	*extnt_size = 0;
620362306a36Sopenharmony_ci
620462306a36Sopenharmony_ci	mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
620562306a36Sopenharmony_ci	if (!mbox)
620662306a36Sopenharmony_ci		return -ENOMEM;
620762306a36Sopenharmony_ci
620862306a36Sopenharmony_ci	/* Find out how many extents are available for this resource type */
620962306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_get_rsrc_extent_info) -
621062306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
621162306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
621262306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_GET_RSRC_EXTENT_INFO,
621362306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
621462306a36Sopenharmony_ci
621562306a36Sopenharmony_ci	/* Send an extents count of 0 - the GET doesn't use it. */
621662306a36Sopenharmony_ci	rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, 0, type,
621762306a36Sopenharmony_ci					LPFC_SLI4_MBX_EMBED);
621862306a36Sopenharmony_ci	if (unlikely(rc)) {
621962306a36Sopenharmony_ci		rc = -EIO;
622062306a36Sopenharmony_ci		goto err_exit;
622162306a36Sopenharmony_ci	}
622262306a36Sopenharmony_ci
622362306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable)
622462306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
622562306a36Sopenharmony_ci	else {
622662306a36Sopenharmony_ci		mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
622762306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
622862306a36Sopenharmony_ci	}
622962306a36Sopenharmony_ci	if (unlikely(rc)) {
623062306a36Sopenharmony_ci		rc = -EIO;
623162306a36Sopenharmony_ci		goto err_exit;
623262306a36Sopenharmony_ci	}
623362306a36Sopenharmony_ci
623462306a36Sopenharmony_ci	rsrc_info = &mbox->u.mqe.un.rsrc_extent_info;
623562306a36Sopenharmony_ci	if (bf_get(lpfc_mbox_hdr_status,
623662306a36Sopenharmony_ci		   &rsrc_info->header.cfg_shdr.response)) {
623762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
623862306a36Sopenharmony_ci				"2930 Failed to get resource extents "
623962306a36Sopenharmony_ci				"Status 0x%x Add'l Status 0x%x\n",
624062306a36Sopenharmony_ci				bf_get(lpfc_mbox_hdr_status,
624162306a36Sopenharmony_ci				       &rsrc_info->header.cfg_shdr.response),
624262306a36Sopenharmony_ci				bf_get(lpfc_mbox_hdr_add_status,
624362306a36Sopenharmony_ci				       &rsrc_info->header.cfg_shdr.response));
624462306a36Sopenharmony_ci		rc = -EIO;
624562306a36Sopenharmony_ci		goto err_exit;
624662306a36Sopenharmony_ci	}
624762306a36Sopenharmony_ci
624862306a36Sopenharmony_ci	*extnt_count = bf_get(lpfc_mbx_get_rsrc_extent_info_cnt,
624962306a36Sopenharmony_ci			      &rsrc_info->u.rsp);
625062306a36Sopenharmony_ci	*extnt_size = bf_get(lpfc_mbx_get_rsrc_extent_info_size,
625162306a36Sopenharmony_ci			     &rsrc_info->u.rsp);
625262306a36Sopenharmony_ci
625362306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
625462306a36Sopenharmony_ci			"3162 Retrieved extents type-%d from port: count:%d, "
625562306a36Sopenharmony_ci			"size:%d\n", type, *extnt_count, *extnt_size);
625662306a36Sopenharmony_ci
625762306a36Sopenharmony_cierr_exit:
625862306a36Sopenharmony_ci	mempool_free(mbox, phba->mbox_mem_pool);
625962306a36Sopenharmony_ci	return rc;
626062306a36Sopenharmony_ci}
626162306a36Sopenharmony_ci
626262306a36Sopenharmony_ci/**
626362306a36Sopenharmony_ci * lpfc_sli4_chk_avail_extnt_rsrc - Check for available SLI4 resource extents.
626462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
626562306a36Sopenharmony_ci * @type: The extent type to check.
626662306a36Sopenharmony_ci *
626762306a36Sopenharmony_ci * This function reads the current available extents from the port and checks
626862306a36Sopenharmony_ci * if the extent count or extent size has changed since the last access.
626962306a36Sopenharmony_ci * Callers use this routine post port reset to understand if there is a
627062306a36Sopenharmony_ci * extent reprovisioning requirement.
627162306a36Sopenharmony_ci *
627262306a36Sopenharmony_ci * Returns:
627362306a36Sopenharmony_ci *   -Error: error indicates problem.
627462306a36Sopenharmony_ci *   1: Extent count or size has changed.
627562306a36Sopenharmony_ci *   0: No changes.
627662306a36Sopenharmony_ci **/
627762306a36Sopenharmony_cistatic int
627862306a36Sopenharmony_cilpfc_sli4_chk_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type)
627962306a36Sopenharmony_ci{
628062306a36Sopenharmony_ci	uint16_t curr_ext_cnt, rsrc_ext_cnt;
628162306a36Sopenharmony_ci	uint16_t size_diff, rsrc_ext_size;
628262306a36Sopenharmony_ci	int rc = 0;
628362306a36Sopenharmony_ci	struct lpfc_rsrc_blks *rsrc_entry;
628462306a36Sopenharmony_ci	struct list_head *rsrc_blk_list = NULL;
628562306a36Sopenharmony_ci
628662306a36Sopenharmony_ci	size_diff = 0;
628762306a36Sopenharmony_ci	curr_ext_cnt = 0;
628862306a36Sopenharmony_ci	rc = lpfc_sli4_get_avail_extnt_rsrc(phba, type,
628962306a36Sopenharmony_ci					    &rsrc_ext_cnt,
629062306a36Sopenharmony_ci					    &rsrc_ext_size);
629162306a36Sopenharmony_ci	if (unlikely(rc))
629262306a36Sopenharmony_ci		return -EIO;
629362306a36Sopenharmony_ci
629462306a36Sopenharmony_ci	switch (type) {
629562306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_RPI:
629662306a36Sopenharmony_ci		rsrc_blk_list = &phba->sli4_hba.lpfc_rpi_blk_list;
629762306a36Sopenharmony_ci		break;
629862306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_VPI:
629962306a36Sopenharmony_ci		rsrc_blk_list = &phba->lpfc_vpi_blk_list;
630062306a36Sopenharmony_ci		break;
630162306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_XRI:
630262306a36Sopenharmony_ci		rsrc_blk_list = &phba->sli4_hba.lpfc_xri_blk_list;
630362306a36Sopenharmony_ci		break;
630462306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_VFI:
630562306a36Sopenharmony_ci		rsrc_blk_list = &phba->sli4_hba.lpfc_vfi_blk_list;
630662306a36Sopenharmony_ci		break;
630762306a36Sopenharmony_ci	default:
630862306a36Sopenharmony_ci		break;
630962306a36Sopenharmony_ci	}
631062306a36Sopenharmony_ci
631162306a36Sopenharmony_ci	list_for_each_entry(rsrc_entry, rsrc_blk_list, list) {
631262306a36Sopenharmony_ci		curr_ext_cnt++;
631362306a36Sopenharmony_ci		if (rsrc_entry->rsrc_size != rsrc_ext_size)
631462306a36Sopenharmony_ci			size_diff++;
631562306a36Sopenharmony_ci	}
631662306a36Sopenharmony_ci
631762306a36Sopenharmony_ci	if (curr_ext_cnt != rsrc_ext_cnt || size_diff != 0)
631862306a36Sopenharmony_ci		rc = 1;
631962306a36Sopenharmony_ci
632062306a36Sopenharmony_ci	return rc;
632162306a36Sopenharmony_ci}
632262306a36Sopenharmony_ci
632362306a36Sopenharmony_ci/**
632462306a36Sopenharmony_ci * lpfc_sli4_cfg_post_extnts -
632562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
632662306a36Sopenharmony_ci * @extnt_cnt: number of available extents.
632762306a36Sopenharmony_ci * @type: the extent type (rpi, xri, vfi, vpi).
632862306a36Sopenharmony_ci * @emb: buffer to hold either MBX_EMBED or MBX_NEMBED operation.
632962306a36Sopenharmony_ci * @mbox: pointer to the caller's allocated mailbox structure.
633062306a36Sopenharmony_ci *
633162306a36Sopenharmony_ci * This function executes the extents allocation request.  It also
633262306a36Sopenharmony_ci * takes care of the amount of memory needed to allocate or get the
633362306a36Sopenharmony_ci * allocated extents. It is the caller's responsibility to evaluate
633462306a36Sopenharmony_ci * the response.
633562306a36Sopenharmony_ci *
633662306a36Sopenharmony_ci * Returns:
633762306a36Sopenharmony_ci *   -Error:  Error value describes the condition found.
633862306a36Sopenharmony_ci *   0: if successful
633962306a36Sopenharmony_ci **/
634062306a36Sopenharmony_cistatic int
634162306a36Sopenharmony_cilpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t extnt_cnt,
634262306a36Sopenharmony_ci			  uint16_t type, bool *emb, LPFC_MBOXQ_t *mbox)
634362306a36Sopenharmony_ci{
634462306a36Sopenharmony_ci	int rc = 0;
634562306a36Sopenharmony_ci	uint32_t req_len;
634662306a36Sopenharmony_ci	uint32_t emb_len;
634762306a36Sopenharmony_ci	uint32_t alloc_len, mbox_tmo;
634862306a36Sopenharmony_ci
634962306a36Sopenharmony_ci	/* Calculate the total requested length of the dma memory */
635062306a36Sopenharmony_ci	req_len = extnt_cnt * sizeof(uint16_t);
635162306a36Sopenharmony_ci
635262306a36Sopenharmony_ci	/*
635362306a36Sopenharmony_ci	 * Calculate the size of an embedded mailbox.  The uint32_t
635462306a36Sopenharmony_ci	 * accounts for extents-specific word.
635562306a36Sopenharmony_ci	 */
635662306a36Sopenharmony_ci	emb_len = sizeof(MAILBOX_t) - sizeof(struct mbox_header) -
635762306a36Sopenharmony_ci		sizeof(uint32_t);
635862306a36Sopenharmony_ci
635962306a36Sopenharmony_ci	/*
636062306a36Sopenharmony_ci	 * Presume the allocation and response will fit into an embedded
636162306a36Sopenharmony_ci	 * mailbox.  If not true, reconfigure to a non-embedded mailbox.
636262306a36Sopenharmony_ci	 */
636362306a36Sopenharmony_ci	*emb = LPFC_SLI4_MBX_EMBED;
636462306a36Sopenharmony_ci	if (req_len > emb_len) {
636562306a36Sopenharmony_ci		req_len = extnt_cnt * sizeof(uint16_t) +
636662306a36Sopenharmony_ci			sizeof(union lpfc_sli4_cfg_shdr) +
636762306a36Sopenharmony_ci			sizeof(uint32_t);
636862306a36Sopenharmony_ci		*emb = LPFC_SLI4_MBX_NEMBED;
636962306a36Sopenharmony_ci	}
637062306a36Sopenharmony_ci
637162306a36Sopenharmony_ci	alloc_len = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
637262306a36Sopenharmony_ci				     LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT,
637362306a36Sopenharmony_ci				     req_len, *emb);
637462306a36Sopenharmony_ci	if (alloc_len < req_len) {
637562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
637662306a36Sopenharmony_ci			"2982 Allocated DMA memory size (x%x) is "
637762306a36Sopenharmony_ci			"less than the requested DMA memory "
637862306a36Sopenharmony_ci			"size (x%x)\n", alloc_len, req_len);
637962306a36Sopenharmony_ci		return -ENOMEM;
638062306a36Sopenharmony_ci	}
638162306a36Sopenharmony_ci	rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, extnt_cnt, type, *emb);
638262306a36Sopenharmony_ci	if (unlikely(rc))
638362306a36Sopenharmony_ci		return -EIO;
638462306a36Sopenharmony_ci
638562306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable)
638662306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
638762306a36Sopenharmony_ci	else {
638862306a36Sopenharmony_ci		mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
638962306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
639062306a36Sopenharmony_ci	}
639162306a36Sopenharmony_ci
639262306a36Sopenharmony_ci	if (unlikely(rc))
639362306a36Sopenharmony_ci		rc = -EIO;
639462306a36Sopenharmony_ci	return rc;
639562306a36Sopenharmony_ci}
639662306a36Sopenharmony_ci
639762306a36Sopenharmony_ci/**
639862306a36Sopenharmony_ci * lpfc_sli4_alloc_extent - Allocate an SLI4 resource extent.
639962306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
640062306a36Sopenharmony_ci * @type:  The resource extent type to allocate.
640162306a36Sopenharmony_ci *
640262306a36Sopenharmony_ci * This function allocates the number of elements for the specified
640362306a36Sopenharmony_ci * resource type.
640462306a36Sopenharmony_ci **/
640562306a36Sopenharmony_cistatic int
640662306a36Sopenharmony_cilpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type)
640762306a36Sopenharmony_ci{
640862306a36Sopenharmony_ci	bool emb = false;
640962306a36Sopenharmony_ci	uint16_t rsrc_id_cnt, rsrc_cnt, rsrc_size;
641062306a36Sopenharmony_ci	uint16_t rsrc_id, rsrc_start, j, k;
641162306a36Sopenharmony_ci	uint16_t *ids;
641262306a36Sopenharmony_ci	int i, rc;
641362306a36Sopenharmony_ci	unsigned long longs;
641462306a36Sopenharmony_ci	unsigned long *bmask;
641562306a36Sopenharmony_ci	struct lpfc_rsrc_blks *rsrc_blks;
641662306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
641762306a36Sopenharmony_ci	uint32_t length;
641862306a36Sopenharmony_ci	struct lpfc_id_range *id_array = NULL;
641962306a36Sopenharmony_ci	void *virtaddr = NULL;
642062306a36Sopenharmony_ci	struct lpfc_mbx_nembed_rsrc_extent *n_rsrc;
642162306a36Sopenharmony_ci	struct lpfc_mbx_alloc_rsrc_extents *rsrc_ext;
642262306a36Sopenharmony_ci	struct list_head *ext_blk_list;
642362306a36Sopenharmony_ci
642462306a36Sopenharmony_ci	rc = lpfc_sli4_get_avail_extnt_rsrc(phba, type,
642562306a36Sopenharmony_ci					    &rsrc_cnt,
642662306a36Sopenharmony_ci					    &rsrc_size);
642762306a36Sopenharmony_ci	if (unlikely(rc))
642862306a36Sopenharmony_ci		return -EIO;
642962306a36Sopenharmony_ci
643062306a36Sopenharmony_ci	if ((rsrc_cnt == 0) || (rsrc_size == 0)) {
643162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
643262306a36Sopenharmony_ci			"3009 No available Resource Extents "
643362306a36Sopenharmony_ci			"for resource type 0x%x: Count: 0x%x, "
643462306a36Sopenharmony_ci			"Size 0x%x\n", type, rsrc_cnt,
643562306a36Sopenharmony_ci			rsrc_size);
643662306a36Sopenharmony_ci		return -ENOMEM;
643762306a36Sopenharmony_ci	}
643862306a36Sopenharmony_ci
643962306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT | LOG_SLI,
644062306a36Sopenharmony_ci			"2903 Post resource extents type-0x%x: "
644162306a36Sopenharmony_ci			"count:%d, size %d\n", type, rsrc_cnt, rsrc_size);
644262306a36Sopenharmony_ci
644362306a36Sopenharmony_ci	mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
644462306a36Sopenharmony_ci	if (!mbox)
644562306a36Sopenharmony_ci		return -ENOMEM;
644662306a36Sopenharmony_ci
644762306a36Sopenharmony_ci	rc = lpfc_sli4_cfg_post_extnts(phba, rsrc_cnt, type, &emb, mbox);
644862306a36Sopenharmony_ci	if (unlikely(rc)) {
644962306a36Sopenharmony_ci		rc = -EIO;
645062306a36Sopenharmony_ci		goto err_exit;
645162306a36Sopenharmony_ci	}
645262306a36Sopenharmony_ci
645362306a36Sopenharmony_ci	/*
645462306a36Sopenharmony_ci	 * Figure out where the response is located.  Then get local pointers
645562306a36Sopenharmony_ci	 * to the response data.  The port does not guarantee to respond to
645662306a36Sopenharmony_ci	 * all extents counts request so update the local variable with the
645762306a36Sopenharmony_ci	 * allocated count from the port.
645862306a36Sopenharmony_ci	 */
645962306a36Sopenharmony_ci	if (emb == LPFC_SLI4_MBX_EMBED) {
646062306a36Sopenharmony_ci		rsrc_ext = &mbox->u.mqe.un.alloc_rsrc_extents;
646162306a36Sopenharmony_ci		id_array = &rsrc_ext->u.rsp.id[0];
646262306a36Sopenharmony_ci		rsrc_cnt = bf_get(lpfc_mbx_rsrc_cnt, &rsrc_ext->u.rsp);
646362306a36Sopenharmony_ci	} else {
646462306a36Sopenharmony_ci		virtaddr = mbox->sge_array->addr[0];
646562306a36Sopenharmony_ci		n_rsrc = (struct lpfc_mbx_nembed_rsrc_extent *) virtaddr;
646662306a36Sopenharmony_ci		rsrc_cnt = bf_get(lpfc_mbx_rsrc_cnt, n_rsrc);
646762306a36Sopenharmony_ci		id_array = &n_rsrc->id;
646862306a36Sopenharmony_ci	}
646962306a36Sopenharmony_ci
647062306a36Sopenharmony_ci	longs = ((rsrc_cnt * rsrc_size) + BITS_PER_LONG - 1) / BITS_PER_LONG;
647162306a36Sopenharmony_ci	rsrc_id_cnt = rsrc_cnt * rsrc_size;
647262306a36Sopenharmony_ci
647362306a36Sopenharmony_ci	/*
647462306a36Sopenharmony_ci	 * Based on the resource size and count, correct the base and max
647562306a36Sopenharmony_ci	 * resource values.
647662306a36Sopenharmony_ci	 */
647762306a36Sopenharmony_ci	length = sizeof(struct lpfc_rsrc_blks);
647862306a36Sopenharmony_ci	switch (type) {
647962306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_RPI:
648062306a36Sopenharmony_ci		phba->sli4_hba.rpi_bmask = kcalloc(longs,
648162306a36Sopenharmony_ci						   sizeof(unsigned long),
648262306a36Sopenharmony_ci						   GFP_KERNEL);
648362306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.rpi_bmask)) {
648462306a36Sopenharmony_ci			rc = -ENOMEM;
648562306a36Sopenharmony_ci			goto err_exit;
648662306a36Sopenharmony_ci		}
648762306a36Sopenharmony_ci		phba->sli4_hba.rpi_ids = kcalloc(rsrc_id_cnt,
648862306a36Sopenharmony_ci						 sizeof(uint16_t),
648962306a36Sopenharmony_ci						 GFP_KERNEL);
649062306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.rpi_ids)) {
649162306a36Sopenharmony_ci			kfree(phba->sli4_hba.rpi_bmask);
649262306a36Sopenharmony_ci			rc = -ENOMEM;
649362306a36Sopenharmony_ci			goto err_exit;
649462306a36Sopenharmony_ci		}
649562306a36Sopenharmony_ci
649662306a36Sopenharmony_ci		/*
649762306a36Sopenharmony_ci		 * The next_rpi was initialized with the maximum available
649862306a36Sopenharmony_ci		 * count but the port may allocate a smaller number.  Catch
649962306a36Sopenharmony_ci		 * that case and update the next_rpi.
650062306a36Sopenharmony_ci		 */
650162306a36Sopenharmony_ci		phba->sli4_hba.next_rpi = rsrc_id_cnt;
650262306a36Sopenharmony_ci
650362306a36Sopenharmony_ci		/* Initialize local ptrs for common extent processing later. */
650462306a36Sopenharmony_ci		bmask = phba->sli4_hba.rpi_bmask;
650562306a36Sopenharmony_ci		ids = phba->sli4_hba.rpi_ids;
650662306a36Sopenharmony_ci		ext_blk_list = &phba->sli4_hba.lpfc_rpi_blk_list;
650762306a36Sopenharmony_ci		break;
650862306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_VPI:
650962306a36Sopenharmony_ci		phba->vpi_bmask = kcalloc(longs, sizeof(unsigned long),
651062306a36Sopenharmony_ci					  GFP_KERNEL);
651162306a36Sopenharmony_ci		if (unlikely(!phba->vpi_bmask)) {
651262306a36Sopenharmony_ci			rc = -ENOMEM;
651362306a36Sopenharmony_ci			goto err_exit;
651462306a36Sopenharmony_ci		}
651562306a36Sopenharmony_ci		phba->vpi_ids = kcalloc(rsrc_id_cnt, sizeof(uint16_t),
651662306a36Sopenharmony_ci					 GFP_KERNEL);
651762306a36Sopenharmony_ci		if (unlikely(!phba->vpi_ids)) {
651862306a36Sopenharmony_ci			kfree(phba->vpi_bmask);
651962306a36Sopenharmony_ci			rc = -ENOMEM;
652062306a36Sopenharmony_ci			goto err_exit;
652162306a36Sopenharmony_ci		}
652262306a36Sopenharmony_ci
652362306a36Sopenharmony_ci		/* Initialize local ptrs for common extent processing later. */
652462306a36Sopenharmony_ci		bmask = phba->vpi_bmask;
652562306a36Sopenharmony_ci		ids = phba->vpi_ids;
652662306a36Sopenharmony_ci		ext_blk_list = &phba->lpfc_vpi_blk_list;
652762306a36Sopenharmony_ci		break;
652862306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_XRI:
652962306a36Sopenharmony_ci		phba->sli4_hba.xri_bmask = kcalloc(longs,
653062306a36Sopenharmony_ci						   sizeof(unsigned long),
653162306a36Sopenharmony_ci						   GFP_KERNEL);
653262306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.xri_bmask)) {
653362306a36Sopenharmony_ci			rc = -ENOMEM;
653462306a36Sopenharmony_ci			goto err_exit;
653562306a36Sopenharmony_ci		}
653662306a36Sopenharmony_ci		phba->sli4_hba.max_cfg_param.xri_used = 0;
653762306a36Sopenharmony_ci		phba->sli4_hba.xri_ids = kcalloc(rsrc_id_cnt,
653862306a36Sopenharmony_ci						 sizeof(uint16_t),
653962306a36Sopenharmony_ci						 GFP_KERNEL);
654062306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.xri_ids)) {
654162306a36Sopenharmony_ci			kfree(phba->sli4_hba.xri_bmask);
654262306a36Sopenharmony_ci			rc = -ENOMEM;
654362306a36Sopenharmony_ci			goto err_exit;
654462306a36Sopenharmony_ci		}
654562306a36Sopenharmony_ci
654662306a36Sopenharmony_ci		/* Initialize local ptrs for common extent processing later. */
654762306a36Sopenharmony_ci		bmask = phba->sli4_hba.xri_bmask;
654862306a36Sopenharmony_ci		ids = phba->sli4_hba.xri_ids;
654962306a36Sopenharmony_ci		ext_blk_list = &phba->sli4_hba.lpfc_xri_blk_list;
655062306a36Sopenharmony_ci		break;
655162306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_VFI:
655262306a36Sopenharmony_ci		phba->sli4_hba.vfi_bmask = kcalloc(longs,
655362306a36Sopenharmony_ci						   sizeof(unsigned long),
655462306a36Sopenharmony_ci						   GFP_KERNEL);
655562306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.vfi_bmask)) {
655662306a36Sopenharmony_ci			rc = -ENOMEM;
655762306a36Sopenharmony_ci			goto err_exit;
655862306a36Sopenharmony_ci		}
655962306a36Sopenharmony_ci		phba->sli4_hba.vfi_ids = kcalloc(rsrc_id_cnt,
656062306a36Sopenharmony_ci						 sizeof(uint16_t),
656162306a36Sopenharmony_ci						 GFP_KERNEL);
656262306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.vfi_ids)) {
656362306a36Sopenharmony_ci			kfree(phba->sli4_hba.vfi_bmask);
656462306a36Sopenharmony_ci			rc = -ENOMEM;
656562306a36Sopenharmony_ci			goto err_exit;
656662306a36Sopenharmony_ci		}
656762306a36Sopenharmony_ci
656862306a36Sopenharmony_ci		/* Initialize local ptrs for common extent processing later. */
656962306a36Sopenharmony_ci		bmask = phba->sli4_hba.vfi_bmask;
657062306a36Sopenharmony_ci		ids = phba->sli4_hba.vfi_ids;
657162306a36Sopenharmony_ci		ext_blk_list = &phba->sli4_hba.lpfc_vfi_blk_list;
657262306a36Sopenharmony_ci		break;
657362306a36Sopenharmony_ci	default:
657462306a36Sopenharmony_ci		/* Unsupported Opcode.  Fail call. */
657562306a36Sopenharmony_ci		id_array = NULL;
657662306a36Sopenharmony_ci		bmask = NULL;
657762306a36Sopenharmony_ci		ids = NULL;
657862306a36Sopenharmony_ci		ext_blk_list = NULL;
657962306a36Sopenharmony_ci		goto err_exit;
658062306a36Sopenharmony_ci	}
658162306a36Sopenharmony_ci
658262306a36Sopenharmony_ci	/*
658362306a36Sopenharmony_ci	 * Complete initializing the extent configuration with the
658462306a36Sopenharmony_ci	 * allocated ids assigned to this function.  The bitmask serves
658562306a36Sopenharmony_ci	 * as an index into the array and manages the available ids.  The
658662306a36Sopenharmony_ci	 * array just stores the ids communicated to the port via the wqes.
658762306a36Sopenharmony_ci	 */
658862306a36Sopenharmony_ci	for (i = 0, j = 0, k = 0; i < rsrc_cnt; i++) {
658962306a36Sopenharmony_ci		if ((i % 2) == 0)
659062306a36Sopenharmony_ci			rsrc_id = bf_get(lpfc_mbx_rsrc_id_word4_0,
659162306a36Sopenharmony_ci					 &id_array[k]);
659262306a36Sopenharmony_ci		else
659362306a36Sopenharmony_ci			rsrc_id = bf_get(lpfc_mbx_rsrc_id_word4_1,
659462306a36Sopenharmony_ci					 &id_array[k]);
659562306a36Sopenharmony_ci
659662306a36Sopenharmony_ci		rsrc_blks = kzalloc(length, GFP_KERNEL);
659762306a36Sopenharmony_ci		if (unlikely(!rsrc_blks)) {
659862306a36Sopenharmony_ci			rc = -ENOMEM;
659962306a36Sopenharmony_ci			kfree(bmask);
660062306a36Sopenharmony_ci			kfree(ids);
660162306a36Sopenharmony_ci			goto err_exit;
660262306a36Sopenharmony_ci		}
660362306a36Sopenharmony_ci		rsrc_blks->rsrc_start = rsrc_id;
660462306a36Sopenharmony_ci		rsrc_blks->rsrc_size = rsrc_size;
660562306a36Sopenharmony_ci		list_add_tail(&rsrc_blks->list, ext_blk_list);
660662306a36Sopenharmony_ci		rsrc_start = rsrc_id;
660762306a36Sopenharmony_ci		if ((type == LPFC_RSC_TYPE_FCOE_XRI) && (j == 0)) {
660862306a36Sopenharmony_ci			phba->sli4_hba.io_xri_start = rsrc_start +
660962306a36Sopenharmony_ci				lpfc_sli4_get_iocb_cnt(phba);
661062306a36Sopenharmony_ci		}
661162306a36Sopenharmony_ci
661262306a36Sopenharmony_ci		while (rsrc_id < (rsrc_start + rsrc_size)) {
661362306a36Sopenharmony_ci			ids[j] = rsrc_id;
661462306a36Sopenharmony_ci			rsrc_id++;
661562306a36Sopenharmony_ci			j++;
661662306a36Sopenharmony_ci		}
661762306a36Sopenharmony_ci		/* Entire word processed.  Get next word.*/
661862306a36Sopenharmony_ci		if ((i % 2) == 1)
661962306a36Sopenharmony_ci			k++;
662062306a36Sopenharmony_ci	}
662162306a36Sopenharmony_ci err_exit:
662262306a36Sopenharmony_ci	lpfc_sli4_mbox_cmd_free(phba, mbox);
662362306a36Sopenharmony_ci	return rc;
662462306a36Sopenharmony_ci}
662562306a36Sopenharmony_ci
662662306a36Sopenharmony_ci
662762306a36Sopenharmony_ci
662862306a36Sopenharmony_ci/**
662962306a36Sopenharmony_ci * lpfc_sli4_dealloc_extent - Deallocate an SLI4 resource extent.
663062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
663162306a36Sopenharmony_ci * @type: the extent's type.
663262306a36Sopenharmony_ci *
663362306a36Sopenharmony_ci * This function deallocates all extents of a particular resource type.
663462306a36Sopenharmony_ci * SLI4 does not allow for deallocating a particular extent range.  It
663562306a36Sopenharmony_ci * is the caller's responsibility to release all kernel memory resources.
663662306a36Sopenharmony_ci **/
663762306a36Sopenharmony_cistatic int
663862306a36Sopenharmony_cilpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type)
663962306a36Sopenharmony_ci{
664062306a36Sopenharmony_ci	int rc;
664162306a36Sopenharmony_ci	uint32_t length, mbox_tmo = 0;
664262306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
664362306a36Sopenharmony_ci	struct lpfc_mbx_dealloc_rsrc_extents *dealloc_rsrc;
664462306a36Sopenharmony_ci	struct lpfc_rsrc_blks *rsrc_blk, *rsrc_blk_next;
664562306a36Sopenharmony_ci
664662306a36Sopenharmony_ci	mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
664762306a36Sopenharmony_ci	if (!mbox)
664862306a36Sopenharmony_ci		return -ENOMEM;
664962306a36Sopenharmony_ci
665062306a36Sopenharmony_ci	/*
665162306a36Sopenharmony_ci	 * This function sends an embedded mailbox because it only sends the
665262306a36Sopenharmony_ci	 * the resource type.  All extents of this type are released by the
665362306a36Sopenharmony_ci	 * port.
665462306a36Sopenharmony_ci	 */
665562306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_dealloc_rsrc_extents) -
665662306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
665762306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
665862306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_DEALLOC_RSRC_EXTENT,
665962306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
666062306a36Sopenharmony_ci
666162306a36Sopenharmony_ci	/* Send an extents count of 0 - the dealloc doesn't use it. */
666262306a36Sopenharmony_ci	rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, 0, type,
666362306a36Sopenharmony_ci					LPFC_SLI4_MBX_EMBED);
666462306a36Sopenharmony_ci	if (unlikely(rc)) {
666562306a36Sopenharmony_ci		rc = -EIO;
666662306a36Sopenharmony_ci		goto out_free_mbox;
666762306a36Sopenharmony_ci	}
666862306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable)
666962306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
667062306a36Sopenharmony_ci	else {
667162306a36Sopenharmony_ci		mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
667262306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
667362306a36Sopenharmony_ci	}
667462306a36Sopenharmony_ci	if (unlikely(rc)) {
667562306a36Sopenharmony_ci		rc = -EIO;
667662306a36Sopenharmony_ci		goto out_free_mbox;
667762306a36Sopenharmony_ci	}
667862306a36Sopenharmony_ci
667962306a36Sopenharmony_ci	dealloc_rsrc = &mbox->u.mqe.un.dealloc_rsrc_extents;
668062306a36Sopenharmony_ci	if (bf_get(lpfc_mbox_hdr_status,
668162306a36Sopenharmony_ci		   &dealloc_rsrc->header.cfg_shdr.response)) {
668262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
668362306a36Sopenharmony_ci				"2919 Failed to release resource extents "
668462306a36Sopenharmony_ci				"for type %d - Status 0x%x Add'l Status 0x%x. "
668562306a36Sopenharmony_ci				"Resource memory not released.\n",
668662306a36Sopenharmony_ci				type,
668762306a36Sopenharmony_ci				bf_get(lpfc_mbox_hdr_status,
668862306a36Sopenharmony_ci				    &dealloc_rsrc->header.cfg_shdr.response),
668962306a36Sopenharmony_ci				bf_get(lpfc_mbox_hdr_add_status,
669062306a36Sopenharmony_ci				    &dealloc_rsrc->header.cfg_shdr.response));
669162306a36Sopenharmony_ci		rc = -EIO;
669262306a36Sopenharmony_ci		goto out_free_mbox;
669362306a36Sopenharmony_ci	}
669462306a36Sopenharmony_ci
669562306a36Sopenharmony_ci	/* Release kernel memory resources for the specific type. */
669662306a36Sopenharmony_ci	switch (type) {
669762306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_VPI:
669862306a36Sopenharmony_ci		kfree(phba->vpi_bmask);
669962306a36Sopenharmony_ci		kfree(phba->vpi_ids);
670062306a36Sopenharmony_ci		bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
670162306a36Sopenharmony_ci		list_for_each_entry_safe(rsrc_blk, rsrc_blk_next,
670262306a36Sopenharmony_ci				    &phba->lpfc_vpi_blk_list, list) {
670362306a36Sopenharmony_ci			list_del_init(&rsrc_blk->list);
670462306a36Sopenharmony_ci			kfree(rsrc_blk);
670562306a36Sopenharmony_ci		}
670662306a36Sopenharmony_ci		phba->sli4_hba.max_cfg_param.vpi_used = 0;
670762306a36Sopenharmony_ci		break;
670862306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_XRI:
670962306a36Sopenharmony_ci		kfree(phba->sli4_hba.xri_bmask);
671062306a36Sopenharmony_ci		kfree(phba->sli4_hba.xri_ids);
671162306a36Sopenharmony_ci		list_for_each_entry_safe(rsrc_blk, rsrc_blk_next,
671262306a36Sopenharmony_ci				    &phba->sli4_hba.lpfc_xri_blk_list, list) {
671362306a36Sopenharmony_ci			list_del_init(&rsrc_blk->list);
671462306a36Sopenharmony_ci			kfree(rsrc_blk);
671562306a36Sopenharmony_ci		}
671662306a36Sopenharmony_ci		break;
671762306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_VFI:
671862306a36Sopenharmony_ci		kfree(phba->sli4_hba.vfi_bmask);
671962306a36Sopenharmony_ci		kfree(phba->sli4_hba.vfi_ids);
672062306a36Sopenharmony_ci		bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
672162306a36Sopenharmony_ci		list_for_each_entry_safe(rsrc_blk, rsrc_blk_next,
672262306a36Sopenharmony_ci				    &phba->sli4_hba.lpfc_vfi_blk_list, list) {
672362306a36Sopenharmony_ci			list_del_init(&rsrc_blk->list);
672462306a36Sopenharmony_ci			kfree(rsrc_blk);
672562306a36Sopenharmony_ci		}
672662306a36Sopenharmony_ci		break;
672762306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_RPI:
672862306a36Sopenharmony_ci		/* RPI bitmask and physical id array are cleaned up earlier. */
672962306a36Sopenharmony_ci		list_for_each_entry_safe(rsrc_blk, rsrc_blk_next,
673062306a36Sopenharmony_ci				    &phba->sli4_hba.lpfc_rpi_blk_list, list) {
673162306a36Sopenharmony_ci			list_del_init(&rsrc_blk->list);
673262306a36Sopenharmony_ci			kfree(rsrc_blk);
673362306a36Sopenharmony_ci		}
673462306a36Sopenharmony_ci		break;
673562306a36Sopenharmony_ci	default:
673662306a36Sopenharmony_ci		break;
673762306a36Sopenharmony_ci	}
673862306a36Sopenharmony_ci
673962306a36Sopenharmony_ci	bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
674062306a36Sopenharmony_ci
674162306a36Sopenharmony_ci out_free_mbox:
674262306a36Sopenharmony_ci	mempool_free(mbox, phba->mbox_mem_pool);
674362306a36Sopenharmony_ci	return rc;
674462306a36Sopenharmony_ci}
674562306a36Sopenharmony_ci
674662306a36Sopenharmony_cistatic void
674762306a36Sopenharmony_cilpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox,
674862306a36Sopenharmony_ci		  uint32_t feature)
674962306a36Sopenharmony_ci{
675062306a36Sopenharmony_ci	uint32_t len;
675162306a36Sopenharmony_ci	u32 sig_freq = 0;
675262306a36Sopenharmony_ci
675362306a36Sopenharmony_ci	len = sizeof(struct lpfc_mbx_set_feature) -
675462306a36Sopenharmony_ci		sizeof(struct lpfc_sli4_cfg_mhdr);
675562306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
675662306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_SET_FEATURES, len,
675762306a36Sopenharmony_ci			 LPFC_SLI4_MBX_EMBED);
675862306a36Sopenharmony_ci
675962306a36Sopenharmony_ci	switch (feature) {
676062306a36Sopenharmony_ci	case LPFC_SET_UE_RECOVERY:
676162306a36Sopenharmony_ci		bf_set(lpfc_mbx_set_feature_UER,
676262306a36Sopenharmony_ci		       &mbox->u.mqe.un.set_feature, 1);
676362306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.feature = LPFC_SET_UE_RECOVERY;
676462306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.param_len = 8;
676562306a36Sopenharmony_ci		break;
676662306a36Sopenharmony_ci	case LPFC_SET_MDS_DIAGS:
676762306a36Sopenharmony_ci		bf_set(lpfc_mbx_set_feature_mds,
676862306a36Sopenharmony_ci		       &mbox->u.mqe.un.set_feature, 1);
676962306a36Sopenharmony_ci		bf_set(lpfc_mbx_set_feature_mds_deep_loopbk,
677062306a36Sopenharmony_ci		       &mbox->u.mqe.un.set_feature, 1);
677162306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.feature = LPFC_SET_MDS_DIAGS;
677262306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.param_len = 8;
677362306a36Sopenharmony_ci		break;
677462306a36Sopenharmony_ci	case LPFC_SET_CGN_SIGNAL:
677562306a36Sopenharmony_ci		if (phba->cmf_active_mode == LPFC_CFG_OFF)
677662306a36Sopenharmony_ci			sig_freq = 0;
677762306a36Sopenharmony_ci		else
677862306a36Sopenharmony_ci			sig_freq = phba->cgn_sig_freq;
677962306a36Sopenharmony_ci
678062306a36Sopenharmony_ci		if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) {
678162306a36Sopenharmony_ci			bf_set(lpfc_mbx_set_feature_CGN_alarm_freq,
678262306a36Sopenharmony_ci			       &mbox->u.mqe.un.set_feature, sig_freq);
678362306a36Sopenharmony_ci			bf_set(lpfc_mbx_set_feature_CGN_warn_freq,
678462306a36Sopenharmony_ci			       &mbox->u.mqe.un.set_feature, sig_freq);
678562306a36Sopenharmony_ci		}
678662306a36Sopenharmony_ci
678762306a36Sopenharmony_ci		if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY)
678862306a36Sopenharmony_ci			bf_set(lpfc_mbx_set_feature_CGN_warn_freq,
678962306a36Sopenharmony_ci			       &mbox->u.mqe.un.set_feature, sig_freq);
679062306a36Sopenharmony_ci
679162306a36Sopenharmony_ci		if (phba->cmf_active_mode == LPFC_CFG_OFF ||
679262306a36Sopenharmony_ci		    phba->cgn_reg_signal == EDC_CG_SIG_NOTSUPPORTED)
679362306a36Sopenharmony_ci			sig_freq = 0;
679462306a36Sopenharmony_ci		else
679562306a36Sopenharmony_ci			sig_freq = lpfc_acqe_cgn_frequency;
679662306a36Sopenharmony_ci
679762306a36Sopenharmony_ci		bf_set(lpfc_mbx_set_feature_CGN_acqe_freq,
679862306a36Sopenharmony_ci		       &mbox->u.mqe.un.set_feature, sig_freq);
679962306a36Sopenharmony_ci
680062306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.feature = LPFC_SET_CGN_SIGNAL;
680162306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.param_len = 12;
680262306a36Sopenharmony_ci		break;
680362306a36Sopenharmony_ci	case LPFC_SET_DUAL_DUMP:
680462306a36Sopenharmony_ci		bf_set(lpfc_mbx_set_feature_dd,
680562306a36Sopenharmony_ci		       &mbox->u.mqe.un.set_feature, LPFC_ENABLE_DUAL_DUMP);
680662306a36Sopenharmony_ci		bf_set(lpfc_mbx_set_feature_ddquery,
680762306a36Sopenharmony_ci		       &mbox->u.mqe.un.set_feature, 0);
680862306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.feature = LPFC_SET_DUAL_DUMP;
680962306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.param_len = 4;
681062306a36Sopenharmony_ci		break;
681162306a36Sopenharmony_ci	case LPFC_SET_ENABLE_MI:
681262306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.feature = LPFC_SET_ENABLE_MI;
681362306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.param_len = 4;
681462306a36Sopenharmony_ci		bf_set(lpfc_mbx_set_feature_milunq, &mbox->u.mqe.un.set_feature,
681562306a36Sopenharmony_ci		       phba->pport->cfg_lun_queue_depth);
681662306a36Sopenharmony_ci		bf_set(lpfc_mbx_set_feature_mi, &mbox->u.mqe.un.set_feature,
681762306a36Sopenharmony_ci		       phba->sli4_hba.pc_sli4_params.mi_ver);
681862306a36Sopenharmony_ci		break;
681962306a36Sopenharmony_ci	case LPFC_SET_LD_SIGNAL:
682062306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.feature = LPFC_SET_LD_SIGNAL;
682162306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.param_len = 16;
682262306a36Sopenharmony_ci		bf_set(lpfc_mbx_set_feature_lds_qry,
682362306a36Sopenharmony_ci		       &mbox->u.mqe.un.set_feature, LPFC_QUERY_LDS_OP);
682462306a36Sopenharmony_ci		break;
682562306a36Sopenharmony_ci	case LPFC_SET_ENABLE_CMF:
682662306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.feature = LPFC_SET_ENABLE_CMF;
682762306a36Sopenharmony_ci		mbox->u.mqe.un.set_feature.param_len = 4;
682862306a36Sopenharmony_ci		bf_set(lpfc_mbx_set_feature_cmf,
682962306a36Sopenharmony_ci		       &mbox->u.mqe.un.set_feature, 1);
683062306a36Sopenharmony_ci		break;
683162306a36Sopenharmony_ci	}
683262306a36Sopenharmony_ci	return;
683362306a36Sopenharmony_ci}
683462306a36Sopenharmony_ci
683562306a36Sopenharmony_ci/**
683662306a36Sopenharmony_ci * lpfc_ras_stop_fwlog: Disable FW logging by the adapter
683762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
683862306a36Sopenharmony_ci *
683962306a36Sopenharmony_ci * Disable FW logging into host memory on the adapter. To
684062306a36Sopenharmony_ci * be done before reading logs from the host memory.
684162306a36Sopenharmony_ci **/
684262306a36Sopenharmony_civoid
684362306a36Sopenharmony_cilpfc_ras_stop_fwlog(struct lpfc_hba *phba)
684462306a36Sopenharmony_ci{
684562306a36Sopenharmony_ci	struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
684662306a36Sopenharmony_ci
684762306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
684862306a36Sopenharmony_ci	ras_fwlog->state = INACTIVE;
684962306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
685062306a36Sopenharmony_ci
685162306a36Sopenharmony_ci	/* Disable FW logging to host memory */
685262306a36Sopenharmony_ci	writel(LPFC_CTL_PDEV_CTL_DDL_RAS,
685362306a36Sopenharmony_ci	       phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET);
685462306a36Sopenharmony_ci
685562306a36Sopenharmony_ci	/* Wait 10ms for firmware to stop using DMA buffer */
685662306a36Sopenharmony_ci	usleep_range(10 * 1000, 20 * 1000);
685762306a36Sopenharmony_ci}
685862306a36Sopenharmony_ci
685962306a36Sopenharmony_ci/**
686062306a36Sopenharmony_ci * lpfc_sli4_ras_dma_free - Free memory allocated for FW logging.
686162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
686262306a36Sopenharmony_ci *
686362306a36Sopenharmony_ci * This function is called to free memory allocated for RAS FW logging
686462306a36Sopenharmony_ci * support in the driver.
686562306a36Sopenharmony_ci **/
686662306a36Sopenharmony_civoid
686762306a36Sopenharmony_cilpfc_sli4_ras_dma_free(struct lpfc_hba *phba)
686862306a36Sopenharmony_ci{
686962306a36Sopenharmony_ci	struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
687062306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf, *next;
687162306a36Sopenharmony_ci
687262306a36Sopenharmony_ci	if (!list_empty(&ras_fwlog->fwlog_buff_list)) {
687362306a36Sopenharmony_ci		list_for_each_entry_safe(dmabuf, next,
687462306a36Sopenharmony_ci				    &ras_fwlog->fwlog_buff_list,
687562306a36Sopenharmony_ci				    list) {
687662306a36Sopenharmony_ci			list_del(&dmabuf->list);
687762306a36Sopenharmony_ci			dma_free_coherent(&phba->pcidev->dev,
687862306a36Sopenharmony_ci					  LPFC_RAS_MAX_ENTRY_SIZE,
687962306a36Sopenharmony_ci					  dmabuf->virt, dmabuf->phys);
688062306a36Sopenharmony_ci			kfree(dmabuf);
688162306a36Sopenharmony_ci		}
688262306a36Sopenharmony_ci	}
688362306a36Sopenharmony_ci
688462306a36Sopenharmony_ci	if (ras_fwlog->lwpd.virt) {
688562306a36Sopenharmony_ci		dma_free_coherent(&phba->pcidev->dev,
688662306a36Sopenharmony_ci				  sizeof(uint32_t) * 2,
688762306a36Sopenharmony_ci				  ras_fwlog->lwpd.virt,
688862306a36Sopenharmony_ci				  ras_fwlog->lwpd.phys);
688962306a36Sopenharmony_ci		ras_fwlog->lwpd.virt = NULL;
689062306a36Sopenharmony_ci	}
689162306a36Sopenharmony_ci
689262306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
689362306a36Sopenharmony_ci	ras_fwlog->state = INACTIVE;
689462306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
689562306a36Sopenharmony_ci}
689662306a36Sopenharmony_ci
689762306a36Sopenharmony_ci/**
689862306a36Sopenharmony_ci * lpfc_sli4_ras_dma_alloc: Allocate memory for FW support
689962306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
690062306a36Sopenharmony_ci * @fwlog_buff_count: Count of buffers to be created.
690162306a36Sopenharmony_ci *
690262306a36Sopenharmony_ci * This routine DMA memory for Log Write Position Data[LPWD] and buffer
690362306a36Sopenharmony_ci * to update FW log is posted to the adapter.
690462306a36Sopenharmony_ci * Buffer count is calculated based on module param ras_fwlog_buffsize
690562306a36Sopenharmony_ci * Size of each buffer posted to FW is 64K.
690662306a36Sopenharmony_ci **/
690762306a36Sopenharmony_ci
690862306a36Sopenharmony_cistatic int
690962306a36Sopenharmony_cilpfc_sli4_ras_dma_alloc(struct lpfc_hba *phba,
691062306a36Sopenharmony_ci			uint32_t fwlog_buff_count)
691162306a36Sopenharmony_ci{
691262306a36Sopenharmony_ci	struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
691362306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
691462306a36Sopenharmony_ci	int rc = 0, i = 0;
691562306a36Sopenharmony_ci
691662306a36Sopenharmony_ci	/* Initialize List */
691762306a36Sopenharmony_ci	INIT_LIST_HEAD(&ras_fwlog->fwlog_buff_list);
691862306a36Sopenharmony_ci
691962306a36Sopenharmony_ci	/* Allocate memory for the LWPD */
692062306a36Sopenharmony_ci	ras_fwlog->lwpd.virt = dma_alloc_coherent(&phba->pcidev->dev,
692162306a36Sopenharmony_ci					    sizeof(uint32_t) * 2,
692262306a36Sopenharmony_ci					    &ras_fwlog->lwpd.phys,
692362306a36Sopenharmony_ci					    GFP_KERNEL);
692462306a36Sopenharmony_ci	if (!ras_fwlog->lwpd.virt) {
692562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
692662306a36Sopenharmony_ci				"6185 LWPD Memory Alloc Failed\n");
692762306a36Sopenharmony_ci
692862306a36Sopenharmony_ci		return -ENOMEM;
692962306a36Sopenharmony_ci	}
693062306a36Sopenharmony_ci
693162306a36Sopenharmony_ci	ras_fwlog->fw_buffcount = fwlog_buff_count;
693262306a36Sopenharmony_ci	for (i = 0; i < ras_fwlog->fw_buffcount; i++) {
693362306a36Sopenharmony_ci		dmabuf = kzalloc(sizeof(struct lpfc_dmabuf),
693462306a36Sopenharmony_ci				 GFP_KERNEL);
693562306a36Sopenharmony_ci		if (!dmabuf) {
693662306a36Sopenharmony_ci			rc = -ENOMEM;
693762306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
693862306a36Sopenharmony_ci					"6186 Memory Alloc failed FW logging");
693962306a36Sopenharmony_ci			goto free_mem;
694062306a36Sopenharmony_ci		}
694162306a36Sopenharmony_ci
694262306a36Sopenharmony_ci		dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
694362306a36Sopenharmony_ci						  LPFC_RAS_MAX_ENTRY_SIZE,
694462306a36Sopenharmony_ci						  &dmabuf->phys, GFP_KERNEL);
694562306a36Sopenharmony_ci		if (!dmabuf->virt) {
694662306a36Sopenharmony_ci			kfree(dmabuf);
694762306a36Sopenharmony_ci			rc = -ENOMEM;
694862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
694962306a36Sopenharmony_ci					"6187 DMA Alloc Failed FW logging");
695062306a36Sopenharmony_ci			goto free_mem;
695162306a36Sopenharmony_ci		}
695262306a36Sopenharmony_ci		dmabuf->buffer_tag = i;
695362306a36Sopenharmony_ci		list_add_tail(&dmabuf->list, &ras_fwlog->fwlog_buff_list);
695462306a36Sopenharmony_ci	}
695562306a36Sopenharmony_ci
695662306a36Sopenharmony_cifree_mem:
695762306a36Sopenharmony_ci	if (rc)
695862306a36Sopenharmony_ci		lpfc_sli4_ras_dma_free(phba);
695962306a36Sopenharmony_ci
696062306a36Sopenharmony_ci	return rc;
696162306a36Sopenharmony_ci}
696262306a36Sopenharmony_ci
696362306a36Sopenharmony_ci/**
696462306a36Sopenharmony_ci * lpfc_sli4_ras_mbox_cmpl: Completion handler for RAS MBX command
696562306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
696662306a36Sopenharmony_ci * @pmb: pointer to the driver internal queue element for mailbox command.
696762306a36Sopenharmony_ci *
696862306a36Sopenharmony_ci * Completion handler for driver's RAS MBX command to the device.
696962306a36Sopenharmony_ci **/
697062306a36Sopenharmony_cistatic void
697162306a36Sopenharmony_cilpfc_sli4_ras_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
697262306a36Sopenharmony_ci{
697362306a36Sopenharmony_ci	MAILBOX_t *mb;
697462306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
697562306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
697662306a36Sopenharmony_ci	struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
697762306a36Sopenharmony_ci
697862306a36Sopenharmony_ci	mb = &pmb->u.mb;
697962306a36Sopenharmony_ci
698062306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)
698162306a36Sopenharmony_ci		&pmb->u.mqe.un.ras_fwlog.header.cfg_shdr;
698262306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
698362306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
698462306a36Sopenharmony_ci
698562306a36Sopenharmony_ci	if (mb->mbxStatus != MBX_SUCCESS || shdr_status) {
698662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
698762306a36Sopenharmony_ci				"6188 FW LOG mailbox "
698862306a36Sopenharmony_ci				"completed with status x%x add_status x%x,"
698962306a36Sopenharmony_ci				" mbx status x%x\n",
699062306a36Sopenharmony_ci				shdr_status, shdr_add_status, mb->mbxStatus);
699162306a36Sopenharmony_ci
699262306a36Sopenharmony_ci		ras_fwlog->ras_hwsupport = false;
699362306a36Sopenharmony_ci		goto disable_ras;
699462306a36Sopenharmony_ci	}
699562306a36Sopenharmony_ci
699662306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
699762306a36Sopenharmony_ci	ras_fwlog->state = ACTIVE;
699862306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
699962306a36Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
700062306a36Sopenharmony_ci
700162306a36Sopenharmony_ci	return;
700262306a36Sopenharmony_ci
700362306a36Sopenharmony_cidisable_ras:
700462306a36Sopenharmony_ci	/* Free RAS DMA memory */
700562306a36Sopenharmony_ci	lpfc_sli4_ras_dma_free(phba);
700662306a36Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
700762306a36Sopenharmony_ci}
700862306a36Sopenharmony_ci
700962306a36Sopenharmony_ci/**
701062306a36Sopenharmony_ci * lpfc_sli4_ras_fwlog_init: Initialize memory and post RAS MBX command
701162306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
701262306a36Sopenharmony_ci * @fwlog_level: Logging verbosity level.
701362306a36Sopenharmony_ci * @fwlog_enable: Enable/Disable logging.
701462306a36Sopenharmony_ci *
701562306a36Sopenharmony_ci * Initialize memory and post mailbox command to enable FW logging in host
701662306a36Sopenharmony_ci * memory.
701762306a36Sopenharmony_ci **/
701862306a36Sopenharmony_ciint
701962306a36Sopenharmony_cilpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba,
702062306a36Sopenharmony_ci			 uint32_t fwlog_level,
702162306a36Sopenharmony_ci			 uint32_t fwlog_enable)
702262306a36Sopenharmony_ci{
702362306a36Sopenharmony_ci	struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
702462306a36Sopenharmony_ci	struct lpfc_mbx_set_ras_fwlog *mbx_fwlog = NULL;
702562306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
702662306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
702762306a36Sopenharmony_ci	uint32_t len = 0, fwlog_buffsize, fwlog_entry_count;
702862306a36Sopenharmony_ci	int rc = 0;
702962306a36Sopenharmony_ci
703062306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
703162306a36Sopenharmony_ci	ras_fwlog->state = INACTIVE;
703262306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
703362306a36Sopenharmony_ci
703462306a36Sopenharmony_ci	fwlog_buffsize = (LPFC_RAS_MIN_BUFF_POST_SIZE *
703562306a36Sopenharmony_ci			  phba->cfg_ras_fwlog_buffsize);
703662306a36Sopenharmony_ci	fwlog_entry_count = (fwlog_buffsize/LPFC_RAS_MAX_ENTRY_SIZE);
703762306a36Sopenharmony_ci
703862306a36Sopenharmony_ci	/*
703962306a36Sopenharmony_ci	 * If re-enabling FW logging support use earlier allocated
704062306a36Sopenharmony_ci	 * DMA buffers while posting MBX command.
704162306a36Sopenharmony_ci	 **/
704262306a36Sopenharmony_ci	if (!ras_fwlog->lwpd.virt) {
704362306a36Sopenharmony_ci		rc = lpfc_sli4_ras_dma_alloc(phba, fwlog_entry_count);
704462306a36Sopenharmony_ci		if (rc) {
704562306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
704662306a36Sopenharmony_ci					"6189 FW Log Memory Allocation Failed");
704762306a36Sopenharmony_ci			return rc;
704862306a36Sopenharmony_ci		}
704962306a36Sopenharmony_ci	}
705062306a36Sopenharmony_ci
705162306a36Sopenharmony_ci	/* Setup Mailbox command */
705262306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
705362306a36Sopenharmony_ci	if (!mbox) {
705462306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
705562306a36Sopenharmony_ci				"6190 RAS MBX Alloc Failed");
705662306a36Sopenharmony_ci		rc = -ENOMEM;
705762306a36Sopenharmony_ci		goto mem_free;
705862306a36Sopenharmony_ci	}
705962306a36Sopenharmony_ci
706062306a36Sopenharmony_ci	ras_fwlog->fw_loglevel = fwlog_level;
706162306a36Sopenharmony_ci	len = (sizeof(struct lpfc_mbx_set_ras_fwlog) -
706262306a36Sopenharmony_ci		sizeof(struct lpfc_sli4_cfg_mhdr));
706362306a36Sopenharmony_ci
706462306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_LOWLEVEL,
706562306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_SET_DIAG_LOG_OPTION,
706662306a36Sopenharmony_ci			 len, LPFC_SLI4_MBX_EMBED);
706762306a36Sopenharmony_ci
706862306a36Sopenharmony_ci	mbx_fwlog = (struct lpfc_mbx_set_ras_fwlog *)&mbox->u.mqe.un.ras_fwlog;
706962306a36Sopenharmony_ci	bf_set(lpfc_fwlog_enable, &mbx_fwlog->u.request,
707062306a36Sopenharmony_ci	       fwlog_enable);
707162306a36Sopenharmony_ci	bf_set(lpfc_fwlog_loglvl, &mbx_fwlog->u.request,
707262306a36Sopenharmony_ci	       ras_fwlog->fw_loglevel);
707362306a36Sopenharmony_ci	bf_set(lpfc_fwlog_buffcnt, &mbx_fwlog->u.request,
707462306a36Sopenharmony_ci	       ras_fwlog->fw_buffcount);
707562306a36Sopenharmony_ci	bf_set(lpfc_fwlog_buffsz, &mbx_fwlog->u.request,
707662306a36Sopenharmony_ci	       LPFC_RAS_MAX_ENTRY_SIZE/SLI4_PAGE_SIZE);
707762306a36Sopenharmony_ci
707862306a36Sopenharmony_ci	/* Update DMA buffer address */
707962306a36Sopenharmony_ci	list_for_each_entry(dmabuf, &ras_fwlog->fwlog_buff_list, list) {
708062306a36Sopenharmony_ci		memset(dmabuf->virt, 0, LPFC_RAS_MAX_ENTRY_SIZE);
708162306a36Sopenharmony_ci
708262306a36Sopenharmony_ci		mbx_fwlog->u.request.buff_fwlog[dmabuf->buffer_tag].addr_lo =
708362306a36Sopenharmony_ci			putPaddrLow(dmabuf->phys);
708462306a36Sopenharmony_ci
708562306a36Sopenharmony_ci		mbx_fwlog->u.request.buff_fwlog[dmabuf->buffer_tag].addr_hi =
708662306a36Sopenharmony_ci			putPaddrHigh(dmabuf->phys);
708762306a36Sopenharmony_ci	}
708862306a36Sopenharmony_ci
708962306a36Sopenharmony_ci	/* Update LPWD address */
709062306a36Sopenharmony_ci	mbx_fwlog->u.request.lwpd.addr_lo = putPaddrLow(ras_fwlog->lwpd.phys);
709162306a36Sopenharmony_ci	mbx_fwlog->u.request.lwpd.addr_hi = putPaddrHigh(ras_fwlog->lwpd.phys);
709262306a36Sopenharmony_ci
709362306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
709462306a36Sopenharmony_ci	ras_fwlog->state = REG_INPROGRESS;
709562306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
709662306a36Sopenharmony_ci	mbox->vport = phba->pport;
709762306a36Sopenharmony_ci	mbox->mbox_cmpl = lpfc_sli4_ras_mbox_cmpl;
709862306a36Sopenharmony_ci
709962306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
710062306a36Sopenharmony_ci
710162306a36Sopenharmony_ci	if (rc == MBX_NOT_FINISHED) {
710262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
710362306a36Sopenharmony_ci				"6191 FW-Log Mailbox failed. "
710462306a36Sopenharmony_ci				"status %d mbxStatus : x%x", rc,
710562306a36Sopenharmony_ci				bf_get(lpfc_mqe_status, &mbox->u.mqe));
710662306a36Sopenharmony_ci		mempool_free(mbox, phba->mbox_mem_pool);
710762306a36Sopenharmony_ci		rc = -EIO;
710862306a36Sopenharmony_ci		goto mem_free;
710962306a36Sopenharmony_ci	} else
711062306a36Sopenharmony_ci		rc = 0;
711162306a36Sopenharmony_cimem_free:
711262306a36Sopenharmony_ci	if (rc)
711362306a36Sopenharmony_ci		lpfc_sli4_ras_dma_free(phba);
711462306a36Sopenharmony_ci
711562306a36Sopenharmony_ci	return rc;
711662306a36Sopenharmony_ci}
711762306a36Sopenharmony_ci
711862306a36Sopenharmony_ci/**
711962306a36Sopenharmony_ci * lpfc_sli4_ras_setup - Check if RAS supported on the adapter
712062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
712162306a36Sopenharmony_ci *
712262306a36Sopenharmony_ci * Check if RAS is supported on the adapter and initialize it.
712362306a36Sopenharmony_ci **/
712462306a36Sopenharmony_civoid
712562306a36Sopenharmony_cilpfc_sli4_ras_setup(struct lpfc_hba *phba)
712662306a36Sopenharmony_ci{
712762306a36Sopenharmony_ci	/* Check RAS FW Log needs to be enabled or not */
712862306a36Sopenharmony_ci	if (lpfc_check_fwlog_support(phba))
712962306a36Sopenharmony_ci		return;
713062306a36Sopenharmony_ci
713162306a36Sopenharmony_ci	lpfc_sli4_ras_fwlog_init(phba, phba->cfg_ras_fwlog_level,
713262306a36Sopenharmony_ci				 LPFC_RAS_ENABLE_LOGGING);
713362306a36Sopenharmony_ci}
713462306a36Sopenharmony_ci
713562306a36Sopenharmony_ci/**
713662306a36Sopenharmony_ci * lpfc_sli4_alloc_resource_identifiers - Allocate all SLI4 resource extents.
713762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
713862306a36Sopenharmony_ci *
713962306a36Sopenharmony_ci * This function allocates all SLI4 resource identifiers.
714062306a36Sopenharmony_ci **/
714162306a36Sopenharmony_ciint
714262306a36Sopenharmony_cilpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba)
714362306a36Sopenharmony_ci{
714462306a36Sopenharmony_ci	int i, rc, error = 0;
714562306a36Sopenharmony_ci	uint16_t count, base;
714662306a36Sopenharmony_ci	unsigned long longs;
714762306a36Sopenharmony_ci
714862306a36Sopenharmony_ci	if (!phba->sli4_hba.rpi_hdrs_in_use)
714962306a36Sopenharmony_ci		phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.max_rpi;
715062306a36Sopenharmony_ci	if (phba->sli4_hba.extents_in_use) {
715162306a36Sopenharmony_ci		/*
715262306a36Sopenharmony_ci		 * The port supports resource extents. The XRI, VPI, VFI, RPI
715362306a36Sopenharmony_ci		 * resource extent count must be read and allocated before
715462306a36Sopenharmony_ci		 * provisioning the resource id arrays.
715562306a36Sopenharmony_ci		 */
715662306a36Sopenharmony_ci		if (bf_get(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags) ==
715762306a36Sopenharmony_ci		    LPFC_IDX_RSRC_RDY) {
715862306a36Sopenharmony_ci			/*
715962306a36Sopenharmony_ci			 * Extent-based resources are set - the driver could
716062306a36Sopenharmony_ci			 * be in a port reset. Figure out if any corrective
716162306a36Sopenharmony_ci			 * actions need to be taken.
716262306a36Sopenharmony_ci			 */
716362306a36Sopenharmony_ci			rc = lpfc_sli4_chk_avail_extnt_rsrc(phba,
716462306a36Sopenharmony_ci						 LPFC_RSC_TYPE_FCOE_VFI);
716562306a36Sopenharmony_ci			if (rc != 0)
716662306a36Sopenharmony_ci				error++;
716762306a36Sopenharmony_ci			rc = lpfc_sli4_chk_avail_extnt_rsrc(phba,
716862306a36Sopenharmony_ci						 LPFC_RSC_TYPE_FCOE_VPI);
716962306a36Sopenharmony_ci			if (rc != 0)
717062306a36Sopenharmony_ci				error++;
717162306a36Sopenharmony_ci			rc = lpfc_sli4_chk_avail_extnt_rsrc(phba,
717262306a36Sopenharmony_ci						 LPFC_RSC_TYPE_FCOE_XRI);
717362306a36Sopenharmony_ci			if (rc != 0)
717462306a36Sopenharmony_ci				error++;
717562306a36Sopenharmony_ci			rc = lpfc_sli4_chk_avail_extnt_rsrc(phba,
717662306a36Sopenharmony_ci						 LPFC_RSC_TYPE_FCOE_RPI);
717762306a36Sopenharmony_ci			if (rc != 0)
717862306a36Sopenharmony_ci				error++;
717962306a36Sopenharmony_ci
718062306a36Sopenharmony_ci			/*
718162306a36Sopenharmony_ci			 * It's possible that the number of resources
718262306a36Sopenharmony_ci			 * provided to this port instance changed between
718362306a36Sopenharmony_ci			 * resets.  Detect this condition and reallocate
718462306a36Sopenharmony_ci			 * resources.  Otherwise, there is no action.
718562306a36Sopenharmony_ci			 */
718662306a36Sopenharmony_ci			if (error) {
718762306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO,
718862306a36Sopenharmony_ci						LOG_MBOX | LOG_INIT,
718962306a36Sopenharmony_ci						"2931 Detected extent resource "
719062306a36Sopenharmony_ci						"change.  Reallocating all "
719162306a36Sopenharmony_ci						"extents.\n");
719262306a36Sopenharmony_ci				rc = lpfc_sli4_dealloc_extent(phba,
719362306a36Sopenharmony_ci						 LPFC_RSC_TYPE_FCOE_VFI);
719462306a36Sopenharmony_ci				rc = lpfc_sli4_dealloc_extent(phba,
719562306a36Sopenharmony_ci						 LPFC_RSC_TYPE_FCOE_VPI);
719662306a36Sopenharmony_ci				rc = lpfc_sli4_dealloc_extent(phba,
719762306a36Sopenharmony_ci						 LPFC_RSC_TYPE_FCOE_XRI);
719862306a36Sopenharmony_ci				rc = lpfc_sli4_dealloc_extent(phba,
719962306a36Sopenharmony_ci						 LPFC_RSC_TYPE_FCOE_RPI);
720062306a36Sopenharmony_ci			} else
720162306a36Sopenharmony_ci				return 0;
720262306a36Sopenharmony_ci		}
720362306a36Sopenharmony_ci
720462306a36Sopenharmony_ci		rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_VFI);
720562306a36Sopenharmony_ci		if (unlikely(rc))
720662306a36Sopenharmony_ci			goto err_exit;
720762306a36Sopenharmony_ci
720862306a36Sopenharmony_ci		rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_VPI);
720962306a36Sopenharmony_ci		if (unlikely(rc))
721062306a36Sopenharmony_ci			goto err_exit;
721162306a36Sopenharmony_ci
721262306a36Sopenharmony_ci		rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_RPI);
721362306a36Sopenharmony_ci		if (unlikely(rc))
721462306a36Sopenharmony_ci			goto err_exit;
721562306a36Sopenharmony_ci
721662306a36Sopenharmony_ci		rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_XRI);
721762306a36Sopenharmony_ci		if (unlikely(rc))
721862306a36Sopenharmony_ci			goto err_exit;
721962306a36Sopenharmony_ci		bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags,
722062306a36Sopenharmony_ci		       LPFC_IDX_RSRC_RDY);
722162306a36Sopenharmony_ci		return rc;
722262306a36Sopenharmony_ci	} else {
722362306a36Sopenharmony_ci		/*
722462306a36Sopenharmony_ci		 * The port does not support resource extents.  The XRI, VPI,
722562306a36Sopenharmony_ci		 * VFI, RPI resource ids were determined from READ_CONFIG.
722662306a36Sopenharmony_ci		 * Just allocate the bitmasks and provision the resource id
722762306a36Sopenharmony_ci		 * arrays.  If a port reset is active, the resources don't
722862306a36Sopenharmony_ci		 * need any action - just exit.
722962306a36Sopenharmony_ci		 */
723062306a36Sopenharmony_ci		if (bf_get(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags) ==
723162306a36Sopenharmony_ci		    LPFC_IDX_RSRC_RDY) {
723262306a36Sopenharmony_ci			lpfc_sli4_dealloc_resource_identifiers(phba);
723362306a36Sopenharmony_ci			lpfc_sli4_remove_rpis(phba);
723462306a36Sopenharmony_ci		}
723562306a36Sopenharmony_ci		/* RPIs. */
723662306a36Sopenharmony_ci		count = phba->sli4_hba.max_cfg_param.max_rpi;
723762306a36Sopenharmony_ci		if (count <= 0) {
723862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
723962306a36Sopenharmony_ci					"3279 Invalid provisioning of "
724062306a36Sopenharmony_ci					"rpi:%d\n", count);
724162306a36Sopenharmony_ci			rc = -EINVAL;
724262306a36Sopenharmony_ci			goto err_exit;
724362306a36Sopenharmony_ci		}
724462306a36Sopenharmony_ci		base = phba->sli4_hba.max_cfg_param.rpi_base;
724562306a36Sopenharmony_ci		longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG;
724662306a36Sopenharmony_ci		phba->sli4_hba.rpi_bmask = kcalloc(longs,
724762306a36Sopenharmony_ci						   sizeof(unsigned long),
724862306a36Sopenharmony_ci						   GFP_KERNEL);
724962306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.rpi_bmask)) {
725062306a36Sopenharmony_ci			rc = -ENOMEM;
725162306a36Sopenharmony_ci			goto err_exit;
725262306a36Sopenharmony_ci		}
725362306a36Sopenharmony_ci		phba->sli4_hba.rpi_ids = kcalloc(count, sizeof(uint16_t),
725462306a36Sopenharmony_ci						 GFP_KERNEL);
725562306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.rpi_ids)) {
725662306a36Sopenharmony_ci			rc = -ENOMEM;
725762306a36Sopenharmony_ci			goto free_rpi_bmask;
725862306a36Sopenharmony_ci		}
725962306a36Sopenharmony_ci
726062306a36Sopenharmony_ci		for (i = 0; i < count; i++)
726162306a36Sopenharmony_ci			phba->sli4_hba.rpi_ids[i] = base + i;
726262306a36Sopenharmony_ci
726362306a36Sopenharmony_ci		/* VPIs. */
726462306a36Sopenharmony_ci		count = phba->sli4_hba.max_cfg_param.max_vpi;
726562306a36Sopenharmony_ci		if (count <= 0) {
726662306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
726762306a36Sopenharmony_ci					"3280 Invalid provisioning of "
726862306a36Sopenharmony_ci					"vpi:%d\n", count);
726962306a36Sopenharmony_ci			rc = -EINVAL;
727062306a36Sopenharmony_ci			goto free_rpi_ids;
727162306a36Sopenharmony_ci		}
727262306a36Sopenharmony_ci		base = phba->sli4_hba.max_cfg_param.vpi_base;
727362306a36Sopenharmony_ci		longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG;
727462306a36Sopenharmony_ci		phba->vpi_bmask = kcalloc(longs, sizeof(unsigned long),
727562306a36Sopenharmony_ci					  GFP_KERNEL);
727662306a36Sopenharmony_ci		if (unlikely(!phba->vpi_bmask)) {
727762306a36Sopenharmony_ci			rc = -ENOMEM;
727862306a36Sopenharmony_ci			goto free_rpi_ids;
727962306a36Sopenharmony_ci		}
728062306a36Sopenharmony_ci		phba->vpi_ids = kcalloc(count, sizeof(uint16_t),
728162306a36Sopenharmony_ci					GFP_KERNEL);
728262306a36Sopenharmony_ci		if (unlikely(!phba->vpi_ids)) {
728362306a36Sopenharmony_ci			rc = -ENOMEM;
728462306a36Sopenharmony_ci			goto free_vpi_bmask;
728562306a36Sopenharmony_ci		}
728662306a36Sopenharmony_ci
728762306a36Sopenharmony_ci		for (i = 0; i < count; i++)
728862306a36Sopenharmony_ci			phba->vpi_ids[i] = base + i;
728962306a36Sopenharmony_ci
729062306a36Sopenharmony_ci		/* XRIs. */
729162306a36Sopenharmony_ci		count = phba->sli4_hba.max_cfg_param.max_xri;
729262306a36Sopenharmony_ci		if (count <= 0) {
729362306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
729462306a36Sopenharmony_ci					"3281 Invalid provisioning of "
729562306a36Sopenharmony_ci					"xri:%d\n", count);
729662306a36Sopenharmony_ci			rc = -EINVAL;
729762306a36Sopenharmony_ci			goto free_vpi_ids;
729862306a36Sopenharmony_ci		}
729962306a36Sopenharmony_ci		base = phba->sli4_hba.max_cfg_param.xri_base;
730062306a36Sopenharmony_ci		longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG;
730162306a36Sopenharmony_ci		phba->sli4_hba.xri_bmask = kcalloc(longs,
730262306a36Sopenharmony_ci						   sizeof(unsigned long),
730362306a36Sopenharmony_ci						   GFP_KERNEL);
730462306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.xri_bmask)) {
730562306a36Sopenharmony_ci			rc = -ENOMEM;
730662306a36Sopenharmony_ci			goto free_vpi_ids;
730762306a36Sopenharmony_ci		}
730862306a36Sopenharmony_ci		phba->sli4_hba.max_cfg_param.xri_used = 0;
730962306a36Sopenharmony_ci		phba->sli4_hba.xri_ids = kcalloc(count, sizeof(uint16_t),
731062306a36Sopenharmony_ci						 GFP_KERNEL);
731162306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.xri_ids)) {
731262306a36Sopenharmony_ci			rc = -ENOMEM;
731362306a36Sopenharmony_ci			goto free_xri_bmask;
731462306a36Sopenharmony_ci		}
731562306a36Sopenharmony_ci
731662306a36Sopenharmony_ci		for (i = 0; i < count; i++)
731762306a36Sopenharmony_ci			phba->sli4_hba.xri_ids[i] = base + i;
731862306a36Sopenharmony_ci
731962306a36Sopenharmony_ci		/* VFIs. */
732062306a36Sopenharmony_ci		count = phba->sli4_hba.max_cfg_param.max_vfi;
732162306a36Sopenharmony_ci		if (count <= 0) {
732262306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
732362306a36Sopenharmony_ci					"3282 Invalid provisioning of "
732462306a36Sopenharmony_ci					"vfi:%d\n", count);
732562306a36Sopenharmony_ci			rc = -EINVAL;
732662306a36Sopenharmony_ci			goto free_xri_ids;
732762306a36Sopenharmony_ci		}
732862306a36Sopenharmony_ci		base = phba->sli4_hba.max_cfg_param.vfi_base;
732962306a36Sopenharmony_ci		longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG;
733062306a36Sopenharmony_ci		phba->sli4_hba.vfi_bmask = kcalloc(longs,
733162306a36Sopenharmony_ci						   sizeof(unsigned long),
733262306a36Sopenharmony_ci						   GFP_KERNEL);
733362306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.vfi_bmask)) {
733462306a36Sopenharmony_ci			rc = -ENOMEM;
733562306a36Sopenharmony_ci			goto free_xri_ids;
733662306a36Sopenharmony_ci		}
733762306a36Sopenharmony_ci		phba->sli4_hba.vfi_ids = kcalloc(count, sizeof(uint16_t),
733862306a36Sopenharmony_ci						 GFP_KERNEL);
733962306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.vfi_ids)) {
734062306a36Sopenharmony_ci			rc = -ENOMEM;
734162306a36Sopenharmony_ci			goto free_vfi_bmask;
734262306a36Sopenharmony_ci		}
734362306a36Sopenharmony_ci
734462306a36Sopenharmony_ci		for (i = 0; i < count; i++)
734562306a36Sopenharmony_ci			phba->sli4_hba.vfi_ids[i] = base + i;
734662306a36Sopenharmony_ci
734762306a36Sopenharmony_ci		/*
734862306a36Sopenharmony_ci		 * Mark all resources ready.  An HBA reset doesn't need
734962306a36Sopenharmony_ci		 * to reset the initialization.
735062306a36Sopenharmony_ci		 */
735162306a36Sopenharmony_ci		bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags,
735262306a36Sopenharmony_ci		       LPFC_IDX_RSRC_RDY);
735362306a36Sopenharmony_ci		return 0;
735462306a36Sopenharmony_ci	}
735562306a36Sopenharmony_ci
735662306a36Sopenharmony_ci free_vfi_bmask:
735762306a36Sopenharmony_ci	kfree(phba->sli4_hba.vfi_bmask);
735862306a36Sopenharmony_ci	phba->sli4_hba.vfi_bmask = NULL;
735962306a36Sopenharmony_ci free_xri_ids:
736062306a36Sopenharmony_ci	kfree(phba->sli4_hba.xri_ids);
736162306a36Sopenharmony_ci	phba->sli4_hba.xri_ids = NULL;
736262306a36Sopenharmony_ci free_xri_bmask:
736362306a36Sopenharmony_ci	kfree(phba->sli4_hba.xri_bmask);
736462306a36Sopenharmony_ci	phba->sli4_hba.xri_bmask = NULL;
736562306a36Sopenharmony_ci free_vpi_ids:
736662306a36Sopenharmony_ci	kfree(phba->vpi_ids);
736762306a36Sopenharmony_ci	phba->vpi_ids = NULL;
736862306a36Sopenharmony_ci free_vpi_bmask:
736962306a36Sopenharmony_ci	kfree(phba->vpi_bmask);
737062306a36Sopenharmony_ci	phba->vpi_bmask = NULL;
737162306a36Sopenharmony_ci free_rpi_ids:
737262306a36Sopenharmony_ci	kfree(phba->sli4_hba.rpi_ids);
737362306a36Sopenharmony_ci	phba->sli4_hba.rpi_ids = NULL;
737462306a36Sopenharmony_ci free_rpi_bmask:
737562306a36Sopenharmony_ci	kfree(phba->sli4_hba.rpi_bmask);
737662306a36Sopenharmony_ci	phba->sli4_hba.rpi_bmask = NULL;
737762306a36Sopenharmony_ci err_exit:
737862306a36Sopenharmony_ci	return rc;
737962306a36Sopenharmony_ci}
738062306a36Sopenharmony_ci
738162306a36Sopenharmony_ci/**
738262306a36Sopenharmony_ci * lpfc_sli4_dealloc_resource_identifiers - Deallocate all SLI4 resource extents.
738362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
738462306a36Sopenharmony_ci *
738562306a36Sopenharmony_ci * This function allocates the number of elements for the specified
738662306a36Sopenharmony_ci * resource type.
738762306a36Sopenharmony_ci **/
738862306a36Sopenharmony_ciint
738962306a36Sopenharmony_cilpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba)
739062306a36Sopenharmony_ci{
739162306a36Sopenharmony_ci	if (phba->sli4_hba.extents_in_use) {
739262306a36Sopenharmony_ci		lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_VPI);
739362306a36Sopenharmony_ci		lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_RPI);
739462306a36Sopenharmony_ci		lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_XRI);
739562306a36Sopenharmony_ci		lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_VFI);
739662306a36Sopenharmony_ci	} else {
739762306a36Sopenharmony_ci		kfree(phba->vpi_bmask);
739862306a36Sopenharmony_ci		phba->sli4_hba.max_cfg_param.vpi_used = 0;
739962306a36Sopenharmony_ci		kfree(phba->vpi_ids);
740062306a36Sopenharmony_ci		bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
740162306a36Sopenharmony_ci		kfree(phba->sli4_hba.xri_bmask);
740262306a36Sopenharmony_ci		kfree(phba->sli4_hba.xri_ids);
740362306a36Sopenharmony_ci		kfree(phba->sli4_hba.vfi_bmask);
740462306a36Sopenharmony_ci		kfree(phba->sli4_hba.vfi_ids);
740562306a36Sopenharmony_ci		bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
740662306a36Sopenharmony_ci		bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
740762306a36Sopenharmony_ci	}
740862306a36Sopenharmony_ci
740962306a36Sopenharmony_ci	return 0;
741062306a36Sopenharmony_ci}
741162306a36Sopenharmony_ci
741262306a36Sopenharmony_ci/**
741362306a36Sopenharmony_ci * lpfc_sli4_get_allocated_extnts - Get the port's allocated extents.
741462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
741562306a36Sopenharmony_ci * @type: The resource extent type.
741662306a36Sopenharmony_ci * @extnt_cnt: buffer to hold port extent count response
741762306a36Sopenharmony_ci * @extnt_size: buffer to hold port extent size response.
741862306a36Sopenharmony_ci *
741962306a36Sopenharmony_ci * This function calls the port to read the host allocated extents
742062306a36Sopenharmony_ci * for a particular type.
742162306a36Sopenharmony_ci **/
742262306a36Sopenharmony_ciint
742362306a36Sopenharmony_cilpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type,
742462306a36Sopenharmony_ci			       uint16_t *extnt_cnt, uint16_t *extnt_size)
742562306a36Sopenharmony_ci{
742662306a36Sopenharmony_ci	bool emb;
742762306a36Sopenharmony_ci	int rc = 0;
742862306a36Sopenharmony_ci	uint16_t curr_blks = 0;
742962306a36Sopenharmony_ci	uint32_t req_len, emb_len;
743062306a36Sopenharmony_ci	uint32_t alloc_len, mbox_tmo;
743162306a36Sopenharmony_ci	struct list_head *blk_list_head;
743262306a36Sopenharmony_ci	struct lpfc_rsrc_blks *rsrc_blk;
743362306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
743462306a36Sopenharmony_ci	void *virtaddr = NULL;
743562306a36Sopenharmony_ci	struct lpfc_mbx_nembed_rsrc_extent *n_rsrc;
743662306a36Sopenharmony_ci	struct lpfc_mbx_alloc_rsrc_extents *rsrc_ext;
743762306a36Sopenharmony_ci	union  lpfc_sli4_cfg_shdr *shdr;
743862306a36Sopenharmony_ci
743962306a36Sopenharmony_ci	switch (type) {
744062306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_VPI:
744162306a36Sopenharmony_ci		blk_list_head = &phba->lpfc_vpi_blk_list;
744262306a36Sopenharmony_ci		break;
744362306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_XRI:
744462306a36Sopenharmony_ci		blk_list_head = &phba->sli4_hba.lpfc_xri_blk_list;
744562306a36Sopenharmony_ci		break;
744662306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_VFI:
744762306a36Sopenharmony_ci		blk_list_head = &phba->sli4_hba.lpfc_vfi_blk_list;
744862306a36Sopenharmony_ci		break;
744962306a36Sopenharmony_ci	case LPFC_RSC_TYPE_FCOE_RPI:
745062306a36Sopenharmony_ci		blk_list_head = &phba->sli4_hba.lpfc_rpi_blk_list;
745162306a36Sopenharmony_ci		break;
745262306a36Sopenharmony_ci	default:
745362306a36Sopenharmony_ci		return -EIO;
745462306a36Sopenharmony_ci	}
745562306a36Sopenharmony_ci
745662306a36Sopenharmony_ci	/* Count the number of extents currently allocatd for this type. */
745762306a36Sopenharmony_ci	list_for_each_entry(rsrc_blk, blk_list_head, list) {
745862306a36Sopenharmony_ci		if (curr_blks == 0) {
745962306a36Sopenharmony_ci			/*
746062306a36Sopenharmony_ci			 * The GET_ALLOCATED mailbox does not return the size,
746162306a36Sopenharmony_ci			 * just the count.  The size should be just the size
746262306a36Sopenharmony_ci			 * stored in the current allocated block and all sizes
746362306a36Sopenharmony_ci			 * for an extent type are the same so set the return
746462306a36Sopenharmony_ci			 * value now.
746562306a36Sopenharmony_ci			 */
746662306a36Sopenharmony_ci			*extnt_size = rsrc_blk->rsrc_size;
746762306a36Sopenharmony_ci		}
746862306a36Sopenharmony_ci		curr_blks++;
746962306a36Sopenharmony_ci	}
747062306a36Sopenharmony_ci
747162306a36Sopenharmony_ci	/*
747262306a36Sopenharmony_ci	 * Calculate the size of an embedded mailbox.  The uint32_t
747362306a36Sopenharmony_ci	 * accounts for extents-specific word.
747462306a36Sopenharmony_ci	 */
747562306a36Sopenharmony_ci	emb_len = sizeof(MAILBOX_t) - sizeof(struct mbox_header) -
747662306a36Sopenharmony_ci		sizeof(uint32_t);
747762306a36Sopenharmony_ci
747862306a36Sopenharmony_ci	/*
747962306a36Sopenharmony_ci	 * Presume the allocation and response will fit into an embedded
748062306a36Sopenharmony_ci	 * mailbox.  If not true, reconfigure to a non-embedded mailbox.
748162306a36Sopenharmony_ci	 */
748262306a36Sopenharmony_ci	emb = LPFC_SLI4_MBX_EMBED;
748362306a36Sopenharmony_ci	req_len = emb_len;
748462306a36Sopenharmony_ci	if (req_len > emb_len) {
748562306a36Sopenharmony_ci		req_len = curr_blks * sizeof(uint16_t) +
748662306a36Sopenharmony_ci			sizeof(union lpfc_sli4_cfg_shdr) +
748762306a36Sopenharmony_ci			sizeof(uint32_t);
748862306a36Sopenharmony_ci		emb = LPFC_SLI4_MBX_NEMBED;
748962306a36Sopenharmony_ci	}
749062306a36Sopenharmony_ci
749162306a36Sopenharmony_ci	mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
749262306a36Sopenharmony_ci	if (!mbox)
749362306a36Sopenharmony_ci		return -ENOMEM;
749462306a36Sopenharmony_ci	memset(mbox, 0, sizeof(LPFC_MBOXQ_t));
749562306a36Sopenharmony_ci
749662306a36Sopenharmony_ci	alloc_len = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
749762306a36Sopenharmony_ci				     LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT,
749862306a36Sopenharmony_ci				     req_len, emb);
749962306a36Sopenharmony_ci	if (alloc_len < req_len) {
750062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
750162306a36Sopenharmony_ci			"2983 Allocated DMA memory size (x%x) is "
750262306a36Sopenharmony_ci			"less than the requested DMA memory "
750362306a36Sopenharmony_ci			"size (x%x)\n", alloc_len, req_len);
750462306a36Sopenharmony_ci		rc = -ENOMEM;
750562306a36Sopenharmony_ci		goto err_exit;
750662306a36Sopenharmony_ci	}
750762306a36Sopenharmony_ci	rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, curr_blks, type, emb);
750862306a36Sopenharmony_ci	if (unlikely(rc)) {
750962306a36Sopenharmony_ci		rc = -EIO;
751062306a36Sopenharmony_ci		goto err_exit;
751162306a36Sopenharmony_ci	}
751262306a36Sopenharmony_ci
751362306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable)
751462306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
751562306a36Sopenharmony_ci	else {
751662306a36Sopenharmony_ci		mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
751762306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
751862306a36Sopenharmony_ci	}
751962306a36Sopenharmony_ci
752062306a36Sopenharmony_ci	if (unlikely(rc)) {
752162306a36Sopenharmony_ci		rc = -EIO;
752262306a36Sopenharmony_ci		goto err_exit;
752362306a36Sopenharmony_ci	}
752462306a36Sopenharmony_ci
752562306a36Sopenharmony_ci	/*
752662306a36Sopenharmony_ci	 * Figure out where the response is located.  Then get local pointers
752762306a36Sopenharmony_ci	 * to the response data.  The port does not guarantee to respond to
752862306a36Sopenharmony_ci	 * all extents counts request so update the local variable with the
752962306a36Sopenharmony_ci	 * allocated count from the port.
753062306a36Sopenharmony_ci	 */
753162306a36Sopenharmony_ci	if (emb == LPFC_SLI4_MBX_EMBED) {
753262306a36Sopenharmony_ci		rsrc_ext = &mbox->u.mqe.un.alloc_rsrc_extents;
753362306a36Sopenharmony_ci		shdr = &rsrc_ext->header.cfg_shdr;
753462306a36Sopenharmony_ci		*extnt_cnt = bf_get(lpfc_mbx_rsrc_cnt, &rsrc_ext->u.rsp);
753562306a36Sopenharmony_ci	} else {
753662306a36Sopenharmony_ci		virtaddr = mbox->sge_array->addr[0];
753762306a36Sopenharmony_ci		n_rsrc = (struct lpfc_mbx_nembed_rsrc_extent *) virtaddr;
753862306a36Sopenharmony_ci		shdr = &n_rsrc->cfg_shdr;
753962306a36Sopenharmony_ci		*extnt_cnt = bf_get(lpfc_mbx_rsrc_cnt, n_rsrc);
754062306a36Sopenharmony_ci	}
754162306a36Sopenharmony_ci
754262306a36Sopenharmony_ci	if (bf_get(lpfc_mbox_hdr_status, &shdr->response)) {
754362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
754462306a36Sopenharmony_ci			"2984 Failed to read allocated resources "
754562306a36Sopenharmony_ci			"for type %d - Status 0x%x Add'l Status 0x%x.\n",
754662306a36Sopenharmony_ci			type,
754762306a36Sopenharmony_ci			bf_get(lpfc_mbox_hdr_status, &shdr->response),
754862306a36Sopenharmony_ci			bf_get(lpfc_mbox_hdr_add_status, &shdr->response));
754962306a36Sopenharmony_ci		rc = -EIO;
755062306a36Sopenharmony_ci		goto err_exit;
755162306a36Sopenharmony_ci	}
755262306a36Sopenharmony_ci err_exit:
755362306a36Sopenharmony_ci	lpfc_sli4_mbox_cmd_free(phba, mbox);
755462306a36Sopenharmony_ci	return rc;
755562306a36Sopenharmony_ci}
755662306a36Sopenharmony_ci
755762306a36Sopenharmony_ci/**
755862306a36Sopenharmony_ci * lpfc_sli4_repost_sgl_list - Repost the buffers sgl pages as block
755962306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
756062306a36Sopenharmony_ci * @sgl_list: linked link of sgl buffers to post
756162306a36Sopenharmony_ci * @cnt: number of linked list buffers
756262306a36Sopenharmony_ci *
756362306a36Sopenharmony_ci * This routine walks the list of buffers that have been allocated and
756462306a36Sopenharmony_ci * repost them to the port by using SGL block post. This is needed after a
756562306a36Sopenharmony_ci * pci_function_reset/warm_start or start. It attempts to construct blocks
756662306a36Sopenharmony_ci * of buffer sgls which contains contiguous xris and uses the non-embedded
756762306a36Sopenharmony_ci * SGL block post mailbox commands to post them to the port. For single
756862306a36Sopenharmony_ci * buffer sgl with non-contiguous xri, if any, it shall use embedded SGL post
756962306a36Sopenharmony_ci * mailbox command for posting.
757062306a36Sopenharmony_ci *
757162306a36Sopenharmony_ci * Returns: 0 = success, non-zero failure.
757262306a36Sopenharmony_ci **/
757362306a36Sopenharmony_cistatic int
757462306a36Sopenharmony_cilpfc_sli4_repost_sgl_list(struct lpfc_hba *phba,
757562306a36Sopenharmony_ci			  struct list_head *sgl_list, int cnt)
757662306a36Sopenharmony_ci{
757762306a36Sopenharmony_ci	struct lpfc_sglq *sglq_entry = NULL;
757862306a36Sopenharmony_ci	struct lpfc_sglq *sglq_entry_next = NULL;
757962306a36Sopenharmony_ci	struct lpfc_sglq *sglq_entry_first = NULL;
758062306a36Sopenharmony_ci	int status, total_cnt;
758162306a36Sopenharmony_ci	int post_cnt = 0, num_posted = 0, block_cnt = 0;
758262306a36Sopenharmony_ci	int last_xritag = NO_XRI;
758362306a36Sopenharmony_ci	LIST_HEAD(prep_sgl_list);
758462306a36Sopenharmony_ci	LIST_HEAD(blck_sgl_list);
758562306a36Sopenharmony_ci	LIST_HEAD(allc_sgl_list);
758662306a36Sopenharmony_ci	LIST_HEAD(post_sgl_list);
758762306a36Sopenharmony_ci	LIST_HEAD(free_sgl_list);
758862306a36Sopenharmony_ci
758962306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
759062306a36Sopenharmony_ci	spin_lock(&phba->sli4_hba.sgl_list_lock);
759162306a36Sopenharmony_ci	list_splice_init(sgl_list, &allc_sgl_list);
759262306a36Sopenharmony_ci	spin_unlock(&phba->sli4_hba.sgl_list_lock);
759362306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
759462306a36Sopenharmony_ci
759562306a36Sopenharmony_ci	total_cnt = cnt;
759662306a36Sopenharmony_ci	list_for_each_entry_safe(sglq_entry, sglq_entry_next,
759762306a36Sopenharmony_ci				 &allc_sgl_list, list) {
759862306a36Sopenharmony_ci		list_del_init(&sglq_entry->list);
759962306a36Sopenharmony_ci		block_cnt++;
760062306a36Sopenharmony_ci		if ((last_xritag != NO_XRI) &&
760162306a36Sopenharmony_ci		    (sglq_entry->sli4_xritag != last_xritag + 1)) {
760262306a36Sopenharmony_ci			/* a hole in xri block, form a sgl posting block */
760362306a36Sopenharmony_ci			list_splice_init(&prep_sgl_list, &blck_sgl_list);
760462306a36Sopenharmony_ci			post_cnt = block_cnt - 1;
760562306a36Sopenharmony_ci			/* prepare list for next posting block */
760662306a36Sopenharmony_ci			list_add_tail(&sglq_entry->list, &prep_sgl_list);
760762306a36Sopenharmony_ci			block_cnt = 1;
760862306a36Sopenharmony_ci		} else {
760962306a36Sopenharmony_ci			/* prepare list for next posting block */
761062306a36Sopenharmony_ci			list_add_tail(&sglq_entry->list, &prep_sgl_list);
761162306a36Sopenharmony_ci			/* enough sgls for non-embed sgl mbox command */
761262306a36Sopenharmony_ci			if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) {
761362306a36Sopenharmony_ci				list_splice_init(&prep_sgl_list,
761462306a36Sopenharmony_ci						 &blck_sgl_list);
761562306a36Sopenharmony_ci				post_cnt = block_cnt;
761662306a36Sopenharmony_ci				block_cnt = 0;
761762306a36Sopenharmony_ci			}
761862306a36Sopenharmony_ci		}
761962306a36Sopenharmony_ci		num_posted++;
762062306a36Sopenharmony_ci
762162306a36Sopenharmony_ci		/* keep track of last sgl's xritag */
762262306a36Sopenharmony_ci		last_xritag = sglq_entry->sli4_xritag;
762362306a36Sopenharmony_ci
762462306a36Sopenharmony_ci		/* end of repost sgl list condition for buffers */
762562306a36Sopenharmony_ci		if (num_posted == total_cnt) {
762662306a36Sopenharmony_ci			if (post_cnt == 0) {
762762306a36Sopenharmony_ci				list_splice_init(&prep_sgl_list,
762862306a36Sopenharmony_ci						 &blck_sgl_list);
762962306a36Sopenharmony_ci				post_cnt = block_cnt;
763062306a36Sopenharmony_ci			} else if (block_cnt == 1) {
763162306a36Sopenharmony_ci				status = lpfc_sli4_post_sgl(phba,
763262306a36Sopenharmony_ci						sglq_entry->phys, 0,
763362306a36Sopenharmony_ci						sglq_entry->sli4_xritag);
763462306a36Sopenharmony_ci				if (!status) {
763562306a36Sopenharmony_ci					/* successful, put sgl to posted list */
763662306a36Sopenharmony_ci					list_add_tail(&sglq_entry->list,
763762306a36Sopenharmony_ci						      &post_sgl_list);
763862306a36Sopenharmony_ci				} else {
763962306a36Sopenharmony_ci					/* Failure, put sgl to free list */
764062306a36Sopenharmony_ci					lpfc_printf_log(phba, KERN_WARNING,
764162306a36Sopenharmony_ci						LOG_SLI,
764262306a36Sopenharmony_ci						"3159 Failed to post "
764362306a36Sopenharmony_ci						"sgl, xritag:x%x\n",
764462306a36Sopenharmony_ci						sglq_entry->sli4_xritag);
764562306a36Sopenharmony_ci					list_add_tail(&sglq_entry->list,
764662306a36Sopenharmony_ci						      &free_sgl_list);
764762306a36Sopenharmony_ci					total_cnt--;
764862306a36Sopenharmony_ci				}
764962306a36Sopenharmony_ci			}
765062306a36Sopenharmony_ci		}
765162306a36Sopenharmony_ci
765262306a36Sopenharmony_ci		/* continue until a nembed page worth of sgls */
765362306a36Sopenharmony_ci		if (post_cnt == 0)
765462306a36Sopenharmony_ci			continue;
765562306a36Sopenharmony_ci
765662306a36Sopenharmony_ci		/* post the buffer list sgls as a block */
765762306a36Sopenharmony_ci		status = lpfc_sli4_post_sgl_list(phba, &blck_sgl_list,
765862306a36Sopenharmony_ci						 post_cnt);
765962306a36Sopenharmony_ci
766062306a36Sopenharmony_ci		if (!status) {
766162306a36Sopenharmony_ci			/* success, put sgl list to posted sgl list */
766262306a36Sopenharmony_ci			list_splice_init(&blck_sgl_list, &post_sgl_list);
766362306a36Sopenharmony_ci		} else {
766462306a36Sopenharmony_ci			/* Failure, put sgl list to free sgl list */
766562306a36Sopenharmony_ci			sglq_entry_first = list_first_entry(&blck_sgl_list,
766662306a36Sopenharmony_ci							    struct lpfc_sglq,
766762306a36Sopenharmony_ci							    list);
766862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
766962306a36Sopenharmony_ci					"3160 Failed to post sgl-list, "
767062306a36Sopenharmony_ci					"xritag:x%x-x%x\n",
767162306a36Sopenharmony_ci					sglq_entry_first->sli4_xritag,
767262306a36Sopenharmony_ci					(sglq_entry_first->sli4_xritag +
767362306a36Sopenharmony_ci					 post_cnt - 1));
767462306a36Sopenharmony_ci			list_splice_init(&blck_sgl_list, &free_sgl_list);
767562306a36Sopenharmony_ci			total_cnt -= post_cnt;
767662306a36Sopenharmony_ci		}
767762306a36Sopenharmony_ci
767862306a36Sopenharmony_ci		/* don't reset xirtag due to hole in xri block */
767962306a36Sopenharmony_ci		if (block_cnt == 0)
768062306a36Sopenharmony_ci			last_xritag = NO_XRI;
768162306a36Sopenharmony_ci
768262306a36Sopenharmony_ci		/* reset sgl post count for next round of posting */
768362306a36Sopenharmony_ci		post_cnt = 0;
768462306a36Sopenharmony_ci	}
768562306a36Sopenharmony_ci
768662306a36Sopenharmony_ci	/* free the sgls failed to post */
768762306a36Sopenharmony_ci	lpfc_free_sgl_list(phba, &free_sgl_list);
768862306a36Sopenharmony_ci
768962306a36Sopenharmony_ci	/* push sgls posted to the available list */
769062306a36Sopenharmony_ci	if (!list_empty(&post_sgl_list)) {
769162306a36Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
769262306a36Sopenharmony_ci		spin_lock(&phba->sli4_hba.sgl_list_lock);
769362306a36Sopenharmony_ci		list_splice_init(&post_sgl_list, sgl_list);
769462306a36Sopenharmony_ci		spin_unlock(&phba->sli4_hba.sgl_list_lock);
769562306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
769662306a36Sopenharmony_ci	} else {
769762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
769862306a36Sopenharmony_ci				"3161 Failure to post sgl to port,status %x "
769962306a36Sopenharmony_ci				"blkcnt %d totalcnt %d postcnt %d\n",
770062306a36Sopenharmony_ci				status, block_cnt, total_cnt, post_cnt);
770162306a36Sopenharmony_ci		return -EIO;
770262306a36Sopenharmony_ci	}
770362306a36Sopenharmony_ci
770462306a36Sopenharmony_ci	/* return the number of XRIs actually posted */
770562306a36Sopenharmony_ci	return total_cnt;
770662306a36Sopenharmony_ci}
770762306a36Sopenharmony_ci
770862306a36Sopenharmony_ci/**
770962306a36Sopenharmony_ci * lpfc_sli4_repost_io_sgl_list - Repost all the allocated nvme buffer sgls
771062306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
771162306a36Sopenharmony_ci *
771262306a36Sopenharmony_ci * This routine walks the list of nvme buffers that have been allocated and
771362306a36Sopenharmony_ci * repost them to the port by using SGL block post. This is needed after a
771462306a36Sopenharmony_ci * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine
771562306a36Sopenharmony_ci * is responsible for moving all nvme buffers on the lpfc_abts_nvme_sgl_list
771662306a36Sopenharmony_ci * to the lpfc_io_buf_list. If the repost fails, reject all nvme buffers.
771762306a36Sopenharmony_ci *
771862306a36Sopenharmony_ci * Returns: 0 = success, non-zero failure.
771962306a36Sopenharmony_ci **/
772062306a36Sopenharmony_cistatic int
772162306a36Sopenharmony_cilpfc_sli4_repost_io_sgl_list(struct lpfc_hba *phba)
772262306a36Sopenharmony_ci{
772362306a36Sopenharmony_ci	LIST_HEAD(post_nblist);
772462306a36Sopenharmony_ci	int num_posted, rc = 0;
772562306a36Sopenharmony_ci
772662306a36Sopenharmony_ci	/* get all NVME buffers need to repost to a local list */
772762306a36Sopenharmony_ci	lpfc_io_buf_flush(phba, &post_nblist);
772862306a36Sopenharmony_ci
772962306a36Sopenharmony_ci	/* post the list of nvme buffer sgls to port if available */
773062306a36Sopenharmony_ci	if (!list_empty(&post_nblist)) {
773162306a36Sopenharmony_ci		num_posted = lpfc_sli4_post_io_sgl_list(
773262306a36Sopenharmony_ci			phba, &post_nblist, phba->sli4_hba.io_xri_cnt);
773362306a36Sopenharmony_ci		/* failed to post any nvme buffer, return error */
773462306a36Sopenharmony_ci		if (num_posted == 0)
773562306a36Sopenharmony_ci			rc = -EIO;
773662306a36Sopenharmony_ci	}
773762306a36Sopenharmony_ci	return rc;
773862306a36Sopenharmony_ci}
773962306a36Sopenharmony_ci
774062306a36Sopenharmony_cistatic void
774162306a36Sopenharmony_cilpfc_set_host_data(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
774262306a36Sopenharmony_ci{
774362306a36Sopenharmony_ci	uint32_t len;
774462306a36Sopenharmony_ci
774562306a36Sopenharmony_ci	len = sizeof(struct lpfc_mbx_set_host_data) -
774662306a36Sopenharmony_ci		sizeof(struct lpfc_sli4_cfg_mhdr);
774762306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
774862306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_SET_HOST_DATA, len,
774962306a36Sopenharmony_ci			 LPFC_SLI4_MBX_EMBED);
775062306a36Sopenharmony_ci
775162306a36Sopenharmony_ci	mbox->u.mqe.un.set_host_data.param_id = LPFC_SET_HOST_OS_DRIVER_VERSION;
775262306a36Sopenharmony_ci	mbox->u.mqe.un.set_host_data.param_len =
775362306a36Sopenharmony_ci					LPFC_HOST_OS_DRIVER_VERSION_SIZE;
775462306a36Sopenharmony_ci	snprintf(mbox->u.mqe.un.set_host_data.un.data,
775562306a36Sopenharmony_ci		 LPFC_HOST_OS_DRIVER_VERSION_SIZE,
775662306a36Sopenharmony_ci		 "Linux %s v"LPFC_DRIVER_VERSION,
775762306a36Sopenharmony_ci		 (phba->hba_flag & HBA_FCOE_MODE) ? "FCoE" : "FC");
775862306a36Sopenharmony_ci}
775962306a36Sopenharmony_ci
776062306a36Sopenharmony_ciint
776162306a36Sopenharmony_cilpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
776262306a36Sopenharmony_ci		    struct lpfc_queue *drq, int count, int idx)
776362306a36Sopenharmony_ci{
776462306a36Sopenharmony_ci	int rc, i;
776562306a36Sopenharmony_ci	struct lpfc_rqe hrqe;
776662306a36Sopenharmony_ci	struct lpfc_rqe drqe;
776762306a36Sopenharmony_ci	struct lpfc_rqb *rqbp;
776862306a36Sopenharmony_ci	unsigned long flags;
776962306a36Sopenharmony_ci	struct rqb_dmabuf *rqb_buffer;
777062306a36Sopenharmony_ci	LIST_HEAD(rqb_buf_list);
777162306a36Sopenharmony_ci
777262306a36Sopenharmony_ci	rqbp = hrq->rqbp;
777362306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
777462306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, flags);
777562306a36Sopenharmony_ci		/* IF RQ is already full, don't bother */
777662306a36Sopenharmony_ci		if (rqbp->buffer_count + i >= rqbp->entry_count - 1) {
777762306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, flags);
777862306a36Sopenharmony_ci			break;
777962306a36Sopenharmony_ci		}
778062306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, flags);
778162306a36Sopenharmony_ci
778262306a36Sopenharmony_ci		rqb_buffer = rqbp->rqb_alloc_buffer(phba);
778362306a36Sopenharmony_ci		if (!rqb_buffer)
778462306a36Sopenharmony_ci			break;
778562306a36Sopenharmony_ci		rqb_buffer->hrq = hrq;
778662306a36Sopenharmony_ci		rqb_buffer->drq = drq;
778762306a36Sopenharmony_ci		rqb_buffer->idx = idx;
778862306a36Sopenharmony_ci		list_add_tail(&rqb_buffer->hbuf.list, &rqb_buf_list);
778962306a36Sopenharmony_ci	}
779062306a36Sopenharmony_ci
779162306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, flags);
779262306a36Sopenharmony_ci	while (!list_empty(&rqb_buf_list)) {
779362306a36Sopenharmony_ci		list_remove_head(&rqb_buf_list, rqb_buffer, struct rqb_dmabuf,
779462306a36Sopenharmony_ci				 hbuf.list);
779562306a36Sopenharmony_ci
779662306a36Sopenharmony_ci		hrqe.address_lo = putPaddrLow(rqb_buffer->hbuf.phys);
779762306a36Sopenharmony_ci		hrqe.address_hi = putPaddrHigh(rqb_buffer->hbuf.phys);
779862306a36Sopenharmony_ci		drqe.address_lo = putPaddrLow(rqb_buffer->dbuf.phys);
779962306a36Sopenharmony_ci		drqe.address_hi = putPaddrHigh(rqb_buffer->dbuf.phys);
780062306a36Sopenharmony_ci		rc = lpfc_sli4_rq_put(hrq, drq, &hrqe, &drqe);
780162306a36Sopenharmony_ci		if (rc < 0) {
780262306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
780362306a36Sopenharmony_ci					"6421 Cannot post to HRQ %d: %x %x %x "
780462306a36Sopenharmony_ci					"DRQ %x %x\n",
780562306a36Sopenharmony_ci					hrq->queue_id,
780662306a36Sopenharmony_ci					hrq->host_index,
780762306a36Sopenharmony_ci					hrq->hba_index,
780862306a36Sopenharmony_ci					hrq->entry_count,
780962306a36Sopenharmony_ci					drq->host_index,
781062306a36Sopenharmony_ci					drq->hba_index);
781162306a36Sopenharmony_ci			rqbp->rqb_free_buffer(phba, rqb_buffer);
781262306a36Sopenharmony_ci		} else {
781362306a36Sopenharmony_ci			list_add_tail(&rqb_buffer->hbuf.list,
781462306a36Sopenharmony_ci				      &rqbp->rqb_buffer_list);
781562306a36Sopenharmony_ci			rqbp->buffer_count++;
781662306a36Sopenharmony_ci		}
781762306a36Sopenharmony_ci	}
781862306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, flags);
781962306a36Sopenharmony_ci	return 1;
782062306a36Sopenharmony_ci}
782162306a36Sopenharmony_ci
782262306a36Sopenharmony_cistatic void
782362306a36Sopenharmony_cilpfc_mbx_cmpl_read_lds_params(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
782462306a36Sopenharmony_ci{
782562306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
782662306a36Sopenharmony_ci	u32 shdr_status, shdr_add_status;
782762306a36Sopenharmony_ci
782862306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)
782962306a36Sopenharmony_ci		&pmb->u.mqe.un.sli4_config.header.cfg_shdr;
783062306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
783162306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
783262306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || pmb->u.mb.mbxStatus) {
783362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LDS_EVENT | LOG_MBOX,
783462306a36Sopenharmony_ci				"4622 SET_FEATURE (x%x) mbox failed, "
783562306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
783662306a36Sopenharmony_ci				LPFC_SET_LD_SIGNAL, shdr_status,
783762306a36Sopenharmony_ci				shdr_add_status, pmb->u.mb.mbxStatus);
783862306a36Sopenharmony_ci		phba->degrade_activate_threshold = 0;
783962306a36Sopenharmony_ci		phba->degrade_deactivate_threshold = 0;
784062306a36Sopenharmony_ci		phba->fec_degrade_interval = 0;
784162306a36Sopenharmony_ci		goto out;
784262306a36Sopenharmony_ci	}
784362306a36Sopenharmony_ci
784462306a36Sopenharmony_ci	phba->degrade_activate_threshold = pmb->u.mqe.un.set_feature.word7;
784562306a36Sopenharmony_ci	phba->degrade_deactivate_threshold = pmb->u.mqe.un.set_feature.word8;
784662306a36Sopenharmony_ci	phba->fec_degrade_interval = pmb->u.mqe.un.set_feature.word10;
784762306a36Sopenharmony_ci
784862306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_LDS_EVENT,
784962306a36Sopenharmony_ci			"4624 Success: da x%x dd x%x interval x%x\n",
785062306a36Sopenharmony_ci			phba->degrade_activate_threshold,
785162306a36Sopenharmony_ci			phba->degrade_deactivate_threshold,
785262306a36Sopenharmony_ci			phba->fec_degrade_interval);
785362306a36Sopenharmony_ciout:
785462306a36Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
785562306a36Sopenharmony_ci}
785662306a36Sopenharmony_ci
785762306a36Sopenharmony_ciint
785862306a36Sopenharmony_cilpfc_read_lds_params(struct lpfc_hba *phba)
785962306a36Sopenharmony_ci{
786062306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
786162306a36Sopenharmony_ci	int rc;
786262306a36Sopenharmony_ci
786362306a36Sopenharmony_ci	mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
786462306a36Sopenharmony_ci	if (!mboxq)
786562306a36Sopenharmony_ci		return -ENOMEM;
786662306a36Sopenharmony_ci
786762306a36Sopenharmony_ci	lpfc_set_features(phba, mboxq, LPFC_SET_LD_SIGNAL);
786862306a36Sopenharmony_ci	mboxq->vport = phba->pport;
786962306a36Sopenharmony_ci	mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_lds_params;
787062306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
787162306a36Sopenharmony_ci	if (rc == MBX_NOT_FINISHED) {
787262306a36Sopenharmony_ci		mempool_free(mboxq, phba->mbox_mem_pool);
787362306a36Sopenharmony_ci		return -EIO;
787462306a36Sopenharmony_ci	}
787562306a36Sopenharmony_ci	return 0;
787662306a36Sopenharmony_ci}
787762306a36Sopenharmony_ci
787862306a36Sopenharmony_cistatic void
787962306a36Sopenharmony_cilpfc_mbx_cmpl_cgn_set_ftrs(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
788062306a36Sopenharmony_ci{
788162306a36Sopenharmony_ci	struct lpfc_vport *vport = pmb->vport;
788262306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
788362306a36Sopenharmony_ci	u32 shdr_status, shdr_add_status;
788462306a36Sopenharmony_ci	u32 sig, acqe;
788562306a36Sopenharmony_ci
788662306a36Sopenharmony_ci	/* Two outcomes. (1) Set featurs was successul and EDC negotiation
788762306a36Sopenharmony_ci	 * is done. (2) Mailbox failed and send FPIN support only.
788862306a36Sopenharmony_ci	 */
788962306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)
789062306a36Sopenharmony_ci		&pmb->u.mqe.un.sli4_config.header.cfg_shdr;
789162306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
789262306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
789362306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || pmb->u.mb.mbxStatus) {
789462306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_CGN_MGMT,
789562306a36Sopenharmony_ci				"2516 CGN SET_FEATURE mbox failed with "
789662306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x "
789762306a36Sopenharmony_ci				"Reset Congestion to FPINs only\n",
789862306a36Sopenharmony_ci				shdr_status, shdr_add_status,
789962306a36Sopenharmony_ci				pmb->u.mb.mbxStatus);
790062306a36Sopenharmony_ci		/* If there is a mbox error, move on to RDF */
790162306a36Sopenharmony_ci		phba->cgn_reg_signal = EDC_CG_SIG_NOTSUPPORTED;
790262306a36Sopenharmony_ci		phba->cgn_reg_fpin = LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM;
790362306a36Sopenharmony_ci		goto out;
790462306a36Sopenharmony_ci	}
790562306a36Sopenharmony_ci
790662306a36Sopenharmony_ci	/* Zero out Congestion Signal ACQE counter */
790762306a36Sopenharmony_ci	phba->cgn_acqe_cnt = 0;
790862306a36Sopenharmony_ci
790962306a36Sopenharmony_ci	acqe = bf_get(lpfc_mbx_set_feature_CGN_acqe_freq,
791062306a36Sopenharmony_ci		      &pmb->u.mqe.un.set_feature);
791162306a36Sopenharmony_ci	sig = bf_get(lpfc_mbx_set_feature_CGN_warn_freq,
791262306a36Sopenharmony_ci		     &pmb->u.mqe.un.set_feature);
791362306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
791462306a36Sopenharmony_ci			"4620 SET_FEATURES Success: Freq: %ds %dms "
791562306a36Sopenharmony_ci			" Reg: x%x x%x\n", acqe, sig,
791662306a36Sopenharmony_ci			phba->cgn_reg_signal, phba->cgn_reg_fpin);
791762306a36Sopenharmony_ciout:
791862306a36Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
791962306a36Sopenharmony_ci
792062306a36Sopenharmony_ci	/* Register for FPIN events from the fabric now that the
792162306a36Sopenharmony_ci	 * EDC common_set_features has completed.
792262306a36Sopenharmony_ci	 */
792362306a36Sopenharmony_ci	lpfc_issue_els_rdf(vport, 0);
792462306a36Sopenharmony_ci}
792562306a36Sopenharmony_ci
792662306a36Sopenharmony_ciint
792762306a36Sopenharmony_cilpfc_config_cgn_signal(struct lpfc_hba *phba)
792862306a36Sopenharmony_ci{
792962306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
793062306a36Sopenharmony_ci	u32 rc;
793162306a36Sopenharmony_ci
793262306a36Sopenharmony_ci	mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
793362306a36Sopenharmony_ci	if (!mboxq)
793462306a36Sopenharmony_ci		goto out_rdf;
793562306a36Sopenharmony_ci
793662306a36Sopenharmony_ci	lpfc_set_features(phba, mboxq, LPFC_SET_CGN_SIGNAL);
793762306a36Sopenharmony_ci	mboxq->vport = phba->pport;
793862306a36Sopenharmony_ci	mboxq->mbox_cmpl = lpfc_mbx_cmpl_cgn_set_ftrs;
793962306a36Sopenharmony_ci
794062306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
794162306a36Sopenharmony_ci			"4621 SET_FEATURES: FREQ sig x%x acqe x%x: "
794262306a36Sopenharmony_ci			"Reg: x%x x%x\n",
794362306a36Sopenharmony_ci			phba->cgn_sig_freq, lpfc_acqe_cgn_frequency,
794462306a36Sopenharmony_ci			phba->cgn_reg_signal, phba->cgn_reg_fpin);
794562306a36Sopenharmony_ci
794662306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
794762306a36Sopenharmony_ci	if (rc == MBX_NOT_FINISHED)
794862306a36Sopenharmony_ci		goto out;
794962306a36Sopenharmony_ci	return 0;
795062306a36Sopenharmony_ci
795162306a36Sopenharmony_ciout:
795262306a36Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
795362306a36Sopenharmony_ciout_rdf:
795462306a36Sopenharmony_ci	/* If there is a mbox error, move on to RDF */
795562306a36Sopenharmony_ci	phba->cgn_reg_fpin = LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM;
795662306a36Sopenharmony_ci	phba->cgn_reg_signal = EDC_CG_SIG_NOTSUPPORTED;
795762306a36Sopenharmony_ci	lpfc_issue_els_rdf(phba->pport, 0);
795862306a36Sopenharmony_ci	return -EIO;
795962306a36Sopenharmony_ci}
796062306a36Sopenharmony_ci
796162306a36Sopenharmony_ci/**
796262306a36Sopenharmony_ci * lpfc_init_idle_stat_hb - Initialize idle_stat tracking
796362306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
796462306a36Sopenharmony_ci *
796562306a36Sopenharmony_ci * This routine initializes the per-eq idle_stat to dynamically dictate
796662306a36Sopenharmony_ci * polling decisions.
796762306a36Sopenharmony_ci *
796862306a36Sopenharmony_ci * Return codes:
796962306a36Sopenharmony_ci *   None
797062306a36Sopenharmony_ci **/
797162306a36Sopenharmony_cistatic void lpfc_init_idle_stat_hb(struct lpfc_hba *phba)
797262306a36Sopenharmony_ci{
797362306a36Sopenharmony_ci	int i;
797462306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *hdwq;
797562306a36Sopenharmony_ci	struct lpfc_queue *eq;
797662306a36Sopenharmony_ci	struct lpfc_idle_stat *idle_stat;
797762306a36Sopenharmony_ci	u64 wall;
797862306a36Sopenharmony_ci
797962306a36Sopenharmony_ci	for_each_present_cpu(i) {
798062306a36Sopenharmony_ci		hdwq = &phba->sli4_hba.hdwq[phba->sli4_hba.cpu_map[i].hdwq];
798162306a36Sopenharmony_ci		eq = hdwq->hba_eq;
798262306a36Sopenharmony_ci
798362306a36Sopenharmony_ci		/* Skip if we've already handled this eq's primary CPU */
798462306a36Sopenharmony_ci		if (eq->chann != i)
798562306a36Sopenharmony_ci			continue;
798662306a36Sopenharmony_ci
798762306a36Sopenharmony_ci		idle_stat = &phba->sli4_hba.idle_stat[i];
798862306a36Sopenharmony_ci
798962306a36Sopenharmony_ci		idle_stat->prev_idle = get_cpu_idle_time(i, &wall, 1);
799062306a36Sopenharmony_ci		idle_stat->prev_wall = wall;
799162306a36Sopenharmony_ci
799262306a36Sopenharmony_ci		if (phba->nvmet_support ||
799362306a36Sopenharmony_ci		    phba->cmf_active_mode != LPFC_CFG_OFF ||
799462306a36Sopenharmony_ci		    phba->intr_type != MSIX)
799562306a36Sopenharmony_ci			eq->poll_mode = LPFC_QUEUE_WORK;
799662306a36Sopenharmony_ci		else
799762306a36Sopenharmony_ci			eq->poll_mode = LPFC_THREADED_IRQ;
799862306a36Sopenharmony_ci	}
799962306a36Sopenharmony_ci
800062306a36Sopenharmony_ci	if (!phba->nvmet_support && phba->intr_type == MSIX)
800162306a36Sopenharmony_ci		schedule_delayed_work(&phba->idle_stat_delay_work,
800262306a36Sopenharmony_ci				      msecs_to_jiffies(LPFC_IDLE_STAT_DELAY));
800362306a36Sopenharmony_ci}
800462306a36Sopenharmony_ci
800562306a36Sopenharmony_cistatic void lpfc_sli4_dip(struct lpfc_hba *phba)
800662306a36Sopenharmony_ci{
800762306a36Sopenharmony_ci	uint32_t if_type;
800862306a36Sopenharmony_ci
800962306a36Sopenharmony_ci	if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
801062306a36Sopenharmony_ci	if (if_type == LPFC_SLI_INTF_IF_TYPE_2 ||
801162306a36Sopenharmony_ci	    if_type == LPFC_SLI_INTF_IF_TYPE_6) {
801262306a36Sopenharmony_ci		struct lpfc_register reg_data;
801362306a36Sopenharmony_ci
801462306a36Sopenharmony_ci		if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
801562306a36Sopenharmony_ci			       &reg_data.word0))
801662306a36Sopenharmony_ci			return;
801762306a36Sopenharmony_ci
801862306a36Sopenharmony_ci		if (bf_get(lpfc_sliport_status_dip, &reg_data))
801962306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
802062306a36Sopenharmony_ci					"2904 Firmware Dump Image Present"
802162306a36Sopenharmony_ci					" on Adapter");
802262306a36Sopenharmony_ci	}
802362306a36Sopenharmony_ci}
802462306a36Sopenharmony_ci
802562306a36Sopenharmony_ci/**
802662306a36Sopenharmony_ci * lpfc_rx_monitor_create_ring - Initialize ring buffer for rx_monitor
802762306a36Sopenharmony_ci * @rx_monitor: Pointer to lpfc_rx_info_monitor object
802862306a36Sopenharmony_ci * @entries: Number of rx_info_entry objects to allocate in ring
802962306a36Sopenharmony_ci *
803062306a36Sopenharmony_ci * Return:
803162306a36Sopenharmony_ci * 0 - Success
803262306a36Sopenharmony_ci * ENOMEM - Failure to kmalloc
803362306a36Sopenharmony_ci **/
803462306a36Sopenharmony_ciint lpfc_rx_monitor_create_ring(struct lpfc_rx_info_monitor *rx_monitor,
803562306a36Sopenharmony_ci				u32 entries)
803662306a36Sopenharmony_ci{
803762306a36Sopenharmony_ci	rx_monitor->ring = kmalloc_array(entries, sizeof(struct rx_info_entry),
803862306a36Sopenharmony_ci					 GFP_KERNEL);
803962306a36Sopenharmony_ci	if (!rx_monitor->ring)
804062306a36Sopenharmony_ci		return -ENOMEM;
804162306a36Sopenharmony_ci
804262306a36Sopenharmony_ci	rx_monitor->head_idx = 0;
804362306a36Sopenharmony_ci	rx_monitor->tail_idx = 0;
804462306a36Sopenharmony_ci	spin_lock_init(&rx_monitor->lock);
804562306a36Sopenharmony_ci	rx_monitor->entries = entries;
804662306a36Sopenharmony_ci
804762306a36Sopenharmony_ci	return 0;
804862306a36Sopenharmony_ci}
804962306a36Sopenharmony_ci
805062306a36Sopenharmony_ci/**
805162306a36Sopenharmony_ci * lpfc_rx_monitor_destroy_ring - Free ring buffer for rx_monitor
805262306a36Sopenharmony_ci * @rx_monitor: Pointer to lpfc_rx_info_monitor object
805362306a36Sopenharmony_ci *
805462306a36Sopenharmony_ci * Called after cancellation of cmf_timer.
805562306a36Sopenharmony_ci **/
805662306a36Sopenharmony_civoid lpfc_rx_monitor_destroy_ring(struct lpfc_rx_info_monitor *rx_monitor)
805762306a36Sopenharmony_ci{
805862306a36Sopenharmony_ci	kfree(rx_monitor->ring);
805962306a36Sopenharmony_ci	rx_monitor->ring = NULL;
806062306a36Sopenharmony_ci	rx_monitor->entries = 0;
806162306a36Sopenharmony_ci	rx_monitor->head_idx = 0;
806262306a36Sopenharmony_ci	rx_monitor->tail_idx = 0;
806362306a36Sopenharmony_ci}
806462306a36Sopenharmony_ci
806562306a36Sopenharmony_ci/**
806662306a36Sopenharmony_ci * lpfc_rx_monitor_record - Insert an entry into rx_monitor's ring
806762306a36Sopenharmony_ci * @rx_monitor: Pointer to lpfc_rx_info_monitor object
806862306a36Sopenharmony_ci * @entry: Pointer to rx_info_entry
806962306a36Sopenharmony_ci *
807062306a36Sopenharmony_ci * Used to insert an rx_info_entry into rx_monitor's ring.  Note that this is a
807162306a36Sopenharmony_ci * deep copy of rx_info_entry not a shallow copy of the rx_info_entry ptr.
807262306a36Sopenharmony_ci *
807362306a36Sopenharmony_ci * This is called from lpfc_cmf_timer, which is in timer/softirq context.
807462306a36Sopenharmony_ci *
807562306a36Sopenharmony_ci * In cases of old data overflow, we do a best effort of FIFO order.
807662306a36Sopenharmony_ci **/
807762306a36Sopenharmony_civoid lpfc_rx_monitor_record(struct lpfc_rx_info_monitor *rx_monitor,
807862306a36Sopenharmony_ci			    struct rx_info_entry *entry)
807962306a36Sopenharmony_ci{
808062306a36Sopenharmony_ci	struct rx_info_entry *ring = rx_monitor->ring;
808162306a36Sopenharmony_ci	u32 *head_idx = &rx_monitor->head_idx;
808262306a36Sopenharmony_ci	u32 *tail_idx = &rx_monitor->tail_idx;
808362306a36Sopenharmony_ci	spinlock_t *ring_lock = &rx_monitor->lock;
808462306a36Sopenharmony_ci	u32 ring_size = rx_monitor->entries;
808562306a36Sopenharmony_ci
808662306a36Sopenharmony_ci	spin_lock(ring_lock);
808762306a36Sopenharmony_ci	memcpy(&ring[*tail_idx], entry, sizeof(*entry));
808862306a36Sopenharmony_ci	*tail_idx = (*tail_idx + 1) % ring_size;
808962306a36Sopenharmony_ci
809062306a36Sopenharmony_ci	/* Best effort of FIFO saved data */
809162306a36Sopenharmony_ci	if (*tail_idx == *head_idx)
809262306a36Sopenharmony_ci		*head_idx = (*head_idx + 1) % ring_size;
809362306a36Sopenharmony_ci
809462306a36Sopenharmony_ci	spin_unlock(ring_lock);
809562306a36Sopenharmony_ci}
809662306a36Sopenharmony_ci
809762306a36Sopenharmony_ci/**
809862306a36Sopenharmony_ci * lpfc_rx_monitor_report - Read out rx_monitor's ring
809962306a36Sopenharmony_ci * @phba: Pointer to lpfc_hba object
810062306a36Sopenharmony_ci * @rx_monitor: Pointer to lpfc_rx_info_monitor object
810162306a36Sopenharmony_ci * @buf: Pointer to char buffer that will contain rx monitor info data
810262306a36Sopenharmony_ci * @buf_len: Length buf including null char
810362306a36Sopenharmony_ci * @max_read_entries: Maximum number of entries to read out of ring
810462306a36Sopenharmony_ci *
810562306a36Sopenharmony_ci * Used to dump/read what's in rx_monitor's ring buffer.
810662306a36Sopenharmony_ci *
810762306a36Sopenharmony_ci * If buf is NULL || buf_len == 0, then it is implied that we want to log the
810862306a36Sopenharmony_ci * information to kmsg instead of filling out buf.
810962306a36Sopenharmony_ci *
811062306a36Sopenharmony_ci * Return:
811162306a36Sopenharmony_ci * Number of entries read out of the ring
811262306a36Sopenharmony_ci **/
811362306a36Sopenharmony_ciu32 lpfc_rx_monitor_report(struct lpfc_hba *phba,
811462306a36Sopenharmony_ci			   struct lpfc_rx_info_monitor *rx_monitor, char *buf,
811562306a36Sopenharmony_ci			   u32 buf_len, u32 max_read_entries)
811662306a36Sopenharmony_ci{
811762306a36Sopenharmony_ci	struct rx_info_entry *ring = rx_monitor->ring;
811862306a36Sopenharmony_ci	struct rx_info_entry *entry;
811962306a36Sopenharmony_ci	u32 *head_idx = &rx_monitor->head_idx;
812062306a36Sopenharmony_ci	u32 *tail_idx = &rx_monitor->tail_idx;
812162306a36Sopenharmony_ci	spinlock_t *ring_lock = &rx_monitor->lock;
812262306a36Sopenharmony_ci	u32 ring_size = rx_monitor->entries;
812362306a36Sopenharmony_ci	u32 cnt = 0;
812462306a36Sopenharmony_ci	char tmp[DBG_LOG_STR_SZ] = {0};
812562306a36Sopenharmony_ci	bool log_to_kmsg = (!buf || !buf_len) ? true : false;
812662306a36Sopenharmony_ci
812762306a36Sopenharmony_ci	if (!log_to_kmsg) {
812862306a36Sopenharmony_ci		/* clear the buffer to be sure */
812962306a36Sopenharmony_ci		memset(buf, 0, buf_len);
813062306a36Sopenharmony_ci
813162306a36Sopenharmony_ci		scnprintf(buf, buf_len, "\t%-16s%-16s%-16s%-16s%-8s%-8s%-8s"
813262306a36Sopenharmony_ci					"%-8s%-8s%-8s%-16s\n",
813362306a36Sopenharmony_ci					"MaxBPI", "Tot_Data_CMF",
813462306a36Sopenharmony_ci					"Tot_Data_Cmd", "Tot_Data_Cmpl",
813562306a36Sopenharmony_ci					"Lat(us)", "Avg_IO", "Max_IO", "Bsy",
813662306a36Sopenharmony_ci					"IO_cnt", "Info", "BWutil(ms)");
813762306a36Sopenharmony_ci	}
813862306a36Sopenharmony_ci
813962306a36Sopenharmony_ci	/* Needs to be _irq because record is called from timer interrupt
814062306a36Sopenharmony_ci	 * context
814162306a36Sopenharmony_ci	 */
814262306a36Sopenharmony_ci	spin_lock_irq(ring_lock);
814362306a36Sopenharmony_ci	while (*head_idx != *tail_idx) {
814462306a36Sopenharmony_ci		entry = &ring[*head_idx];
814562306a36Sopenharmony_ci
814662306a36Sopenharmony_ci		/* Read out this entry's data. */
814762306a36Sopenharmony_ci		if (!log_to_kmsg) {
814862306a36Sopenharmony_ci			/* If !log_to_kmsg, then store to buf. */
814962306a36Sopenharmony_ci			scnprintf(tmp, sizeof(tmp),
815062306a36Sopenharmony_ci				  "%03d:\t%-16llu%-16llu%-16llu%-16llu%-8llu"
815162306a36Sopenharmony_ci				  "%-8llu%-8llu%-8u%-8u%-8u%u(%u)\n",
815262306a36Sopenharmony_ci				  *head_idx, entry->max_bytes_per_interval,
815362306a36Sopenharmony_ci				  entry->cmf_bytes, entry->total_bytes,
815462306a36Sopenharmony_ci				  entry->rcv_bytes, entry->avg_io_latency,
815562306a36Sopenharmony_ci				  entry->avg_io_size, entry->max_read_cnt,
815662306a36Sopenharmony_ci				  entry->cmf_busy, entry->io_cnt,
815762306a36Sopenharmony_ci				  entry->cmf_info, entry->timer_utilization,
815862306a36Sopenharmony_ci				  entry->timer_interval);
815962306a36Sopenharmony_ci
816062306a36Sopenharmony_ci			/* Check for buffer overflow */
816162306a36Sopenharmony_ci			if ((strlen(buf) + strlen(tmp)) >= buf_len)
816262306a36Sopenharmony_ci				break;
816362306a36Sopenharmony_ci
816462306a36Sopenharmony_ci			/* Append entry's data to buffer */
816562306a36Sopenharmony_ci			strlcat(buf, tmp, buf_len);
816662306a36Sopenharmony_ci		} else {
816762306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
816862306a36Sopenharmony_ci					"4410 %02u: MBPI %llu Xmit %llu "
816962306a36Sopenharmony_ci					"Cmpl %llu Lat %llu ASz %llu Info %02u "
817062306a36Sopenharmony_ci					"BWUtil %u Int %u slot %u\n",
817162306a36Sopenharmony_ci					cnt, entry->max_bytes_per_interval,
817262306a36Sopenharmony_ci					entry->total_bytes, entry->rcv_bytes,
817362306a36Sopenharmony_ci					entry->avg_io_latency,
817462306a36Sopenharmony_ci					entry->avg_io_size, entry->cmf_info,
817562306a36Sopenharmony_ci					entry->timer_utilization,
817662306a36Sopenharmony_ci					entry->timer_interval, *head_idx);
817762306a36Sopenharmony_ci		}
817862306a36Sopenharmony_ci
817962306a36Sopenharmony_ci		*head_idx = (*head_idx + 1) % ring_size;
818062306a36Sopenharmony_ci
818162306a36Sopenharmony_ci		/* Don't feed more than max_read_entries */
818262306a36Sopenharmony_ci		cnt++;
818362306a36Sopenharmony_ci		if (cnt >= max_read_entries)
818462306a36Sopenharmony_ci			break;
818562306a36Sopenharmony_ci	}
818662306a36Sopenharmony_ci	spin_unlock_irq(ring_lock);
818762306a36Sopenharmony_ci
818862306a36Sopenharmony_ci	return cnt;
818962306a36Sopenharmony_ci}
819062306a36Sopenharmony_ci
819162306a36Sopenharmony_ci/**
819262306a36Sopenharmony_ci * lpfc_cmf_setup - Initialize idle_stat tracking
819362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
819462306a36Sopenharmony_ci *
819562306a36Sopenharmony_ci * This is called from HBA setup during driver load or when the HBA
819662306a36Sopenharmony_ci * comes online. this does all the initialization to support CMF and MI.
819762306a36Sopenharmony_ci **/
819862306a36Sopenharmony_cistatic int
819962306a36Sopenharmony_cilpfc_cmf_setup(struct lpfc_hba *phba)
820062306a36Sopenharmony_ci{
820162306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
820262306a36Sopenharmony_ci	struct lpfc_dmabuf *mp;
820362306a36Sopenharmony_ci	struct lpfc_pc_sli4_params *sli4_params;
820462306a36Sopenharmony_ci	int rc, cmf, mi_ver;
820562306a36Sopenharmony_ci
820662306a36Sopenharmony_ci	rc = lpfc_sli4_refresh_params(phba);
820762306a36Sopenharmony_ci	if (unlikely(rc))
820862306a36Sopenharmony_ci		return rc;
820962306a36Sopenharmony_ci
821062306a36Sopenharmony_ci	mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
821162306a36Sopenharmony_ci	if (!mboxq)
821262306a36Sopenharmony_ci		return -ENOMEM;
821362306a36Sopenharmony_ci
821462306a36Sopenharmony_ci	sli4_params = &phba->sli4_hba.pc_sli4_params;
821562306a36Sopenharmony_ci
821662306a36Sopenharmony_ci	/* Always try to enable MI feature if we can */
821762306a36Sopenharmony_ci	if (sli4_params->mi_ver) {
821862306a36Sopenharmony_ci		lpfc_set_features(phba, mboxq, LPFC_SET_ENABLE_MI);
821962306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
822062306a36Sopenharmony_ci		mi_ver = bf_get(lpfc_mbx_set_feature_mi,
822162306a36Sopenharmony_ci				 &mboxq->u.mqe.un.set_feature);
822262306a36Sopenharmony_ci
822362306a36Sopenharmony_ci		if (rc == MBX_SUCCESS) {
822462306a36Sopenharmony_ci			if (mi_ver) {
822562306a36Sopenharmony_ci				lpfc_printf_log(phba,
822662306a36Sopenharmony_ci						KERN_WARNING, LOG_CGN_MGMT,
822762306a36Sopenharmony_ci						"6215 MI is enabled\n");
822862306a36Sopenharmony_ci				sli4_params->mi_ver = mi_ver;
822962306a36Sopenharmony_ci			} else {
823062306a36Sopenharmony_ci				lpfc_printf_log(phba,
823162306a36Sopenharmony_ci						KERN_WARNING, LOG_CGN_MGMT,
823262306a36Sopenharmony_ci						"6338 MI is disabled\n");
823362306a36Sopenharmony_ci				sli4_params->mi_ver = 0;
823462306a36Sopenharmony_ci			}
823562306a36Sopenharmony_ci		} else {
823662306a36Sopenharmony_ci			/* mi_ver is already set from GET_SLI4_PARAMETERS */
823762306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO,
823862306a36Sopenharmony_ci					LOG_CGN_MGMT | LOG_INIT,
823962306a36Sopenharmony_ci					"6245 Enable MI Mailbox x%x (x%x/x%x) "
824062306a36Sopenharmony_ci					"failed, rc:x%x mi:x%x\n",
824162306a36Sopenharmony_ci					bf_get(lpfc_mqe_command, &mboxq->u.mqe),
824262306a36Sopenharmony_ci					lpfc_sli_config_mbox_subsys_get
824362306a36Sopenharmony_ci						(phba, mboxq),
824462306a36Sopenharmony_ci					lpfc_sli_config_mbox_opcode_get
824562306a36Sopenharmony_ci						(phba, mboxq),
824662306a36Sopenharmony_ci					rc, sli4_params->mi_ver);
824762306a36Sopenharmony_ci		}
824862306a36Sopenharmony_ci	} else {
824962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT,
825062306a36Sopenharmony_ci				"6217 MI is disabled\n");
825162306a36Sopenharmony_ci	}
825262306a36Sopenharmony_ci
825362306a36Sopenharmony_ci	/* Ensure FDMI is enabled for MI if enable_mi is set */
825462306a36Sopenharmony_ci	if (sli4_params->mi_ver)
825562306a36Sopenharmony_ci		phba->cfg_fdmi_on = LPFC_FDMI_SUPPORT;
825662306a36Sopenharmony_ci
825762306a36Sopenharmony_ci	/* Always try to enable CMF feature if we can */
825862306a36Sopenharmony_ci	if (sli4_params->cmf) {
825962306a36Sopenharmony_ci		lpfc_set_features(phba, mboxq, LPFC_SET_ENABLE_CMF);
826062306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
826162306a36Sopenharmony_ci		cmf = bf_get(lpfc_mbx_set_feature_cmf,
826262306a36Sopenharmony_ci			     &mboxq->u.mqe.un.set_feature);
826362306a36Sopenharmony_ci		if (rc == MBX_SUCCESS && cmf) {
826462306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT,
826562306a36Sopenharmony_ci					"6218 CMF is enabled: mode %d\n",
826662306a36Sopenharmony_ci					phba->cmf_active_mode);
826762306a36Sopenharmony_ci		} else {
826862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING,
826962306a36Sopenharmony_ci					LOG_CGN_MGMT | LOG_INIT,
827062306a36Sopenharmony_ci					"6219 Enable CMF Mailbox x%x (x%x/x%x) "
827162306a36Sopenharmony_ci					"failed, rc:x%x dd:x%x\n",
827262306a36Sopenharmony_ci					bf_get(lpfc_mqe_command, &mboxq->u.mqe),
827362306a36Sopenharmony_ci					lpfc_sli_config_mbox_subsys_get
827462306a36Sopenharmony_ci						(phba, mboxq),
827562306a36Sopenharmony_ci					lpfc_sli_config_mbox_opcode_get
827662306a36Sopenharmony_ci						(phba, mboxq),
827762306a36Sopenharmony_ci					rc, cmf);
827862306a36Sopenharmony_ci			sli4_params->cmf = 0;
827962306a36Sopenharmony_ci			phba->cmf_active_mode = LPFC_CFG_OFF;
828062306a36Sopenharmony_ci			goto no_cmf;
828162306a36Sopenharmony_ci		}
828262306a36Sopenharmony_ci
828362306a36Sopenharmony_ci		/* Allocate Congestion Information Buffer */
828462306a36Sopenharmony_ci		if (!phba->cgn_i) {
828562306a36Sopenharmony_ci			mp = kmalloc(sizeof(*mp), GFP_KERNEL);
828662306a36Sopenharmony_ci			if (mp)
828762306a36Sopenharmony_ci				mp->virt = dma_alloc_coherent
828862306a36Sopenharmony_ci						(&phba->pcidev->dev,
828962306a36Sopenharmony_ci						sizeof(struct lpfc_cgn_info),
829062306a36Sopenharmony_ci						&mp->phys, GFP_KERNEL);
829162306a36Sopenharmony_ci			if (!mp || !mp->virt) {
829262306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
829362306a36Sopenharmony_ci						"2640 Failed to alloc memory "
829462306a36Sopenharmony_ci						"for Congestion Info\n");
829562306a36Sopenharmony_ci				kfree(mp);
829662306a36Sopenharmony_ci				sli4_params->cmf = 0;
829762306a36Sopenharmony_ci				phba->cmf_active_mode = LPFC_CFG_OFF;
829862306a36Sopenharmony_ci				goto no_cmf;
829962306a36Sopenharmony_ci			}
830062306a36Sopenharmony_ci			phba->cgn_i = mp;
830162306a36Sopenharmony_ci
830262306a36Sopenharmony_ci			/* initialize congestion buffer info */
830362306a36Sopenharmony_ci			lpfc_init_congestion_buf(phba);
830462306a36Sopenharmony_ci			lpfc_init_congestion_stat(phba);
830562306a36Sopenharmony_ci
830662306a36Sopenharmony_ci			/* Zero out Congestion Signal counters */
830762306a36Sopenharmony_ci			atomic64_set(&phba->cgn_acqe_stat.alarm, 0);
830862306a36Sopenharmony_ci			atomic64_set(&phba->cgn_acqe_stat.warn, 0);
830962306a36Sopenharmony_ci		}
831062306a36Sopenharmony_ci
831162306a36Sopenharmony_ci		rc = lpfc_sli4_cgn_params_read(phba);
831262306a36Sopenharmony_ci		if (rc < 0) {
831362306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT,
831462306a36Sopenharmony_ci					"6242 Error reading Cgn Params (%d)\n",
831562306a36Sopenharmony_ci					rc);
831662306a36Sopenharmony_ci			/* Ensure CGN Mode is off */
831762306a36Sopenharmony_ci			sli4_params->cmf = 0;
831862306a36Sopenharmony_ci		} else if (!rc) {
831962306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT,
832062306a36Sopenharmony_ci					"6243 CGN Event empty object.\n");
832162306a36Sopenharmony_ci			/* Ensure CGN Mode is off */
832262306a36Sopenharmony_ci			sli4_params->cmf = 0;
832362306a36Sopenharmony_ci		}
832462306a36Sopenharmony_ci	} else {
832562306a36Sopenharmony_cino_cmf:
832662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT,
832762306a36Sopenharmony_ci				"6220 CMF is disabled\n");
832862306a36Sopenharmony_ci	}
832962306a36Sopenharmony_ci
833062306a36Sopenharmony_ci	/* Only register congestion buffer with firmware if BOTH
833162306a36Sopenharmony_ci	 * CMF and E2E are enabled.
833262306a36Sopenharmony_ci	 */
833362306a36Sopenharmony_ci	if (sli4_params->cmf && sli4_params->mi_ver) {
833462306a36Sopenharmony_ci		rc = lpfc_reg_congestion_buf(phba);
833562306a36Sopenharmony_ci		if (rc) {
833662306a36Sopenharmony_ci			dma_free_coherent(&phba->pcidev->dev,
833762306a36Sopenharmony_ci					  sizeof(struct lpfc_cgn_info),
833862306a36Sopenharmony_ci					  phba->cgn_i->virt, phba->cgn_i->phys);
833962306a36Sopenharmony_ci			kfree(phba->cgn_i);
834062306a36Sopenharmony_ci			phba->cgn_i = NULL;
834162306a36Sopenharmony_ci			/* Ensure CGN Mode is off */
834262306a36Sopenharmony_ci			phba->cmf_active_mode = LPFC_CFG_OFF;
834362306a36Sopenharmony_ci			sli4_params->cmf = 0;
834462306a36Sopenharmony_ci			return 0;
834562306a36Sopenharmony_ci		}
834662306a36Sopenharmony_ci	}
834762306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
834862306a36Sopenharmony_ci			"6470 Setup MI version %d CMF %d mode %d\n",
834962306a36Sopenharmony_ci			sli4_params->mi_ver, sli4_params->cmf,
835062306a36Sopenharmony_ci			phba->cmf_active_mode);
835162306a36Sopenharmony_ci
835262306a36Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
835362306a36Sopenharmony_ci
835462306a36Sopenharmony_ci	/* Initialize atomic counters */
835562306a36Sopenharmony_ci	atomic_set(&phba->cgn_fabric_warn_cnt, 0);
835662306a36Sopenharmony_ci	atomic_set(&phba->cgn_fabric_alarm_cnt, 0);
835762306a36Sopenharmony_ci	atomic_set(&phba->cgn_sync_alarm_cnt, 0);
835862306a36Sopenharmony_ci	atomic_set(&phba->cgn_sync_warn_cnt, 0);
835962306a36Sopenharmony_ci	atomic_set(&phba->cgn_driver_evt_cnt, 0);
836062306a36Sopenharmony_ci	atomic_set(&phba->cgn_latency_evt_cnt, 0);
836162306a36Sopenharmony_ci	atomic64_set(&phba->cgn_latency_evt, 0);
836262306a36Sopenharmony_ci
836362306a36Sopenharmony_ci	phba->cmf_interval_rate = LPFC_CMF_INTERVAL;
836462306a36Sopenharmony_ci
836562306a36Sopenharmony_ci	/* Allocate RX Monitor Buffer */
836662306a36Sopenharmony_ci	if (!phba->rx_monitor) {
836762306a36Sopenharmony_ci		phba->rx_monitor = kzalloc(sizeof(*phba->rx_monitor),
836862306a36Sopenharmony_ci					   GFP_KERNEL);
836962306a36Sopenharmony_ci
837062306a36Sopenharmony_ci		if (!phba->rx_monitor) {
837162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
837262306a36Sopenharmony_ci					"2644 Failed to alloc memory "
837362306a36Sopenharmony_ci					"for RX Monitor Buffer\n");
837462306a36Sopenharmony_ci			return -ENOMEM;
837562306a36Sopenharmony_ci		}
837662306a36Sopenharmony_ci
837762306a36Sopenharmony_ci		/* Instruct the rx_monitor object to instantiate its ring */
837862306a36Sopenharmony_ci		if (lpfc_rx_monitor_create_ring(phba->rx_monitor,
837962306a36Sopenharmony_ci						LPFC_MAX_RXMONITOR_ENTRY)) {
838062306a36Sopenharmony_ci			kfree(phba->rx_monitor);
838162306a36Sopenharmony_ci			phba->rx_monitor = NULL;
838262306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
838362306a36Sopenharmony_ci					"2645 Failed to alloc memory "
838462306a36Sopenharmony_ci					"for RX Monitor's Ring\n");
838562306a36Sopenharmony_ci			return -ENOMEM;
838662306a36Sopenharmony_ci		}
838762306a36Sopenharmony_ci	}
838862306a36Sopenharmony_ci
838962306a36Sopenharmony_ci	return 0;
839062306a36Sopenharmony_ci}
839162306a36Sopenharmony_ci
839262306a36Sopenharmony_cistatic int
839362306a36Sopenharmony_cilpfc_set_host_tm(struct lpfc_hba *phba)
839462306a36Sopenharmony_ci{
839562306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
839662306a36Sopenharmony_ci	uint32_t len, rc;
839762306a36Sopenharmony_ci	struct timespec64 cur_time;
839862306a36Sopenharmony_ci	struct tm broken;
839962306a36Sopenharmony_ci	uint32_t month, day, year;
840062306a36Sopenharmony_ci	uint32_t hour, minute, second;
840162306a36Sopenharmony_ci	struct lpfc_mbx_set_host_date_time *tm;
840262306a36Sopenharmony_ci
840362306a36Sopenharmony_ci	mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
840462306a36Sopenharmony_ci	if (!mboxq)
840562306a36Sopenharmony_ci		return -ENOMEM;
840662306a36Sopenharmony_ci
840762306a36Sopenharmony_ci	len = sizeof(struct lpfc_mbx_set_host_data) -
840862306a36Sopenharmony_ci		sizeof(struct lpfc_sli4_cfg_mhdr);
840962306a36Sopenharmony_ci	lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
841062306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_SET_HOST_DATA, len,
841162306a36Sopenharmony_ci			 LPFC_SLI4_MBX_EMBED);
841262306a36Sopenharmony_ci
841362306a36Sopenharmony_ci	mboxq->u.mqe.un.set_host_data.param_id = LPFC_SET_HOST_DATE_TIME;
841462306a36Sopenharmony_ci	mboxq->u.mqe.un.set_host_data.param_len =
841562306a36Sopenharmony_ci			sizeof(struct lpfc_mbx_set_host_date_time);
841662306a36Sopenharmony_ci	tm = &mboxq->u.mqe.un.set_host_data.un.tm;
841762306a36Sopenharmony_ci	ktime_get_real_ts64(&cur_time);
841862306a36Sopenharmony_ci	time64_to_tm(cur_time.tv_sec, 0, &broken);
841962306a36Sopenharmony_ci	month = broken.tm_mon + 1;
842062306a36Sopenharmony_ci	day = broken.tm_mday;
842162306a36Sopenharmony_ci	year = broken.tm_year - 100;
842262306a36Sopenharmony_ci	hour = broken.tm_hour;
842362306a36Sopenharmony_ci	minute = broken.tm_min;
842462306a36Sopenharmony_ci	second = broken.tm_sec;
842562306a36Sopenharmony_ci	bf_set(lpfc_mbx_set_host_month, tm, month);
842662306a36Sopenharmony_ci	bf_set(lpfc_mbx_set_host_day, tm, day);
842762306a36Sopenharmony_ci	bf_set(lpfc_mbx_set_host_year, tm, year);
842862306a36Sopenharmony_ci	bf_set(lpfc_mbx_set_host_hour, tm, hour);
842962306a36Sopenharmony_ci	bf_set(lpfc_mbx_set_host_min, tm, minute);
843062306a36Sopenharmony_ci	bf_set(lpfc_mbx_set_host_sec, tm, second);
843162306a36Sopenharmony_ci
843262306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
843362306a36Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
843462306a36Sopenharmony_ci	return rc;
843562306a36Sopenharmony_ci}
843662306a36Sopenharmony_ci
843762306a36Sopenharmony_ci/**
843862306a36Sopenharmony_ci * lpfc_sli4_hba_setup - SLI4 device initialization PCI function
843962306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
844062306a36Sopenharmony_ci *
844162306a36Sopenharmony_ci * This function is the main SLI4 device initialization PCI function. This
844262306a36Sopenharmony_ci * function is called by the HBA initialization code, HBA reset code and
844362306a36Sopenharmony_ci * HBA error attention handler code. Caller is not required to hold any
844462306a36Sopenharmony_ci * locks.
844562306a36Sopenharmony_ci **/
844662306a36Sopenharmony_ciint
844762306a36Sopenharmony_cilpfc_sli4_hba_setup(struct lpfc_hba *phba)
844862306a36Sopenharmony_ci{
844962306a36Sopenharmony_ci	int rc, i, cnt, len, dd;
845062306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
845162306a36Sopenharmony_ci	struct lpfc_mqe *mqe;
845262306a36Sopenharmony_ci	uint8_t *vpd;
845362306a36Sopenharmony_ci	uint32_t vpd_size;
845462306a36Sopenharmony_ci	uint32_t ftr_rsp = 0;
845562306a36Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport);
845662306a36Sopenharmony_ci	struct lpfc_vport *vport = phba->pport;
845762306a36Sopenharmony_ci	struct lpfc_dmabuf *mp;
845862306a36Sopenharmony_ci	struct lpfc_rqb *rqbp;
845962306a36Sopenharmony_ci	u32 flg;
846062306a36Sopenharmony_ci
846162306a36Sopenharmony_ci	/* Perform a PCI function reset to start from clean */
846262306a36Sopenharmony_ci	rc = lpfc_pci_function_reset(phba);
846362306a36Sopenharmony_ci	if (unlikely(rc))
846462306a36Sopenharmony_ci		return -ENODEV;
846562306a36Sopenharmony_ci
846662306a36Sopenharmony_ci	/* Check the HBA Host Status Register for readyness */
846762306a36Sopenharmony_ci	rc = lpfc_sli4_post_status_check(phba);
846862306a36Sopenharmony_ci	if (unlikely(rc))
846962306a36Sopenharmony_ci		return -ENODEV;
847062306a36Sopenharmony_ci	else {
847162306a36Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
847262306a36Sopenharmony_ci		phba->sli.sli_flag |= LPFC_SLI_ACTIVE;
847362306a36Sopenharmony_ci		flg = phba->sli.sli_flag;
847462306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
847562306a36Sopenharmony_ci		/* Allow a little time after setting SLI_ACTIVE for any polled
847662306a36Sopenharmony_ci		 * MBX commands to complete via BSG.
847762306a36Sopenharmony_ci		 */
847862306a36Sopenharmony_ci		for (i = 0; i < 50 && (flg & LPFC_SLI_MBOX_ACTIVE); i++) {
847962306a36Sopenharmony_ci			msleep(20);
848062306a36Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
848162306a36Sopenharmony_ci			flg = phba->sli.sli_flag;
848262306a36Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
848362306a36Sopenharmony_ci		}
848462306a36Sopenharmony_ci	}
848562306a36Sopenharmony_ci	phba->hba_flag &= ~HBA_SETUP;
848662306a36Sopenharmony_ci
848762306a36Sopenharmony_ci	lpfc_sli4_dip(phba);
848862306a36Sopenharmony_ci
848962306a36Sopenharmony_ci	/*
849062306a36Sopenharmony_ci	 * Allocate a single mailbox container for initializing the
849162306a36Sopenharmony_ci	 * port.
849262306a36Sopenharmony_ci	 */
849362306a36Sopenharmony_ci	mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
849462306a36Sopenharmony_ci	if (!mboxq)
849562306a36Sopenharmony_ci		return -ENOMEM;
849662306a36Sopenharmony_ci
849762306a36Sopenharmony_ci	/* Issue READ_REV to collect vpd and FW information. */
849862306a36Sopenharmony_ci	vpd_size = SLI4_PAGE_SIZE;
849962306a36Sopenharmony_ci	vpd = kzalloc(vpd_size, GFP_KERNEL);
850062306a36Sopenharmony_ci	if (!vpd) {
850162306a36Sopenharmony_ci		rc = -ENOMEM;
850262306a36Sopenharmony_ci		goto out_free_mbox;
850362306a36Sopenharmony_ci	}
850462306a36Sopenharmony_ci
850562306a36Sopenharmony_ci	rc = lpfc_sli4_read_rev(phba, mboxq, vpd, &vpd_size);
850662306a36Sopenharmony_ci	if (unlikely(rc)) {
850762306a36Sopenharmony_ci		kfree(vpd);
850862306a36Sopenharmony_ci		goto out_free_mbox;
850962306a36Sopenharmony_ci	}
851062306a36Sopenharmony_ci
851162306a36Sopenharmony_ci	mqe = &mboxq->u.mqe;
851262306a36Sopenharmony_ci	phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev);
851362306a36Sopenharmony_ci	if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev)) {
851462306a36Sopenharmony_ci		phba->hba_flag |= HBA_FCOE_MODE;
851562306a36Sopenharmony_ci		phba->fcp_embed_io = 0;	/* SLI4 FC support only */
851662306a36Sopenharmony_ci	} else {
851762306a36Sopenharmony_ci		phba->hba_flag &= ~HBA_FCOE_MODE;
851862306a36Sopenharmony_ci	}
851962306a36Sopenharmony_ci
852062306a36Sopenharmony_ci	if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) ==
852162306a36Sopenharmony_ci		LPFC_DCBX_CEE_MODE)
852262306a36Sopenharmony_ci		phba->hba_flag |= HBA_FIP_SUPPORT;
852362306a36Sopenharmony_ci	else
852462306a36Sopenharmony_ci		phba->hba_flag &= ~HBA_FIP_SUPPORT;
852562306a36Sopenharmony_ci
852662306a36Sopenharmony_ci	phba->hba_flag &= ~HBA_IOQ_FLUSH;
852762306a36Sopenharmony_ci
852862306a36Sopenharmony_ci	if (phba->sli_rev != LPFC_SLI_REV4) {
852962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
853062306a36Sopenharmony_ci			"0376 READ_REV Error. SLI Level %d "
853162306a36Sopenharmony_ci			"FCoE enabled %d\n",
853262306a36Sopenharmony_ci			phba->sli_rev, phba->hba_flag & HBA_FCOE_MODE);
853362306a36Sopenharmony_ci		rc = -EIO;
853462306a36Sopenharmony_ci		kfree(vpd);
853562306a36Sopenharmony_ci		goto out_free_mbox;
853662306a36Sopenharmony_ci	}
853762306a36Sopenharmony_ci
853862306a36Sopenharmony_ci	rc = lpfc_set_host_tm(phba);
853962306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
854062306a36Sopenharmony_ci			"6468 Set host date / time: Status x%x:\n", rc);
854162306a36Sopenharmony_ci
854262306a36Sopenharmony_ci	/*
854362306a36Sopenharmony_ci	 * Continue initialization with default values even if driver failed
854462306a36Sopenharmony_ci	 * to read FCoE param config regions, only read parameters if the
854562306a36Sopenharmony_ci	 * board is FCoE
854662306a36Sopenharmony_ci	 */
854762306a36Sopenharmony_ci	if (phba->hba_flag & HBA_FCOE_MODE &&
854862306a36Sopenharmony_ci	    lpfc_sli4_read_fcoe_params(phba))
854962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_INIT,
855062306a36Sopenharmony_ci			"2570 Failed to read FCoE parameters\n");
855162306a36Sopenharmony_ci
855262306a36Sopenharmony_ci	/*
855362306a36Sopenharmony_ci	 * Retrieve sli4 device physical port name, failure of doing it
855462306a36Sopenharmony_ci	 * is considered as non-fatal.
855562306a36Sopenharmony_ci	 */
855662306a36Sopenharmony_ci	rc = lpfc_sli4_retrieve_pport_name(phba);
855762306a36Sopenharmony_ci	if (!rc)
855862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
855962306a36Sopenharmony_ci				"3080 Successful retrieving SLI4 device "
856062306a36Sopenharmony_ci				"physical port name: %s.\n", phba->Port);
856162306a36Sopenharmony_ci
856262306a36Sopenharmony_ci	rc = lpfc_sli4_get_ctl_attr(phba);
856362306a36Sopenharmony_ci	if (!rc)
856462306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
856562306a36Sopenharmony_ci				"8351 Successful retrieving SLI4 device "
856662306a36Sopenharmony_ci				"CTL ATTR\n");
856762306a36Sopenharmony_ci
856862306a36Sopenharmony_ci	/*
856962306a36Sopenharmony_ci	 * Evaluate the read rev and vpd data. Populate the driver
857062306a36Sopenharmony_ci	 * state with the results. If this routine fails, the failure
857162306a36Sopenharmony_ci	 * is not fatal as the driver will use generic values.
857262306a36Sopenharmony_ci	 */
857362306a36Sopenharmony_ci	rc = lpfc_parse_vpd(phba, vpd, vpd_size);
857462306a36Sopenharmony_ci	if (unlikely(!rc)) {
857562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
857662306a36Sopenharmony_ci				"0377 Error %d parsing vpd. "
857762306a36Sopenharmony_ci				"Using defaults.\n", rc);
857862306a36Sopenharmony_ci		rc = 0;
857962306a36Sopenharmony_ci	}
858062306a36Sopenharmony_ci	kfree(vpd);
858162306a36Sopenharmony_ci
858262306a36Sopenharmony_ci	/* Save information as VPD data */
858362306a36Sopenharmony_ci	phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev;
858462306a36Sopenharmony_ci	phba->vpd.rev.smRev = mqe->un.read_rev.second_hw_rev;
858562306a36Sopenharmony_ci
858662306a36Sopenharmony_ci	/*
858762306a36Sopenharmony_ci	 * This is because first G7 ASIC doesn't support the standard
858862306a36Sopenharmony_ci	 * 0x5a NVME cmd descriptor type/subtype
858962306a36Sopenharmony_ci	 */
859062306a36Sopenharmony_ci	if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
859162306a36Sopenharmony_ci			LPFC_SLI_INTF_IF_TYPE_6) &&
859262306a36Sopenharmony_ci	    (phba->vpd.rev.biuRev == LPFC_G7_ASIC_1) &&
859362306a36Sopenharmony_ci	    (phba->vpd.rev.smRev == 0) &&
859462306a36Sopenharmony_ci	    (phba->cfg_nvme_embed_cmd == 1))
859562306a36Sopenharmony_ci		phba->cfg_nvme_embed_cmd = 0;
859662306a36Sopenharmony_ci
859762306a36Sopenharmony_ci	phba->vpd.rev.endecRev = mqe->un.read_rev.third_hw_rev;
859862306a36Sopenharmony_ci	phba->vpd.rev.fcphHigh = bf_get(lpfc_mbx_rd_rev_fcph_high,
859962306a36Sopenharmony_ci					 &mqe->un.read_rev);
860062306a36Sopenharmony_ci	phba->vpd.rev.fcphLow = bf_get(lpfc_mbx_rd_rev_fcph_low,
860162306a36Sopenharmony_ci				       &mqe->un.read_rev);
860262306a36Sopenharmony_ci	phba->vpd.rev.feaLevelHigh = bf_get(lpfc_mbx_rd_rev_ftr_lvl_high,
860362306a36Sopenharmony_ci					    &mqe->un.read_rev);
860462306a36Sopenharmony_ci	phba->vpd.rev.feaLevelLow = bf_get(lpfc_mbx_rd_rev_ftr_lvl_low,
860562306a36Sopenharmony_ci					   &mqe->un.read_rev);
860662306a36Sopenharmony_ci	phba->vpd.rev.sli1FwRev = mqe->un.read_rev.fw_id_rev;
860762306a36Sopenharmony_ci	memcpy(phba->vpd.rev.sli1FwName, mqe->un.read_rev.fw_name, 16);
860862306a36Sopenharmony_ci	phba->vpd.rev.sli2FwRev = mqe->un.read_rev.ulp_fw_id_rev;
860962306a36Sopenharmony_ci	memcpy(phba->vpd.rev.sli2FwName, mqe->un.read_rev.ulp_fw_name, 16);
861062306a36Sopenharmony_ci	phba->vpd.rev.opFwRev = mqe->un.read_rev.fw_id_rev;
861162306a36Sopenharmony_ci	memcpy(phba->vpd.rev.opFwName, mqe->un.read_rev.fw_name, 16);
861262306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
861362306a36Sopenharmony_ci			"(%d):0380 READ_REV Status x%x "
861462306a36Sopenharmony_ci			"fw_rev:%s fcphHi:%x fcphLo:%x flHi:%x flLo:%x\n",
861562306a36Sopenharmony_ci			mboxq->vport ? mboxq->vport->vpi : 0,
861662306a36Sopenharmony_ci			bf_get(lpfc_mqe_status, mqe),
861762306a36Sopenharmony_ci			phba->vpd.rev.opFwName,
861862306a36Sopenharmony_ci			phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow,
861962306a36Sopenharmony_ci			phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow);
862062306a36Sopenharmony_ci
862162306a36Sopenharmony_ci	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
862262306a36Sopenharmony_ci	    LPFC_SLI_INTF_IF_TYPE_0) {
862362306a36Sopenharmony_ci		lpfc_set_features(phba, mboxq, LPFC_SET_UE_RECOVERY);
862462306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
862562306a36Sopenharmony_ci		if (rc == MBX_SUCCESS) {
862662306a36Sopenharmony_ci			phba->hba_flag |= HBA_RECOVERABLE_UE;
862762306a36Sopenharmony_ci			/* Set 1Sec interval to detect UE */
862862306a36Sopenharmony_ci			phba->eratt_poll_interval = 1;
862962306a36Sopenharmony_ci			phba->sli4_hba.ue_to_sr = bf_get(
863062306a36Sopenharmony_ci					lpfc_mbx_set_feature_UESR,
863162306a36Sopenharmony_ci					&mboxq->u.mqe.un.set_feature);
863262306a36Sopenharmony_ci			phba->sli4_hba.ue_to_rp = bf_get(
863362306a36Sopenharmony_ci					lpfc_mbx_set_feature_UERP,
863462306a36Sopenharmony_ci					&mboxq->u.mqe.un.set_feature);
863562306a36Sopenharmony_ci		}
863662306a36Sopenharmony_ci	}
863762306a36Sopenharmony_ci
863862306a36Sopenharmony_ci	if (phba->cfg_enable_mds_diags && phba->mds_diags_support) {
863962306a36Sopenharmony_ci		/* Enable MDS Diagnostics only if the SLI Port supports it */
864062306a36Sopenharmony_ci		lpfc_set_features(phba, mboxq, LPFC_SET_MDS_DIAGS);
864162306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
864262306a36Sopenharmony_ci		if (rc != MBX_SUCCESS)
864362306a36Sopenharmony_ci			phba->mds_diags_support = 0;
864462306a36Sopenharmony_ci	}
864562306a36Sopenharmony_ci
864662306a36Sopenharmony_ci	/*
864762306a36Sopenharmony_ci	 * Discover the port's supported feature set and match it against the
864862306a36Sopenharmony_ci	 * hosts requests.
864962306a36Sopenharmony_ci	 */
865062306a36Sopenharmony_ci	lpfc_request_features(phba, mboxq);
865162306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
865262306a36Sopenharmony_ci	if (unlikely(rc)) {
865362306a36Sopenharmony_ci		rc = -EIO;
865462306a36Sopenharmony_ci		goto out_free_mbox;
865562306a36Sopenharmony_ci	}
865662306a36Sopenharmony_ci
865762306a36Sopenharmony_ci	/* Disable VMID if app header is not supported */
865862306a36Sopenharmony_ci	if (phba->cfg_vmid_app_header && !(bf_get(lpfc_mbx_rq_ftr_rsp_ashdr,
865962306a36Sopenharmony_ci						  &mqe->un.req_ftrs))) {
866062306a36Sopenharmony_ci		bf_set(lpfc_ftr_ashdr, &phba->sli4_hba.sli4_flags, 0);
866162306a36Sopenharmony_ci		phba->cfg_vmid_app_header = 0;
866262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_DEBUG, LOG_SLI,
866362306a36Sopenharmony_ci				"1242 vmid feature not supported\n");
866462306a36Sopenharmony_ci	}
866562306a36Sopenharmony_ci
866662306a36Sopenharmony_ci	/*
866762306a36Sopenharmony_ci	 * The port must support FCP initiator mode as this is the
866862306a36Sopenharmony_ci	 * only mode running in the host.
866962306a36Sopenharmony_ci	 */
867062306a36Sopenharmony_ci	if (!(bf_get(lpfc_mbx_rq_ftr_rsp_fcpi, &mqe->un.req_ftrs))) {
867162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
867262306a36Sopenharmony_ci				"0378 No support for fcpi mode.\n");
867362306a36Sopenharmony_ci		ftr_rsp++;
867462306a36Sopenharmony_ci	}
867562306a36Sopenharmony_ci
867662306a36Sopenharmony_ci	/* Performance Hints are ONLY for FCoE */
867762306a36Sopenharmony_ci	if (phba->hba_flag & HBA_FCOE_MODE) {
867862306a36Sopenharmony_ci		if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs))
867962306a36Sopenharmony_ci			phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED;
868062306a36Sopenharmony_ci		else
868162306a36Sopenharmony_ci			phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED;
868262306a36Sopenharmony_ci	}
868362306a36Sopenharmony_ci
868462306a36Sopenharmony_ci	/*
868562306a36Sopenharmony_ci	 * If the port cannot support the host's requested features
868662306a36Sopenharmony_ci	 * then turn off the global config parameters to disable the
868762306a36Sopenharmony_ci	 * feature in the driver.  This is not a fatal error.
868862306a36Sopenharmony_ci	 */
868962306a36Sopenharmony_ci	if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
869062306a36Sopenharmony_ci		if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))) {
869162306a36Sopenharmony_ci			phba->cfg_enable_bg = 0;
869262306a36Sopenharmony_ci			phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED;
869362306a36Sopenharmony_ci			ftr_rsp++;
869462306a36Sopenharmony_ci		}
869562306a36Sopenharmony_ci	}
869662306a36Sopenharmony_ci
869762306a36Sopenharmony_ci	if (phba->max_vpi && phba->cfg_enable_npiv &&
869862306a36Sopenharmony_ci	    !(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs)))
869962306a36Sopenharmony_ci		ftr_rsp++;
870062306a36Sopenharmony_ci
870162306a36Sopenharmony_ci	if (ftr_rsp) {
870262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
870362306a36Sopenharmony_ci				"0379 Feature Mismatch Data: x%08x %08x "
870462306a36Sopenharmony_ci				"x%x x%x x%x\n", mqe->un.req_ftrs.word2,
870562306a36Sopenharmony_ci				mqe->un.req_ftrs.word3, phba->cfg_enable_bg,
870662306a36Sopenharmony_ci				phba->cfg_enable_npiv, phba->max_vpi);
870762306a36Sopenharmony_ci		if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs)))
870862306a36Sopenharmony_ci			phba->cfg_enable_bg = 0;
870962306a36Sopenharmony_ci		if (!(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs)))
871062306a36Sopenharmony_ci			phba->cfg_enable_npiv = 0;
871162306a36Sopenharmony_ci	}
871262306a36Sopenharmony_ci
871362306a36Sopenharmony_ci	/* These SLI3 features are assumed in SLI4 */
871462306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
871562306a36Sopenharmony_ci	phba->sli3_options |= (LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED);
871662306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
871762306a36Sopenharmony_ci
871862306a36Sopenharmony_ci	/* Always try to enable dual dump feature if we can */
871962306a36Sopenharmony_ci	lpfc_set_features(phba, mboxq, LPFC_SET_DUAL_DUMP);
872062306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
872162306a36Sopenharmony_ci	dd = bf_get(lpfc_mbx_set_feature_dd, &mboxq->u.mqe.un.set_feature);
872262306a36Sopenharmony_ci	if ((rc == MBX_SUCCESS) && (dd == LPFC_ENABLE_DUAL_DUMP))
872362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
872462306a36Sopenharmony_ci				"6448 Dual Dump is enabled\n");
872562306a36Sopenharmony_ci	else
872662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_SLI | LOG_INIT,
872762306a36Sopenharmony_ci				"6447 Dual Dump Mailbox x%x (x%x/x%x) failed, "
872862306a36Sopenharmony_ci				"rc:x%x dd:x%x\n",
872962306a36Sopenharmony_ci				bf_get(lpfc_mqe_command, &mboxq->u.mqe),
873062306a36Sopenharmony_ci				lpfc_sli_config_mbox_subsys_get(
873162306a36Sopenharmony_ci					phba, mboxq),
873262306a36Sopenharmony_ci				lpfc_sli_config_mbox_opcode_get(
873362306a36Sopenharmony_ci					phba, mboxq),
873462306a36Sopenharmony_ci				rc, dd);
873562306a36Sopenharmony_ci	/*
873662306a36Sopenharmony_ci	 * Allocate all resources (xri,rpi,vpi,vfi) now.  Subsequent
873762306a36Sopenharmony_ci	 * calls depends on these resources to complete port setup.
873862306a36Sopenharmony_ci	 */
873962306a36Sopenharmony_ci	rc = lpfc_sli4_alloc_resource_identifiers(phba);
874062306a36Sopenharmony_ci	if (rc) {
874162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
874262306a36Sopenharmony_ci				"2920 Failed to alloc Resource IDs "
874362306a36Sopenharmony_ci				"rc = x%x\n", rc);
874462306a36Sopenharmony_ci		goto out_free_mbox;
874562306a36Sopenharmony_ci	}
874662306a36Sopenharmony_ci
874762306a36Sopenharmony_ci	lpfc_set_host_data(phba, mboxq);
874862306a36Sopenharmony_ci
874962306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
875062306a36Sopenharmony_ci	if (rc) {
875162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
875262306a36Sopenharmony_ci				"2134 Failed to set host os driver version %x",
875362306a36Sopenharmony_ci				rc);
875462306a36Sopenharmony_ci	}
875562306a36Sopenharmony_ci
875662306a36Sopenharmony_ci	/* Read the port's service parameters. */
875762306a36Sopenharmony_ci	rc = lpfc_read_sparam(phba, mboxq, vport->vpi);
875862306a36Sopenharmony_ci	if (rc) {
875962306a36Sopenharmony_ci		phba->link_state = LPFC_HBA_ERROR;
876062306a36Sopenharmony_ci		rc = -ENOMEM;
876162306a36Sopenharmony_ci		goto out_free_mbox;
876262306a36Sopenharmony_ci	}
876362306a36Sopenharmony_ci
876462306a36Sopenharmony_ci	mboxq->vport = vport;
876562306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
876662306a36Sopenharmony_ci	mp = (struct lpfc_dmabuf *)mboxq->ctx_buf;
876762306a36Sopenharmony_ci	if (rc == MBX_SUCCESS) {
876862306a36Sopenharmony_ci		memcpy(&vport->fc_sparam, mp->virt, sizeof(struct serv_parm));
876962306a36Sopenharmony_ci		rc = 0;
877062306a36Sopenharmony_ci	}
877162306a36Sopenharmony_ci
877262306a36Sopenharmony_ci	/*
877362306a36Sopenharmony_ci	 * This memory was allocated by the lpfc_read_sparam routine but is
877462306a36Sopenharmony_ci	 * no longer needed.  It is released and ctx_buf NULLed to prevent
877562306a36Sopenharmony_ci	 * unintended pointer access as the mbox is reused.
877662306a36Sopenharmony_ci	 */
877762306a36Sopenharmony_ci	lpfc_mbuf_free(phba, mp->virt, mp->phys);
877862306a36Sopenharmony_ci	kfree(mp);
877962306a36Sopenharmony_ci	mboxq->ctx_buf = NULL;
878062306a36Sopenharmony_ci	if (unlikely(rc)) {
878162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
878262306a36Sopenharmony_ci				"0382 READ_SPARAM command failed "
878362306a36Sopenharmony_ci				"status %d, mbxStatus x%x\n",
878462306a36Sopenharmony_ci				rc, bf_get(lpfc_mqe_status, mqe));
878562306a36Sopenharmony_ci		phba->link_state = LPFC_HBA_ERROR;
878662306a36Sopenharmony_ci		rc = -EIO;
878762306a36Sopenharmony_ci		goto out_free_mbox;
878862306a36Sopenharmony_ci	}
878962306a36Sopenharmony_ci
879062306a36Sopenharmony_ci	lpfc_update_vport_wwn(vport);
879162306a36Sopenharmony_ci
879262306a36Sopenharmony_ci	/* Update the fc_host data structures with new wwn. */
879362306a36Sopenharmony_ci	fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
879462306a36Sopenharmony_ci	fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
879562306a36Sopenharmony_ci
879662306a36Sopenharmony_ci	/* Create all the SLI4 queues */
879762306a36Sopenharmony_ci	rc = lpfc_sli4_queue_create(phba);
879862306a36Sopenharmony_ci	if (rc) {
879962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
880062306a36Sopenharmony_ci				"3089 Failed to allocate queues\n");
880162306a36Sopenharmony_ci		rc = -ENODEV;
880262306a36Sopenharmony_ci		goto out_free_mbox;
880362306a36Sopenharmony_ci	}
880462306a36Sopenharmony_ci	/* Set up all the queues to the device */
880562306a36Sopenharmony_ci	rc = lpfc_sli4_queue_setup(phba);
880662306a36Sopenharmony_ci	if (unlikely(rc)) {
880762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
880862306a36Sopenharmony_ci				"0381 Error %d during queue setup.\n ", rc);
880962306a36Sopenharmony_ci		goto out_stop_timers;
881062306a36Sopenharmony_ci	}
881162306a36Sopenharmony_ci	/* Initialize the driver internal SLI layer lists. */
881262306a36Sopenharmony_ci	lpfc_sli4_setup(phba);
881362306a36Sopenharmony_ci	lpfc_sli4_queue_init(phba);
881462306a36Sopenharmony_ci
881562306a36Sopenharmony_ci	/* update host els xri-sgl sizes and mappings */
881662306a36Sopenharmony_ci	rc = lpfc_sli4_els_sgl_update(phba);
881762306a36Sopenharmony_ci	if (unlikely(rc)) {
881862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
881962306a36Sopenharmony_ci				"1400 Failed to update xri-sgl size and "
882062306a36Sopenharmony_ci				"mapping: %d\n", rc);
882162306a36Sopenharmony_ci		goto out_destroy_queue;
882262306a36Sopenharmony_ci	}
882362306a36Sopenharmony_ci
882462306a36Sopenharmony_ci	/* register the els sgl pool to the port */
882562306a36Sopenharmony_ci	rc = lpfc_sli4_repost_sgl_list(phba, &phba->sli4_hba.lpfc_els_sgl_list,
882662306a36Sopenharmony_ci				       phba->sli4_hba.els_xri_cnt);
882762306a36Sopenharmony_ci	if (unlikely(rc < 0)) {
882862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
882962306a36Sopenharmony_ci				"0582 Error %d during els sgl post "
883062306a36Sopenharmony_ci				"operation\n", rc);
883162306a36Sopenharmony_ci		rc = -ENODEV;
883262306a36Sopenharmony_ci		goto out_destroy_queue;
883362306a36Sopenharmony_ci	}
883462306a36Sopenharmony_ci	phba->sli4_hba.els_xri_cnt = rc;
883562306a36Sopenharmony_ci
883662306a36Sopenharmony_ci	if (phba->nvmet_support) {
883762306a36Sopenharmony_ci		/* update host nvmet xri-sgl sizes and mappings */
883862306a36Sopenharmony_ci		rc = lpfc_sli4_nvmet_sgl_update(phba);
883962306a36Sopenharmony_ci		if (unlikely(rc)) {
884062306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
884162306a36Sopenharmony_ci					"6308 Failed to update nvmet-sgl size "
884262306a36Sopenharmony_ci					"and mapping: %d\n", rc);
884362306a36Sopenharmony_ci			goto out_destroy_queue;
884462306a36Sopenharmony_ci		}
884562306a36Sopenharmony_ci
884662306a36Sopenharmony_ci		/* register the nvmet sgl pool to the port */
884762306a36Sopenharmony_ci		rc = lpfc_sli4_repost_sgl_list(
884862306a36Sopenharmony_ci			phba,
884962306a36Sopenharmony_ci			&phba->sli4_hba.lpfc_nvmet_sgl_list,
885062306a36Sopenharmony_ci			phba->sli4_hba.nvmet_xri_cnt);
885162306a36Sopenharmony_ci		if (unlikely(rc < 0)) {
885262306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
885362306a36Sopenharmony_ci					"3117 Error %d during nvmet "
885462306a36Sopenharmony_ci					"sgl post\n", rc);
885562306a36Sopenharmony_ci			rc = -ENODEV;
885662306a36Sopenharmony_ci			goto out_destroy_queue;
885762306a36Sopenharmony_ci		}
885862306a36Sopenharmony_ci		phba->sli4_hba.nvmet_xri_cnt = rc;
885962306a36Sopenharmony_ci
886062306a36Sopenharmony_ci		/* We allocate an iocbq for every receive context SGL.
886162306a36Sopenharmony_ci		 * The additional allocation is for abort and ls handling.
886262306a36Sopenharmony_ci		 */
886362306a36Sopenharmony_ci		cnt = phba->sli4_hba.nvmet_xri_cnt +
886462306a36Sopenharmony_ci			phba->sli4_hba.max_cfg_param.max_xri;
886562306a36Sopenharmony_ci	} else {
886662306a36Sopenharmony_ci		/* update host common xri-sgl sizes and mappings */
886762306a36Sopenharmony_ci		rc = lpfc_sli4_io_sgl_update(phba);
886862306a36Sopenharmony_ci		if (unlikely(rc)) {
886962306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
887062306a36Sopenharmony_ci					"6082 Failed to update nvme-sgl size "
887162306a36Sopenharmony_ci					"and mapping: %d\n", rc);
887262306a36Sopenharmony_ci			goto out_destroy_queue;
887362306a36Sopenharmony_ci		}
887462306a36Sopenharmony_ci
887562306a36Sopenharmony_ci		/* register the allocated common sgl pool to the port */
887662306a36Sopenharmony_ci		rc = lpfc_sli4_repost_io_sgl_list(phba);
887762306a36Sopenharmony_ci		if (unlikely(rc)) {
887862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
887962306a36Sopenharmony_ci					"6116 Error %d during nvme sgl post "
888062306a36Sopenharmony_ci					"operation\n", rc);
888162306a36Sopenharmony_ci			/* Some NVME buffers were moved to abort nvme list */
888262306a36Sopenharmony_ci			/* A pci function reset will repost them */
888362306a36Sopenharmony_ci			rc = -ENODEV;
888462306a36Sopenharmony_ci			goto out_destroy_queue;
888562306a36Sopenharmony_ci		}
888662306a36Sopenharmony_ci		/* Each lpfc_io_buf job structure has an iocbq element.
888762306a36Sopenharmony_ci		 * This cnt provides for abort, els, ct and ls requests.
888862306a36Sopenharmony_ci		 */
888962306a36Sopenharmony_ci		cnt = phba->sli4_hba.max_cfg_param.max_xri;
889062306a36Sopenharmony_ci	}
889162306a36Sopenharmony_ci
889262306a36Sopenharmony_ci	if (!phba->sli.iocbq_lookup) {
889362306a36Sopenharmony_ci		/* Initialize and populate the iocb list per host */
889462306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
889562306a36Sopenharmony_ci				"2821 initialize iocb list with %d entries\n",
889662306a36Sopenharmony_ci				cnt);
889762306a36Sopenharmony_ci		rc = lpfc_init_iocb_list(phba, cnt);
889862306a36Sopenharmony_ci		if (rc) {
889962306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
890062306a36Sopenharmony_ci					"1413 Failed to init iocb list.\n");
890162306a36Sopenharmony_ci			goto out_destroy_queue;
890262306a36Sopenharmony_ci		}
890362306a36Sopenharmony_ci	}
890462306a36Sopenharmony_ci
890562306a36Sopenharmony_ci	if (phba->nvmet_support)
890662306a36Sopenharmony_ci		lpfc_nvmet_create_targetport(phba);
890762306a36Sopenharmony_ci
890862306a36Sopenharmony_ci	if (phba->nvmet_support && phba->cfg_nvmet_mrq) {
890962306a36Sopenharmony_ci		/* Post initial buffers to all RQs created */
891062306a36Sopenharmony_ci		for (i = 0; i < phba->cfg_nvmet_mrq; i++) {
891162306a36Sopenharmony_ci			rqbp = phba->sli4_hba.nvmet_mrq_hdr[i]->rqbp;
891262306a36Sopenharmony_ci			INIT_LIST_HEAD(&rqbp->rqb_buffer_list);
891362306a36Sopenharmony_ci			rqbp->rqb_alloc_buffer = lpfc_sli4_nvmet_alloc;
891462306a36Sopenharmony_ci			rqbp->rqb_free_buffer = lpfc_sli4_nvmet_free;
891562306a36Sopenharmony_ci			rqbp->entry_count = LPFC_NVMET_RQE_DEF_COUNT;
891662306a36Sopenharmony_ci			rqbp->buffer_count = 0;
891762306a36Sopenharmony_ci
891862306a36Sopenharmony_ci			lpfc_post_rq_buffer(
891962306a36Sopenharmony_ci				phba, phba->sli4_hba.nvmet_mrq_hdr[i],
892062306a36Sopenharmony_ci				phba->sli4_hba.nvmet_mrq_data[i],
892162306a36Sopenharmony_ci				phba->cfg_nvmet_mrq_post, i);
892262306a36Sopenharmony_ci		}
892362306a36Sopenharmony_ci	}
892462306a36Sopenharmony_ci
892562306a36Sopenharmony_ci	/* Post the rpi header region to the device. */
892662306a36Sopenharmony_ci	rc = lpfc_sli4_post_all_rpi_hdrs(phba);
892762306a36Sopenharmony_ci	if (unlikely(rc)) {
892862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
892962306a36Sopenharmony_ci				"0393 Error %d during rpi post operation\n",
893062306a36Sopenharmony_ci				rc);
893162306a36Sopenharmony_ci		rc = -ENODEV;
893262306a36Sopenharmony_ci		goto out_free_iocblist;
893362306a36Sopenharmony_ci	}
893462306a36Sopenharmony_ci	lpfc_sli4_node_prep(phba);
893562306a36Sopenharmony_ci
893662306a36Sopenharmony_ci	if (!(phba->hba_flag & HBA_FCOE_MODE)) {
893762306a36Sopenharmony_ci		if ((phba->nvmet_support == 0) || (phba->cfg_nvmet_mrq == 1)) {
893862306a36Sopenharmony_ci			/*
893962306a36Sopenharmony_ci			 * The FC Port needs to register FCFI (index 0)
894062306a36Sopenharmony_ci			 */
894162306a36Sopenharmony_ci			lpfc_reg_fcfi(phba, mboxq);
894262306a36Sopenharmony_ci			mboxq->vport = phba->pport;
894362306a36Sopenharmony_ci			rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
894462306a36Sopenharmony_ci			if (rc != MBX_SUCCESS)
894562306a36Sopenharmony_ci				goto out_unset_queue;
894662306a36Sopenharmony_ci			rc = 0;
894762306a36Sopenharmony_ci			phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi,
894862306a36Sopenharmony_ci						&mboxq->u.mqe.un.reg_fcfi);
894962306a36Sopenharmony_ci		} else {
895062306a36Sopenharmony_ci			/* We are a NVME Target mode with MRQ > 1 */
895162306a36Sopenharmony_ci
895262306a36Sopenharmony_ci			/* First register the FCFI */
895362306a36Sopenharmony_ci			lpfc_reg_fcfi_mrq(phba, mboxq, 0);
895462306a36Sopenharmony_ci			mboxq->vport = phba->pport;
895562306a36Sopenharmony_ci			rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
895662306a36Sopenharmony_ci			if (rc != MBX_SUCCESS)
895762306a36Sopenharmony_ci				goto out_unset_queue;
895862306a36Sopenharmony_ci			rc = 0;
895962306a36Sopenharmony_ci			phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_mrq_fcfi,
896062306a36Sopenharmony_ci						&mboxq->u.mqe.un.reg_fcfi_mrq);
896162306a36Sopenharmony_ci
896262306a36Sopenharmony_ci			/* Next register the MRQs */
896362306a36Sopenharmony_ci			lpfc_reg_fcfi_mrq(phba, mboxq, 1);
896462306a36Sopenharmony_ci			mboxq->vport = phba->pport;
896562306a36Sopenharmony_ci			rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
896662306a36Sopenharmony_ci			if (rc != MBX_SUCCESS)
896762306a36Sopenharmony_ci				goto out_unset_queue;
896862306a36Sopenharmony_ci			rc = 0;
896962306a36Sopenharmony_ci		}
897062306a36Sopenharmony_ci		/* Check if the port is configured to be disabled */
897162306a36Sopenharmony_ci		lpfc_sli_read_link_ste(phba);
897262306a36Sopenharmony_ci	}
897362306a36Sopenharmony_ci
897462306a36Sopenharmony_ci	/* Don't post more new bufs if repost already recovered
897562306a36Sopenharmony_ci	 * the nvme sgls.
897662306a36Sopenharmony_ci	 */
897762306a36Sopenharmony_ci	if (phba->nvmet_support == 0) {
897862306a36Sopenharmony_ci		if (phba->sli4_hba.io_xri_cnt == 0) {
897962306a36Sopenharmony_ci			len = lpfc_new_io_buf(
898062306a36Sopenharmony_ci					      phba, phba->sli4_hba.io_xri_max);
898162306a36Sopenharmony_ci			if (len == 0) {
898262306a36Sopenharmony_ci				rc = -ENOMEM;
898362306a36Sopenharmony_ci				goto out_unset_queue;
898462306a36Sopenharmony_ci			}
898562306a36Sopenharmony_ci
898662306a36Sopenharmony_ci			if (phba->cfg_xri_rebalancing)
898762306a36Sopenharmony_ci				lpfc_create_multixri_pools(phba);
898862306a36Sopenharmony_ci		}
898962306a36Sopenharmony_ci	} else {
899062306a36Sopenharmony_ci		phba->cfg_xri_rebalancing = 0;
899162306a36Sopenharmony_ci	}
899262306a36Sopenharmony_ci
899362306a36Sopenharmony_ci	/* Allow asynchronous mailbox command to go through */
899462306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
899562306a36Sopenharmony_ci	phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK;
899662306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
899762306a36Sopenharmony_ci
899862306a36Sopenharmony_ci	/* Post receive buffers to the device */
899962306a36Sopenharmony_ci	lpfc_sli4_rb_setup(phba);
900062306a36Sopenharmony_ci
900162306a36Sopenharmony_ci	/* Reset HBA FCF states after HBA reset */
900262306a36Sopenharmony_ci	phba->fcf.fcf_flag = 0;
900362306a36Sopenharmony_ci	phba->fcf.current_rec.flag = 0;
900462306a36Sopenharmony_ci
900562306a36Sopenharmony_ci	/* Start the ELS watchdog timer */
900662306a36Sopenharmony_ci	mod_timer(&vport->els_tmofunc,
900762306a36Sopenharmony_ci		  jiffies + msecs_to_jiffies(1000 * (phba->fc_ratov * 2)));
900862306a36Sopenharmony_ci
900962306a36Sopenharmony_ci	/* Start heart beat timer */
901062306a36Sopenharmony_ci	mod_timer(&phba->hb_tmofunc,
901162306a36Sopenharmony_ci		  jiffies + msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL));
901262306a36Sopenharmony_ci	phba->hba_flag &= ~(HBA_HBEAT_INP | HBA_HBEAT_TMO);
901362306a36Sopenharmony_ci	phba->last_completion_time = jiffies;
901462306a36Sopenharmony_ci
901562306a36Sopenharmony_ci	/* start eq_delay heartbeat */
901662306a36Sopenharmony_ci	if (phba->cfg_auto_imax)
901762306a36Sopenharmony_ci		queue_delayed_work(phba->wq, &phba->eq_delay_work,
901862306a36Sopenharmony_ci				   msecs_to_jiffies(LPFC_EQ_DELAY_MSECS));
901962306a36Sopenharmony_ci
902062306a36Sopenharmony_ci	/* start per phba idle_stat_delay heartbeat */
902162306a36Sopenharmony_ci	lpfc_init_idle_stat_hb(phba);
902262306a36Sopenharmony_ci
902362306a36Sopenharmony_ci	/* Start error attention (ERATT) polling timer */
902462306a36Sopenharmony_ci	mod_timer(&phba->eratt_poll,
902562306a36Sopenharmony_ci		  jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval));
902662306a36Sopenharmony_ci
902762306a36Sopenharmony_ci	/*
902862306a36Sopenharmony_ci	 * The port is ready, set the host's link state to LINK_DOWN
902962306a36Sopenharmony_ci	 * in preparation for link interrupts.
903062306a36Sopenharmony_ci	 */
903162306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
903262306a36Sopenharmony_ci	phba->link_state = LPFC_LINK_DOWN;
903362306a36Sopenharmony_ci
903462306a36Sopenharmony_ci	/* Check if physical ports are trunked */
903562306a36Sopenharmony_ci	if (bf_get(lpfc_conf_trunk_port0, &phba->sli4_hba))
903662306a36Sopenharmony_ci		phba->trunk_link.link0.state = LPFC_LINK_DOWN;
903762306a36Sopenharmony_ci	if (bf_get(lpfc_conf_trunk_port1, &phba->sli4_hba))
903862306a36Sopenharmony_ci		phba->trunk_link.link1.state = LPFC_LINK_DOWN;
903962306a36Sopenharmony_ci	if (bf_get(lpfc_conf_trunk_port2, &phba->sli4_hba))
904062306a36Sopenharmony_ci		phba->trunk_link.link2.state = LPFC_LINK_DOWN;
904162306a36Sopenharmony_ci	if (bf_get(lpfc_conf_trunk_port3, &phba->sli4_hba))
904262306a36Sopenharmony_ci		phba->trunk_link.link3.state = LPFC_LINK_DOWN;
904362306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
904462306a36Sopenharmony_ci
904562306a36Sopenharmony_ci	/* Arm the CQs and then EQs on device */
904662306a36Sopenharmony_ci	lpfc_sli4_arm_cqeq_intr(phba);
904762306a36Sopenharmony_ci
904862306a36Sopenharmony_ci	/* Indicate device interrupt mode */
904962306a36Sopenharmony_ci	phba->sli4_hba.intr_enable = 1;
905062306a36Sopenharmony_ci
905162306a36Sopenharmony_ci	/* Setup CMF after HBA is initialized */
905262306a36Sopenharmony_ci	lpfc_cmf_setup(phba);
905362306a36Sopenharmony_ci
905462306a36Sopenharmony_ci	if (!(phba->hba_flag & HBA_FCOE_MODE) &&
905562306a36Sopenharmony_ci	    (phba->hba_flag & LINK_DISABLED)) {
905662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
905762306a36Sopenharmony_ci				"3103 Adapter Link is disabled.\n");
905862306a36Sopenharmony_ci		lpfc_down_link(phba, mboxq);
905962306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
906062306a36Sopenharmony_ci		if (rc != MBX_SUCCESS) {
906162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
906262306a36Sopenharmony_ci					"3104 Adapter failed to issue "
906362306a36Sopenharmony_ci					"DOWN_LINK mbox cmd, rc:x%x\n", rc);
906462306a36Sopenharmony_ci			goto out_io_buff_free;
906562306a36Sopenharmony_ci		}
906662306a36Sopenharmony_ci	} else if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) {
906762306a36Sopenharmony_ci		/* don't perform init_link on SLI4 FC port loopback test */
906862306a36Sopenharmony_ci		if (!(phba->link_flag & LS_LOOPBACK_MODE)) {
906962306a36Sopenharmony_ci			rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
907062306a36Sopenharmony_ci			if (rc)
907162306a36Sopenharmony_ci				goto out_io_buff_free;
907262306a36Sopenharmony_ci		}
907362306a36Sopenharmony_ci	}
907462306a36Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
907562306a36Sopenharmony_ci
907662306a36Sopenharmony_ci	/* Enable RAS FW log support */
907762306a36Sopenharmony_ci	lpfc_sli4_ras_setup(phba);
907862306a36Sopenharmony_ci
907962306a36Sopenharmony_ci	phba->hba_flag |= HBA_SETUP;
908062306a36Sopenharmony_ci	return rc;
908162306a36Sopenharmony_ci
908262306a36Sopenharmony_ciout_io_buff_free:
908362306a36Sopenharmony_ci	/* Free allocated IO Buffers */
908462306a36Sopenharmony_ci	lpfc_io_free(phba);
908562306a36Sopenharmony_ciout_unset_queue:
908662306a36Sopenharmony_ci	/* Unset all the queues set up in this routine when error out */
908762306a36Sopenharmony_ci	lpfc_sli4_queue_unset(phba);
908862306a36Sopenharmony_ciout_free_iocblist:
908962306a36Sopenharmony_ci	lpfc_free_iocb_list(phba);
909062306a36Sopenharmony_ciout_destroy_queue:
909162306a36Sopenharmony_ci	lpfc_sli4_queue_destroy(phba);
909262306a36Sopenharmony_ciout_stop_timers:
909362306a36Sopenharmony_ci	lpfc_stop_hba_timers(phba);
909462306a36Sopenharmony_ciout_free_mbox:
909562306a36Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
909662306a36Sopenharmony_ci	return rc;
909762306a36Sopenharmony_ci}
909862306a36Sopenharmony_ci
909962306a36Sopenharmony_ci/**
910062306a36Sopenharmony_ci * lpfc_mbox_timeout - Timeout call back function for mbox timer
910162306a36Sopenharmony_ci * @t: Context to fetch pointer to hba structure from.
910262306a36Sopenharmony_ci *
910362306a36Sopenharmony_ci * This is the callback function for mailbox timer. The mailbox
910462306a36Sopenharmony_ci * timer is armed when a new mailbox command is issued and the timer
910562306a36Sopenharmony_ci * is deleted when the mailbox complete. The function is called by
910662306a36Sopenharmony_ci * the kernel timer code when a mailbox does not complete within
910762306a36Sopenharmony_ci * expected time. This function wakes up the worker thread to
910862306a36Sopenharmony_ci * process the mailbox timeout and returns. All the processing is
910962306a36Sopenharmony_ci * done by the worker thread function lpfc_mbox_timeout_handler.
911062306a36Sopenharmony_ci **/
911162306a36Sopenharmony_civoid
911262306a36Sopenharmony_cilpfc_mbox_timeout(struct timer_list *t)
911362306a36Sopenharmony_ci{
911462306a36Sopenharmony_ci	struct lpfc_hba  *phba = from_timer(phba, t, sli.mbox_tmo);
911562306a36Sopenharmony_ci	unsigned long iflag;
911662306a36Sopenharmony_ci	uint32_t tmo_posted;
911762306a36Sopenharmony_ci
911862306a36Sopenharmony_ci	spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
911962306a36Sopenharmony_ci	tmo_posted = phba->pport->work_port_events & WORKER_MBOX_TMO;
912062306a36Sopenharmony_ci	if (!tmo_posted)
912162306a36Sopenharmony_ci		phba->pport->work_port_events |= WORKER_MBOX_TMO;
912262306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
912362306a36Sopenharmony_ci
912462306a36Sopenharmony_ci	if (!tmo_posted)
912562306a36Sopenharmony_ci		lpfc_worker_wake_up(phba);
912662306a36Sopenharmony_ci	return;
912762306a36Sopenharmony_ci}
912862306a36Sopenharmony_ci
912962306a36Sopenharmony_ci/**
913062306a36Sopenharmony_ci * lpfc_sli4_mbox_completions_pending - check to see if any mailbox completions
913162306a36Sopenharmony_ci *                                    are pending
913262306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
913362306a36Sopenharmony_ci *
913462306a36Sopenharmony_ci * This function checks if any mailbox completions are present on the mailbox
913562306a36Sopenharmony_ci * completion queue.
913662306a36Sopenharmony_ci **/
913762306a36Sopenharmony_cistatic bool
913862306a36Sopenharmony_cilpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
913962306a36Sopenharmony_ci{
914062306a36Sopenharmony_ci
914162306a36Sopenharmony_ci	uint32_t idx;
914262306a36Sopenharmony_ci	struct lpfc_queue *mcq;
914362306a36Sopenharmony_ci	struct lpfc_mcqe *mcqe;
914462306a36Sopenharmony_ci	bool pending_completions = false;
914562306a36Sopenharmony_ci	uint8_t	qe_valid;
914662306a36Sopenharmony_ci
914762306a36Sopenharmony_ci	if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4))
914862306a36Sopenharmony_ci		return false;
914962306a36Sopenharmony_ci
915062306a36Sopenharmony_ci	/* Check for completions on mailbox completion queue */
915162306a36Sopenharmony_ci
915262306a36Sopenharmony_ci	mcq = phba->sli4_hba.mbx_cq;
915362306a36Sopenharmony_ci	idx = mcq->hba_index;
915462306a36Sopenharmony_ci	qe_valid = mcq->qe_valid;
915562306a36Sopenharmony_ci	while (bf_get_le32(lpfc_cqe_valid,
915662306a36Sopenharmony_ci	       (struct lpfc_cqe *)lpfc_sli4_qe(mcq, idx)) == qe_valid) {
915762306a36Sopenharmony_ci		mcqe = (struct lpfc_mcqe *)(lpfc_sli4_qe(mcq, idx));
915862306a36Sopenharmony_ci		if (bf_get_le32(lpfc_trailer_completed, mcqe) &&
915962306a36Sopenharmony_ci		    (!bf_get_le32(lpfc_trailer_async, mcqe))) {
916062306a36Sopenharmony_ci			pending_completions = true;
916162306a36Sopenharmony_ci			break;
916262306a36Sopenharmony_ci		}
916362306a36Sopenharmony_ci		idx = (idx + 1) % mcq->entry_count;
916462306a36Sopenharmony_ci		if (mcq->hba_index == idx)
916562306a36Sopenharmony_ci			break;
916662306a36Sopenharmony_ci
916762306a36Sopenharmony_ci		/* if the index wrapped around, toggle the valid bit */
916862306a36Sopenharmony_ci		if (phba->sli4_hba.pc_sli4_params.cqav && !idx)
916962306a36Sopenharmony_ci			qe_valid = (qe_valid) ? 0 : 1;
917062306a36Sopenharmony_ci	}
917162306a36Sopenharmony_ci	return pending_completions;
917262306a36Sopenharmony_ci
917362306a36Sopenharmony_ci}
917462306a36Sopenharmony_ci
917562306a36Sopenharmony_ci/**
917662306a36Sopenharmony_ci * lpfc_sli4_process_missed_mbox_completions - process mbox completions
917762306a36Sopenharmony_ci *					      that were missed.
917862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
917962306a36Sopenharmony_ci *
918062306a36Sopenharmony_ci * For sli4, it is possible to miss an interrupt. As such mbox completions
918162306a36Sopenharmony_ci * maybe missed causing erroneous mailbox timeouts to occur. This function
918262306a36Sopenharmony_ci * checks to see if mbox completions are on the mailbox completion queue
918362306a36Sopenharmony_ci * and will process all the completions associated with the eq for the
918462306a36Sopenharmony_ci * mailbox completion queue.
918562306a36Sopenharmony_ci **/
918662306a36Sopenharmony_cistatic bool
918762306a36Sopenharmony_cilpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
918862306a36Sopenharmony_ci{
918962306a36Sopenharmony_ci	struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
919062306a36Sopenharmony_ci	uint32_t eqidx;
919162306a36Sopenharmony_ci	struct lpfc_queue *fpeq = NULL;
919262306a36Sopenharmony_ci	struct lpfc_queue *eq;
919362306a36Sopenharmony_ci	bool mbox_pending;
919462306a36Sopenharmony_ci
919562306a36Sopenharmony_ci	if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4))
919662306a36Sopenharmony_ci		return false;
919762306a36Sopenharmony_ci
919862306a36Sopenharmony_ci	/* Find the EQ associated with the mbox CQ */
919962306a36Sopenharmony_ci	if (sli4_hba->hdwq) {
920062306a36Sopenharmony_ci		for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++) {
920162306a36Sopenharmony_ci			eq = phba->sli4_hba.hba_eq_hdl[eqidx].eq;
920262306a36Sopenharmony_ci			if (eq && eq->queue_id == sli4_hba->mbx_cq->assoc_qid) {
920362306a36Sopenharmony_ci				fpeq = eq;
920462306a36Sopenharmony_ci				break;
920562306a36Sopenharmony_ci			}
920662306a36Sopenharmony_ci		}
920762306a36Sopenharmony_ci	}
920862306a36Sopenharmony_ci	if (!fpeq)
920962306a36Sopenharmony_ci		return false;
921062306a36Sopenharmony_ci
921162306a36Sopenharmony_ci	/* Turn off interrupts from this EQ */
921262306a36Sopenharmony_ci
921362306a36Sopenharmony_ci	sli4_hba->sli4_eq_clr_intr(fpeq);
921462306a36Sopenharmony_ci
921562306a36Sopenharmony_ci	/* Check to see if a mbox completion is pending */
921662306a36Sopenharmony_ci
921762306a36Sopenharmony_ci	mbox_pending = lpfc_sli4_mbox_completions_pending(phba);
921862306a36Sopenharmony_ci
921962306a36Sopenharmony_ci	/*
922062306a36Sopenharmony_ci	 * If a mbox completion is pending, process all the events on EQ
922162306a36Sopenharmony_ci	 * associated with the mbox completion queue (this could include
922262306a36Sopenharmony_ci	 * mailbox commands, async events, els commands, receive queue data
922362306a36Sopenharmony_ci	 * and fcp commands)
922462306a36Sopenharmony_ci	 */
922562306a36Sopenharmony_ci
922662306a36Sopenharmony_ci	if (mbox_pending)
922762306a36Sopenharmony_ci		/* process and rearm the EQ */
922862306a36Sopenharmony_ci		lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM,
922962306a36Sopenharmony_ci				     LPFC_QUEUE_WORK);
923062306a36Sopenharmony_ci	else
923162306a36Sopenharmony_ci		/* Always clear and re-arm the EQ */
923262306a36Sopenharmony_ci		sli4_hba->sli4_write_eq_db(phba, fpeq, 0, LPFC_QUEUE_REARM);
923362306a36Sopenharmony_ci
923462306a36Sopenharmony_ci	return mbox_pending;
923562306a36Sopenharmony_ci
923662306a36Sopenharmony_ci}
923762306a36Sopenharmony_ci
923862306a36Sopenharmony_ci/**
923962306a36Sopenharmony_ci * lpfc_mbox_timeout_handler - Worker thread function to handle mailbox timeout
924062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
924162306a36Sopenharmony_ci *
924262306a36Sopenharmony_ci * This function is called from worker thread when a mailbox command times out.
924362306a36Sopenharmony_ci * The caller is not required to hold any locks. This function will reset the
924462306a36Sopenharmony_ci * HBA and recover all the pending commands.
924562306a36Sopenharmony_ci **/
924662306a36Sopenharmony_civoid
924762306a36Sopenharmony_cilpfc_mbox_timeout_handler(struct lpfc_hba *phba)
924862306a36Sopenharmony_ci{
924962306a36Sopenharmony_ci	LPFC_MBOXQ_t *pmbox = phba->sli.mbox_active;
925062306a36Sopenharmony_ci	MAILBOX_t *mb = NULL;
925162306a36Sopenharmony_ci
925262306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
925362306a36Sopenharmony_ci
925462306a36Sopenharmony_ci	/* If the mailbox completed, process the completion */
925562306a36Sopenharmony_ci	lpfc_sli4_process_missed_mbox_completions(phba);
925662306a36Sopenharmony_ci
925762306a36Sopenharmony_ci	if (!(psli->sli_flag & LPFC_SLI_ACTIVE))
925862306a36Sopenharmony_ci		return;
925962306a36Sopenharmony_ci
926062306a36Sopenharmony_ci	if (pmbox != NULL)
926162306a36Sopenharmony_ci		mb = &pmbox->u.mb;
926262306a36Sopenharmony_ci	/* Check the pmbox pointer first.  There is a race condition
926362306a36Sopenharmony_ci	 * between the mbox timeout handler getting executed in the
926462306a36Sopenharmony_ci	 * worklist and the mailbox actually completing. When this
926562306a36Sopenharmony_ci	 * race condition occurs, the mbox_active will be NULL.
926662306a36Sopenharmony_ci	 */
926762306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
926862306a36Sopenharmony_ci	if (pmbox == NULL) {
926962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING,
927062306a36Sopenharmony_ci				LOG_MBOX | LOG_SLI,
927162306a36Sopenharmony_ci				"0353 Active Mailbox cleared - mailbox timeout "
927262306a36Sopenharmony_ci				"exiting\n");
927362306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
927462306a36Sopenharmony_ci		return;
927562306a36Sopenharmony_ci	}
927662306a36Sopenharmony_ci
927762306a36Sopenharmony_ci	/* Mbox cmd <mbxCommand> timeout */
927862306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
927962306a36Sopenharmony_ci			"0310 Mailbox command x%x timeout Data: x%x x%x x%px\n",
928062306a36Sopenharmony_ci			mb->mbxCommand,
928162306a36Sopenharmony_ci			phba->pport->port_state,
928262306a36Sopenharmony_ci			phba->sli.sli_flag,
928362306a36Sopenharmony_ci			phba->sli.mbox_active);
928462306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
928562306a36Sopenharmony_ci
928662306a36Sopenharmony_ci	/* Setting state unknown so lpfc_sli_abort_iocb_ring
928762306a36Sopenharmony_ci	 * would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing
928862306a36Sopenharmony_ci	 * it to fail all outstanding SCSI IO.
928962306a36Sopenharmony_ci	 */
929062306a36Sopenharmony_ci	set_bit(MBX_TMO_ERR, &phba->bit_flags);
929162306a36Sopenharmony_ci	spin_lock_irq(&phba->pport->work_port_lock);
929262306a36Sopenharmony_ci	phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
929362306a36Sopenharmony_ci	spin_unlock_irq(&phba->pport->work_port_lock);
929462306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
929562306a36Sopenharmony_ci	phba->link_state = LPFC_LINK_UNKNOWN;
929662306a36Sopenharmony_ci	psli->sli_flag &= ~LPFC_SLI_ACTIVE;
929762306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
929862306a36Sopenharmony_ci
929962306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
930062306a36Sopenharmony_ci			"0345 Resetting board due to mailbox timeout\n");
930162306a36Sopenharmony_ci
930262306a36Sopenharmony_ci	/* Reset the HBA device */
930362306a36Sopenharmony_ci	lpfc_reset_hba(phba);
930462306a36Sopenharmony_ci}
930562306a36Sopenharmony_ci
930662306a36Sopenharmony_ci/**
930762306a36Sopenharmony_ci * lpfc_sli_issue_mbox_s3 - Issue an SLI3 mailbox command to firmware
930862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
930962306a36Sopenharmony_ci * @pmbox: Pointer to mailbox object.
931062306a36Sopenharmony_ci * @flag: Flag indicating how the mailbox need to be processed.
931162306a36Sopenharmony_ci *
931262306a36Sopenharmony_ci * This function is called by discovery code and HBA management code
931362306a36Sopenharmony_ci * to submit a mailbox command to firmware with SLI-3 interface spec. This
931462306a36Sopenharmony_ci * function gets the hbalock to protect the data structures.
931562306a36Sopenharmony_ci * The mailbox command can be submitted in polling mode, in which case
931662306a36Sopenharmony_ci * this function will wait in a polling loop for the completion of the
931762306a36Sopenharmony_ci * mailbox.
931862306a36Sopenharmony_ci * If the mailbox is submitted in no_wait mode (not polling) the
931962306a36Sopenharmony_ci * function will submit the command and returns immediately without waiting
932062306a36Sopenharmony_ci * for the mailbox completion. The no_wait is supported only when HBA
932162306a36Sopenharmony_ci * is in SLI2/SLI3 mode - interrupts are enabled.
932262306a36Sopenharmony_ci * The SLI interface allows only one mailbox pending at a time. If the
932362306a36Sopenharmony_ci * mailbox is issued in polling mode and there is already a mailbox
932462306a36Sopenharmony_ci * pending, then the function will return an error. If the mailbox is issued
932562306a36Sopenharmony_ci * in NO_WAIT mode and there is a mailbox pending already, the function
932662306a36Sopenharmony_ci * will return MBX_BUSY after queuing the mailbox into mailbox queue.
932762306a36Sopenharmony_ci * The sli layer owns the mailbox object until the completion of mailbox
932862306a36Sopenharmony_ci * command if this function return MBX_BUSY or MBX_SUCCESS. For all other
932962306a36Sopenharmony_ci * return codes the caller owns the mailbox command after the return of
933062306a36Sopenharmony_ci * the function.
933162306a36Sopenharmony_ci **/
933262306a36Sopenharmony_cistatic int
933362306a36Sopenharmony_cilpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
933462306a36Sopenharmony_ci		       uint32_t flag)
933562306a36Sopenharmony_ci{
933662306a36Sopenharmony_ci	MAILBOX_t *mbx;
933762306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
933862306a36Sopenharmony_ci	uint32_t status, evtctr;
933962306a36Sopenharmony_ci	uint32_t ha_copy, hc_copy;
934062306a36Sopenharmony_ci	int i;
934162306a36Sopenharmony_ci	unsigned long timeout;
934262306a36Sopenharmony_ci	unsigned long drvr_flag = 0;
934362306a36Sopenharmony_ci	uint32_t word0, ldata;
934462306a36Sopenharmony_ci	void __iomem *to_slim;
934562306a36Sopenharmony_ci	int processing_queue = 0;
934662306a36Sopenharmony_ci
934762306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, drvr_flag);
934862306a36Sopenharmony_ci	if (!pmbox) {
934962306a36Sopenharmony_ci		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
935062306a36Sopenharmony_ci		/* processing mbox queue from intr_handler */
935162306a36Sopenharmony_ci		if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) {
935262306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
935362306a36Sopenharmony_ci			return MBX_SUCCESS;
935462306a36Sopenharmony_ci		}
935562306a36Sopenharmony_ci		processing_queue = 1;
935662306a36Sopenharmony_ci		pmbox = lpfc_mbox_get(phba);
935762306a36Sopenharmony_ci		if (!pmbox) {
935862306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
935962306a36Sopenharmony_ci			return MBX_SUCCESS;
936062306a36Sopenharmony_ci		}
936162306a36Sopenharmony_ci	}
936262306a36Sopenharmony_ci
936362306a36Sopenharmony_ci	if (pmbox->mbox_cmpl && pmbox->mbox_cmpl != lpfc_sli_def_mbox_cmpl &&
936462306a36Sopenharmony_ci		pmbox->mbox_cmpl != lpfc_sli_wake_mbox_wait) {
936562306a36Sopenharmony_ci		if(!pmbox->vport) {
936662306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
936762306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR,
936862306a36Sopenharmony_ci					LOG_MBOX | LOG_VPORT,
936962306a36Sopenharmony_ci					"1806 Mbox x%x failed. No vport\n",
937062306a36Sopenharmony_ci					pmbox->u.mb.mbxCommand);
937162306a36Sopenharmony_ci			dump_stack();
937262306a36Sopenharmony_ci			goto out_not_finished;
937362306a36Sopenharmony_ci		}
937462306a36Sopenharmony_ci	}
937562306a36Sopenharmony_ci
937662306a36Sopenharmony_ci	/* If the PCI channel is in offline state, do not post mbox. */
937762306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(phba->pcidev))) {
937862306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
937962306a36Sopenharmony_ci		goto out_not_finished;
938062306a36Sopenharmony_ci	}
938162306a36Sopenharmony_ci
938262306a36Sopenharmony_ci	/* If HBA has a deferred error attention, fail the iocb. */
938362306a36Sopenharmony_ci	if (unlikely(phba->hba_flag & DEFER_ERATT)) {
938462306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
938562306a36Sopenharmony_ci		goto out_not_finished;
938662306a36Sopenharmony_ci	}
938762306a36Sopenharmony_ci
938862306a36Sopenharmony_ci	psli = &phba->sli;
938962306a36Sopenharmony_ci
939062306a36Sopenharmony_ci	mbx = &pmbox->u.mb;
939162306a36Sopenharmony_ci	status = MBX_SUCCESS;
939262306a36Sopenharmony_ci
939362306a36Sopenharmony_ci	if (phba->link_state == LPFC_HBA_ERROR) {
939462306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
939562306a36Sopenharmony_ci
939662306a36Sopenharmony_ci		/* Mbox command <mbxCommand> cannot issue */
939762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
939862306a36Sopenharmony_ci				"(%d):0311 Mailbox command x%x cannot "
939962306a36Sopenharmony_ci				"issue Data: x%x x%x\n",
940062306a36Sopenharmony_ci				pmbox->vport ? pmbox->vport->vpi : 0,
940162306a36Sopenharmony_ci				pmbox->u.mb.mbxCommand, psli->sli_flag, flag);
940262306a36Sopenharmony_ci		goto out_not_finished;
940362306a36Sopenharmony_ci	}
940462306a36Sopenharmony_ci
940562306a36Sopenharmony_ci	if (mbx->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT) {
940662306a36Sopenharmony_ci		if (lpfc_readl(phba->HCregaddr, &hc_copy) ||
940762306a36Sopenharmony_ci			!(hc_copy & HC_MBINT_ENA)) {
940862306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
940962306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
941062306a36Sopenharmony_ci				"(%d):2528 Mailbox command x%x cannot "
941162306a36Sopenharmony_ci				"issue Data: x%x x%x\n",
941262306a36Sopenharmony_ci				pmbox->vport ? pmbox->vport->vpi : 0,
941362306a36Sopenharmony_ci				pmbox->u.mb.mbxCommand, psli->sli_flag, flag);
941462306a36Sopenharmony_ci			goto out_not_finished;
941562306a36Sopenharmony_ci		}
941662306a36Sopenharmony_ci	}
941762306a36Sopenharmony_ci
941862306a36Sopenharmony_ci	if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
941962306a36Sopenharmony_ci		/* Polling for a mbox command when another one is already active
942062306a36Sopenharmony_ci		 * is not allowed in SLI. Also, the driver must have established
942162306a36Sopenharmony_ci		 * SLI2 mode to queue and process multiple mbox commands.
942262306a36Sopenharmony_ci		 */
942362306a36Sopenharmony_ci
942462306a36Sopenharmony_ci		if (flag & MBX_POLL) {
942562306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
942662306a36Sopenharmony_ci
942762306a36Sopenharmony_ci			/* Mbox command <mbxCommand> cannot issue */
942862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
942962306a36Sopenharmony_ci					"(%d):2529 Mailbox command x%x "
943062306a36Sopenharmony_ci					"cannot issue Data: x%x x%x\n",
943162306a36Sopenharmony_ci					pmbox->vport ? pmbox->vport->vpi : 0,
943262306a36Sopenharmony_ci					pmbox->u.mb.mbxCommand,
943362306a36Sopenharmony_ci					psli->sli_flag, flag);
943462306a36Sopenharmony_ci			goto out_not_finished;
943562306a36Sopenharmony_ci		}
943662306a36Sopenharmony_ci
943762306a36Sopenharmony_ci		if (!(psli->sli_flag & LPFC_SLI_ACTIVE)) {
943862306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
943962306a36Sopenharmony_ci			/* Mbox command <mbxCommand> cannot issue */
944062306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
944162306a36Sopenharmony_ci					"(%d):2530 Mailbox command x%x "
944262306a36Sopenharmony_ci					"cannot issue Data: x%x x%x\n",
944362306a36Sopenharmony_ci					pmbox->vport ? pmbox->vport->vpi : 0,
944462306a36Sopenharmony_ci					pmbox->u.mb.mbxCommand,
944562306a36Sopenharmony_ci					psli->sli_flag, flag);
944662306a36Sopenharmony_ci			goto out_not_finished;
944762306a36Sopenharmony_ci		}
944862306a36Sopenharmony_ci
944962306a36Sopenharmony_ci		/* Another mailbox command is still being processed, queue this
945062306a36Sopenharmony_ci		 * command to be processed later.
945162306a36Sopenharmony_ci		 */
945262306a36Sopenharmony_ci		lpfc_mbox_put(phba, pmbox);
945362306a36Sopenharmony_ci
945462306a36Sopenharmony_ci		/* Mbox cmd issue - BUSY */
945562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
945662306a36Sopenharmony_ci				"(%d):0308 Mbox cmd issue - BUSY Data: "
945762306a36Sopenharmony_ci				"x%x x%x x%x x%x\n",
945862306a36Sopenharmony_ci				pmbox->vport ? pmbox->vport->vpi : 0xffffff,
945962306a36Sopenharmony_ci				mbx->mbxCommand,
946062306a36Sopenharmony_ci				phba->pport ? phba->pport->port_state : 0xff,
946162306a36Sopenharmony_ci				psli->sli_flag, flag);
946262306a36Sopenharmony_ci
946362306a36Sopenharmony_ci		psli->slistat.mbox_busy++;
946462306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
946562306a36Sopenharmony_ci
946662306a36Sopenharmony_ci		if (pmbox->vport) {
946762306a36Sopenharmony_ci			lpfc_debugfs_disc_trc(pmbox->vport,
946862306a36Sopenharmony_ci				LPFC_DISC_TRC_MBOX_VPORT,
946962306a36Sopenharmony_ci				"MBOX Bsy vport:  cmd:x%x mb:x%x x%x",
947062306a36Sopenharmony_ci				(uint32_t)mbx->mbxCommand,
947162306a36Sopenharmony_ci				mbx->un.varWords[0], mbx->un.varWords[1]);
947262306a36Sopenharmony_ci		}
947362306a36Sopenharmony_ci		else {
947462306a36Sopenharmony_ci			lpfc_debugfs_disc_trc(phba->pport,
947562306a36Sopenharmony_ci				LPFC_DISC_TRC_MBOX,
947662306a36Sopenharmony_ci				"MBOX Bsy:        cmd:x%x mb:x%x x%x",
947762306a36Sopenharmony_ci				(uint32_t)mbx->mbxCommand,
947862306a36Sopenharmony_ci				mbx->un.varWords[0], mbx->un.varWords[1]);
947962306a36Sopenharmony_ci		}
948062306a36Sopenharmony_ci
948162306a36Sopenharmony_ci		return MBX_BUSY;
948262306a36Sopenharmony_ci	}
948362306a36Sopenharmony_ci
948462306a36Sopenharmony_ci	psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
948562306a36Sopenharmony_ci
948662306a36Sopenharmony_ci	/* If we are not polling, we MUST be in SLI2 mode */
948762306a36Sopenharmony_ci	if (flag != MBX_POLL) {
948862306a36Sopenharmony_ci		if (!(psli->sli_flag & LPFC_SLI_ACTIVE) &&
948962306a36Sopenharmony_ci		    (mbx->mbxCommand != MBX_KILL_BOARD)) {
949062306a36Sopenharmony_ci			psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
949162306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
949262306a36Sopenharmony_ci			/* Mbox command <mbxCommand> cannot issue */
949362306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
949462306a36Sopenharmony_ci					"(%d):2531 Mailbox command x%x "
949562306a36Sopenharmony_ci					"cannot issue Data: x%x x%x\n",
949662306a36Sopenharmony_ci					pmbox->vport ? pmbox->vport->vpi : 0,
949762306a36Sopenharmony_ci					pmbox->u.mb.mbxCommand,
949862306a36Sopenharmony_ci					psli->sli_flag, flag);
949962306a36Sopenharmony_ci			goto out_not_finished;
950062306a36Sopenharmony_ci		}
950162306a36Sopenharmony_ci		/* timeout active mbox command */
950262306a36Sopenharmony_ci		timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox) *
950362306a36Sopenharmony_ci					   1000);
950462306a36Sopenharmony_ci		mod_timer(&psli->mbox_tmo, jiffies + timeout);
950562306a36Sopenharmony_ci	}
950662306a36Sopenharmony_ci
950762306a36Sopenharmony_ci	/* Mailbox cmd <cmd> issue */
950862306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
950962306a36Sopenharmony_ci			"(%d):0309 Mailbox cmd x%x issue Data: x%x x%x "
951062306a36Sopenharmony_ci			"x%x\n",
951162306a36Sopenharmony_ci			pmbox->vport ? pmbox->vport->vpi : 0,
951262306a36Sopenharmony_ci			mbx->mbxCommand,
951362306a36Sopenharmony_ci			phba->pport ? phba->pport->port_state : 0xff,
951462306a36Sopenharmony_ci			psli->sli_flag, flag);
951562306a36Sopenharmony_ci
951662306a36Sopenharmony_ci	if (mbx->mbxCommand != MBX_HEARTBEAT) {
951762306a36Sopenharmony_ci		if (pmbox->vport) {
951862306a36Sopenharmony_ci			lpfc_debugfs_disc_trc(pmbox->vport,
951962306a36Sopenharmony_ci				LPFC_DISC_TRC_MBOX_VPORT,
952062306a36Sopenharmony_ci				"MBOX Send vport: cmd:x%x mb:x%x x%x",
952162306a36Sopenharmony_ci				(uint32_t)mbx->mbxCommand,
952262306a36Sopenharmony_ci				mbx->un.varWords[0], mbx->un.varWords[1]);
952362306a36Sopenharmony_ci		}
952462306a36Sopenharmony_ci		else {
952562306a36Sopenharmony_ci			lpfc_debugfs_disc_trc(phba->pport,
952662306a36Sopenharmony_ci				LPFC_DISC_TRC_MBOX,
952762306a36Sopenharmony_ci				"MBOX Send:       cmd:x%x mb:x%x x%x",
952862306a36Sopenharmony_ci				(uint32_t)mbx->mbxCommand,
952962306a36Sopenharmony_ci				mbx->un.varWords[0], mbx->un.varWords[1]);
953062306a36Sopenharmony_ci		}
953162306a36Sopenharmony_ci	}
953262306a36Sopenharmony_ci
953362306a36Sopenharmony_ci	psli->slistat.mbox_cmd++;
953462306a36Sopenharmony_ci	evtctr = psli->slistat.mbox_event;
953562306a36Sopenharmony_ci
953662306a36Sopenharmony_ci	/* next set own bit for the adapter and copy over command word */
953762306a36Sopenharmony_ci	mbx->mbxOwner = OWN_CHIP;
953862306a36Sopenharmony_ci
953962306a36Sopenharmony_ci	if (psli->sli_flag & LPFC_SLI_ACTIVE) {
954062306a36Sopenharmony_ci		/* Populate mbox extension offset word. */
954162306a36Sopenharmony_ci		if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) {
954262306a36Sopenharmony_ci			*(((uint32_t *)mbx) + pmbox->mbox_offset_word)
954362306a36Sopenharmony_ci				= (uint8_t *)phba->mbox_ext
954462306a36Sopenharmony_ci				  - (uint8_t *)phba->mbox;
954562306a36Sopenharmony_ci		}
954662306a36Sopenharmony_ci
954762306a36Sopenharmony_ci		/* Copy the mailbox extension data */
954862306a36Sopenharmony_ci		if (pmbox->in_ext_byte_len && pmbox->ctx_buf) {
954962306a36Sopenharmony_ci			lpfc_sli_pcimem_bcopy(pmbox->ctx_buf,
955062306a36Sopenharmony_ci					      (uint8_t *)phba->mbox_ext,
955162306a36Sopenharmony_ci					      pmbox->in_ext_byte_len);
955262306a36Sopenharmony_ci		}
955362306a36Sopenharmony_ci		/* Copy command data to host SLIM area */
955462306a36Sopenharmony_ci		lpfc_sli_pcimem_bcopy(mbx, phba->mbox, MAILBOX_CMD_SIZE);
955562306a36Sopenharmony_ci	} else {
955662306a36Sopenharmony_ci		/* Populate mbox extension offset word. */
955762306a36Sopenharmony_ci		if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len)
955862306a36Sopenharmony_ci			*(((uint32_t *)mbx) + pmbox->mbox_offset_word)
955962306a36Sopenharmony_ci				= MAILBOX_HBA_EXT_OFFSET;
956062306a36Sopenharmony_ci
956162306a36Sopenharmony_ci		/* Copy the mailbox extension data */
956262306a36Sopenharmony_ci		if (pmbox->in_ext_byte_len && pmbox->ctx_buf)
956362306a36Sopenharmony_ci			lpfc_memcpy_to_slim(phba->MBslimaddr +
956462306a36Sopenharmony_ci				MAILBOX_HBA_EXT_OFFSET,
956562306a36Sopenharmony_ci				pmbox->ctx_buf, pmbox->in_ext_byte_len);
956662306a36Sopenharmony_ci
956762306a36Sopenharmony_ci		if (mbx->mbxCommand == MBX_CONFIG_PORT)
956862306a36Sopenharmony_ci			/* copy command data into host mbox for cmpl */
956962306a36Sopenharmony_ci			lpfc_sli_pcimem_bcopy(mbx, phba->mbox,
957062306a36Sopenharmony_ci					      MAILBOX_CMD_SIZE);
957162306a36Sopenharmony_ci
957262306a36Sopenharmony_ci		/* First copy mbox command data to HBA SLIM, skip past first
957362306a36Sopenharmony_ci		   word */
957462306a36Sopenharmony_ci		to_slim = phba->MBslimaddr + sizeof (uint32_t);
957562306a36Sopenharmony_ci		lpfc_memcpy_to_slim(to_slim, &mbx->un.varWords[0],
957662306a36Sopenharmony_ci			    MAILBOX_CMD_SIZE - sizeof (uint32_t));
957762306a36Sopenharmony_ci
957862306a36Sopenharmony_ci		/* Next copy over first word, with mbxOwner set */
957962306a36Sopenharmony_ci		ldata = *((uint32_t *)mbx);
958062306a36Sopenharmony_ci		to_slim = phba->MBslimaddr;
958162306a36Sopenharmony_ci		writel(ldata, to_slim);
958262306a36Sopenharmony_ci		readl(to_slim); /* flush */
958362306a36Sopenharmony_ci
958462306a36Sopenharmony_ci		if (mbx->mbxCommand == MBX_CONFIG_PORT)
958562306a36Sopenharmony_ci			/* switch over to host mailbox */
958662306a36Sopenharmony_ci			psli->sli_flag |= LPFC_SLI_ACTIVE;
958762306a36Sopenharmony_ci	}
958862306a36Sopenharmony_ci
958962306a36Sopenharmony_ci	wmb();
959062306a36Sopenharmony_ci
959162306a36Sopenharmony_ci	switch (flag) {
959262306a36Sopenharmony_ci	case MBX_NOWAIT:
959362306a36Sopenharmony_ci		/* Set up reference to mailbox command */
959462306a36Sopenharmony_ci		psli->mbox_active = pmbox;
959562306a36Sopenharmony_ci		/* Interrupt board to do it */
959662306a36Sopenharmony_ci		writel(CA_MBATT, phba->CAregaddr);
959762306a36Sopenharmony_ci		readl(phba->CAregaddr); /* flush */
959862306a36Sopenharmony_ci		/* Don't wait for it to finish, just return */
959962306a36Sopenharmony_ci		break;
960062306a36Sopenharmony_ci
960162306a36Sopenharmony_ci	case MBX_POLL:
960262306a36Sopenharmony_ci		/* Set up null reference to mailbox command */
960362306a36Sopenharmony_ci		psli->mbox_active = NULL;
960462306a36Sopenharmony_ci		/* Interrupt board to do it */
960562306a36Sopenharmony_ci		writel(CA_MBATT, phba->CAregaddr);
960662306a36Sopenharmony_ci		readl(phba->CAregaddr); /* flush */
960762306a36Sopenharmony_ci
960862306a36Sopenharmony_ci		if (psli->sli_flag & LPFC_SLI_ACTIVE) {
960962306a36Sopenharmony_ci			/* First read mbox status word */
961062306a36Sopenharmony_ci			word0 = *((uint32_t *)phba->mbox);
961162306a36Sopenharmony_ci			word0 = le32_to_cpu(word0);
961262306a36Sopenharmony_ci		} else {
961362306a36Sopenharmony_ci			/* First read mbox status word */
961462306a36Sopenharmony_ci			if (lpfc_readl(phba->MBslimaddr, &word0)) {
961562306a36Sopenharmony_ci				spin_unlock_irqrestore(&phba->hbalock,
961662306a36Sopenharmony_ci						       drvr_flag);
961762306a36Sopenharmony_ci				goto out_not_finished;
961862306a36Sopenharmony_ci			}
961962306a36Sopenharmony_ci		}
962062306a36Sopenharmony_ci
962162306a36Sopenharmony_ci		/* Read the HBA Host Attention Register */
962262306a36Sopenharmony_ci		if (lpfc_readl(phba->HAregaddr, &ha_copy)) {
962362306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock,
962462306a36Sopenharmony_ci						       drvr_flag);
962562306a36Sopenharmony_ci			goto out_not_finished;
962662306a36Sopenharmony_ci		}
962762306a36Sopenharmony_ci		timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox) *
962862306a36Sopenharmony_ci							1000) + jiffies;
962962306a36Sopenharmony_ci		i = 0;
963062306a36Sopenharmony_ci		/* Wait for command to complete */
963162306a36Sopenharmony_ci		while (((word0 & OWN_CHIP) == OWN_CHIP) ||
963262306a36Sopenharmony_ci		       (!(ha_copy & HA_MBATT) &&
963362306a36Sopenharmony_ci			(phba->link_state > LPFC_WARM_START))) {
963462306a36Sopenharmony_ci			if (time_after(jiffies, timeout)) {
963562306a36Sopenharmony_ci				psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
963662306a36Sopenharmony_ci				spin_unlock_irqrestore(&phba->hbalock,
963762306a36Sopenharmony_ci						       drvr_flag);
963862306a36Sopenharmony_ci				goto out_not_finished;
963962306a36Sopenharmony_ci			}
964062306a36Sopenharmony_ci
964162306a36Sopenharmony_ci			/* Check if we took a mbox interrupt while we were
964262306a36Sopenharmony_ci			   polling */
964362306a36Sopenharmony_ci			if (((word0 & OWN_CHIP) != OWN_CHIP)
964462306a36Sopenharmony_ci			    && (evtctr != psli->slistat.mbox_event))
964562306a36Sopenharmony_ci				break;
964662306a36Sopenharmony_ci
964762306a36Sopenharmony_ci			if (i++ > 10) {
964862306a36Sopenharmony_ci				spin_unlock_irqrestore(&phba->hbalock,
964962306a36Sopenharmony_ci						       drvr_flag);
965062306a36Sopenharmony_ci				msleep(1);
965162306a36Sopenharmony_ci				spin_lock_irqsave(&phba->hbalock, drvr_flag);
965262306a36Sopenharmony_ci			}
965362306a36Sopenharmony_ci
965462306a36Sopenharmony_ci			if (psli->sli_flag & LPFC_SLI_ACTIVE) {
965562306a36Sopenharmony_ci				/* First copy command data */
965662306a36Sopenharmony_ci				word0 = *((uint32_t *)phba->mbox);
965762306a36Sopenharmony_ci				word0 = le32_to_cpu(word0);
965862306a36Sopenharmony_ci				if (mbx->mbxCommand == MBX_CONFIG_PORT) {
965962306a36Sopenharmony_ci					MAILBOX_t *slimmb;
966062306a36Sopenharmony_ci					uint32_t slimword0;
966162306a36Sopenharmony_ci					/* Check real SLIM for any errors */
966262306a36Sopenharmony_ci					slimword0 = readl(phba->MBslimaddr);
966362306a36Sopenharmony_ci					slimmb = (MAILBOX_t *) & slimword0;
966462306a36Sopenharmony_ci					if (((slimword0 & OWN_CHIP) != OWN_CHIP)
966562306a36Sopenharmony_ci					    && slimmb->mbxStatus) {
966662306a36Sopenharmony_ci						psli->sli_flag &=
966762306a36Sopenharmony_ci						    ~LPFC_SLI_ACTIVE;
966862306a36Sopenharmony_ci						word0 = slimword0;
966962306a36Sopenharmony_ci					}
967062306a36Sopenharmony_ci				}
967162306a36Sopenharmony_ci			} else {
967262306a36Sopenharmony_ci				/* First copy command data */
967362306a36Sopenharmony_ci				word0 = readl(phba->MBslimaddr);
967462306a36Sopenharmony_ci			}
967562306a36Sopenharmony_ci			/* Read the HBA Host Attention Register */
967662306a36Sopenharmony_ci			if (lpfc_readl(phba->HAregaddr, &ha_copy)) {
967762306a36Sopenharmony_ci				spin_unlock_irqrestore(&phba->hbalock,
967862306a36Sopenharmony_ci						       drvr_flag);
967962306a36Sopenharmony_ci				goto out_not_finished;
968062306a36Sopenharmony_ci			}
968162306a36Sopenharmony_ci		}
968262306a36Sopenharmony_ci
968362306a36Sopenharmony_ci		if (psli->sli_flag & LPFC_SLI_ACTIVE) {
968462306a36Sopenharmony_ci			/* copy results back to user */
968562306a36Sopenharmony_ci			lpfc_sli_pcimem_bcopy(phba->mbox, mbx,
968662306a36Sopenharmony_ci						MAILBOX_CMD_SIZE);
968762306a36Sopenharmony_ci			/* Copy the mailbox extension data */
968862306a36Sopenharmony_ci			if (pmbox->out_ext_byte_len && pmbox->ctx_buf) {
968962306a36Sopenharmony_ci				lpfc_sli_pcimem_bcopy(phba->mbox_ext,
969062306a36Sopenharmony_ci						      pmbox->ctx_buf,
969162306a36Sopenharmony_ci						      pmbox->out_ext_byte_len);
969262306a36Sopenharmony_ci			}
969362306a36Sopenharmony_ci		} else {
969462306a36Sopenharmony_ci			/* First copy command data */
969562306a36Sopenharmony_ci			lpfc_memcpy_from_slim(mbx, phba->MBslimaddr,
969662306a36Sopenharmony_ci						MAILBOX_CMD_SIZE);
969762306a36Sopenharmony_ci			/* Copy the mailbox extension data */
969862306a36Sopenharmony_ci			if (pmbox->out_ext_byte_len && pmbox->ctx_buf) {
969962306a36Sopenharmony_ci				lpfc_memcpy_from_slim(
970062306a36Sopenharmony_ci					pmbox->ctx_buf,
970162306a36Sopenharmony_ci					phba->MBslimaddr +
970262306a36Sopenharmony_ci					MAILBOX_HBA_EXT_OFFSET,
970362306a36Sopenharmony_ci					pmbox->out_ext_byte_len);
970462306a36Sopenharmony_ci			}
970562306a36Sopenharmony_ci		}
970662306a36Sopenharmony_ci
970762306a36Sopenharmony_ci		writel(HA_MBATT, phba->HAregaddr);
970862306a36Sopenharmony_ci		readl(phba->HAregaddr); /* flush */
970962306a36Sopenharmony_ci
971062306a36Sopenharmony_ci		psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
971162306a36Sopenharmony_ci		status = mbx->mbxStatus;
971262306a36Sopenharmony_ci	}
971362306a36Sopenharmony_ci
971462306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
971562306a36Sopenharmony_ci	return status;
971662306a36Sopenharmony_ci
971762306a36Sopenharmony_ciout_not_finished:
971862306a36Sopenharmony_ci	if (processing_queue) {
971962306a36Sopenharmony_ci		pmbox->u.mb.mbxStatus = MBX_NOT_FINISHED;
972062306a36Sopenharmony_ci		lpfc_mbox_cmpl_put(phba, pmbox);
972162306a36Sopenharmony_ci	}
972262306a36Sopenharmony_ci	return MBX_NOT_FINISHED;
972362306a36Sopenharmony_ci}
972462306a36Sopenharmony_ci
972562306a36Sopenharmony_ci/**
972662306a36Sopenharmony_ci * lpfc_sli4_async_mbox_block - Block posting SLI4 asynchronous mailbox command
972762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
972862306a36Sopenharmony_ci *
972962306a36Sopenharmony_ci * The function blocks the posting of SLI4 asynchronous mailbox commands from
973062306a36Sopenharmony_ci * the driver internal pending mailbox queue. It will then try to wait out the
973162306a36Sopenharmony_ci * possible outstanding mailbox command before return.
973262306a36Sopenharmony_ci *
973362306a36Sopenharmony_ci * Returns:
973462306a36Sopenharmony_ci * 	0 - the outstanding mailbox command completed; otherwise, the wait for
973562306a36Sopenharmony_ci * 	the outstanding mailbox command timed out.
973662306a36Sopenharmony_ci **/
973762306a36Sopenharmony_cistatic int
973862306a36Sopenharmony_cilpfc_sli4_async_mbox_block(struct lpfc_hba *phba)
973962306a36Sopenharmony_ci{
974062306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
974162306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
974262306a36Sopenharmony_ci	int rc = 0;
974362306a36Sopenharmony_ci	unsigned long timeout = 0;
974462306a36Sopenharmony_ci	u32 sli_flag;
974562306a36Sopenharmony_ci	u8 cmd, subsys, opcode;
974662306a36Sopenharmony_ci
974762306a36Sopenharmony_ci	/* Mark the asynchronous mailbox command posting as blocked */
974862306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
974962306a36Sopenharmony_ci	psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK;
975062306a36Sopenharmony_ci	/* Determine how long we might wait for the active mailbox
975162306a36Sopenharmony_ci	 * command to be gracefully completed by firmware.
975262306a36Sopenharmony_ci	 */
975362306a36Sopenharmony_ci	if (phba->sli.mbox_active)
975462306a36Sopenharmony_ci		timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba,
975562306a36Sopenharmony_ci						phba->sli.mbox_active) *
975662306a36Sopenharmony_ci						1000) + jiffies;
975762306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
975862306a36Sopenharmony_ci
975962306a36Sopenharmony_ci	/* Make sure the mailbox is really active */
976062306a36Sopenharmony_ci	if (timeout)
976162306a36Sopenharmony_ci		lpfc_sli4_process_missed_mbox_completions(phba);
976262306a36Sopenharmony_ci
976362306a36Sopenharmony_ci	/* Wait for the outstanding mailbox command to complete */
976462306a36Sopenharmony_ci	while (phba->sli.mbox_active) {
976562306a36Sopenharmony_ci		/* Check active mailbox complete status every 2ms */
976662306a36Sopenharmony_ci		msleep(2);
976762306a36Sopenharmony_ci		if (time_after(jiffies, timeout)) {
976862306a36Sopenharmony_ci			/* Timeout, mark the outstanding cmd not complete */
976962306a36Sopenharmony_ci
977062306a36Sopenharmony_ci			/* Sanity check sli.mbox_active has not completed or
977162306a36Sopenharmony_ci			 * cancelled from another context during last 2ms sleep,
977262306a36Sopenharmony_ci			 * so take hbalock to be sure before logging.
977362306a36Sopenharmony_ci			 */
977462306a36Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
977562306a36Sopenharmony_ci			if (phba->sli.mbox_active) {
977662306a36Sopenharmony_ci				mboxq = phba->sli.mbox_active;
977762306a36Sopenharmony_ci				cmd = mboxq->u.mb.mbxCommand;
977862306a36Sopenharmony_ci				subsys = lpfc_sli_config_mbox_subsys_get(phba,
977962306a36Sopenharmony_ci									 mboxq);
978062306a36Sopenharmony_ci				opcode = lpfc_sli_config_mbox_opcode_get(phba,
978162306a36Sopenharmony_ci									 mboxq);
978262306a36Sopenharmony_ci				sli_flag = psli->sli_flag;
978362306a36Sopenharmony_ci				spin_unlock_irq(&phba->hbalock);
978462306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
978562306a36Sopenharmony_ci						"2352 Mailbox command x%x "
978662306a36Sopenharmony_ci						"(x%x/x%x) sli_flag x%x could "
978762306a36Sopenharmony_ci						"not complete\n",
978862306a36Sopenharmony_ci						cmd, subsys, opcode,
978962306a36Sopenharmony_ci						sli_flag);
979062306a36Sopenharmony_ci			} else {
979162306a36Sopenharmony_ci				spin_unlock_irq(&phba->hbalock);
979262306a36Sopenharmony_ci			}
979362306a36Sopenharmony_ci
979462306a36Sopenharmony_ci			rc = 1;
979562306a36Sopenharmony_ci			break;
979662306a36Sopenharmony_ci		}
979762306a36Sopenharmony_ci	}
979862306a36Sopenharmony_ci
979962306a36Sopenharmony_ci	/* Can not cleanly block async mailbox command, fails it */
980062306a36Sopenharmony_ci	if (rc) {
980162306a36Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
980262306a36Sopenharmony_ci		psli->sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK;
980362306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
980462306a36Sopenharmony_ci	}
980562306a36Sopenharmony_ci	return rc;
980662306a36Sopenharmony_ci}
980762306a36Sopenharmony_ci
980862306a36Sopenharmony_ci/**
980962306a36Sopenharmony_ci * lpfc_sli4_async_mbox_unblock - Block posting SLI4 async mailbox command
981062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
981162306a36Sopenharmony_ci *
981262306a36Sopenharmony_ci * The function unblocks and resume posting of SLI4 asynchronous mailbox
981362306a36Sopenharmony_ci * commands from the driver internal pending mailbox queue. It makes sure
981462306a36Sopenharmony_ci * that there is no outstanding mailbox command before resuming posting
981562306a36Sopenharmony_ci * asynchronous mailbox commands. If, for any reason, there is outstanding
981662306a36Sopenharmony_ci * mailbox command, it will try to wait it out before resuming asynchronous
981762306a36Sopenharmony_ci * mailbox command posting.
981862306a36Sopenharmony_ci **/
981962306a36Sopenharmony_cistatic void
982062306a36Sopenharmony_cilpfc_sli4_async_mbox_unblock(struct lpfc_hba *phba)
982162306a36Sopenharmony_ci{
982262306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
982362306a36Sopenharmony_ci
982462306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
982562306a36Sopenharmony_ci	if (!(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) {
982662306a36Sopenharmony_ci		/* Asynchronous mailbox posting is not blocked, do nothing */
982762306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
982862306a36Sopenharmony_ci		return;
982962306a36Sopenharmony_ci	}
983062306a36Sopenharmony_ci
983162306a36Sopenharmony_ci	/* Outstanding synchronous mailbox command is guaranteed to be done,
983262306a36Sopenharmony_ci	 * successful or timeout, after timing-out the outstanding mailbox
983362306a36Sopenharmony_ci	 * command shall always be removed, so just unblock posting async
983462306a36Sopenharmony_ci	 * mailbox command and resume
983562306a36Sopenharmony_ci	 */
983662306a36Sopenharmony_ci	psli->sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK;
983762306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
983862306a36Sopenharmony_ci
983962306a36Sopenharmony_ci	/* wake up worker thread to post asynchronous mailbox command */
984062306a36Sopenharmony_ci	lpfc_worker_wake_up(phba);
984162306a36Sopenharmony_ci}
984262306a36Sopenharmony_ci
984362306a36Sopenharmony_ci/**
984462306a36Sopenharmony_ci * lpfc_sli4_wait_bmbx_ready - Wait for bootstrap mailbox register ready
984562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
984662306a36Sopenharmony_ci * @mboxq: Pointer to mailbox object.
984762306a36Sopenharmony_ci *
984862306a36Sopenharmony_ci * The function waits for the bootstrap mailbox register ready bit from
984962306a36Sopenharmony_ci * port for twice the regular mailbox command timeout value.
985062306a36Sopenharmony_ci *
985162306a36Sopenharmony_ci *      0 - no timeout on waiting for bootstrap mailbox register ready.
985262306a36Sopenharmony_ci *      MBXERR_ERROR - wait for bootstrap mailbox register timed out or port
985362306a36Sopenharmony_ci *                     is in an unrecoverable state.
985462306a36Sopenharmony_ci **/
985562306a36Sopenharmony_cistatic int
985662306a36Sopenharmony_cilpfc_sli4_wait_bmbx_ready(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
985762306a36Sopenharmony_ci{
985862306a36Sopenharmony_ci	uint32_t db_ready;
985962306a36Sopenharmony_ci	unsigned long timeout;
986062306a36Sopenharmony_ci	struct lpfc_register bmbx_reg;
986162306a36Sopenharmony_ci	struct lpfc_register portstat_reg = {-1};
986262306a36Sopenharmony_ci
986362306a36Sopenharmony_ci	/* Sanity check - there is no point to wait if the port is in an
986462306a36Sopenharmony_ci	 * unrecoverable state.
986562306a36Sopenharmony_ci	 */
986662306a36Sopenharmony_ci	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >=
986762306a36Sopenharmony_ci	    LPFC_SLI_INTF_IF_TYPE_2) {
986862306a36Sopenharmony_ci		if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
986962306a36Sopenharmony_ci			       &portstat_reg.word0) ||
987062306a36Sopenharmony_ci		    lpfc_sli4_unrecoverable_port(&portstat_reg)) {
987162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
987262306a36Sopenharmony_ci					"3858 Skipping bmbx ready because "
987362306a36Sopenharmony_ci					"Port Status x%x\n",
987462306a36Sopenharmony_ci					portstat_reg.word0);
987562306a36Sopenharmony_ci			return MBXERR_ERROR;
987662306a36Sopenharmony_ci		}
987762306a36Sopenharmony_ci	}
987862306a36Sopenharmony_ci
987962306a36Sopenharmony_ci	timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq)
988062306a36Sopenharmony_ci				   * 1000) + jiffies;
988162306a36Sopenharmony_ci
988262306a36Sopenharmony_ci	do {
988362306a36Sopenharmony_ci		bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr);
988462306a36Sopenharmony_ci		db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg);
988562306a36Sopenharmony_ci		if (!db_ready)
988662306a36Sopenharmony_ci			mdelay(2);
988762306a36Sopenharmony_ci
988862306a36Sopenharmony_ci		if (time_after(jiffies, timeout))
988962306a36Sopenharmony_ci			return MBXERR_ERROR;
989062306a36Sopenharmony_ci	} while (!db_ready);
989162306a36Sopenharmony_ci
989262306a36Sopenharmony_ci	return 0;
989362306a36Sopenharmony_ci}
989462306a36Sopenharmony_ci
989562306a36Sopenharmony_ci/**
989662306a36Sopenharmony_ci * lpfc_sli4_post_sync_mbox - Post an SLI4 mailbox to the bootstrap mailbox
989762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
989862306a36Sopenharmony_ci * @mboxq: Pointer to mailbox object.
989962306a36Sopenharmony_ci *
990062306a36Sopenharmony_ci * The function posts a mailbox to the port.  The mailbox is expected
990162306a36Sopenharmony_ci * to be comletely filled in and ready for the port to operate on it.
990262306a36Sopenharmony_ci * This routine executes a synchronous completion operation on the
990362306a36Sopenharmony_ci * mailbox by polling for its completion.
990462306a36Sopenharmony_ci *
990562306a36Sopenharmony_ci * The caller must not be holding any locks when calling this routine.
990662306a36Sopenharmony_ci *
990762306a36Sopenharmony_ci * Returns:
990862306a36Sopenharmony_ci *	MBX_SUCCESS - mailbox posted successfully
990962306a36Sopenharmony_ci *	Any of the MBX error values.
991062306a36Sopenharmony_ci **/
991162306a36Sopenharmony_cistatic int
991262306a36Sopenharmony_cilpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
991362306a36Sopenharmony_ci{
991462306a36Sopenharmony_ci	int rc = MBX_SUCCESS;
991562306a36Sopenharmony_ci	unsigned long iflag;
991662306a36Sopenharmony_ci	uint32_t mcqe_status;
991762306a36Sopenharmony_ci	uint32_t mbx_cmnd;
991862306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
991962306a36Sopenharmony_ci	struct lpfc_mqe *mb = &mboxq->u.mqe;
992062306a36Sopenharmony_ci	struct lpfc_bmbx_create *mbox_rgn;
992162306a36Sopenharmony_ci	struct dma_address *dma_address;
992262306a36Sopenharmony_ci
992362306a36Sopenharmony_ci	/*
992462306a36Sopenharmony_ci	 * Only one mailbox can be active to the bootstrap mailbox region
992562306a36Sopenharmony_ci	 * at a time and there is no queueing provided.
992662306a36Sopenharmony_ci	 */
992762306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflag);
992862306a36Sopenharmony_ci	if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
992962306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
993062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
993162306a36Sopenharmony_ci				"(%d):2532 Mailbox command x%x (x%x/x%x) "
993262306a36Sopenharmony_ci				"cannot issue Data: x%x x%x\n",
993362306a36Sopenharmony_ci				mboxq->vport ? mboxq->vport->vpi : 0,
993462306a36Sopenharmony_ci				mboxq->u.mb.mbxCommand,
993562306a36Sopenharmony_ci				lpfc_sli_config_mbox_subsys_get(phba, mboxq),
993662306a36Sopenharmony_ci				lpfc_sli_config_mbox_opcode_get(phba, mboxq),
993762306a36Sopenharmony_ci				psli->sli_flag, MBX_POLL);
993862306a36Sopenharmony_ci		return MBXERR_ERROR;
993962306a36Sopenharmony_ci	}
994062306a36Sopenharmony_ci	/* The server grabs the token and owns it until release */
994162306a36Sopenharmony_ci	psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
994262306a36Sopenharmony_ci	phba->sli.mbox_active = mboxq;
994362306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflag);
994462306a36Sopenharmony_ci
994562306a36Sopenharmony_ci	/* wait for bootstrap mbox register for readyness */
994662306a36Sopenharmony_ci	rc = lpfc_sli4_wait_bmbx_ready(phba, mboxq);
994762306a36Sopenharmony_ci	if (rc)
994862306a36Sopenharmony_ci		goto exit;
994962306a36Sopenharmony_ci	/*
995062306a36Sopenharmony_ci	 * Initialize the bootstrap memory region to avoid stale data areas
995162306a36Sopenharmony_ci	 * in the mailbox post.  Then copy the caller's mailbox contents to
995262306a36Sopenharmony_ci	 * the bmbx mailbox region.
995362306a36Sopenharmony_ci	 */
995462306a36Sopenharmony_ci	mbx_cmnd = bf_get(lpfc_mqe_command, mb);
995562306a36Sopenharmony_ci	memset(phba->sli4_hba.bmbx.avirt, 0, sizeof(struct lpfc_bmbx_create));
995662306a36Sopenharmony_ci	lpfc_sli4_pcimem_bcopy(mb, phba->sli4_hba.bmbx.avirt,
995762306a36Sopenharmony_ci			       sizeof(struct lpfc_mqe));
995862306a36Sopenharmony_ci
995962306a36Sopenharmony_ci	/* Post the high mailbox dma address to the port and wait for ready. */
996062306a36Sopenharmony_ci	dma_address = &phba->sli4_hba.bmbx.dma_address;
996162306a36Sopenharmony_ci	writel(dma_address->addr_hi, phba->sli4_hba.BMBXregaddr);
996262306a36Sopenharmony_ci
996362306a36Sopenharmony_ci	/* wait for bootstrap mbox register for hi-address write done */
996462306a36Sopenharmony_ci	rc = lpfc_sli4_wait_bmbx_ready(phba, mboxq);
996562306a36Sopenharmony_ci	if (rc)
996662306a36Sopenharmony_ci		goto exit;
996762306a36Sopenharmony_ci
996862306a36Sopenharmony_ci	/* Post the low mailbox dma address to the port. */
996962306a36Sopenharmony_ci	writel(dma_address->addr_lo, phba->sli4_hba.BMBXregaddr);
997062306a36Sopenharmony_ci
997162306a36Sopenharmony_ci	/* wait for bootstrap mbox register for low address write done */
997262306a36Sopenharmony_ci	rc = lpfc_sli4_wait_bmbx_ready(phba, mboxq);
997362306a36Sopenharmony_ci	if (rc)
997462306a36Sopenharmony_ci		goto exit;
997562306a36Sopenharmony_ci
997662306a36Sopenharmony_ci	/*
997762306a36Sopenharmony_ci	 * Read the CQ to ensure the mailbox has completed.
997862306a36Sopenharmony_ci	 * If so, update the mailbox status so that the upper layers
997962306a36Sopenharmony_ci	 * can complete the request normally.
998062306a36Sopenharmony_ci	 */
998162306a36Sopenharmony_ci	lpfc_sli4_pcimem_bcopy(phba->sli4_hba.bmbx.avirt, mb,
998262306a36Sopenharmony_ci			       sizeof(struct lpfc_mqe));
998362306a36Sopenharmony_ci	mbox_rgn = (struct lpfc_bmbx_create *) phba->sli4_hba.bmbx.avirt;
998462306a36Sopenharmony_ci	lpfc_sli4_pcimem_bcopy(&mbox_rgn->mcqe, &mboxq->mcqe,
998562306a36Sopenharmony_ci			       sizeof(struct lpfc_mcqe));
998662306a36Sopenharmony_ci	mcqe_status = bf_get(lpfc_mcqe_status, &mbox_rgn->mcqe);
998762306a36Sopenharmony_ci	/*
998862306a36Sopenharmony_ci	 * When the CQE status indicates a failure and the mailbox status
998962306a36Sopenharmony_ci	 * indicates success then copy the CQE status into the mailbox status
999062306a36Sopenharmony_ci	 * (and prefix it with x4000).
999162306a36Sopenharmony_ci	 */
999262306a36Sopenharmony_ci	if (mcqe_status != MB_CQE_STATUS_SUCCESS) {
999362306a36Sopenharmony_ci		if (bf_get(lpfc_mqe_status, mb) == MBX_SUCCESS)
999462306a36Sopenharmony_ci			bf_set(lpfc_mqe_status, mb,
999562306a36Sopenharmony_ci			       (LPFC_MBX_ERROR_RANGE | mcqe_status));
999662306a36Sopenharmony_ci		rc = MBXERR_ERROR;
999762306a36Sopenharmony_ci	} else
999862306a36Sopenharmony_ci		lpfc_sli4_swap_str(phba, mboxq);
999962306a36Sopenharmony_ci
1000062306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
1000162306a36Sopenharmony_ci			"(%d):0356 Mailbox cmd x%x (x%x/x%x) Status x%x "
1000262306a36Sopenharmony_ci			"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x x%x x%x"
1000362306a36Sopenharmony_ci			" x%x x%x CQ: x%x x%x x%x x%x\n",
1000462306a36Sopenharmony_ci			mboxq->vport ? mboxq->vport->vpi : 0, mbx_cmnd,
1000562306a36Sopenharmony_ci			lpfc_sli_config_mbox_subsys_get(phba, mboxq),
1000662306a36Sopenharmony_ci			lpfc_sli_config_mbox_opcode_get(phba, mboxq),
1000762306a36Sopenharmony_ci			bf_get(lpfc_mqe_status, mb),
1000862306a36Sopenharmony_ci			mb->un.mb_words[0], mb->un.mb_words[1],
1000962306a36Sopenharmony_ci			mb->un.mb_words[2], mb->un.mb_words[3],
1001062306a36Sopenharmony_ci			mb->un.mb_words[4], mb->un.mb_words[5],
1001162306a36Sopenharmony_ci			mb->un.mb_words[6], mb->un.mb_words[7],
1001262306a36Sopenharmony_ci			mb->un.mb_words[8], mb->un.mb_words[9],
1001362306a36Sopenharmony_ci			mb->un.mb_words[10], mb->un.mb_words[11],
1001462306a36Sopenharmony_ci			mb->un.mb_words[12], mboxq->mcqe.word0,
1001562306a36Sopenharmony_ci			mboxq->mcqe.mcqe_tag0, 	mboxq->mcqe.mcqe_tag1,
1001662306a36Sopenharmony_ci			mboxq->mcqe.trailer);
1001762306a36Sopenharmony_ciexit:
1001862306a36Sopenharmony_ci	/* We are holding the token, no needed for lock when release */
1001962306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflag);
1002062306a36Sopenharmony_ci	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
1002162306a36Sopenharmony_ci	phba->sli.mbox_active = NULL;
1002262306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflag);
1002362306a36Sopenharmony_ci	return rc;
1002462306a36Sopenharmony_ci}
1002562306a36Sopenharmony_ci
1002662306a36Sopenharmony_ci/**
1002762306a36Sopenharmony_ci * lpfc_sli_issue_mbox_s4 - Issue an SLI4 mailbox command to firmware
1002862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1002962306a36Sopenharmony_ci * @mboxq: Pointer to mailbox object.
1003062306a36Sopenharmony_ci * @flag: Flag indicating how the mailbox need to be processed.
1003162306a36Sopenharmony_ci *
1003262306a36Sopenharmony_ci * This function is called by discovery code and HBA management code to submit
1003362306a36Sopenharmony_ci * a mailbox command to firmware with SLI-4 interface spec.
1003462306a36Sopenharmony_ci *
1003562306a36Sopenharmony_ci * Return codes the caller owns the mailbox command after the return of the
1003662306a36Sopenharmony_ci * function.
1003762306a36Sopenharmony_ci **/
1003862306a36Sopenharmony_cistatic int
1003962306a36Sopenharmony_cilpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
1004062306a36Sopenharmony_ci		       uint32_t flag)
1004162306a36Sopenharmony_ci{
1004262306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
1004362306a36Sopenharmony_ci	unsigned long iflags;
1004462306a36Sopenharmony_ci	int rc;
1004562306a36Sopenharmony_ci
1004662306a36Sopenharmony_ci	/* dump from issue mailbox command if setup */
1004762306a36Sopenharmony_ci	lpfc_idiag_mbxacc_dump_issue_mbox(phba, &mboxq->u.mb);
1004862306a36Sopenharmony_ci
1004962306a36Sopenharmony_ci	rc = lpfc_mbox_dev_check(phba);
1005062306a36Sopenharmony_ci	if (unlikely(rc)) {
1005162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1005262306a36Sopenharmony_ci				"(%d):2544 Mailbox command x%x (x%x/x%x) "
1005362306a36Sopenharmony_ci				"cannot issue Data: x%x x%x\n",
1005462306a36Sopenharmony_ci				mboxq->vport ? mboxq->vport->vpi : 0,
1005562306a36Sopenharmony_ci				mboxq->u.mb.mbxCommand,
1005662306a36Sopenharmony_ci				lpfc_sli_config_mbox_subsys_get(phba, mboxq),
1005762306a36Sopenharmony_ci				lpfc_sli_config_mbox_opcode_get(phba, mboxq),
1005862306a36Sopenharmony_ci				psli->sli_flag, flag);
1005962306a36Sopenharmony_ci		goto out_not_finished;
1006062306a36Sopenharmony_ci	}
1006162306a36Sopenharmony_ci
1006262306a36Sopenharmony_ci	/* Detect polling mode and jump to a handler */
1006362306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable) {
1006462306a36Sopenharmony_ci		if (flag == MBX_POLL)
1006562306a36Sopenharmony_ci			rc = lpfc_sli4_post_sync_mbox(phba, mboxq);
1006662306a36Sopenharmony_ci		else
1006762306a36Sopenharmony_ci			rc = -EIO;
1006862306a36Sopenharmony_ci		if (rc != MBX_SUCCESS)
1006962306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
1007062306a36Sopenharmony_ci					"(%d):2541 Mailbox command x%x "
1007162306a36Sopenharmony_ci					"(x%x/x%x) failure: "
1007262306a36Sopenharmony_ci					"mqe_sta: x%x mcqe_sta: x%x/x%x "
1007362306a36Sopenharmony_ci					"Data: x%x x%x\n",
1007462306a36Sopenharmony_ci					mboxq->vport ? mboxq->vport->vpi : 0,
1007562306a36Sopenharmony_ci					mboxq->u.mb.mbxCommand,
1007662306a36Sopenharmony_ci					lpfc_sli_config_mbox_subsys_get(phba,
1007762306a36Sopenharmony_ci									mboxq),
1007862306a36Sopenharmony_ci					lpfc_sli_config_mbox_opcode_get(phba,
1007962306a36Sopenharmony_ci									mboxq),
1008062306a36Sopenharmony_ci					bf_get(lpfc_mqe_status, &mboxq->u.mqe),
1008162306a36Sopenharmony_ci					bf_get(lpfc_mcqe_status, &mboxq->mcqe),
1008262306a36Sopenharmony_ci					bf_get(lpfc_mcqe_ext_status,
1008362306a36Sopenharmony_ci					       &mboxq->mcqe),
1008462306a36Sopenharmony_ci					psli->sli_flag, flag);
1008562306a36Sopenharmony_ci		return rc;
1008662306a36Sopenharmony_ci	} else if (flag == MBX_POLL) {
1008762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
1008862306a36Sopenharmony_ci				"(%d):2542 Try to issue mailbox command "
1008962306a36Sopenharmony_ci				"x%x (x%x/x%x) synchronously ahead of async "
1009062306a36Sopenharmony_ci				"mailbox command queue: x%x x%x\n",
1009162306a36Sopenharmony_ci				mboxq->vport ? mboxq->vport->vpi : 0,
1009262306a36Sopenharmony_ci				mboxq->u.mb.mbxCommand,
1009362306a36Sopenharmony_ci				lpfc_sli_config_mbox_subsys_get(phba, mboxq),
1009462306a36Sopenharmony_ci				lpfc_sli_config_mbox_opcode_get(phba, mboxq),
1009562306a36Sopenharmony_ci				psli->sli_flag, flag);
1009662306a36Sopenharmony_ci		/* Try to block the asynchronous mailbox posting */
1009762306a36Sopenharmony_ci		rc = lpfc_sli4_async_mbox_block(phba);
1009862306a36Sopenharmony_ci		if (!rc) {
1009962306a36Sopenharmony_ci			/* Successfully blocked, now issue sync mbox cmd */
1010062306a36Sopenharmony_ci			rc = lpfc_sli4_post_sync_mbox(phba, mboxq);
1010162306a36Sopenharmony_ci			if (rc != MBX_SUCCESS)
1010262306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_WARNING,
1010362306a36Sopenharmony_ci					LOG_MBOX | LOG_SLI,
1010462306a36Sopenharmony_ci					"(%d):2597 Sync Mailbox command "
1010562306a36Sopenharmony_ci					"x%x (x%x/x%x) failure: "
1010662306a36Sopenharmony_ci					"mqe_sta: x%x mcqe_sta: x%x/x%x "
1010762306a36Sopenharmony_ci					"Data: x%x x%x\n",
1010862306a36Sopenharmony_ci					mboxq->vport ? mboxq->vport->vpi : 0,
1010962306a36Sopenharmony_ci					mboxq->u.mb.mbxCommand,
1011062306a36Sopenharmony_ci					lpfc_sli_config_mbox_subsys_get(phba,
1011162306a36Sopenharmony_ci									mboxq),
1011262306a36Sopenharmony_ci					lpfc_sli_config_mbox_opcode_get(phba,
1011362306a36Sopenharmony_ci									mboxq),
1011462306a36Sopenharmony_ci					bf_get(lpfc_mqe_status, &mboxq->u.mqe),
1011562306a36Sopenharmony_ci					bf_get(lpfc_mcqe_status, &mboxq->mcqe),
1011662306a36Sopenharmony_ci					bf_get(lpfc_mcqe_ext_status,
1011762306a36Sopenharmony_ci					       &mboxq->mcqe),
1011862306a36Sopenharmony_ci					psli->sli_flag, flag);
1011962306a36Sopenharmony_ci			/* Unblock the async mailbox posting afterward */
1012062306a36Sopenharmony_ci			lpfc_sli4_async_mbox_unblock(phba);
1012162306a36Sopenharmony_ci		}
1012262306a36Sopenharmony_ci		return rc;
1012362306a36Sopenharmony_ci	}
1012462306a36Sopenharmony_ci
1012562306a36Sopenharmony_ci	/* Now, interrupt mode asynchronous mailbox command */
1012662306a36Sopenharmony_ci	rc = lpfc_mbox_cmd_check(phba, mboxq);
1012762306a36Sopenharmony_ci	if (rc) {
1012862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1012962306a36Sopenharmony_ci				"(%d):2543 Mailbox command x%x (x%x/x%x) "
1013062306a36Sopenharmony_ci				"cannot issue Data: x%x x%x\n",
1013162306a36Sopenharmony_ci				mboxq->vport ? mboxq->vport->vpi : 0,
1013262306a36Sopenharmony_ci				mboxq->u.mb.mbxCommand,
1013362306a36Sopenharmony_ci				lpfc_sli_config_mbox_subsys_get(phba, mboxq),
1013462306a36Sopenharmony_ci				lpfc_sli_config_mbox_opcode_get(phba, mboxq),
1013562306a36Sopenharmony_ci				psli->sli_flag, flag);
1013662306a36Sopenharmony_ci		goto out_not_finished;
1013762306a36Sopenharmony_ci	}
1013862306a36Sopenharmony_ci
1013962306a36Sopenharmony_ci	/* Put the mailbox command to the driver internal FIFO */
1014062306a36Sopenharmony_ci	psli->slistat.mbox_busy++;
1014162306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1014262306a36Sopenharmony_ci	lpfc_mbox_put(phba, mboxq);
1014362306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1014462306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
1014562306a36Sopenharmony_ci			"(%d):0354 Mbox cmd issue - Enqueue Data: "
1014662306a36Sopenharmony_ci			"x%x (x%x/x%x) x%x x%x x%x\n",
1014762306a36Sopenharmony_ci			mboxq->vport ? mboxq->vport->vpi : 0xffffff,
1014862306a36Sopenharmony_ci			bf_get(lpfc_mqe_command, &mboxq->u.mqe),
1014962306a36Sopenharmony_ci			lpfc_sli_config_mbox_subsys_get(phba, mboxq),
1015062306a36Sopenharmony_ci			lpfc_sli_config_mbox_opcode_get(phba, mboxq),
1015162306a36Sopenharmony_ci			phba->pport->port_state,
1015262306a36Sopenharmony_ci			psli->sli_flag, MBX_NOWAIT);
1015362306a36Sopenharmony_ci	/* Wake up worker thread to transport mailbox command from head */
1015462306a36Sopenharmony_ci	lpfc_worker_wake_up(phba);
1015562306a36Sopenharmony_ci
1015662306a36Sopenharmony_ci	return MBX_BUSY;
1015762306a36Sopenharmony_ci
1015862306a36Sopenharmony_ciout_not_finished:
1015962306a36Sopenharmony_ci	return MBX_NOT_FINISHED;
1016062306a36Sopenharmony_ci}
1016162306a36Sopenharmony_ci
1016262306a36Sopenharmony_ci/**
1016362306a36Sopenharmony_ci * lpfc_sli4_post_async_mbox - Post an SLI4 mailbox command to device
1016462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1016562306a36Sopenharmony_ci *
1016662306a36Sopenharmony_ci * This function is called by worker thread to send a mailbox command to
1016762306a36Sopenharmony_ci * SLI4 HBA firmware.
1016862306a36Sopenharmony_ci *
1016962306a36Sopenharmony_ci **/
1017062306a36Sopenharmony_ciint
1017162306a36Sopenharmony_cilpfc_sli4_post_async_mbox(struct lpfc_hba *phba)
1017262306a36Sopenharmony_ci{
1017362306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
1017462306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
1017562306a36Sopenharmony_ci	int rc = MBX_SUCCESS;
1017662306a36Sopenharmony_ci	unsigned long iflags;
1017762306a36Sopenharmony_ci	struct lpfc_mqe *mqe;
1017862306a36Sopenharmony_ci	uint32_t mbx_cmnd;
1017962306a36Sopenharmony_ci
1018062306a36Sopenharmony_ci	/* Check interrupt mode before post async mailbox command */
1018162306a36Sopenharmony_ci	if (unlikely(!phba->sli4_hba.intr_enable))
1018262306a36Sopenharmony_ci		return MBX_NOT_FINISHED;
1018362306a36Sopenharmony_ci
1018462306a36Sopenharmony_ci	/* Check for mailbox command service token */
1018562306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1018662306a36Sopenharmony_ci	if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) {
1018762306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1018862306a36Sopenharmony_ci		return MBX_NOT_FINISHED;
1018962306a36Sopenharmony_ci	}
1019062306a36Sopenharmony_ci	if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
1019162306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1019262306a36Sopenharmony_ci		return MBX_NOT_FINISHED;
1019362306a36Sopenharmony_ci	}
1019462306a36Sopenharmony_ci	if (unlikely(phba->sli.mbox_active)) {
1019562306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1019662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1019762306a36Sopenharmony_ci				"0384 There is pending active mailbox cmd\n");
1019862306a36Sopenharmony_ci		return MBX_NOT_FINISHED;
1019962306a36Sopenharmony_ci	}
1020062306a36Sopenharmony_ci	/* Take the mailbox command service token */
1020162306a36Sopenharmony_ci	psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
1020262306a36Sopenharmony_ci
1020362306a36Sopenharmony_ci	/* Get the next mailbox command from head of queue */
1020462306a36Sopenharmony_ci	mboxq = lpfc_mbox_get(phba);
1020562306a36Sopenharmony_ci
1020662306a36Sopenharmony_ci	/* If no more mailbox command waiting for post, we're done */
1020762306a36Sopenharmony_ci	if (!mboxq) {
1020862306a36Sopenharmony_ci		psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
1020962306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1021062306a36Sopenharmony_ci		return MBX_SUCCESS;
1021162306a36Sopenharmony_ci	}
1021262306a36Sopenharmony_ci	phba->sli.mbox_active = mboxq;
1021362306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1021462306a36Sopenharmony_ci
1021562306a36Sopenharmony_ci	/* Check device readiness for posting mailbox command */
1021662306a36Sopenharmony_ci	rc = lpfc_mbox_dev_check(phba);
1021762306a36Sopenharmony_ci	if (unlikely(rc))
1021862306a36Sopenharmony_ci		/* Driver clean routine will clean up pending mailbox */
1021962306a36Sopenharmony_ci		goto out_not_finished;
1022062306a36Sopenharmony_ci
1022162306a36Sopenharmony_ci	/* Prepare the mbox command to be posted */
1022262306a36Sopenharmony_ci	mqe = &mboxq->u.mqe;
1022362306a36Sopenharmony_ci	mbx_cmnd = bf_get(lpfc_mqe_command, mqe);
1022462306a36Sopenharmony_ci
1022562306a36Sopenharmony_ci	/* Start timer for the mbox_tmo and log some mailbox post messages */
1022662306a36Sopenharmony_ci	mod_timer(&psli->mbox_tmo, (jiffies +
1022762306a36Sopenharmony_ci		  msecs_to_jiffies(1000 * lpfc_mbox_tmo_val(phba, mboxq))));
1022862306a36Sopenharmony_ci
1022962306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
1023062306a36Sopenharmony_ci			"(%d):0355 Mailbox cmd x%x (x%x/x%x) issue Data: "
1023162306a36Sopenharmony_ci			"x%x x%x\n",
1023262306a36Sopenharmony_ci			mboxq->vport ? mboxq->vport->vpi : 0, mbx_cmnd,
1023362306a36Sopenharmony_ci			lpfc_sli_config_mbox_subsys_get(phba, mboxq),
1023462306a36Sopenharmony_ci			lpfc_sli_config_mbox_opcode_get(phba, mboxq),
1023562306a36Sopenharmony_ci			phba->pport->port_state, psli->sli_flag);
1023662306a36Sopenharmony_ci
1023762306a36Sopenharmony_ci	if (mbx_cmnd != MBX_HEARTBEAT) {
1023862306a36Sopenharmony_ci		if (mboxq->vport) {
1023962306a36Sopenharmony_ci			lpfc_debugfs_disc_trc(mboxq->vport,
1024062306a36Sopenharmony_ci				LPFC_DISC_TRC_MBOX_VPORT,
1024162306a36Sopenharmony_ci				"MBOX Send vport: cmd:x%x mb:x%x x%x",
1024262306a36Sopenharmony_ci				mbx_cmnd, mqe->un.mb_words[0],
1024362306a36Sopenharmony_ci				mqe->un.mb_words[1]);
1024462306a36Sopenharmony_ci		} else {
1024562306a36Sopenharmony_ci			lpfc_debugfs_disc_trc(phba->pport,
1024662306a36Sopenharmony_ci				LPFC_DISC_TRC_MBOX,
1024762306a36Sopenharmony_ci				"MBOX Send: cmd:x%x mb:x%x x%x",
1024862306a36Sopenharmony_ci				mbx_cmnd, mqe->un.mb_words[0],
1024962306a36Sopenharmony_ci				mqe->un.mb_words[1]);
1025062306a36Sopenharmony_ci		}
1025162306a36Sopenharmony_ci	}
1025262306a36Sopenharmony_ci	psli->slistat.mbox_cmd++;
1025362306a36Sopenharmony_ci
1025462306a36Sopenharmony_ci	/* Post the mailbox command to the port */
1025562306a36Sopenharmony_ci	rc = lpfc_sli4_mq_put(phba->sli4_hba.mbx_wq, mqe);
1025662306a36Sopenharmony_ci	if (rc != MBX_SUCCESS) {
1025762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1025862306a36Sopenharmony_ci				"(%d):2533 Mailbox command x%x (x%x/x%x) "
1025962306a36Sopenharmony_ci				"cannot issue Data: x%x x%x\n",
1026062306a36Sopenharmony_ci				mboxq->vport ? mboxq->vport->vpi : 0,
1026162306a36Sopenharmony_ci				mboxq->u.mb.mbxCommand,
1026262306a36Sopenharmony_ci				lpfc_sli_config_mbox_subsys_get(phba, mboxq),
1026362306a36Sopenharmony_ci				lpfc_sli_config_mbox_opcode_get(phba, mboxq),
1026462306a36Sopenharmony_ci				psli->sli_flag, MBX_NOWAIT);
1026562306a36Sopenharmony_ci		goto out_not_finished;
1026662306a36Sopenharmony_ci	}
1026762306a36Sopenharmony_ci
1026862306a36Sopenharmony_ci	return rc;
1026962306a36Sopenharmony_ci
1027062306a36Sopenharmony_ciout_not_finished:
1027162306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1027262306a36Sopenharmony_ci	if (phba->sli.mbox_active) {
1027362306a36Sopenharmony_ci		mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED;
1027462306a36Sopenharmony_ci		__lpfc_mbox_cmpl_put(phba, mboxq);
1027562306a36Sopenharmony_ci		/* Release the token */
1027662306a36Sopenharmony_ci		psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
1027762306a36Sopenharmony_ci		phba->sli.mbox_active = NULL;
1027862306a36Sopenharmony_ci	}
1027962306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1028062306a36Sopenharmony_ci
1028162306a36Sopenharmony_ci	return MBX_NOT_FINISHED;
1028262306a36Sopenharmony_ci}
1028362306a36Sopenharmony_ci
1028462306a36Sopenharmony_ci/**
1028562306a36Sopenharmony_ci * lpfc_sli_issue_mbox - Wrapper func for issuing mailbox command
1028662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1028762306a36Sopenharmony_ci * @pmbox: Pointer to mailbox object.
1028862306a36Sopenharmony_ci * @flag: Flag indicating how the mailbox need to be processed.
1028962306a36Sopenharmony_ci *
1029062306a36Sopenharmony_ci * This routine wraps the actual SLI3 or SLI4 mailbox issuing routine from
1029162306a36Sopenharmony_ci * the API jump table function pointer from the lpfc_hba struct.
1029262306a36Sopenharmony_ci *
1029362306a36Sopenharmony_ci * Return codes the caller owns the mailbox command after the return of the
1029462306a36Sopenharmony_ci * function.
1029562306a36Sopenharmony_ci **/
1029662306a36Sopenharmony_ciint
1029762306a36Sopenharmony_cilpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
1029862306a36Sopenharmony_ci{
1029962306a36Sopenharmony_ci	return phba->lpfc_sli_issue_mbox(phba, pmbox, flag);
1030062306a36Sopenharmony_ci}
1030162306a36Sopenharmony_ci
1030262306a36Sopenharmony_ci/**
1030362306a36Sopenharmony_ci * lpfc_mbox_api_table_setup - Set up mbox api function jump table
1030462306a36Sopenharmony_ci * @phba: The hba struct for which this call is being executed.
1030562306a36Sopenharmony_ci * @dev_grp: The HBA PCI-Device group number.
1030662306a36Sopenharmony_ci *
1030762306a36Sopenharmony_ci * This routine sets up the mbox interface API function jump table in @phba
1030862306a36Sopenharmony_ci * struct.
1030962306a36Sopenharmony_ci * Returns: 0 - success, -ENODEV - failure.
1031062306a36Sopenharmony_ci **/
1031162306a36Sopenharmony_ciint
1031262306a36Sopenharmony_cilpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
1031362306a36Sopenharmony_ci{
1031462306a36Sopenharmony_ci
1031562306a36Sopenharmony_ci	switch (dev_grp) {
1031662306a36Sopenharmony_ci	case LPFC_PCI_DEV_LP:
1031762306a36Sopenharmony_ci		phba->lpfc_sli_issue_mbox = lpfc_sli_issue_mbox_s3;
1031862306a36Sopenharmony_ci		phba->lpfc_sli_handle_slow_ring_event =
1031962306a36Sopenharmony_ci				lpfc_sli_handle_slow_ring_event_s3;
1032062306a36Sopenharmony_ci		phba->lpfc_sli_hbq_to_firmware = lpfc_sli_hbq_to_firmware_s3;
1032162306a36Sopenharmony_ci		phba->lpfc_sli_brdrestart = lpfc_sli_brdrestart_s3;
1032262306a36Sopenharmony_ci		phba->lpfc_sli_brdready = lpfc_sli_brdready_s3;
1032362306a36Sopenharmony_ci		break;
1032462306a36Sopenharmony_ci	case LPFC_PCI_DEV_OC:
1032562306a36Sopenharmony_ci		phba->lpfc_sli_issue_mbox = lpfc_sli_issue_mbox_s4;
1032662306a36Sopenharmony_ci		phba->lpfc_sli_handle_slow_ring_event =
1032762306a36Sopenharmony_ci				lpfc_sli_handle_slow_ring_event_s4;
1032862306a36Sopenharmony_ci		phba->lpfc_sli_hbq_to_firmware = lpfc_sli_hbq_to_firmware_s4;
1032962306a36Sopenharmony_ci		phba->lpfc_sli_brdrestart = lpfc_sli_brdrestart_s4;
1033062306a36Sopenharmony_ci		phba->lpfc_sli_brdready = lpfc_sli_brdready_s4;
1033162306a36Sopenharmony_ci		break;
1033262306a36Sopenharmony_ci	default:
1033362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
1033462306a36Sopenharmony_ci				"1420 Invalid HBA PCI-device group: 0x%x\n",
1033562306a36Sopenharmony_ci				dev_grp);
1033662306a36Sopenharmony_ci		return -ENODEV;
1033762306a36Sopenharmony_ci	}
1033862306a36Sopenharmony_ci	return 0;
1033962306a36Sopenharmony_ci}
1034062306a36Sopenharmony_ci
1034162306a36Sopenharmony_ci/**
1034262306a36Sopenharmony_ci * __lpfc_sli_ringtx_put - Add an iocb to the txq
1034362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1034462306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
1034562306a36Sopenharmony_ci * @piocb: Pointer to address of newly added command iocb.
1034662306a36Sopenharmony_ci *
1034762306a36Sopenharmony_ci * This function is called with hbalock held for SLI3 ports or
1034862306a36Sopenharmony_ci * the ring lock held for SLI4 ports to add a command
1034962306a36Sopenharmony_ci * iocb to the txq when SLI layer cannot submit the command iocb
1035062306a36Sopenharmony_ci * to the ring.
1035162306a36Sopenharmony_ci **/
1035262306a36Sopenharmony_civoid
1035362306a36Sopenharmony_ci__lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
1035462306a36Sopenharmony_ci		    struct lpfc_iocbq *piocb)
1035562306a36Sopenharmony_ci{
1035662306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
1035762306a36Sopenharmony_ci		lockdep_assert_held(&pring->ring_lock);
1035862306a36Sopenharmony_ci	else
1035962306a36Sopenharmony_ci		lockdep_assert_held(&phba->hbalock);
1036062306a36Sopenharmony_ci	/* Insert the caller's iocb in the txq tail for later processing. */
1036162306a36Sopenharmony_ci	list_add_tail(&piocb->list, &pring->txq);
1036262306a36Sopenharmony_ci}
1036362306a36Sopenharmony_ci
1036462306a36Sopenharmony_ci/**
1036562306a36Sopenharmony_ci * lpfc_sli_next_iocb - Get the next iocb in the txq
1036662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1036762306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
1036862306a36Sopenharmony_ci * @piocb: Pointer to address of newly added command iocb.
1036962306a36Sopenharmony_ci *
1037062306a36Sopenharmony_ci * This function is called with hbalock held before a new
1037162306a36Sopenharmony_ci * iocb is submitted to the firmware. This function checks
1037262306a36Sopenharmony_ci * txq to flush the iocbs in txq to Firmware before
1037362306a36Sopenharmony_ci * submitting new iocbs to the Firmware.
1037462306a36Sopenharmony_ci * If there are iocbs in the txq which need to be submitted
1037562306a36Sopenharmony_ci * to firmware, lpfc_sli_next_iocb returns the first element
1037662306a36Sopenharmony_ci * of the txq after dequeuing it from txq.
1037762306a36Sopenharmony_ci * If there is no iocb in the txq then the function will return
1037862306a36Sopenharmony_ci * *piocb and *piocb is set to NULL. Caller needs to check
1037962306a36Sopenharmony_ci * *piocb to find if there are more commands in the txq.
1038062306a36Sopenharmony_ci **/
1038162306a36Sopenharmony_cistatic struct lpfc_iocbq *
1038262306a36Sopenharmony_cilpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
1038362306a36Sopenharmony_ci		   struct lpfc_iocbq **piocb)
1038462306a36Sopenharmony_ci{
1038562306a36Sopenharmony_ci	struct lpfc_iocbq * nextiocb;
1038662306a36Sopenharmony_ci
1038762306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
1038862306a36Sopenharmony_ci
1038962306a36Sopenharmony_ci	nextiocb = lpfc_sli_ringtx_get(phba, pring);
1039062306a36Sopenharmony_ci	if (!nextiocb) {
1039162306a36Sopenharmony_ci		nextiocb = *piocb;
1039262306a36Sopenharmony_ci		*piocb = NULL;
1039362306a36Sopenharmony_ci	}
1039462306a36Sopenharmony_ci
1039562306a36Sopenharmony_ci	return nextiocb;
1039662306a36Sopenharmony_ci}
1039762306a36Sopenharmony_ci
1039862306a36Sopenharmony_ci/**
1039962306a36Sopenharmony_ci * __lpfc_sli_issue_iocb_s3 - SLI3 device lockless ver of lpfc_sli_issue_iocb
1040062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1040162306a36Sopenharmony_ci * @ring_number: SLI ring number to issue iocb on.
1040262306a36Sopenharmony_ci * @piocb: Pointer to command iocb.
1040362306a36Sopenharmony_ci * @flag: Flag indicating if this command can be put into txq.
1040462306a36Sopenharmony_ci *
1040562306a36Sopenharmony_ci * __lpfc_sli_issue_iocb_s3 is used by other functions in the driver to issue
1040662306a36Sopenharmony_ci * an iocb command to an HBA with SLI-3 interface spec. If the PCI slot is
1040762306a36Sopenharmony_ci * recovering from error state, if HBA is resetting or if LPFC_STOP_IOCB_EVENT
1040862306a36Sopenharmony_ci * flag is turned on, the function returns IOCB_ERROR. When the link is down,
1040962306a36Sopenharmony_ci * this function allows only iocbs for posting buffers. This function finds
1041062306a36Sopenharmony_ci * next available slot in the command ring and posts the command to the
1041162306a36Sopenharmony_ci * available slot and writes the port attention register to request HBA start
1041262306a36Sopenharmony_ci * processing new iocb. If there is no slot available in the ring and
1041362306a36Sopenharmony_ci * flag & SLI_IOCB_RET_IOCB is set, the new iocb is added to the txq, otherwise
1041462306a36Sopenharmony_ci * the function returns IOCB_BUSY.
1041562306a36Sopenharmony_ci *
1041662306a36Sopenharmony_ci * This function is called with hbalock held. The function will return success
1041762306a36Sopenharmony_ci * after it successfully submit the iocb to firmware or after adding to the
1041862306a36Sopenharmony_ci * txq.
1041962306a36Sopenharmony_ci **/
1042062306a36Sopenharmony_cistatic int
1042162306a36Sopenharmony_ci__lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number,
1042262306a36Sopenharmony_ci		    struct lpfc_iocbq *piocb, uint32_t flag)
1042362306a36Sopenharmony_ci{
1042462306a36Sopenharmony_ci	struct lpfc_iocbq *nextiocb;
1042562306a36Sopenharmony_ci	IOCB_t *iocb;
1042662306a36Sopenharmony_ci	struct lpfc_sli_ring *pring = &phba->sli.sli3_ring[ring_number];
1042762306a36Sopenharmony_ci
1042862306a36Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
1042962306a36Sopenharmony_ci
1043062306a36Sopenharmony_ci	if (piocb->cmd_cmpl && (!piocb->vport) &&
1043162306a36Sopenharmony_ci	   (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
1043262306a36Sopenharmony_ci	   (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
1043362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1043462306a36Sopenharmony_ci				"1807 IOCB x%x failed. No vport\n",
1043562306a36Sopenharmony_ci				piocb->iocb.ulpCommand);
1043662306a36Sopenharmony_ci		dump_stack();
1043762306a36Sopenharmony_ci		return IOCB_ERROR;
1043862306a36Sopenharmony_ci	}
1043962306a36Sopenharmony_ci
1044062306a36Sopenharmony_ci
1044162306a36Sopenharmony_ci	/* If the PCI channel is in offline state, do not post iocbs. */
1044262306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(phba->pcidev)))
1044362306a36Sopenharmony_ci		return IOCB_ERROR;
1044462306a36Sopenharmony_ci
1044562306a36Sopenharmony_ci	/* If HBA has a deferred error attention, fail the iocb. */
1044662306a36Sopenharmony_ci	if (unlikely(phba->hba_flag & DEFER_ERATT))
1044762306a36Sopenharmony_ci		return IOCB_ERROR;
1044862306a36Sopenharmony_ci
1044962306a36Sopenharmony_ci	/*
1045062306a36Sopenharmony_ci	 * We should never get an IOCB if we are in a < LINK_DOWN state
1045162306a36Sopenharmony_ci	 */
1045262306a36Sopenharmony_ci	if (unlikely(phba->link_state < LPFC_LINK_DOWN))
1045362306a36Sopenharmony_ci		return IOCB_ERROR;
1045462306a36Sopenharmony_ci
1045562306a36Sopenharmony_ci	/*
1045662306a36Sopenharmony_ci	 * Check to see if we are blocking IOCB processing because of a
1045762306a36Sopenharmony_ci	 * outstanding event.
1045862306a36Sopenharmony_ci	 */
1045962306a36Sopenharmony_ci	if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT))
1046062306a36Sopenharmony_ci		goto iocb_busy;
1046162306a36Sopenharmony_ci
1046262306a36Sopenharmony_ci	if (unlikely(phba->link_state == LPFC_LINK_DOWN)) {
1046362306a36Sopenharmony_ci		/*
1046462306a36Sopenharmony_ci		 * Only CREATE_XRI, CLOSE_XRI, and QUE_RING_BUF
1046562306a36Sopenharmony_ci		 * can be issued if the link is not up.
1046662306a36Sopenharmony_ci		 */
1046762306a36Sopenharmony_ci		switch (piocb->iocb.ulpCommand) {
1046862306a36Sopenharmony_ci		case CMD_QUE_RING_BUF_CN:
1046962306a36Sopenharmony_ci		case CMD_QUE_RING_BUF64_CN:
1047062306a36Sopenharmony_ci			/*
1047162306a36Sopenharmony_ci			 * For IOCBs, like QUE_RING_BUF, that have no rsp ring
1047262306a36Sopenharmony_ci			 * completion, cmd_cmpl MUST be 0.
1047362306a36Sopenharmony_ci			 */
1047462306a36Sopenharmony_ci			if (piocb->cmd_cmpl)
1047562306a36Sopenharmony_ci				piocb->cmd_cmpl = NULL;
1047662306a36Sopenharmony_ci			fallthrough;
1047762306a36Sopenharmony_ci		case CMD_CREATE_XRI_CR:
1047862306a36Sopenharmony_ci		case CMD_CLOSE_XRI_CN:
1047962306a36Sopenharmony_ci		case CMD_CLOSE_XRI_CX:
1048062306a36Sopenharmony_ci			break;
1048162306a36Sopenharmony_ci		default:
1048262306a36Sopenharmony_ci			goto iocb_busy;
1048362306a36Sopenharmony_ci		}
1048462306a36Sopenharmony_ci
1048562306a36Sopenharmony_ci	/*
1048662306a36Sopenharmony_ci	 * For FCP commands, we must be in a state where we can process link
1048762306a36Sopenharmony_ci	 * attention events.
1048862306a36Sopenharmony_ci	 */
1048962306a36Sopenharmony_ci	} else if (unlikely(pring->ringno == LPFC_FCP_RING &&
1049062306a36Sopenharmony_ci			    !(phba->sli.sli_flag & LPFC_PROCESS_LA))) {
1049162306a36Sopenharmony_ci		goto iocb_busy;
1049262306a36Sopenharmony_ci	}
1049362306a36Sopenharmony_ci
1049462306a36Sopenharmony_ci	while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
1049562306a36Sopenharmony_ci	       (nextiocb = lpfc_sli_next_iocb(phba, pring, &piocb)))
1049662306a36Sopenharmony_ci		lpfc_sli_submit_iocb(phba, pring, iocb, nextiocb);
1049762306a36Sopenharmony_ci
1049862306a36Sopenharmony_ci	if (iocb)
1049962306a36Sopenharmony_ci		lpfc_sli_update_ring(phba, pring);
1050062306a36Sopenharmony_ci	else
1050162306a36Sopenharmony_ci		lpfc_sli_update_full_ring(phba, pring);
1050262306a36Sopenharmony_ci
1050362306a36Sopenharmony_ci	if (!piocb)
1050462306a36Sopenharmony_ci		return IOCB_SUCCESS;
1050562306a36Sopenharmony_ci
1050662306a36Sopenharmony_ci	goto out_busy;
1050762306a36Sopenharmony_ci
1050862306a36Sopenharmony_ci iocb_busy:
1050962306a36Sopenharmony_ci	pring->stats.iocb_cmd_delay++;
1051062306a36Sopenharmony_ci
1051162306a36Sopenharmony_ci out_busy:
1051262306a36Sopenharmony_ci
1051362306a36Sopenharmony_ci	if (!(flag & SLI_IOCB_RET_IOCB)) {
1051462306a36Sopenharmony_ci		__lpfc_sli_ringtx_put(phba, pring, piocb);
1051562306a36Sopenharmony_ci		return IOCB_SUCCESS;
1051662306a36Sopenharmony_ci	}
1051762306a36Sopenharmony_ci
1051862306a36Sopenharmony_ci	return IOCB_BUSY;
1051962306a36Sopenharmony_ci}
1052062306a36Sopenharmony_ci
1052162306a36Sopenharmony_ci/**
1052262306a36Sopenharmony_ci * __lpfc_sli_issue_fcp_io_s3 - SLI3 device for sending fcp io iocb
1052362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1052462306a36Sopenharmony_ci * @ring_number: SLI ring number to issue wqe on.
1052562306a36Sopenharmony_ci * @piocb: Pointer to command iocb.
1052662306a36Sopenharmony_ci * @flag: Flag indicating if this command can be put into txq.
1052762306a36Sopenharmony_ci *
1052862306a36Sopenharmony_ci * __lpfc_sli_issue_fcp_io_s3 is wrapper function to invoke lockless func to
1052962306a36Sopenharmony_ci * send  an iocb command to an HBA with SLI-3 interface spec.
1053062306a36Sopenharmony_ci *
1053162306a36Sopenharmony_ci * This function takes the hbalock before invoking the lockless version.
1053262306a36Sopenharmony_ci * The function will return success after it successfully submit the wqe to
1053362306a36Sopenharmony_ci * firmware or after adding to the txq.
1053462306a36Sopenharmony_ci **/
1053562306a36Sopenharmony_cistatic int
1053662306a36Sopenharmony_ci__lpfc_sli_issue_fcp_io_s3(struct lpfc_hba *phba, uint32_t ring_number,
1053762306a36Sopenharmony_ci			   struct lpfc_iocbq *piocb, uint32_t flag)
1053862306a36Sopenharmony_ci{
1053962306a36Sopenharmony_ci	unsigned long iflags;
1054062306a36Sopenharmony_ci	int rc;
1054162306a36Sopenharmony_ci
1054262306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1054362306a36Sopenharmony_ci	rc = __lpfc_sli_issue_iocb_s3(phba, ring_number, piocb, flag);
1054462306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1054562306a36Sopenharmony_ci
1054662306a36Sopenharmony_ci	return rc;
1054762306a36Sopenharmony_ci}
1054862306a36Sopenharmony_ci
1054962306a36Sopenharmony_ci/**
1055062306a36Sopenharmony_ci * __lpfc_sli_issue_fcp_io_s4 - SLI4 device for sending fcp io wqe
1055162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1055262306a36Sopenharmony_ci * @ring_number: SLI ring number to issue wqe on.
1055362306a36Sopenharmony_ci * @piocb: Pointer to command iocb.
1055462306a36Sopenharmony_ci * @flag: Flag indicating if this command can be put into txq.
1055562306a36Sopenharmony_ci *
1055662306a36Sopenharmony_ci * __lpfc_sli_issue_fcp_io_s4 is used by other functions in the driver to issue
1055762306a36Sopenharmony_ci * an wqe command to an HBA with SLI-4 interface spec.
1055862306a36Sopenharmony_ci *
1055962306a36Sopenharmony_ci * This function is a lockless version. The function will return success
1056062306a36Sopenharmony_ci * after it successfully submit the wqe to firmware or after adding to the
1056162306a36Sopenharmony_ci * txq.
1056262306a36Sopenharmony_ci **/
1056362306a36Sopenharmony_cistatic int
1056462306a36Sopenharmony_ci__lpfc_sli_issue_fcp_io_s4(struct lpfc_hba *phba, uint32_t ring_number,
1056562306a36Sopenharmony_ci			   struct lpfc_iocbq *piocb, uint32_t flag)
1056662306a36Sopenharmony_ci{
1056762306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_cmd = piocb->io_buf;
1056862306a36Sopenharmony_ci
1056962306a36Sopenharmony_ci	lpfc_prep_embed_io(phba, lpfc_cmd);
1057062306a36Sopenharmony_ci	return lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, piocb);
1057162306a36Sopenharmony_ci}
1057262306a36Sopenharmony_ci
1057362306a36Sopenharmony_civoid
1057462306a36Sopenharmony_cilpfc_prep_embed_io(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
1057562306a36Sopenharmony_ci{
1057662306a36Sopenharmony_ci	struct lpfc_iocbq *piocb = &lpfc_cmd->cur_iocbq;
1057762306a36Sopenharmony_ci	union lpfc_wqe128 *wqe = &lpfc_cmd->cur_iocbq.wqe;
1057862306a36Sopenharmony_ci	struct sli4_sge *sgl;
1057962306a36Sopenharmony_ci
1058062306a36Sopenharmony_ci	/* 128 byte wqe support here */
1058162306a36Sopenharmony_ci	sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl;
1058262306a36Sopenharmony_ci
1058362306a36Sopenharmony_ci	if (phba->fcp_embed_io) {
1058462306a36Sopenharmony_ci		struct fcp_cmnd *fcp_cmnd;
1058562306a36Sopenharmony_ci		u32 *ptr;
1058662306a36Sopenharmony_ci
1058762306a36Sopenharmony_ci		fcp_cmnd = lpfc_cmd->fcp_cmnd;
1058862306a36Sopenharmony_ci
1058962306a36Sopenharmony_ci		/* Word 0-2 - FCP_CMND */
1059062306a36Sopenharmony_ci		wqe->generic.bde.tus.f.bdeFlags =
1059162306a36Sopenharmony_ci			BUFF_TYPE_BDE_IMMED;
1059262306a36Sopenharmony_ci		wqe->generic.bde.tus.f.bdeSize = sgl->sge_len;
1059362306a36Sopenharmony_ci		wqe->generic.bde.addrHigh = 0;
1059462306a36Sopenharmony_ci		wqe->generic.bde.addrLow =  88;  /* Word 22 */
1059562306a36Sopenharmony_ci
1059662306a36Sopenharmony_ci		bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1);
1059762306a36Sopenharmony_ci		bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0);
1059862306a36Sopenharmony_ci
1059962306a36Sopenharmony_ci		/* Word 22-29  FCP CMND Payload */
1060062306a36Sopenharmony_ci		ptr = &wqe->words[22];
1060162306a36Sopenharmony_ci		memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
1060262306a36Sopenharmony_ci	} else {
1060362306a36Sopenharmony_ci		/* Word 0-2 - Inline BDE */
1060462306a36Sopenharmony_ci		wqe->generic.bde.tus.f.bdeFlags =  BUFF_TYPE_BDE_64;
1060562306a36Sopenharmony_ci		wqe->generic.bde.tus.f.bdeSize = sizeof(struct fcp_cmnd);
1060662306a36Sopenharmony_ci		wqe->generic.bde.addrHigh = sgl->addr_hi;
1060762306a36Sopenharmony_ci		wqe->generic.bde.addrLow =  sgl->addr_lo;
1060862306a36Sopenharmony_ci
1060962306a36Sopenharmony_ci		/* Word 10 */
1061062306a36Sopenharmony_ci		bf_set(wqe_dbde, &wqe->generic.wqe_com, 1);
1061162306a36Sopenharmony_ci		bf_set(wqe_wqes, &wqe->generic.wqe_com, 0);
1061262306a36Sopenharmony_ci	}
1061362306a36Sopenharmony_ci
1061462306a36Sopenharmony_ci	/* add the VMID tags as per switch response */
1061562306a36Sopenharmony_ci	if (unlikely(piocb->cmd_flag & LPFC_IO_VMID)) {
1061662306a36Sopenharmony_ci		if (phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) {
1061762306a36Sopenharmony_ci			bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1);
1061862306a36Sopenharmony_ci			bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com,
1061962306a36Sopenharmony_ci					(piocb->vmid_tag.cs_ctl_vmid));
1062062306a36Sopenharmony_ci		} else if (phba->cfg_vmid_app_header) {
1062162306a36Sopenharmony_ci			bf_set(wqe_appid, &wqe->fcp_iwrite.wqe_com, 1);
1062262306a36Sopenharmony_ci			bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1);
1062362306a36Sopenharmony_ci			wqe->words[31] = piocb->vmid_tag.app_id;
1062462306a36Sopenharmony_ci		}
1062562306a36Sopenharmony_ci	}
1062662306a36Sopenharmony_ci}
1062762306a36Sopenharmony_ci
1062862306a36Sopenharmony_ci/**
1062962306a36Sopenharmony_ci * __lpfc_sli_issue_iocb_s4 - SLI4 device lockless ver of lpfc_sli_issue_iocb
1063062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1063162306a36Sopenharmony_ci * @ring_number: SLI ring number to issue iocb on.
1063262306a36Sopenharmony_ci * @piocb: Pointer to command iocb.
1063362306a36Sopenharmony_ci * @flag: Flag indicating if this command can be put into txq.
1063462306a36Sopenharmony_ci *
1063562306a36Sopenharmony_ci * __lpfc_sli_issue_iocb_s4 is used by other functions in the driver to issue
1063662306a36Sopenharmony_ci * an iocb command to an HBA with SLI-4 interface spec.
1063762306a36Sopenharmony_ci *
1063862306a36Sopenharmony_ci * This function is called with ringlock held. The function will return success
1063962306a36Sopenharmony_ci * after it successfully submit the iocb to firmware or after adding to the
1064062306a36Sopenharmony_ci * txq.
1064162306a36Sopenharmony_ci **/
1064262306a36Sopenharmony_cistatic int
1064362306a36Sopenharmony_ci__lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
1064462306a36Sopenharmony_ci			 struct lpfc_iocbq *piocb, uint32_t flag)
1064562306a36Sopenharmony_ci{
1064662306a36Sopenharmony_ci	struct lpfc_sglq *sglq;
1064762306a36Sopenharmony_ci	union lpfc_wqe128 *wqe;
1064862306a36Sopenharmony_ci	struct lpfc_queue *wq;
1064962306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1065062306a36Sopenharmony_ci	u32 ulp_command = get_job_cmnd(phba, piocb);
1065162306a36Sopenharmony_ci
1065262306a36Sopenharmony_ci	/* Get the WQ */
1065362306a36Sopenharmony_ci	if ((piocb->cmd_flag & LPFC_IO_FCP) ||
1065462306a36Sopenharmony_ci	    (piocb->cmd_flag & LPFC_USE_FCPWQIDX)) {
1065562306a36Sopenharmony_ci		wq = phba->sli4_hba.hdwq[piocb->hba_wqidx].io_wq;
1065662306a36Sopenharmony_ci	} else {
1065762306a36Sopenharmony_ci		wq = phba->sli4_hba.els_wq;
1065862306a36Sopenharmony_ci	}
1065962306a36Sopenharmony_ci
1066062306a36Sopenharmony_ci	/* Get corresponding ring */
1066162306a36Sopenharmony_ci	pring = wq->pring;
1066262306a36Sopenharmony_ci
1066362306a36Sopenharmony_ci	/*
1066462306a36Sopenharmony_ci	 * The WQE can be either 64 or 128 bytes,
1066562306a36Sopenharmony_ci	 */
1066662306a36Sopenharmony_ci
1066762306a36Sopenharmony_ci	lockdep_assert_held(&pring->ring_lock);
1066862306a36Sopenharmony_ci	wqe = &piocb->wqe;
1066962306a36Sopenharmony_ci	if (piocb->sli4_xritag == NO_XRI) {
1067062306a36Sopenharmony_ci		if (ulp_command == CMD_ABORT_XRI_CX)
1067162306a36Sopenharmony_ci			sglq = NULL;
1067262306a36Sopenharmony_ci		else {
1067362306a36Sopenharmony_ci			sglq = __lpfc_sli_get_els_sglq(phba, piocb);
1067462306a36Sopenharmony_ci			if (!sglq) {
1067562306a36Sopenharmony_ci				if (!(flag & SLI_IOCB_RET_IOCB)) {
1067662306a36Sopenharmony_ci					__lpfc_sli_ringtx_put(phba,
1067762306a36Sopenharmony_ci							pring,
1067862306a36Sopenharmony_ci							piocb);
1067962306a36Sopenharmony_ci					return IOCB_SUCCESS;
1068062306a36Sopenharmony_ci				} else {
1068162306a36Sopenharmony_ci					return IOCB_BUSY;
1068262306a36Sopenharmony_ci				}
1068362306a36Sopenharmony_ci			}
1068462306a36Sopenharmony_ci		}
1068562306a36Sopenharmony_ci	} else if (piocb->cmd_flag &  LPFC_IO_FCP) {
1068662306a36Sopenharmony_ci		/* These IO's already have an XRI and a mapped sgl. */
1068762306a36Sopenharmony_ci		sglq = NULL;
1068862306a36Sopenharmony_ci	}
1068962306a36Sopenharmony_ci	else {
1069062306a36Sopenharmony_ci		/*
1069162306a36Sopenharmony_ci		 * This is a continuation of a commandi,(CX) so this
1069262306a36Sopenharmony_ci		 * sglq is on the active list
1069362306a36Sopenharmony_ci		 */
1069462306a36Sopenharmony_ci		sglq = __lpfc_get_active_sglq(phba, piocb->sli4_lxritag);
1069562306a36Sopenharmony_ci		if (!sglq)
1069662306a36Sopenharmony_ci			return IOCB_ERROR;
1069762306a36Sopenharmony_ci	}
1069862306a36Sopenharmony_ci
1069962306a36Sopenharmony_ci	if (sglq) {
1070062306a36Sopenharmony_ci		piocb->sli4_lxritag = sglq->sli4_lxritag;
1070162306a36Sopenharmony_ci		piocb->sli4_xritag = sglq->sli4_xritag;
1070262306a36Sopenharmony_ci
1070362306a36Sopenharmony_ci		/* ABTS sent by initiator to CT exchange, the
1070462306a36Sopenharmony_ci		 * RX_ID field will be filled with the newly
1070562306a36Sopenharmony_ci		 * allocated responder XRI.
1070662306a36Sopenharmony_ci		 */
1070762306a36Sopenharmony_ci		if (ulp_command == CMD_XMIT_BLS_RSP64_CX &&
1070862306a36Sopenharmony_ci		    piocb->abort_bls == LPFC_ABTS_UNSOL_INT)
1070962306a36Sopenharmony_ci			bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp,
1071062306a36Sopenharmony_ci			       piocb->sli4_xritag);
1071162306a36Sopenharmony_ci
1071262306a36Sopenharmony_ci		bf_set(wqe_xri_tag, &wqe->generic.wqe_com,
1071362306a36Sopenharmony_ci		       piocb->sli4_xritag);
1071462306a36Sopenharmony_ci
1071562306a36Sopenharmony_ci		if (lpfc_wqe_bpl2sgl(phba, piocb, sglq) == NO_XRI)
1071662306a36Sopenharmony_ci			return IOCB_ERROR;
1071762306a36Sopenharmony_ci	}
1071862306a36Sopenharmony_ci
1071962306a36Sopenharmony_ci	if (lpfc_sli4_wq_put(wq, wqe))
1072062306a36Sopenharmony_ci		return IOCB_ERROR;
1072162306a36Sopenharmony_ci
1072262306a36Sopenharmony_ci	lpfc_sli_ringtxcmpl_put(phba, pring, piocb);
1072362306a36Sopenharmony_ci
1072462306a36Sopenharmony_ci	return 0;
1072562306a36Sopenharmony_ci}
1072662306a36Sopenharmony_ci
1072762306a36Sopenharmony_ci/*
1072862306a36Sopenharmony_ci * lpfc_sli_issue_fcp_io - Wrapper func for issuing fcp i/o
1072962306a36Sopenharmony_ci *
1073062306a36Sopenharmony_ci * This routine wraps the actual fcp i/o function for issusing WQE for sli-4
1073162306a36Sopenharmony_ci * or IOCB for sli-3  function.
1073262306a36Sopenharmony_ci * pointer from the lpfc_hba struct.
1073362306a36Sopenharmony_ci *
1073462306a36Sopenharmony_ci * Return codes:
1073562306a36Sopenharmony_ci * IOCB_ERROR - Error
1073662306a36Sopenharmony_ci * IOCB_SUCCESS - Success
1073762306a36Sopenharmony_ci * IOCB_BUSY - Busy
1073862306a36Sopenharmony_ci **/
1073962306a36Sopenharmony_ciint
1074062306a36Sopenharmony_cilpfc_sli_issue_fcp_io(struct lpfc_hba *phba, uint32_t ring_number,
1074162306a36Sopenharmony_ci		      struct lpfc_iocbq *piocb, uint32_t flag)
1074262306a36Sopenharmony_ci{
1074362306a36Sopenharmony_ci	return phba->__lpfc_sli_issue_fcp_io(phba, ring_number, piocb, flag);
1074462306a36Sopenharmony_ci}
1074562306a36Sopenharmony_ci
1074662306a36Sopenharmony_ci/*
1074762306a36Sopenharmony_ci * __lpfc_sli_issue_iocb - Wrapper func of lockless version for issuing iocb
1074862306a36Sopenharmony_ci *
1074962306a36Sopenharmony_ci * This routine wraps the actual lockless version for issusing IOCB function
1075062306a36Sopenharmony_ci * pointer from the lpfc_hba struct.
1075162306a36Sopenharmony_ci *
1075262306a36Sopenharmony_ci * Return codes:
1075362306a36Sopenharmony_ci * IOCB_ERROR - Error
1075462306a36Sopenharmony_ci * IOCB_SUCCESS - Success
1075562306a36Sopenharmony_ci * IOCB_BUSY - Busy
1075662306a36Sopenharmony_ci **/
1075762306a36Sopenharmony_ciint
1075862306a36Sopenharmony_ci__lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
1075962306a36Sopenharmony_ci		struct lpfc_iocbq *piocb, uint32_t flag)
1076062306a36Sopenharmony_ci{
1076162306a36Sopenharmony_ci	return phba->__lpfc_sli_issue_iocb(phba, ring_number, piocb, flag);
1076262306a36Sopenharmony_ci}
1076362306a36Sopenharmony_ci
1076462306a36Sopenharmony_cistatic void
1076562306a36Sopenharmony_ci__lpfc_sli_prep_els_req_rsp_s3(struct lpfc_iocbq *cmdiocbq,
1076662306a36Sopenharmony_ci			       struct lpfc_vport *vport,
1076762306a36Sopenharmony_ci			       struct lpfc_dmabuf *bmp, u16 cmd_size, u32 did,
1076862306a36Sopenharmony_ci			       u32 elscmd, u8 tmo, u8 expect_rsp)
1076962306a36Sopenharmony_ci{
1077062306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
1077162306a36Sopenharmony_ci	IOCB_t *cmd;
1077262306a36Sopenharmony_ci
1077362306a36Sopenharmony_ci	cmd = &cmdiocbq->iocb;
1077462306a36Sopenharmony_ci	memset(cmd, 0, sizeof(*cmd));
1077562306a36Sopenharmony_ci
1077662306a36Sopenharmony_ci	cmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
1077762306a36Sopenharmony_ci	cmd->un.elsreq64.bdl.addrLow = putPaddrLow(bmp->phys);
1077862306a36Sopenharmony_ci	cmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
1077962306a36Sopenharmony_ci
1078062306a36Sopenharmony_ci	if (expect_rsp) {
1078162306a36Sopenharmony_ci		cmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64));
1078262306a36Sopenharmony_ci		cmd->un.elsreq64.remoteID = did; /* DID */
1078362306a36Sopenharmony_ci		cmd->ulpCommand = CMD_ELS_REQUEST64_CR;
1078462306a36Sopenharmony_ci		cmd->ulpTimeout = tmo;
1078562306a36Sopenharmony_ci	} else {
1078662306a36Sopenharmony_ci		cmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64);
1078762306a36Sopenharmony_ci		cmd->un.genreq64.xmit_els_remoteID = did; /* DID */
1078862306a36Sopenharmony_ci		cmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
1078962306a36Sopenharmony_ci		cmd->ulpPU = PARM_NPIV_DID;
1079062306a36Sopenharmony_ci	}
1079162306a36Sopenharmony_ci	cmd->ulpBdeCount = 1;
1079262306a36Sopenharmony_ci	cmd->ulpLe = 1;
1079362306a36Sopenharmony_ci	cmd->ulpClass = CLASS3;
1079462306a36Sopenharmony_ci
1079562306a36Sopenharmony_ci	/* If we have NPIV enabled, we want to send ELS traffic by VPI. */
1079662306a36Sopenharmony_ci	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
1079762306a36Sopenharmony_ci		if (expect_rsp) {
1079862306a36Sopenharmony_ci			cmd->un.elsreq64.myID = vport->fc_myDID;
1079962306a36Sopenharmony_ci
1080062306a36Sopenharmony_ci			/* For ELS_REQUEST64_CR, use the VPI by default */
1080162306a36Sopenharmony_ci			cmd->ulpContext = phba->vpi_ids[vport->vpi];
1080262306a36Sopenharmony_ci		}
1080362306a36Sopenharmony_ci
1080462306a36Sopenharmony_ci		cmd->ulpCt_h = 0;
1080562306a36Sopenharmony_ci		/* The CT field must be 0=INVALID_RPI for the ECHO cmd */
1080662306a36Sopenharmony_ci		if (elscmd == ELS_CMD_ECHO)
1080762306a36Sopenharmony_ci			cmd->ulpCt_l = 0; /* context = invalid RPI */
1080862306a36Sopenharmony_ci		else
1080962306a36Sopenharmony_ci			cmd->ulpCt_l = 1; /* context = VPI */
1081062306a36Sopenharmony_ci	}
1081162306a36Sopenharmony_ci}
1081262306a36Sopenharmony_ci
1081362306a36Sopenharmony_cistatic void
1081462306a36Sopenharmony_ci__lpfc_sli_prep_els_req_rsp_s4(struct lpfc_iocbq *cmdiocbq,
1081562306a36Sopenharmony_ci			       struct lpfc_vport *vport,
1081662306a36Sopenharmony_ci			       struct lpfc_dmabuf *bmp, u16 cmd_size, u32 did,
1081762306a36Sopenharmony_ci			       u32 elscmd, u8 tmo, u8 expect_rsp)
1081862306a36Sopenharmony_ci{
1081962306a36Sopenharmony_ci	struct lpfc_hba  *phba = vport->phba;
1082062306a36Sopenharmony_ci	union lpfc_wqe128 *wqe;
1082162306a36Sopenharmony_ci	struct ulp_bde64_le *bde;
1082262306a36Sopenharmony_ci	u8 els_id;
1082362306a36Sopenharmony_ci
1082462306a36Sopenharmony_ci	wqe = &cmdiocbq->wqe;
1082562306a36Sopenharmony_ci	memset(wqe, 0, sizeof(*wqe));
1082662306a36Sopenharmony_ci
1082762306a36Sopenharmony_ci	/* Word 0 - 2 BDE */
1082862306a36Sopenharmony_ci	bde = (struct ulp_bde64_le *)&wqe->generic.bde;
1082962306a36Sopenharmony_ci	bde->addr_low = cpu_to_le32(putPaddrLow(bmp->phys));
1083062306a36Sopenharmony_ci	bde->addr_high = cpu_to_le32(putPaddrHigh(bmp->phys));
1083162306a36Sopenharmony_ci	bde->type_size = cpu_to_le32(cmd_size);
1083262306a36Sopenharmony_ci	bde->type_size |= cpu_to_le32(ULP_BDE64_TYPE_BDE_64);
1083362306a36Sopenharmony_ci
1083462306a36Sopenharmony_ci	if (expect_rsp) {
1083562306a36Sopenharmony_ci		bf_set(wqe_cmnd, &wqe->els_req.wqe_com, CMD_ELS_REQUEST64_WQE);
1083662306a36Sopenharmony_ci
1083762306a36Sopenharmony_ci		/* Transfer length */
1083862306a36Sopenharmony_ci		wqe->els_req.payload_len = cmd_size;
1083962306a36Sopenharmony_ci		wqe->els_req.max_response_payload_len = FCELSSIZE;
1084062306a36Sopenharmony_ci
1084162306a36Sopenharmony_ci		/* DID */
1084262306a36Sopenharmony_ci		bf_set(wqe_els_did, &wqe->els_req.wqe_dest, did);
1084362306a36Sopenharmony_ci
1084462306a36Sopenharmony_ci		/* Word 11 - ELS_ID */
1084562306a36Sopenharmony_ci		switch (elscmd) {
1084662306a36Sopenharmony_ci		case ELS_CMD_PLOGI:
1084762306a36Sopenharmony_ci			els_id = LPFC_ELS_ID_PLOGI;
1084862306a36Sopenharmony_ci			break;
1084962306a36Sopenharmony_ci		case ELS_CMD_FLOGI:
1085062306a36Sopenharmony_ci			els_id = LPFC_ELS_ID_FLOGI;
1085162306a36Sopenharmony_ci			break;
1085262306a36Sopenharmony_ci		case ELS_CMD_LOGO:
1085362306a36Sopenharmony_ci			els_id = LPFC_ELS_ID_LOGO;
1085462306a36Sopenharmony_ci			break;
1085562306a36Sopenharmony_ci		case ELS_CMD_FDISC:
1085662306a36Sopenharmony_ci			if (!vport->fc_myDID) {
1085762306a36Sopenharmony_ci				els_id = LPFC_ELS_ID_FDISC;
1085862306a36Sopenharmony_ci				break;
1085962306a36Sopenharmony_ci			}
1086062306a36Sopenharmony_ci			fallthrough;
1086162306a36Sopenharmony_ci		default:
1086262306a36Sopenharmony_ci			els_id = LPFC_ELS_ID_DEFAULT;
1086362306a36Sopenharmony_ci			break;
1086462306a36Sopenharmony_ci		}
1086562306a36Sopenharmony_ci
1086662306a36Sopenharmony_ci		bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id);
1086762306a36Sopenharmony_ci	} else {
1086862306a36Sopenharmony_ci		/* DID */
1086962306a36Sopenharmony_ci		bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest, did);
1087062306a36Sopenharmony_ci
1087162306a36Sopenharmony_ci		/* Transfer length */
1087262306a36Sopenharmony_ci		wqe->xmit_els_rsp.response_payload_len = cmd_size;
1087362306a36Sopenharmony_ci
1087462306a36Sopenharmony_ci		bf_set(wqe_cmnd, &wqe->xmit_els_rsp.wqe_com,
1087562306a36Sopenharmony_ci		       CMD_XMIT_ELS_RSP64_WQE);
1087662306a36Sopenharmony_ci	}
1087762306a36Sopenharmony_ci
1087862306a36Sopenharmony_ci	bf_set(wqe_tmo, &wqe->generic.wqe_com, tmo);
1087962306a36Sopenharmony_ci	bf_set(wqe_reqtag, &wqe->generic.wqe_com, cmdiocbq->iotag);
1088062306a36Sopenharmony_ci	bf_set(wqe_class, &wqe->generic.wqe_com, CLASS3);
1088162306a36Sopenharmony_ci
1088262306a36Sopenharmony_ci	/* If we have NPIV enabled, we want to send ELS traffic by VPI.
1088362306a36Sopenharmony_ci	 * For SLI4, since the driver controls VPIs we also want to include
1088462306a36Sopenharmony_ci	 * all ELS pt2pt protocol traffic as well.
1088562306a36Sopenharmony_ci	 */
1088662306a36Sopenharmony_ci	if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) ||
1088762306a36Sopenharmony_ci	    (vport->fc_flag & FC_PT2PT)) {
1088862306a36Sopenharmony_ci		if (expect_rsp) {
1088962306a36Sopenharmony_ci			bf_set(els_req64_sid, &wqe->els_req, vport->fc_myDID);
1089062306a36Sopenharmony_ci
1089162306a36Sopenharmony_ci			/* For ELS_REQUEST64_WQE, use the VPI by default */
1089262306a36Sopenharmony_ci			bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
1089362306a36Sopenharmony_ci			       phba->vpi_ids[vport->vpi]);
1089462306a36Sopenharmony_ci		}
1089562306a36Sopenharmony_ci
1089662306a36Sopenharmony_ci		/* The CT field must be 0=INVALID_RPI for the ECHO cmd */
1089762306a36Sopenharmony_ci		if (elscmd == ELS_CMD_ECHO)
1089862306a36Sopenharmony_ci			bf_set(wqe_ct, &wqe->generic.wqe_com, 0);
1089962306a36Sopenharmony_ci		else
1090062306a36Sopenharmony_ci			bf_set(wqe_ct, &wqe->generic.wqe_com, 1);
1090162306a36Sopenharmony_ci	}
1090262306a36Sopenharmony_ci}
1090362306a36Sopenharmony_ci
1090462306a36Sopenharmony_civoid
1090562306a36Sopenharmony_cilpfc_sli_prep_els_req_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq,
1090662306a36Sopenharmony_ci			  struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
1090762306a36Sopenharmony_ci			  u16 cmd_size, u32 did, u32 elscmd, u8 tmo,
1090862306a36Sopenharmony_ci			  u8 expect_rsp)
1090962306a36Sopenharmony_ci{
1091062306a36Sopenharmony_ci	phba->__lpfc_sli_prep_els_req_rsp(cmdiocbq, vport, bmp, cmd_size, did,
1091162306a36Sopenharmony_ci					  elscmd, tmo, expect_rsp);
1091262306a36Sopenharmony_ci}
1091362306a36Sopenharmony_ci
1091462306a36Sopenharmony_cistatic void
1091562306a36Sopenharmony_ci__lpfc_sli_prep_gen_req_s3(struct lpfc_iocbq *cmdiocbq, struct lpfc_dmabuf *bmp,
1091662306a36Sopenharmony_ci			   u16 rpi, u32 num_entry, u8 tmo)
1091762306a36Sopenharmony_ci{
1091862306a36Sopenharmony_ci	IOCB_t *cmd;
1091962306a36Sopenharmony_ci
1092062306a36Sopenharmony_ci	cmd = &cmdiocbq->iocb;
1092162306a36Sopenharmony_ci	memset(cmd, 0, sizeof(*cmd));
1092262306a36Sopenharmony_ci
1092362306a36Sopenharmony_ci	cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
1092462306a36Sopenharmony_ci	cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
1092562306a36Sopenharmony_ci	cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
1092662306a36Sopenharmony_ci	cmd->un.genreq64.bdl.bdeSize = num_entry * sizeof(struct ulp_bde64);
1092762306a36Sopenharmony_ci
1092862306a36Sopenharmony_ci	cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
1092962306a36Sopenharmony_ci	cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT;
1093062306a36Sopenharmony_ci	cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
1093162306a36Sopenharmony_ci
1093262306a36Sopenharmony_ci	cmd->ulpContext = rpi;
1093362306a36Sopenharmony_ci	cmd->ulpClass = CLASS3;
1093462306a36Sopenharmony_ci	cmd->ulpCommand = CMD_GEN_REQUEST64_CR;
1093562306a36Sopenharmony_ci	cmd->ulpBdeCount = 1;
1093662306a36Sopenharmony_ci	cmd->ulpLe = 1;
1093762306a36Sopenharmony_ci	cmd->ulpOwner = OWN_CHIP;
1093862306a36Sopenharmony_ci	cmd->ulpTimeout = tmo;
1093962306a36Sopenharmony_ci}
1094062306a36Sopenharmony_ci
1094162306a36Sopenharmony_cistatic void
1094262306a36Sopenharmony_ci__lpfc_sli_prep_gen_req_s4(struct lpfc_iocbq *cmdiocbq, struct lpfc_dmabuf *bmp,
1094362306a36Sopenharmony_ci			   u16 rpi, u32 num_entry, u8 tmo)
1094462306a36Sopenharmony_ci{
1094562306a36Sopenharmony_ci	union lpfc_wqe128 *cmdwqe;
1094662306a36Sopenharmony_ci	struct ulp_bde64_le *bde, *bpl;
1094762306a36Sopenharmony_ci	u32 xmit_len = 0, total_len = 0, size, type, i;
1094862306a36Sopenharmony_ci
1094962306a36Sopenharmony_ci	cmdwqe = &cmdiocbq->wqe;
1095062306a36Sopenharmony_ci	memset(cmdwqe, 0, sizeof(*cmdwqe));
1095162306a36Sopenharmony_ci
1095262306a36Sopenharmony_ci	/* Calculate total_len and xmit_len */
1095362306a36Sopenharmony_ci	bpl = (struct ulp_bde64_le *)bmp->virt;
1095462306a36Sopenharmony_ci	for (i = 0; i < num_entry; i++) {
1095562306a36Sopenharmony_ci		size = le32_to_cpu(bpl[i].type_size) & ULP_BDE64_SIZE_MASK;
1095662306a36Sopenharmony_ci		total_len += size;
1095762306a36Sopenharmony_ci	}
1095862306a36Sopenharmony_ci	for (i = 0; i < num_entry; i++) {
1095962306a36Sopenharmony_ci		size = le32_to_cpu(bpl[i].type_size) & ULP_BDE64_SIZE_MASK;
1096062306a36Sopenharmony_ci		type = le32_to_cpu(bpl[i].type_size) & ULP_BDE64_TYPE_MASK;
1096162306a36Sopenharmony_ci		if (type != ULP_BDE64_TYPE_BDE_64)
1096262306a36Sopenharmony_ci			break;
1096362306a36Sopenharmony_ci		xmit_len += size;
1096462306a36Sopenharmony_ci	}
1096562306a36Sopenharmony_ci
1096662306a36Sopenharmony_ci	/* Words 0 - 2 */
1096762306a36Sopenharmony_ci	bde = (struct ulp_bde64_le *)&cmdwqe->generic.bde;
1096862306a36Sopenharmony_ci	bde->addr_low = bpl->addr_low;
1096962306a36Sopenharmony_ci	bde->addr_high = bpl->addr_high;
1097062306a36Sopenharmony_ci	bde->type_size = cpu_to_le32(xmit_len);
1097162306a36Sopenharmony_ci	bde->type_size |= cpu_to_le32(ULP_BDE64_TYPE_BDE_64);
1097262306a36Sopenharmony_ci
1097362306a36Sopenharmony_ci	/* Word 3 */
1097462306a36Sopenharmony_ci	cmdwqe->gen_req.request_payload_len = xmit_len;
1097562306a36Sopenharmony_ci
1097662306a36Sopenharmony_ci	/* Word 5 */
1097762306a36Sopenharmony_ci	bf_set(wqe_type, &cmdwqe->gen_req.wge_ctl, FC_TYPE_CT);
1097862306a36Sopenharmony_ci	bf_set(wqe_rctl, &cmdwqe->gen_req.wge_ctl, FC_RCTL_DD_UNSOL_CTL);
1097962306a36Sopenharmony_ci	bf_set(wqe_si, &cmdwqe->gen_req.wge_ctl, 1);
1098062306a36Sopenharmony_ci	bf_set(wqe_la, &cmdwqe->gen_req.wge_ctl, 1);
1098162306a36Sopenharmony_ci
1098262306a36Sopenharmony_ci	/* Word 6 */
1098362306a36Sopenharmony_ci	bf_set(wqe_ctxt_tag, &cmdwqe->gen_req.wqe_com, rpi);
1098462306a36Sopenharmony_ci
1098562306a36Sopenharmony_ci	/* Word 7 */
1098662306a36Sopenharmony_ci	bf_set(wqe_tmo, &cmdwqe->gen_req.wqe_com, tmo);
1098762306a36Sopenharmony_ci	bf_set(wqe_class, &cmdwqe->gen_req.wqe_com, CLASS3);
1098862306a36Sopenharmony_ci	bf_set(wqe_cmnd, &cmdwqe->gen_req.wqe_com, CMD_GEN_REQUEST64_CR);
1098962306a36Sopenharmony_ci	bf_set(wqe_ct, &cmdwqe->gen_req.wqe_com, SLI4_CT_RPI);
1099062306a36Sopenharmony_ci
1099162306a36Sopenharmony_ci	/* Word 12 */
1099262306a36Sopenharmony_ci	cmdwqe->gen_req.max_response_payload_len = total_len - xmit_len;
1099362306a36Sopenharmony_ci}
1099462306a36Sopenharmony_ci
1099562306a36Sopenharmony_civoid
1099662306a36Sopenharmony_cilpfc_sli_prep_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq,
1099762306a36Sopenharmony_ci		      struct lpfc_dmabuf *bmp, u16 rpi, u32 num_entry, u8 tmo)
1099862306a36Sopenharmony_ci{
1099962306a36Sopenharmony_ci	phba->__lpfc_sli_prep_gen_req(cmdiocbq, bmp, rpi, num_entry, tmo);
1100062306a36Sopenharmony_ci}
1100162306a36Sopenharmony_ci
1100262306a36Sopenharmony_cistatic void
1100362306a36Sopenharmony_ci__lpfc_sli_prep_xmit_seq64_s3(struct lpfc_iocbq *cmdiocbq,
1100462306a36Sopenharmony_ci			      struct lpfc_dmabuf *bmp, u16 rpi, u16 ox_id,
1100562306a36Sopenharmony_ci			      u32 num_entry, u8 rctl, u8 last_seq, u8 cr_cx_cmd)
1100662306a36Sopenharmony_ci{
1100762306a36Sopenharmony_ci	IOCB_t *icmd;
1100862306a36Sopenharmony_ci
1100962306a36Sopenharmony_ci	icmd = &cmdiocbq->iocb;
1101062306a36Sopenharmony_ci	memset(icmd, 0, sizeof(*icmd));
1101162306a36Sopenharmony_ci
1101262306a36Sopenharmony_ci	icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
1101362306a36Sopenharmony_ci	icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys);
1101462306a36Sopenharmony_ci	icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
1101562306a36Sopenharmony_ci	icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64));
1101662306a36Sopenharmony_ci	icmd->un.xseq64.w5.hcsw.Fctl = LA;
1101762306a36Sopenharmony_ci	if (last_seq)
1101862306a36Sopenharmony_ci		icmd->un.xseq64.w5.hcsw.Fctl |= LS;
1101962306a36Sopenharmony_ci	icmd->un.xseq64.w5.hcsw.Dfctl = 0;
1102062306a36Sopenharmony_ci	icmd->un.xseq64.w5.hcsw.Rctl = rctl;
1102162306a36Sopenharmony_ci	icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT;
1102262306a36Sopenharmony_ci
1102362306a36Sopenharmony_ci	icmd->ulpBdeCount = 1;
1102462306a36Sopenharmony_ci	icmd->ulpLe = 1;
1102562306a36Sopenharmony_ci	icmd->ulpClass = CLASS3;
1102662306a36Sopenharmony_ci
1102762306a36Sopenharmony_ci	switch (cr_cx_cmd) {
1102862306a36Sopenharmony_ci	case CMD_XMIT_SEQUENCE64_CR:
1102962306a36Sopenharmony_ci		icmd->ulpContext = rpi;
1103062306a36Sopenharmony_ci		icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR;
1103162306a36Sopenharmony_ci		break;
1103262306a36Sopenharmony_ci	case CMD_XMIT_SEQUENCE64_CX:
1103362306a36Sopenharmony_ci		icmd->ulpContext = ox_id;
1103462306a36Sopenharmony_ci		icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX;
1103562306a36Sopenharmony_ci		break;
1103662306a36Sopenharmony_ci	default:
1103762306a36Sopenharmony_ci		break;
1103862306a36Sopenharmony_ci	}
1103962306a36Sopenharmony_ci}
1104062306a36Sopenharmony_ci
1104162306a36Sopenharmony_cistatic void
1104262306a36Sopenharmony_ci__lpfc_sli_prep_xmit_seq64_s4(struct lpfc_iocbq *cmdiocbq,
1104362306a36Sopenharmony_ci			      struct lpfc_dmabuf *bmp, u16 rpi, u16 ox_id,
1104462306a36Sopenharmony_ci			      u32 full_size, u8 rctl, u8 last_seq, u8 cr_cx_cmd)
1104562306a36Sopenharmony_ci{
1104662306a36Sopenharmony_ci	union lpfc_wqe128 *wqe;
1104762306a36Sopenharmony_ci	struct ulp_bde64 *bpl;
1104862306a36Sopenharmony_ci
1104962306a36Sopenharmony_ci	wqe = &cmdiocbq->wqe;
1105062306a36Sopenharmony_ci	memset(wqe, 0, sizeof(*wqe));
1105162306a36Sopenharmony_ci
1105262306a36Sopenharmony_ci	/* Words 0 - 2 */
1105362306a36Sopenharmony_ci	bpl = (struct ulp_bde64 *)bmp->virt;
1105462306a36Sopenharmony_ci	wqe->xmit_sequence.bde.addrHigh = bpl->addrHigh;
1105562306a36Sopenharmony_ci	wqe->xmit_sequence.bde.addrLow = bpl->addrLow;
1105662306a36Sopenharmony_ci	wqe->xmit_sequence.bde.tus.w = bpl->tus.w;
1105762306a36Sopenharmony_ci
1105862306a36Sopenharmony_ci	/* Word 5 */
1105962306a36Sopenharmony_ci	bf_set(wqe_ls, &wqe->xmit_sequence.wge_ctl, last_seq);
1106062306a36Sopenharmony_ci	bf_set(wqe_la, &wqe->xmit_sequence.wge_ctl, 1);
1106162306a36Sopenharmony_ci	bf_set(wqe_dfctl, &wqe->xmit_sequence.wge_ctl, 0);
1106262306a36Sopenharmony_ci	bf_set(wqe_rctl, &wqe->xmit_sequence.wge_ctl, rctl);
1106362306a36Sopenharmony_ci	bf_set(wqe_type, &wqe->xmit_sequence.wge_ctl, FC_TYPE_CT);
1106462306a36Sopenharmony_ci
1106562306a36Sopenharmony_ci	/* Word 6 */
1106662306a36Sopenharmony_ci	bf_set(wqe_ctxt_tag, &wqe->xmit_sequence.wqe_com, rpi);
1106762306a36Sopenharmony_ci
1106862306a36Sopenharmony_ci	bf_set(wqe_cmnd, &wqe->xmit_sequence.wqe_com,
1106962306a36Sopenharmony_ci	       CMD_XMIT_SEQUENCE64_WQE);
1107062306a36Sopenharmony_ci
1107162306a36Sopenharmony_ci	/* Word 7 */
1107262306a36Sopenharmony_ci	bf_set(wqe_class, &wqe->xmit_sequence.wqe_com, CLASS3);
1107362306a36Sopenharmony_ci
1107462306a36Sopenharmony_ci	/* Word 9 */
1107562306a36Sopenharmony_ci	bf_set(wqe_rcvoxid, &wqe->xmit_sequence.wqe_com, ox_id);
1107662306a36Sopenharmony_ci
1107762306a36Sopenharmony_ci	/* Word 12 */
1107862306a36Sopenharmony_ci	if (cmdiocbq->cmd_flag & (LPFC_IO_LIBDFC | LPFC_IO_LOOPBACK))
1107962306a36Sopenharmony_ci		wqe->xmit_sequence.xmit_len = full_size;
1108062306a36Sopenharmony_ci	else
1108162306a36Sopenharmony_ci		wqe->xmit_sequence.xmit_len =
1108262306a36Sopenharmony_ci			wqe->xmit_sequence.bde.tus.f.bdeSize;
1108362306a36Sopenharmony_ci}
1108462306a36Sopenharmony_ci
1108562306a36Sopenharmony_civoid
1108662306a36Sopenharmony_cilpfc_sli_prep_xmit_seq64(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq,
1108762306a36Sopenharmony_ci			 struct lpfc_dmabuf *bmp, u16 rpi, u16 ox_id,
1108862306a36Sopenharmony_ci			 u32 num_entry, u8 rctl, u8 last_seq, u8 cr_cx_cmd)
1108962306a36Sopenharmony_ci{
1109062306a36Sopenharmony_ci	phba->__lpfc_sli_prep_xmit_seq64(cmdiocbq, bmp, rpi, ox_id, num_entry,
1109162306a36Sopenharmony_ci					 rctl, last_seq, cr_cx_cmd);
1109262306a36Sopenharmony_ci}
1109362306a36Sopenharmony_ci
1109462306a36Sopenharmony_cistatic void
1109562306a36Sopenharmony_ci__lpfc_sli_prep_abort_xri_s3(struct lpfc_iocbq *cmdiocbq, u16 ulp_context,
1109662306a36Sopenharmony_ci			     u16 iotag, u8 ulp_class, u16 cqid, bool ia,
1109762306a36Sopenharmony_ci			     bool wqec)
1109862306a36Sopenharmony_ci{
1109962306a36Sopenharmony_ci	IOCB_t *icmd = NULL;
1110062306a36Sopenharmony_ci
1110162306a36Sopenharmony_ci	icmd = &cmdiocbq->iocb;
1110262306a36Sopenharmony_ci	memset(icmd, 0, sizeof(*icmd));
1110362306a36Sopenharmony_ci
1110462306a36Sopenharmony_ci	/* Word 5 */
1110562306a36Sopenharmony_ci	icmd->un.acxri.abortContextTag = ulp_context;
1110662306a36Sopenharmony_ci	icmd->un.acxri.abortIoTag = iotag;
1110762306a36Sopenharmony_ci
1110862306a36Sopenharmony_ci	if (ia) {
1110962306a36Sopenharmony_ci		/* Word 7 */
1111062306a36Sopenharmony_ci		icmd->ulpCommand = CMD_CLOSE_XRI_CN;
1111162306a36Sopenharmony_ci	} else {
1111262306a36Sopenharmony_ci		/* Word 3 */
1111362306a36Sopenharmony_ci		icmd->un.acxri.abortType = ABORT_TYPE_ABTS;
1111462306a36Sopenharmony_ci
1111562306a36Sopenharmony_ci		/* Word 7 */
1111662306a36Sopenharmony_ci		icmd->ulpClass = ulp_class;
1111762306a36Sopenharmony_ci		icmd->ulpCommand = CMD_ABORT_XRI_CN;
1111862306a36Sopenharmony_ci	}
1111962306a36Sopenharmony_ci
1112062306a36Sopenharmony_ci	/* Word 7 */
1112162306a36Sopenharmony_ci	icmd->ulpLe = 1;
1112262306a36Sopenharmony_ci}
1112362306a36Sopenharmony_ci
1112462306a36Sopenharmony_cistatic void
1112562306a36Sopenharmony_ci__lpfc_sli_prep_abort_xri_s4(struct lpfc_iocbq *cmdiocbq, u16 ulp_context,
1112662306a36Sopenharmony_ci			     u16 iotag, u8 ulp_class, u16 cqid, bool ia,
1112762306a36Sopenharmony_ci			     bool wqec)
1112862306a36Sopenharmony_ci{
1112962306a36Sopenharmony_ci	union lpfc_wqe128 *wqe;
1113062306a36Sopenharmony_ci
1113162306a36Sopenharmony_ci	wqe = &cmdiocbq->wqe;
1113262306a36Sopenharmony_ci	memset(wqe, 0, sizeof(*wqe));
1113362306a36Sopenharmony_ci
1113462306a36Sopenharmony_ci	/* Word 3 */
1113562306a36Sopenharmony_ci	bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG);
1113662306a36Sopenharmony_ci	if (ia)
1113762306a36Sopenharmony_ci		bf_set(abort_cmd_ia, &wqe->abort_cmd, 1);
1113862306a36Sopenharmony_ci	else
1113962306a36Sopenharmony_ci		bf_set(abort_cmd_ia, &wqe->abort_cmd, 0);
1114062306a36Sopenharmony_ci
1114162306a36Sopenharmony_ci	/* Word 7 */
1114262306a36Sopenharmony_ci	bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_WQE);
1114362306a36Sopenharmony_ci
1114462306a36Sopenharmony_ci	/* Word 8 */
1114562306a36Sopenharmony_ci	wqe->abort_cmd.wqe_com.abort_tag = ulp_context;
1114662306a36Sopenharmony_ci
1114762306a36Sopenharmony_ci	/* Word 9 */
1114862306a36Sopenharmony_ci	bf_set(wqe_reqtag, &wqe->abort_cmd.wqe_com, iotag);
1114962306a36Sopenharmony_ci
1115062306a36Sopenharmony_ci	/* Word 10 */
1115162306a36Sopenharmony_ci	bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1);
1115262306a36Sopenharmony_ci
1115362306a36Sopenharmony_ci	/* Word 11 */
1115462306a36Sopenharmony_ci	if (wqec)
1115562306a36Sopenharmony_ci		bf_set(wqe_wqec, &wqe->abort_cmd.wqe_com, 1);
1115662306a36Sopenharmony_ci	bf_set(wqe_cqid, &wqe->abort_cmd.wqe_com, cqid);
1115762306a36Sopenharmony_ci	bf_set(wqe_cmd_type, &wqe->abort_cmd.wqe_com, OTHER_COMMAND);
1115862306a36Sopenharmony_ci}
1115962306a36Sopenharmony_ci
1116062306a36Sopenharmony_civoid
1116162306a36Sopenharmony_cilpfc_sli_prep_abort_xri(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq,
1116262306a36Sopenharmony_ci			u16 ulp_context, u16 iotag, u8 ulp_class, u16 cqid,
1116362306a36Sopenharmony_ci			bool ia, bool wqec)
1116462306a36Sopenharmony_ci{
1116562306a36Sopenharmony_ci	phba->__lpfc_sli_prep_abort_xri(cmdiocbq, ulp_context, iotag, ulp_class,
1116662306a36Sopenharmony_ci					cqid, ia, wqec);
1116762306a36Sopenharmony_ci}
1116862306a36Sopenharmony_ci
1116962306a36Sopenharmony_ci/**
1117062306a36Sopenharmony_ci * lpfc_sli_api_table_setup - Set up sli api function jump table
1117162306a36Sopenharmony_ci * @phba: The hba struct for which this call is being executed.
1117262306a36Sopenharmony_ci * @dev_grp: The HBA PCI-Device group number.
1117362306a36Sopenharmony_ci *
1117462306a36Sopenharmony_ci * This routine sets up the SLI interface API function jump table in @phba
1117562306a36Sopenharmony_ci * struct.
1117662306a36Sopenharmony_ci * Returns: 0 - success, -ENODEV - failure.
1117762306a36Sopenharmony_ci **/
1117862306a36Sopenharmony_ciint
1117962306a36Sopenharmony_cilpfc_sli_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
1118062306a36Sopenharmony_ci{
1118162306a36Sopenharmony_ci
1118262306a36Sopenharmony_ci	switch (dev_grp) {
1118362306a36Sopenharmony_ci	case LPFC_PCI_DEV_LP:
1118462306a36Sopenharmony_ci		phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s3;
1118562306a36Sopenharmony_ci		phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s3;
1118662306a36Sopenharmony_ci		phba->__lpfc_sli_issue_fcp_io = __lpfc_sli_issue_fcp_io_s3;
1118762306a36Sopenharmony_ci		phba->__lpfc_sli_prep_els_req_rsp = __lpfc_sli_prep_els_req_rsp_s3;
1118862306a36Sopenharmony_ci		phba->__lpfc_sli_prep_gen_req = __lpfc_sli_prep_gen_req_s3;
1118962306a36Sopenharmony_ci		phba->__lpfc_sli_prep_xmit_seq64 = __lpfc_sli_prep_xmit_seq64_s3;
1119062306a36Sopenharmony_ci		phba->__lpfc_sli_prep_abort_xri = __lpfc_sli_prep_abort_xri_s3;
1119162306a36Sopenharmony_ci		break;
1119262306a36Sopenharmony_ci	case LPFC_PCI_DEV_OC:
1119362306a36Sopenharmony_ci		phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s4;
1119462306a36Sopenharmony_ci		phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s4;
1119562306a36Sopenharmony_ci		phba->__lpfc_sli_issue_fcp_io = __lpfc_sli_issue_fcp_io_s4;
1119662306a36Sopenharmony_ci		phba->__lpfc_sli_prep_els_req_rsp = __lpfc_sli_prep_els_req_rsp_s4;
1119762306a36Sopenharmony_ci		phba->__lpfc_sli_prep_gen_req = __lpfc_sli_prep_gen_req_s4;
1119862306a36Sopenharmony_ci		phba->__lpfc_sli_prep_xmit_seq64 = __lpfc_sli_prep_xmit_seq64_s4;
1119962306a36Sopenharmony_ci		phba->__lpfc_sli_prep_abort_xri = __lpfc_sli_prep_abort_xri_s4;
1120062306a36Sopenharmony_ci		break;
1120162306a36Sopenharmony_ci	default:
1120262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
1120362306a36Sopenharmony_ci				"1419 Invalid HBA PCI-device group: 0x%x\n",
1120462306a36Sopenharmony_ci				dev_grp);
1120562306a36Sopenharmony_ci		return -ENODEV;
1120662306a36Sopenharmony_ci	}
1120762306a36Sopenharmony_ci	return 0;
1120862306a36Sopenharmony_ci}
1120962306a36Sopenharmony_ci
1121062306a36Sopenharmony_ci/**
1121162306a36Sopenharmony_ci * lpfc_sli4_calc_ring - Calculates which ring to use
1121262306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1121362306a36Sopenharmony_ci * @piocb: Pointer to command iocb.
1121462306a36Sopenharmony_ci *
1121562306a36Sopenharmony_ci * For SLI4 only, FCP IO can deferred to one fo many WQs, based on
1121662306a36Sopenharmony_ci * hba_wqidx, thus we need to calculate the corresponding ring.
1121762306a36Sopenharmony_ci * Since ABORTS must go on the same WQ of the command they are
1121862306a36Sopenharmony_ci * aborting, we use command's hba_wqidx.
1121962306a36Sopenharmony_ci */
1122062306a36Sopenharmony_cistruct lpfc_sli_ring *
1122162306a36Sopenharmony_cilpfc_sli4_calc_ring(struct lpfc_hba *phba, struct lpfc_iocbq *piocb)
1122262306a36Sopenharmony_ci{
1122362306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_cmd;
1122462306a36Sopenharmony_ci
1122562306a36Sopenharmony_ci	if (piocb->cmd_flag & (LPFC_IO_FCP | LPFC_USE_FCPWQIDX)) {
1122662306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.hdwq))
1122762306a36Sopenharmony_ci			return NULL;
1122862306a36Sopenharmony_ci		/*
1122962306a36Sopenharmony_ci		 * for abort iocb hba_wqidx should already
1123062306a36Sopenharmony_ci		 * be setup based on what work queue we used.
1123162306a36Sopenharmony_ci		 */
1123262306a36Sopenharmony_ci		if (!(piocb->cmd_flag & LPFC_USE_FCPWQIDX)) {
1123362306a36Sopenharmony_ci			lpfc_cmd = piocb->io_buf;
1123462306a36Sopenharmony_ci			piocb->hba_wqidx = lpfc_cmd->hdwq_no;
1123562306a36Sopenharmony_ci		}
1123662306a36Sopenharmony_ci		return phba->sli4_hba.hdwq[piocb->hba_wqidx].io_wq->pring;
1123762306a36Sopenharmony_ci	} else {
1123862306a36Sopenharmony_ci		if (unlikely(!phba->sli4_hba.els_wq))
1123962306a36Sopenharmony_ci			return NULL;
1124062306a36Sopenharmony_ci		piocb->hba_wqidx = 0;
1124162306a36Sopenharmony_ci		return phba->sli4_hba.els_wq->pring;
1124262306a36Sopenharmony_ci	}
1124362306a36Sopenharmony_ci}
1124462306a36Sopenharmony_ci
1124562306a36Sopenharmony_ciinline void lpfc_sli4_poll_eq(struct lpfc_queue *eq)
1124662306a36Sopenharmony_ci{
1124762306a36Sopenharmony_ci	struct lpfc_hba *phba = eq->phba;
1124862306a36Sopenharmony_ci
1124962306a36Sopenharmony_ci	/*
1125062306a36Sopenharmony_ci	 * Unlocking an irq is one of the entry point to check
1125162306a36Sopenharmony_ci	 * for re-schedule, but we are good for io submission
1125262306a36Sopenharmony_ci	 * path as midlayer does a get_cpu to glue us in. Flush
1125362306a36Sopenharmony_ci	 * out the invalidate queue so we can see the updated
1125462306a36Sopenharmony_ci	 * value for flag.
1125562306a36Sopenharmony_ci	 */
1125662306a36Sopenharmony_ci	smp_rmb();
1125762306a36Sopenharmony_ci
1125862306a36Sopenharmony_ci	if (READ_ONCE(eq->mode) == LPFC_EQ_POLL)
1125962306a36Sopenharmony_ci		/* We will not likely get the completion for the caller
1126062306a36Sopenharmony_ci		 * during this iteration but i guess that's fine.
1126162306a36Sopenharmony_ci		 * Future io's coming on this eq should be able to
1126262306a36Sopenharmony_ci		 * pick it up.  As for the case of single io's, they
1126362306a36Sopenharmony_ci		 * will be handled through a sched from polling timer
1126462306a36Sopenharmony_ci		 * function which is currently triggered every 1msec.
1126562306a36Sopenharmony_ci		 */
1126662306a36Sopenharmony_ci		lpfc_sli4_process_eq(phba, eq, LPFC_QUEUE_NOARM,
1126762306a36Sopenharmony_ci				     LPFC_QUEUE_WORK);
1126862306a36Sopenharmony_ci}
1126962306a36Sopenharmony_ci
1127062306a36Sopenharmony_ci/**
1127162306a36Sopenharmony_ci * lpfc_sli_issue_iocb - Wrapper function for __lpfc_sli_issue_iocb
1127262306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1127362306a36Sopenharmony_ci * @ring_number: Ring number
1127462306a36Sopenharmony_ci * @piocb: Pointer to command iocb.
1127562306a36Sopenharmony_ci * @flag: Flag indicating if this command can be put into txq.
1127662306a36Sopenharmony_ci *
1127762306a36Sopenharmony_ci * lpfc_sli_issue_iocb is a wrapper around __lpfc_sli_issue_iocb
1127862306a36Sopenharmony_ci * function. This function gets the hbalock and calls
1127962306a36Sopenharmony_ci * __lpfc_sli_issue_iocb function and will return the error returned
1128062306a36Sopenharmony_ci * by __lpfc_sli_issue_iocb function. This wrapper is used by
1128162306a36Sopenharmony_ci * functions which do not hold hbalock.
1128262306a36Sopenharmony_ci **/
1128362306a36Sopenharmony_ciint
1128462306a36Sopenharmony_cilpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
1128562306a36Sopenharmony_ci		    struct lpfc_iocbq *piocb, uint32_t flag)
1128662306a36Sopenharmony_ci{
1128762306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1128862306a36Sopenharmony_ci	struct lpfc_queue *eq;
1128962306a36Sopenharmony_ci	unsigned long iflags;
1129062306a36Sopenharmony_ci	int rc;
1129162306a36Sopenharmony_ci
1129262306a36Sopenharmony_ci	/* If the PCI channel is in offline state, do not post iocbs. */
1129362306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(phba->pcidev)))
1129462306a36Sopenharmony_ci		return IOCB_ERROR;
1129562306a36Sopenharmony_ci
1129662306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4) {
1129762306a36Sopenharmony_ci		lpfc_sli_prep_wqe(phba, piocb);
1129862306a36Sopenharmony_ci
1129962306a36Sopenharmony_ci		eq = phba->sli4_hba.hdwq[piocb->hba_wqidx].hba_eq;
1130062306a36Sopenharmony_ci
1130162306a36Sopenharmony_ci		pring = lpfc_sli4_calc_ring(phba, piocb);
1130262306a36Sopenharmony_ci		if (unlikely(pring == NULL))
1130362306a36Sopenharmony_ci			return IOCB_ERROR;
1130462306a36Sopenharmony_ci
1130562306a36Sopenharmony_ci		spin_lock_irqsave(&pring->ring_lock, iflags);
1130662306a36Sopenharmony_ci		rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag);
1130762306a36Sopenharmony_ci		spin_unlock_irqrestore(&pring->ring_lock, iflags);
1130862306a36Sopenharmony_ci
1130962306a36Sopenharmony_ci		lpfc_sli4_poll_eq(eq);
1131062306a36Sopenharmony_ci	} else {
1131162306a36Sopenharmony_ci		/* For now, SLI2/3 will still use hbalock */
1131262306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1131362306a36Sopenharmony_ci		rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag);
1131462306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1131562306a36Sopenharmony_ci	}
1131662306a36Sopenharmony_ci	return rc;
1131762306a36Sopenharmony_ci}
1131862306a36Sopenharmony_ci
1131962306a36Sopenharmony_ci/**
1132062306a36Sopenharmony_ci * lpfc_extra_ring_setup - Extra ring setup function
1132162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1132262306a36Sopenharmony_ci *
1132362306a36Sopenharmony_ci * This function is called while driver attaches with the
1132462306a36Sopenharmony_ci * HBA to setup the extra ring. The extra ring is used
1132562306a36Sopenharmony_ci * only when driver needs to support target mode functionality
1132662306a36Sopenharmony_ci * or IP over FC functionalities.
1132762306a36Sopenharmony_ci *
1132862306a36Sopenharmony_ci * This function is called with no lock held. SLI3 only.
1132962306a36Sopenharmony_ci **/
1133062306a36Sopenharmony_cistatic int
1133162306a36Sopenharmony_cilpfc_extra_ring_setup( struct lpfc_hba *phba)
1133262306a36Sopenharmony_ci{
1133362306a36Sopenharmony_ci	struct lpfc_sli *psli;
1133462306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1133562306a36Sopenharmony_ci
1133662306a36Sopenharmony_ci	psli = &phba->sli;
1133762306a36Sopenharmony_ci
1133862306a36Sopenharmony_ci	/* Adjust cmd/rsp ring iocb entries more evenly */
1133962306a36Sopenharmony_ci
1134062306a36Sopenharmony_ci	/* Take some away from the FCP ring */
1134162306a36Sopenharmony_ci	pring = &psli->sli3_ring[LPFC_FCP_RING];
1134262306a36Sopenharmony_ci	pring->sli.sli3.numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES;
1134362306a36Sopenharmony_ci	pring->sli.sli3.numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES;
1134462306a36Sopenharmony_ci	pring->sli.sli3.numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES;
1134562306a36Sopenharmony_ci	pring->sli.sli3.numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES;
1134662306a36Sopenharmony_ci
1134762306a36Sopenharmony_ci	/* and give them to the extra ring */
1134862306a36Sopenharmony_ci	pring = &psli->sli3_ring[LPFC_EXTRA_RING];
1134962306a36Sopenharmony_ci
1135062306a36Sopenharmony_ci	pring->sli.sli3.numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES;
1135162306a36Sopenharmony_ci	pring->sli.sli3.numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES;
1135262306a36Sopenharmony_ci	pring->sli.sli3.numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES;
1135362306a36Sopenharmony_ci	pring->sli.sli3.numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES;
1135462306a36Sopenharmony_ci
1135562306a36Sopenharmony_ci	/* Setup default profile for this ring */
1135662306a36Sopenharmony_ci	pring->iotag_max = 4096;
1135762306a36Sopenharmony_ci	pring->num_mask = 1;
1135862306a36Sopenharmony_ci	pring->prt[0].profile = 0;      /* Mask 0 */
1135962306a36Sopenharmony_ci	pring->prt[0].rctl = phba->cfg_multi_ring_rctl;
1136062306a36Sopenharmony_ci	pring->prt[0].type = phba->cfg_multi_ring_type;
1136162306a36Sopenharmony_ci	pring->prt[0].lpfc_sli_rcv_unsol_event = NULL;
1136262306a36Sopenharmony_ci	return 0;
1136362306a36Sopenharmony_ci}
1136462306a36Sopenharmony_ci
1136562306a36Sopenharmony_cistatic void
1136662306a36Sopenharmony_cilpfc_sli_post_recovery_event(struct lpfc_hba *phba,
1136762306a36Sopenharmony_ci			     struct lpfc_nodelist *ndlp)
1136862306a36Sopenharmony_ci{
1136962306a36Sopenharmony_ci	unsigned long iflags;
1137062306a36Sopenharmony_ci	struct lpfc_work_evt  *evtp = &ndlp->recovery_evt;
1137162306a36Sopenharmony_ci
1137262306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1137362306a36Sopenharmony_ci	if (!list_empty(&evtp->evt_listp)) {
1137462306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1137562306a36Sopenharmony_ci		return;
1137662306a36Sopenharmony_ci	}
1137762306a36Sopenharmony_ci
1137862306a36Sopenharmony_ci	/* Incrementing the reference count until the queued work is done. */
1137962306a36Sopenharmony_ci	evtp->evt_arg1  = lpfc_nlp_get(ndlp);
1138062306a36Sopenharmony_ci	if (!evtp->evt_arg1) {
1138162306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1138262306a36Sopenharmony_ci		return;
1138362306a36Sopenharmony_ci	}
1138462306a36Sopenharmony_ci	evtp->evt = LPFC_EVT_RECOVER_PORT;
1138562306a36Sopenharmony_ci	list_add_tail(&evtp->evt_listp, &phba->work_list);
1138662306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1138762306a36Sopenharmony_ci
1138862306a36Sopenharmony_ci	lpfc_worker_wake_up(phba);
1138962306a36Sopenharmony_ci}
1139062306a36Sopenharmony_ci
1139162306a36Sopenharmony_ci/* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port.
1139262306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1139362306a36Sopenharmony_ci * @iocbq: Pointer to iocb object.
1139462306a36Sopenharmony_ci *
1139562306a36Sopenharmony_ci * The async_event handler calls this routine when it receives
1139662306a36Sopenharmony_ci * an ASYNC_STATUS_CN event from the port.  The port generates
1139762306a36Sopenharmony_ci * this event when an Abort Sequence request to an rport fails
1139862306a36Sopenharmony_ci * twice in succession.  The abort could be originated by the
1139962306a36Sopenharmony_ci * driver or by the port.  The ABTS could have been for an ELS
1140062306a36Sopenharmony_ci * or FCP IO.  The port only generates this event when an ABTS
1140162306a36Sopenharmony_ci * fails to complete after one retry.
1140262306a36Sopenharmony_ci */
1140362306a36Sopenharmony_cistatic void
1140462306a36Sopenharmony_cilpfc_sli_abts_err_handler(struct lpfc_hba *phba,
1140562306a36Sopenharmony_ci			  struct lpfc_iocbq *iocbq)
1140662306a36Sopenharmony_ci{
1140762306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp = NULL;
1140862306a36Sopenharmony_ci	uint16_t rpi = 0, vpi = 0;
1140962306a36Sopenharmony_ci	struct lpfc_vport *vport = NULL;
1141062306a36Sopenharmony_ci
1141162306a36Sopenharmony_ci	/* The rpi in the ulpContext is vport-sensitive. */
1141262306a36Sopenharmony_ci	vpi = iocbq->iocb.un.asyncstat.sub_ctxt_tag;
1141362306a36Sopenharmony_ci	rpi = iocbq->iocb.ulpContext;
1141462306a36Sopenharmony_ci
1141562306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
1141662306a36Sopenharmony_ci			"3092 Port generated ABTS async event "
1141762306a36Sopenharmony_ci			"on vpi %d rpi %d status 0x%x\n",
1141862306a36Sopenharmony_ci			vpi, rpi, iocbq->iocb.ulpStatus);
1141962306a36Sopenharmony_ci
1142062306a36Sopenharmony_ci	vport = lpfc_find_vport_by_vpid(phba, vpi);
1142162306a36Sopenharmony_ci	if (!vport)
1142262306a36Sopenharmony_ci		goto err_exit;
1142362306a36Sopenharmony_ci	ndlp = lpfc_findnode_rpi(vport, rpi);
1142462306a36Sopenharmony_ci	if (!ndlp)
1142562306a36Sopenharmony_ci		goto err_exit;
1142662306a36Sopenharmony_ci
1142762306a36Sopenharmony_ci	if (iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT)
1142862306a36Sopenharmony_ci		lpfc_sli_abts_recover_port(vport, ndlp);
1142962306a36Sopenharmony_ci	return;
1143062306a36Sopenharmony_ci
1143162306a36Sopenharmony_ci err_exit:
1143262306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
1143362306a36Sopenharmony_ci			"3095 Event Context not found, no "
1143462306a36Sopenharmony_ci			"action on vpi %d rpi %d status 0x%x, reason 0x%x\n",
1143562306a36Sopenharmony_ci			vpi, rpi, iocbq->iocb.ulpStatus,
1143662306a36Sopenharmony_ci			iocbq->iocb.ulpContext);
1143762306a36Sopenharmony_ci}
1143862306a36Sopenharmony_ci
1143962306a36Sopenharmony_ci/* lpfc_sli4_abts_err_handler - handle a failed ABTS request from an SLI4 port.
1144062306a36Sopenharmony_ci * @phba: pointer to HBA context object.
1144162306a36Sopenharmony_ci * @ndlp: nodelist pointer for the impacted rport.
1144262306a36Sopenharmony_ci * @axri: pointer to the wcqe containing the failed exchange.
1144362306a36Sopenharmony_ci *
1144462306a36Sopenharmony_ci * The driver calls this routine when it receives an ABORT_XRI_FCP CQE from the
1144562306a36Sopenharmony_ci * port.  The port generates this event when an abort exchange request to an
1144662306a36Sopenharmony_ci * rport fails twice in succession with no reply.  The abort could be originated
1144762306a36Sopenharmony_ci * by the driver or by the port.  The ABTS could have been for an ELS or FCP IO.
1144862306a36Sopenharmony_ci */
1144962306a36Sopenharmony_civoid
1145062306a36Sopenharmony_cilpfc_sli4_abts_err_handler(struct lpfc_hba *phba,
1145162306a36Sopenharmony_ci			   struct lpfc_nodelist *ndlp,
1145262306a36Sopenharmony_ci			   struct sli4_wcqe_xri_aborted *axri)
1145362306a36Sopenharmony_ci{
1145462306a36Sopenharmony_ci	uint32_t ext_status = 0;
1145562306a36Sopenharmony_ci
1145662306a36Sopenharmony_ci	if (!ndlp) {
1145762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
1145862306a36Sopenharmony_ci				"3115 Node Context not found, driver "
1145962306a36Sopenharmony_ci				"ignoring abts err event\n");
1146062306a36Sopenharmony_ci		return;
1146162306a36Sopenharmony_ci	}
1146262306a36Sopenharmony_ci
1146362306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
1146462306a36Sopenharmony_ci			"3116 Port generated FCP XRI ABORT event on "
1146562306a36Sopenharmony_ci			"vpi %d rpi %d xri x%x status 0x%x parameter x%x\n",
1146662306a36Sopenharmony_ci			ndlp->vport->vpi, phba->sli4_hba.rpi_ids[ndlp->nlp_rpi],
1146762306a36Sopenharmony_ci			bf_get(lpfc_wcqe_xa_xri, axri),
1146862306a36Sopenharmony_ci			bf_get(lpfc_wcqe_xa_status, axri),
1146962306a36Sopenharmony_ci			axri->parameter);
1147062306a36Sopenharmony_ci
1147162306a36Sopenharmony_ci	/*
1147262306a36Sopenharmony_ci	 * Catch the ABTS protocol failure case.  Older OCe FW releases returned
1147362306a36Sopenharmony_ci	 * LOCAL_REJECT and 0 for a failed ABTS exchange and later OCe and
1147462306a36Sopenharmony_ci	 * LPe FW releases returned LOCAL_REJECT and SEQUENCE_TIMEOUT.
1147562306a36Sopenharmony_ci	 */
1147662306a36Sopenharmony_ci	ext_status = axri->parameter & IOERR_PARAM_MASK;
1147762306a36Sopenharmony_ci	if ((bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) &&
1147862306a36Sopenharmony_ci	    ((ext_status == IOERR_SEQUENCE_TIMEOUT) || (ext_status == 0)))
1147962306a36Sopenharmony_ci		lpfc_sli_post_recovery_event(phba, ndlp);
1148062306a36Sopenharmony_ci}
1148162306a36Sopenharmony_ci
1148262306a36Sopenharmony_ci/**
1148362306a36Sopenharmony_ci * lpfc_sli_async_event_handler - ASYNC iocb handler function
1148462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1148562306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
1148662306a36Sopenharmony_ci * @iocbq: Pointer to iocb object.
1148762306a36Sopenharmony_ci *
1148862306a36Sopenharmony_ci * This function is called by the slow ring event handler
1148962306a36Sopenharmony_ci * function when there is an ASYNC event iocb in the ring.
1149062306a36Sopenharmony_ci * This function is called with no lock held.
1149162306a36Sopenharmony_ci * Currently this function handles only temperature related
1149262306a36Sopenharmony_ci * ASYNC events. The function decodes the temperature sensor
1149362306a36Sopenharmony_ci * event message and posts events for the management applications.
1149462306a36Sopenharmony_ci **/
1149562306a36Sopenharmony_cistatic void
1149662306a36Sopenharmony_cilpfc_sli_async_event_handler(struct lpfc_hba * phba,
1149762306a36Sopenharmony_ci	struct lpfc_sli_ring * pring, struct lpfc_iocbq * iocbq)
1149862306a36Sopenharmony_ci{
1149962306a36Sopenharmony_ci	IOCB_t *icmd;
1150062306a36Sopenharmony_ci	uint16_t evt_code;
1150162306a36Sopenharmony_ci	struct temp_event temp_event_data;
1150262306a36Sopenharmony_ci	struct Scsi_Host *shost;
1150362306a36Sopenharmony_ci	uint32_t *iocb_w;
1150462306a36Sopenharmony_ci
1150562306a36Sopenharmony_ci	icmd = &iocbq->iocb;
1150662306a36Sopenharmony_ci	evt_code = icmd->un.asyncstat.evt_code;
1150762306a36Sopenharmony_ci
1150862306a36Sopenharmony_ci	switch (evt_code) {
1150962306a36Sopenharmony_ci	case ASYNC_TEMP_WARN:
1151062306a36Sopenharmony_ci	case ASYNC_TEMP_SAFE:
1151162306a36Sopenharmony_ci		temp_event_data.data = (uint32_t) icmd->ulpContext;
1151262306a36Sopenharmony_ci		temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
1151362306a36Sopenharmony_ci		if (evt_code == ASYNC_TEMP_WARN) {
1151462306a36Sopenharmony_ci			temp_event_data.event_code = LPFC_THRESHOLD_TEMP;
1151562306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1151662306a36Sopenharmony_ci				"0347 Adapter is very hot, please take "
1151762306a36Sopenharmony_ci				"corrective action. temperature : %d Celsius\n",
1151862306a36Sopenharmony_ci				(uint32_t) icmd->ulpContext);
1151962306a36Sopenharmony_ci		} else {
1152062306a36Sopenharmony_ci			temp_event_data.event_code = LPFC_NORMAL_TEMP;
1152162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1152262306a36Sopenharmony_ci				"0340 Adapter temperature is OK now. "
1152362306a36Sopenharmony_ci				"temperature : %d Celsius\n",
1152462306a36Sopenharmony_ci				(uint32_t) icmd->ulpContext);
1152562306a36Sopenharmony_ci		}
1152662306a36Sopenharmony_ci
1152762306a36Sopenharmony_ci		/* Send temperature change event to applications */
1152862306a36Sopenharmony_ci		shost = lpfc_shost_from_vport(phba->pport);
1152962306a36Sopenharmony_ci		fc_host_post_vendor_event(shost, fc_get_event_number(),
1153062306a36Sopenharmony_ci			sizeof(temp_event_data), (char *) &temp_event_data,
1153162306a36Sopenharmony_ci			LPFC_NL_VENDOR_ID);
1153262306a36Sopenharmony_ci		break;
1153362306a36Sopenharmony_ci	case ASYNC_STATUS_CN:
1153462306a36Sopenharmony_ci		lpfc_sli_abts_err_handler(phba, iocbq);
1153562306a36Sopenharmony_ci		break;
1153662306a36Sopenharmony_ci	default:
1153762306a36Sopenharmony_ci		iocb_w = (uint32_t *) icmd;
1153862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1153962306a36Sopenharmony_ci			"0346 Ring %d handler: unexpected ASYNC_STATUS"
1154062306a36Sopenharmony_ci			" evt_code 0x%x\n"
1154162306a36Sopenharmony_ci			"W0  0x%08x W1  0x%08x W2  0x%08x W3  0x%08x\n"
1154262306a36Sopenharmony_ci			"W4  0x%08x W5  0x%08x W6  0x%08x W7  0x%08x\n"
1154362306a36Sopenharmony_ci			"W8  0x%08x W9  0x%08x W10 0x%08x W11 0x%08x\n"
1154462306a36Sopenharmony_ci			"W12 0x%08x W13 0x%08x W14 0x%08x W15 0x%08x\n",
1154562306a36Sopenharmony_ci			pring->ringno, icmd->un.asyncstat.evt_code,
1154662306a36Sopenharmony_ci			iocb_w[0], iocb_w[1], iocb_w[2], iocb_w[3],
1154762306a36Sopenharmony_ci			iocb_w[4], iocb_w[5], iocb_w[6], iocb_w[7],
1154862306a36Sopenharmony_ci			iocb_w[8], iocb_w[9], iocb_w[10], iocb_w[11],
1154962306a36Sopenharmony_ci			iocb_w[12], iocb_w[13], iocb_w[14], iocb_w[15]);
1155062306a36Sopenharmony_ci
1155162306a36Sopenharmony_ci		break;
1155262306a36Sopenharmony_ci	}
1155362306a36Sopenharmony_ci}
1155462306a36Sopenharmony_ci
1155562306a36Sopenharmony_ci
1155662306a36Sopenharmony_ci/**
1155762306a36Sopenharmony_ci * lpfc_sli4_setup - SLI ring setup function
1155862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1155962306a36Sopenharmony_ci *
1156062306a36Sopenharmony_ci * lpfc_sli_setup sets up rings of the SLI interface with
1156162306a36Sopenharmony_ci * number of iocbs per ring and iotags. This function is
1156262306a36Sopenharmony_ci * called while driver attach to the HBA and before the
1156362306a36Sopenharmony_ci * interrupts are enabled. So there is no need for locking.
1156462306a36Sopenharmony_ci *
1156562306a36Sopenharmony_ci * This function always returns 0.
1156662306a36Sopenharmony_ci **/
1156762306a36Sopenharmony_ciint
1156862306a36Sopenharmony_cilpfc_sli4_setup(struct lpfc_hba *phba)
1156962306a36Sopenharmony_ci{
1157062306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1157162306a36Sopenharmony_ci
1157262306a36Sopenharmony_ci	pring = phba->sli4_hba.els_wq->pring;
1157362306a36Sopenharmony_ci	pring->num_mask = LPFC_MAX_RING_MASK;
1157462306a36Sopenharmony_ci	pring->prt[0].profile = 0;	/* Mask 0 */
1157562306a36Sopenharmony_ci	pring->prt[0].rctl = FC_RCTL_ELS_REQ;
1157662306a36Sopenharmony_ci	pring->prt[0].type = FC_TYPE_ELS;
1157762306a36Sopenharmony_ci	pring->prt[0].lpfc_sli_rcv_unsol_event =
1157862306a36Sopenharmony_ci	    lpfc_els_unsol_event;
1157962306a36Sopenharmony_ci	pring->prt[1].profile = 0;	/* Mask 1 */
1158062306a36Sopenharmony_ci	pring->prt[1].rctl = FC_RCTL_ELS_REP;
1158162306a36Sopenharmony_ci	pring->prt[1].type = FC_TYPE_ELS;
1158262306a36Sopenharmony_ci	pring->prt[1].lpfc_sli_rcv_unsol_event =
1158362306a36Sopenharmony_ci	    lpfc_els_unsol_event;
1158462306a36Sopenharmony_ci	pring->prt[2].profile = 0;	/* Mask 2 */
1158562306a36Sopenharmony_ci	/* NameServer Inquiry */
1158662306a36Sopenharmony_ci	pring->prt[2].rctl = FC_RCTL_DD_UNSOL_CTL;
1158762306a36Sopenharmony_ci	/* NameServer */
1158862306a36Sopenharmony_ci	pring->prt[2].type = FC_TYPE_CT;
1158962306a36Sopenharmony_ci	pring->prt[2].lpfc_sli_rcv_unsol_event =
1159062306a36Sopenharmony_ci	    lpfc_ct_unsol_event;
1159162306a36Sopenharmony_ci	pring->prt[3].profile = 0;	/* Mask 3 */
1159262306a36Sopenharmony_ci	/* NameServer response */
1159362306a36Sopenharmony_ci	pring->prt[3].rctl = FC_RCTL_DD_SOL_CTL;
1159462306a36Sopenharmony_ci	/* NameServer */
1159562306a36Sopenharmony_ci	pring->prt[3].type = FC_TYPE_CT;
1159662306a36Sopenharmony_ci	pring->prt[3].lpfc_sli_rcv_unsol_event =
1159762306a36Sopenharmony_ci	    lpfc_ct_unsol_event;
1159862306a36Sopenharmony_ci	return 0;
1159962306a36Sopenharmony_ci}
1160062306a36Sopenharmony_ci
1160162306a36Sopenharmony_ci/**
1160262306a36Sopenharmony_ci * lpfc_sli_setup - SLI ring setup function
1160362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1160462306a36Sopenharmony_ci *
1160562306a36Sopenharmony_ci * lpfc_sli_setup sets up rings of the SLI interface with
1160662306a36Sopenharmony_ci * number of iocbs per ring and iotags. This function is
1160762306a36Sopenharmony_ci * called while driver attach to the HBA and before the
1160862306a36Sopenharmony_ci * interrupts are enabled. So there is no need for locking.
1160962306a36Sopenharmony_ci *
1161062306a36Sopenharmony_ci * This function always returns 0. SLI3 only.
1161162306a36Sopenharmony_ci **/
1161262306a36Sopenharmony_ciint
1161362306a36Sopenharmony_cilpfc_sli_setup(struct lpfc_hba *phba)
1161462306a36Sopenharmony_ci{
1161562306a36Sopenharmony_ci	int i, totiocbsize = 0;
1161662306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
1161762306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1161862306a36Sopenharmony_ci
1161962306a36Sopenharmony_ci	psli->num_rings = MAX_SLI3_CONFIGURED_RINGS;
1162062306a36Sopenharmony_ci	psli->sli_flag = 0;
1162162306a36Sopenharmony_ci
1162262306a36Sopenharmony_ci	psli->iocbq_lookup = NULL;
1162362306a36Sopenharmony_ci	psli->iocbq_lookup_len = 0;
1162462306a36Sopenharmony_ci	psli->last_iotag = 0;
1162562306a36Sopenharmony_ci
1162662306a36Sopenharmony_ci	for (i = 0; i < psli->num_rings; i++) {
1162762306a36Sopenharmony_ci		pring = &psli->sli3_ring[i];
1162862306a36Sopenharmony_ci		switch (i) {
1162962306a36Sopenharmony_ci		case LPFC_FCP_RING:	/* ring 0 - FCP */
1163062306a36Sopenharmony_ci			/* numCiocb and numRiocb are used in config_port */
1163162306a36Sopenharmony_ci			pring->sli.sli3.numCiocb = SLI2_IOCB_CMD_R0_ENTRIES;
1163262306a36Sopenharmony_ci			pring->sli.sli3.numRiocb = SLI2_IOCB_RSP_R0_ENTRIES;
1163362306a36Sopenharmony_ci			pring->sli.sli3.numCiocb +=
1163462306a36Sopenharmony_ci				SLI2_IOCB_CMD_R1XTRA_ENTRIES;
1163562306a36Sopenharmony_ci			pring->sli.sli3.numRiocb +=
1163662306a36Sopenharmony_ci				SLI2_IOCB_RSP_R1XTRA_ENTRIES;
1163762306a36Sopenharmony_ci			pring->sli.sli3.numCiocb +=
1163862306a36Sopenharmony_ci				SLI2_IOCB_CMD_R3XTRA_ENTRIES;
1163962306a36Sopenharmony_ci			pring->sli.sli3.numRiocb +=
1164062306a36Sopenharmony_ci				SLI2_IOCB_RSP_R3XTRA_ENTRIES;
1164162306a36Sopenharmony_ci			pring->sli.sli3.sizeCiocb = (phba->sli_rev == 3) ?
1164262306a36Sopenharmony_ci							SLI3_IOCB_CMD_SIZE :
1164362306a36Sopenharmony_ci							SLI2_IOCB_CMD_SIZE;
1164462306a36Sopenharmony_ci			pring->sli.sli3.sizeRiocb = (phba->sli_rev == 3) ?
1164562306a36Sopenharmony_ci							SLI3_IOCB_RSP_SIZE :
1164662306a36Sopenharmony_ci							SLI2_IOCB_RSP_SIZE;
1164762306a36Sopenharmony_ci			pring->iotag_ctr = 0;
1164862306a36Sopenharmony_ci			pring->iotag_max =
1164962306a36Sopenharmony_ci			    (phba->cfg_hba_queue_depth * 2);
1165062306a36Sopenharmony_ci			pring->fast_iotag = pring->iotag_max;
1165162306a36Sopenharmony_ci			pring->num_mask = 0;
1165262306a36Sopenharmony_ci			break;
1165362306a36Sopenharmony_ci		case LPFC_EXTRA_RING:	/* ring 1 - EXTRA */
1165462306a36Sopenharmony_ci			/* numCiocb and numRiocb are used in config_port */
1165562306a36Sopenharmony_ci			pring->sli.sli3.numCiocb = SLI2_IOCB_CMD_R1_ENTRIES;
1165662306a36Sopenharmony_ci			pring->sli.sli3.numRiocb = SLI2_IOCB_RSP_R1_ENTRIES;
1165762306a36Sopenharmony_ci			pring->sli.sli3.sizeCiocb = (phba->sli_rev == 3) ?
1165862306a36Sopenharmony_ci							SLI3_IOCB_CMD_SIZE :
1165962306a36Sopenharmony_ci							SLI2_IOCB_CMD_SIZE;
1166062306a36Sopenharmony_ci			pring->sli.sli3.sizeRiocb = (phba->sli_rev == 3) ?
1166162306a36Sopenharmony_ci							SLI3_IOCB_RSP_SIZE :
1166262306a36Sopenharmony_ci							SLI2_IOCB_RSP_SIZE;
1166362306a36Sopenharmony_ci			pring->iotag_max = phba->cfg_hba_queue_depth;
1166462306a36Sopenharmony_ci			pring->num_mask = 0;
1166562306a36Sopenharmony_ci			break;
1166662306a36Sopenharmony_ci		case LPFC_ELS_RING:	/* ring 2 - ELS / CT */
1166762306a36Sopenharmony_ci			/* numCiocb and numRiocb are used in config_port */
1166862306a36Sopenharmony_ci			pring->sli.sli3.numCiocb = SLI2_IOCB_CMD_R2_ENTRIES;
1166962306a36Sopenharmony_ci			pring->sli.sli3.numRiocb = SLI2_IOCB_RSP_R2_ENTRIES;
1167062306a36Sopenharmony_ci			pring->sli.sli3.sizeCiocb = (phba->sli_rev == 3) ?
1167162306a36Sopenharmony_ci							SLI3_IOCB_CMD_SIZE :
1167262306a36Sopenharmony_ci							SLI2_IOCB_CMD_SIZE;
1167362306a36Sopenharmony_ci			pring->sli.sli3.sizeRiocb = (phba->sli_rev == 3) ?
1167462306a36Sopenharmony_ci							SLI3_IOCB_RSP_SIZE :
1167562306a36Sopenharmony_ci							SLI2_IOCB_RSP_SIZE;
1167662306a36Sopenharmony_ci			pring->fast_iotag = 0;
1167762306a36Sopenharmony_ci			pring->iotag_ctr = 0;
1167862306a36Sopenharmony_ci			pring->iotag_max = 4096;
1167962306a36Sopenharmony_ci			pring->lpfc_sli_rcv_async_status =
1168062306a36Sopenharmony_ci				lpfc_sli_async_event_handler;
1168162306a36Sopenharmony_ci			pring->num_mask = LPFC_MAX_RING_MASK;
1168262306a36Sopenharmony_ci			pring->prt[0].profile = 0;	/* Mask 0 */
1168362306a36Sopenharmony_ci			pring->prt[0].rctl = FC_RCTL_ELS_REQ;
1168462306a36Sopenharmony_ci			pring->prt[0].type = FC_TYPE_ELS;
1168562306a36Sopenharmony_ci			pring->prt[0].lpfc_sli_rcv_unsol_event =
1168662306a36Sopenharmony_ci			    lpfc_els_unsol_event;
1168762306a36Sopenharmony_ci			pring->prt[1].profile = 0;	/* Mask 1 */
1168862306a36Sopenharmony_ci			pring->prt[1].rctl = FC_RCTL_ELS_REP;
1168962306a36Sopenharmony_ci			pring->prt[1].type = FC_TYPE_ELS;
1169062306a36Sopenharmony_ci			pring->prt[1].lpfc_sli_rcv_unsol_event =
1169162306a36Sopenharmony_ci			    lpfc_els_unsol_event;
1169262306a36Sopenharmony_ci			pring->prt[2].profile = 0;	/* Mask 2 */
1169362306a36Sopenharmony_ci			/* NameServer Inquiry */
1169462306a36Sopenharmony_ci			pring->prt[2].rctl = FC_RCTL_DD_UNSOL_CTL;
1169562306a36Sopenharmony_ci			/* NameServer */
1169662306a36Sopenharmony_ci			pring->prt[2].type = FC_TYPE_CT;
1169762306a36Sopenharmony_ci			pring->prt[2].lpfc_sli_rcv_unsol_event =
1169862306a36Sopenharmony_ci			    lpfc_ct_unsol_event;
1169962306a36Sopenharmony_ci			pring->prt[3].profile = 0;	/* Mask 3 */
1170062306a36Sopenharmony_ci			/* NameServer response */
1170162306a36Sopenharmony_ci			pring->prt[3].rctl = FC_RCTL_DD_SOL_CTL;
1170262306a36Sopenharmony_ci			/* NameServer */
1170362306a36Sopenharmony_ci			pring->prt[3].type = FC_TYPE_CT;
1170462306a36Sopenharmony_ci			pring->prt[3].lpfc_sli_rcv_unsol_event =
1170562306a36Sopenharmony_ci			    lpfc_ct_unsol_event;
1170662306a36Sopenharmony_ci			break;
1170762306a36Sopenharmony_ci		}
1170862306a36Sopenharmony_ci		totiocbsize += (pring->sli.sli3.numCiocb *
1170962306a36Sopenharmony_ci			pring->sli.sli3.sizeCiocb) +
1171062306a36Sopenharmony_ci			(pring->sli.sli3.numRiocb * pring->sli.sli3.sizeRiocb);
1171162306a36Sopenharmony_ci	}
1171262306a36Sopenharmony_ci	if (totiocbsize > MAX_SLIM_IOCB_SIZE) {
1171362306a36Sopenharmony_ci		/* Too many cmd / rsp ring entries in SLI2 SLIM */
1171462306a36Sopenharmony_ci		printk(KERN_ERR "%d:0462 Too many cmd / rsp ring entries in "
1171562306a36Sopenharmony_ci		       "SLI2 SLIM Data: x%x x%lx\n",
1171662306a36Sopenharmony_ci		       phba->brd_no, totiocbsize,
1171762306a36Sopenharmony_ci		       (unsigned long) MAX_SLIM_IOCB_SIZE);
1171862306a36Sopenharmony_ci	}
1171962306a36Sopenharmony_ci	if (phba->cfg_multi_ring_support == 2)
1172062306a36Sopenharmony_ci		lpfc_extra_ring_setup(phba);
1172162306a36Sopenharmony_ci
1172262306a36Sopenharmony_ci	return 0;
1172362306a36Sopenharmony_ci}
1172462306a36Sopenharmony_ci
1172562306a36Sopenharmony_ci/**
1172662306a36Sopenharmony_ci * lpfc_sli4_queue_init - Queue initialization function
1172762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1172862306a36Sopenharmony_ci *
1172962306a36Sopenharmony_ci * lpfc_sli4_queue_init sets up mailbox queues and iocb queues for each
1173062306a36Sopenharmony_ci * ring. This function also initializes ring indices of each ring.
1173162306a36Sopenharmony_ci * This function is called during the initialization of the SLI
1173262306a36Sopenharmony_ci * interface of an HBA.
1173362306a36Sopenharmony_ci * This function is called with no lock held and always returns
1173462306a36Sopenharmony_ci * 1.
1173562306a36Sopenharmony_ci **/
1173662306a36Sopenharmony_civoid
1173762306a36Sopenharmony_cilpfc_sli4_queue_init(struct lpfc_hba *phba)
1173862306a36Sopenharmony_ci{
1173962306a36Sopenharmony_ci	struct lpfc_sli *psli;
1174062306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1174162306a36Sopenharmony_ci	int i;
1174262306a36Sopenharmony_ci
1174362306a36Sopenharmony_ci	psli = &phba->sli;
1174462306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
1174562306a36Sopenharmony_ci	INIT_LIST_HEAD(&psli->mboxq);
1174662306a36Sopenharmony_ci	INIT_LIST_HEAD(&psli->mboxq_cmpl);
1174762306a36Sopenharmony_ci	/* Initialize list headers for txq and txcmplq as double linked lists */
1174862306a36Sopenharmony_ci	for (i = 0; i < phba->cfg_hdw_queue; i++) {
1174962306a36Sopenharmony_ci		pring = phba->sli4_hba.hdwq[i].io_wq->pring;
1175062306a36Sopenharmony_ci		pring->flag = 0;
1175162306a36Sopenharmony_ci		pring->ringno = LPFC_FCP_RING;
1175262306a36Sopenharmony_ci		pring->txcmplq_cnt = 0;
1175362306a36Sopenharmony_ci		INIT_LIST_HEAD(&pring->txq);
1175462306a36Sopenharmony_ci		INIT_LIST_HEAD(&pring->txcmplq);
1175562306a36Sopenharmony_ci		INIT_LIST_HEAD(&pring->iocb_continueq);
1175662306a36Sopenharmony_ci		spin_lock_init(&pring->ring_lock);
1175762306a36Sopenharmony_ci	}
1175862306a36Sopenharmony_ci	pring = phba->sli4_hba.els_wq->pring;
1175962306a36Sopenharmony_ci	pring->flag = 0;
1176062306a36Sopenharmony_ci	pring->ringno = LPFC_ELS_RING;
1176162306a36Sopenharmony_ci	pring->txcmplq_cnt = 0;
1176262306a36Sopenharmony_ci	INIT_LIST_HEAD(&pring->txq);
1176362306a36Sopenharmony_ci	INIT_LIST_HEAD(&pring->txcmplq);
1176462306a36Sopenharmony_ci	INIT_LIST_HEAD(&pring->iocb_continueq);
1176562306a36Sopenharmony_ci	spin_lock_init(&pring->ring_lock);
1176662306a36Sopenharmony_ci
1176762306a36Sopenharmony_ci	if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
1176862306a36Sopenharmony_ci		pring = phba->sli4_hba.nvmels_wq->pring;
1176962306a36Sopenharmony_ci		pring->flag = 0;
1177062306a36Sopenharmony_ci		pring->ringno = LPFC_ELS_RING;
1177162306a36Sopenharmony_ci		pring->txcmplq_cnt = 0;
1177262306a36Sopenharmony_ci		INIT_LIST_HEAD(&pring->txq);
1177362306a36Sopenharmony_ci		INIT_LIST_HEAD(&pring->txcmplq);
1177462306a36Sopenharmony_ci		INIT_LIST_HEAD(&pring->iocb_continueq);
1177562306a36Sopenharmony_ci		spin_lock_init(&pring->ring_lock);
1177662306a36Sopenharmony_ci	}
1177762306a36Sopenharmony_ci
1177862306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
1177962306a36Sopenharmony_ci}
1178062306a36Sopenharmony_ci
1178162306a36Sopenharmony_ci/**
1178262306a36Sopenharmony_ci * lpfc_sli_queue_init - Queue initialization function
1178362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1178462306a36Sopenharmony_ci *
1178562306a36Sopenharmony_ci * lpfc_sli_queue_init sets up mailbox queues and iocb queues for each
1178662306a36Sopenharmony_ci * ring. This function also initializes ring indices of each ring.
1178762306a36Sopenharmony_ci * This function is called during the initialization of the SLI
1178862306a36Sopenharmony_ci * interface of an HBA.
1178962306a36Sopenharmony_ci * This function is called with no lock held and always returns
1179062306a36Sopenharmony_ci * 1.
1179162306a36Sopenharmony_ci **/
1179262306a36Sopenharmony_civoid
1179362306a36Sopenharmony_cilpfc_sli_queue_init(struct lpfc_hba *phba)
1179462306a36Sopenharmony_ci{
1179562306a36Sopenharmony_ci	struct lpfc_sli *psli;
1179662306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1179762306a36Sopenharmony_ci	int i;
1179862306a36Sopenharmony_ci
1179962306a36Sopenharmony_ci	psli = &phba->sli;
1180062306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
1180162306a36Sopenharmony_ci	INIT_LIST_HEAD(&psli->mboxq);
1180262306a36Sopenharmony_ci	INIT_LIST_HEAD(&psli->mboxq_cmpl);
1180362306a36Sopenharmony_ci	/* Initialize list headers for txq and txcmplq as double linked lists */
1180462306a36Sopenharmony_ci	for (i = 0; i < psli->num_rings; i++) {
1180562306a36Sopenharmony_ci		pring = &psli->sli3_ring[i];
1180662306a36Sopenharmony_ci		pring->ringno = i;
1180762306a36Sopenharmony_ci		pring->sli.sli3.next_cmdidx  = 0;
1180862306a36Sopenharmony_ci		pring->sli.sli3.local_getidx = 0;
1180962306a36Sopenharmony_ci		pring->sli.sli3.cmdidx = 0;
1181062306a36Sopenharmony_ci		INIT_LIST_HEAD(&pring->iocb_continueq);
1181162306a36Sopenharmony_ci		INIT_LIST_HEAD(&pring->iocb_continue_saveq);
1181262306a36Sopenharmony_ci		INIT_LIST_HEAD(&pring->postbufq);
1181362306a36Sopenharmony_ci		pring->flag = 0;
1181462306a36Sopenharmony_ci		INIT_LIST_HEAD(&pring->txq);
1181562306a36Sopenharmony_ci		INIT_LIST_HEAD(&pring->txcmplq);
1181662306a36Sopenharmony_ci		spin_lock_init(&pring->ring_lock);
1181762306a36Sopenharmony_ci	}
1181862306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
1181962306a36Sopenharmony_ci}
1182062306a36Sopenharmony_ci
1182162306a36Sopenharmony_ci/**
1182262306a36Sopenharmony_ci * lpfc_sli_mbox_sys_flush - Flush mailbox command sub-system
1182362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1182462306a36Sopenharmony_ci *
1182562306a36Sopenharmony_ci * This routine flushes the mailbox command subsystem. It will unconditionally
1182662306a36Sopenharmony_ci * flush all the mailbox commands in the three possible stages in the mailbox
1182762306a36Sopenharmony_ci * command sub-system: pending mailbox command queue; the outstanding mailbox
1182862306a36Sopenharmony_ci * command; and completed mailbox command queue. It is caller's responsibility
1182962306a36Sopenharmony_ci * to make sure that the driver is in the proper state to flush the mailbox
1183062306a36Sopenharmony_ci * command sub-system. Namely, the posting of mailbox commands into the
1183162306a36Sopenharmony_ci * pending mailbox command queue from the various clients must be stopped;
1183262306a36Sopenharmony_ci * either the HBA is in a state that it will never works on the outstanding
1183362306a36Sopenharmony_ci * mailbox command (such as in EEH or ERATT conditions) or the outstanding
1183462306a36Sopenharmony_ci * mailbox command has been completed.
1183562306a36Sopenharmony_ci **/
1183662306a36Sopenharmony_cistatic void
1183762306a36Sopenharmony_cilpfc_sli_mbox_sys_flush(struct lpfc_hba *phba)
1183862306a36Sopenharmony_ci{
1183962306a36Sopenharmony_ci	LIST_HEAD(completions);
1184062306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
1184162306a36Sopenharmony_ci	LPFC_MBOXQ_t *pmb;
1184262306a36Sopenharmony_ci	unsigned long iflag;
1184362306a36Sopenharmony_ci
1184462306a36Sopenharmony_ci	/* Disable softirqs, including timers from obtaining phba->hbalock */
1184562306a36Sopenharmony_ci	local_bh_disable();
1184662306a36Sopenharmony_ci
1184762306a36Sopenharmony_ci	/* Flush all the mailbox commands in the mbox system */
1184862306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflag);
1184962306a36Sopenharmony_ci
1185062306a36Sopenharmony_ci	/* The pending mailbox command queue */
1185162306a36Sopenharmony_ci	list_splice_init(&phba->sli.mboxq, &completions);
1185262306a36Sopenharmony_ci	/* The outstanding active mailbox command */
1185362306a36Sopenharmony_ci	if (psli->mbox_active) {
1185462306a36Sopenharmony_ci		list_add_tail(&psli->mbox_active->list, &completions);
1185562306a36Sopenharmony_ci		psli->mbox_active = NULL;
1185662306a36Sopenharmony_ci		psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
1185762306a36Sopenharmony_ci	}
1185862306a36Sopenharmony_ci	/* The completed mailbox command queue */
1185962306a36Sopenharmony_ci	list_splice_init(&phba->sli.mboxq_cmpl, &completions);
1186062306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflag);
1186162306a36Sopenharmony_ci
1186262306a36Sopenharmony_ci	/* Enable softirqs again, done with phba->hbalock */
1186362306a36Sopenharmony_ci	local_bh_enable();
1186462306a36Sopenharmony_ci
1186562306a36Sopenharmony_ci	/* Return all flushed mailbox commands with MBX_NOT_FINISHED status */
1186662306a36Sopenharmony_ci	while (!list_empty(&completions)) {
1186762306a36Sopenharmony_ci		list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list);
1186862306a36Sopenharmony_ci		pmb->u.mb.mbxStatus = MBX_NOT_FINISHED;
1186962306a36Sopenharmony_ci		if (pmb->mbox_cmpl)
1187062306a36Sopenharmony_ci			pmb->mbox_cmpl(phba, pmb);
1187162306a36Sopenharmony_ci	}
1187262306a36Sopenharmony_ci}
1187362306a36Sopenharmony_ci
1187462306a36Sopenharmony_ci/**
1187562306a36Sopenharmony_ci * lpfc_sli_host_down - Vport cleanup function
1187662306a36Sopenharmony_ci * @vport: Pointer to virtual port object.
1187762306a36Sopenharmony_ci *
1187862306a36Sopenharmony_ci * lpfc_sli_host_down is called to clean up the resources
1187962306a36Sopenharmony_ci * associated with a vport before destroying virtual
1188062306a36Sopenharmony_ci * port data structures.
1188162306a36Sopenharmony_ci * This function does following operations:
1188262306a36Sopenharmony_ci * - Free discovery resources associated with this virtual
1188362306a36Sopenharmony_ci *   port.
1188462306a36Sopenharmony_ci * - Free iocbs associated with this virtual port in
1188562306a36Sopenharmony_ci *   the txq.
1188662306a36Sopenharmony_ci * - Send abort for all iocb commands associated with this
1188762306a36Sopenharmony_ci *   vport in txcmplq.
1188862306a36Sopenharmony_ci *
1188962306a36Sopenharmony_ci * This function is called with no lock held and always returns 1.
1189062306a36Sopenharmony_ci **/
1189162306a36Sopenharmony_ciint
1189262306a36Sopenharmony_cilpfc_sli_host_down(struct lpfc_vport *vport)
1189362306a36Sopenharmony_ci{
1189462306a36Sopenharmony_ci	LIST_HEAD(completions);
1189562306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
1189662306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
1189762306a36Sopenharmony_ci	struct lpfc_queue *qp = NULL;
1189862306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1189962306a36Sopenharmony_ci	struct lpfc_iocbq *iocb, *next_iocb;
1190062306a36Sopenharmony_ci	int i;
1190162306a36Sopenharmony_ci	unsigned long flags = 0;
1190262306a36Sopenharmony_ci	uint16_t prev_pring_flag;
1190362306a36Sopenharmony_ci
1190462306a36Sopenharmony_ci	lpfc_cleanup_discovery_resources(vport);
1190562306a36Sopenharmony_ci
1190662306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, flags);
1190762306a36Sopenharmony_ci
1190862306a36Sopenharmony_ci	/*
1190962306a36Sopenharmony_ci	 * Error everything on the txq since these iocbs
1191062306a36Sopenharmony_ci	 * have not been given to the FW yet.
1191162306a36Sopenharmony_ci	 * Also issue ABTS for everything on the txcmplq
1191262306a36Sopenharmony_ci	 */
1191362306a36Sopenharmony_ci	if (phba->sli_rev != LPFC_SLI_REV4) {
1191462306a36Sopenharmony_ci		for (i = 0; i < psli->num_rings; i++) {
1191562306a36Sopenharmony_ci			pring = &psli->sli3_ring[i];
1191662306a36Sopenharmony_ci			prev_pring_flag = pring->flag;
1191762306a36Sopenharmony_ci			/* Only slow rings */
1191862306a36Sopenharmony_ci			if (pring->ringno == LPFC_ELS_RING) {
1191962306a36Sopenharmony_ci				pring->flag |= LPFC_DEFERRED_RING_EVENT;
1192062306a36Sopenharmony_ci				/* Set the lpfc data pending flag */
1192162306a36Sopenharmony_ci				set_bit(LPFC_DATA_READY, &phba->data_flags);
1192262306a36Sopenharmony_ci			}
1192362306a36Sopenharmony_ci			list_for_each_entry_safe(iocb, next_iocb,
1192462306a36Sopenharmony_ci						 &pring->txq, list) {
1192562306a36Sopenharmony_ci				if (iocb->vport != vport)
1192662306a36Sopenharmony_ci					continue;
1192762306a36Sopenharmony_ci				list_move_tail(&iocb->list, &completions);
1192862306a36Sopenharmony_ci			}
1192962306a36Sopenharmony_ci			list_for_each_entry_safe(iocb, next_iocb,
1193062306a36Sopenharmony_ci						 &pring->txcmplq, list) {
1193162306a36Sopenharmony_ci				if (iocb->vport != vport)
1193262306a36Sopenharmony_ci					continue;
1193362306a36Sopenharmony_ci				lpfc_sli_issue_abort_iotag(phba, pring, iocb,
1193462306a36Sopenharmony_ci							   NULL);
1193562306a36Sopenharmony_ci			}
1193662306a36Sopenharmony_ci			pring->flag = prev_pring_flag;
1193762306a36Sopenharmony_ci		}
1193862306a36Sopenharmony_ci	} else {
1193962306a36Sopenharmony_ci		list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) {
1194062306a36Sopenharmony_ci			pring = qp->pring;
1194162306a36Sopenharmony_ci			if (!pring)
1194262306a36Sopenharmony_ci				continue;
1194362306a36Sopenharmony_ci			if (pring == phba->sli4_hba.els_wq->pring) {
1194462306a36Sopenharmony_ci				pring->flag |= LPFC_DEFERRED_RING_EVENT;
1194562306a36Sopenharmony_ci				/* Set the lpfc data pending flag */
1194662306a36Sopenharmony_ci				set_bit(LPFC_DATA_READY, &phba->data_flags);
1194762306a36Sopenharmony_ci			}
1194862306a36Sopenharmony_ci			prev_pring_flag = pring->flag;
1194962306a36Sopenharmony_ci			spin_lock(&pring->ring_lock);
1195062306a36Sopenharmony_ci			list_for_each_entry_safe(iocb, next_iocb,
1195162306a36Sopenharmony_ci						 &pring->txq, list) {
1195262306a36Sopenharmony_ci				if (iocb->vport != vport)
1195362306a36Sopenharmony_ci					continue;
1195462306a36Sopenharmony_ci				list_move_tail(&iocb->list, &completions);
1195562306a36Sopenharmony_ci			}
1195662306a36Sopenharmony_ci			spin_unlock(&pring->ring_lock);
1195762306a36Sopenharmony_ci			list_for_each_entry_safe(iocb, next_iocb,
1195862306a36Sopenharmony_ci						 &pring->txcmplq, list) {
1195962306a36Sopenharmony_ci				if (iocb->vport != vport)
1196062306a36Sopenharmony_ci					continue;
1196162306a36Sopenharmony_ci				lpfc_sli_issue_abort_iotag(phba, pring, iocb,
1196262306a36Sopenharmony_ci							   NULL);
1196362306a36Sopenharmony_ci			}
1196462306a36Sopenharmony_ci			pring->flag = prev_pring_flag;
1196562306a36Sopenharmony_ci		}
1196662306a36Sopenharmony_ci	}
1196762306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, flags);
1196862306a36Sopenharmony_ci
1196962306a36Sopenharmony_ci	/* Make sure HBA is alive */
1197062306a36Sopenharmony_ci	lpfc_issue_hb_tmo(phba);
1197162306a36Sopenharmony_ci
1197262306a36Sopenharmony_ci	/* Cancel all the IOCBs from the completions list */
1197362306a36Sopenharmony_ci	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
1197462306a36Sopenharmony_ci			      IOERR_SLI_DOWN);
1197562306a36Sopenharmony_ci	return 1;
1197662306a36Sopenharmony_ci}
1197762306a36Sopenharmony_ci
1197862306a36Sopenharmony_ci/**
1197962306a36Sopenharmony_ci * lpfc_sli_hba_down - Resource cleanup function for the HBA
1198062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1198162306a36Sopenharmony_ci *
1198262306a36Sopenharmony_ci * This function cleans up all iocb, buffers, mailbox commands
1198362306a36Sopenharmony_ci * while shutting down the HBA. This function is called with no
1198462306a36Sopenharmony_ci * lock held and always returns 1.
1198562306a36Sopenharmony_ci * This function does the following to cleanup driver resources:
1198662306a36Sopenharmony_ci * - Free discovery resources for each virtual port
1198762306a36Sopenharmony_ci * - Cleanup any pending fabric iocbs
1198862306a36Sopenharmony_ci * - Iterate through the iocb txq and free each entry
1198962306a36Sopenharmony_ci *   in the list.
1199062306a36Sopenharmony_ci * - Free up any buffer posted to the HBA
1199162306a36Sopenharmony_ci * - Free mailbox commands in the mailbox queue.
1199262306a36Sopenharmony_ci **/
1199362306a36Sopenharmony_ciint
1199462306a36Sopenharmony_cilpfc_sli_hba_down(struct lpfc_hba *phba)
1199562306a36Sopenharmony_ci{
1199662306a36Sopenharmony_ci	LIST_HEAD(completions);
1199762306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
1199862306a36Sopenharmony_ci	struct lpfc_queue *qp = NULL;
1199962306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1200062306a36Sopenharmony_ci	struct lpfc_dmabuf *buf_ptr;
1200162306a36Sopenharmony_ci	unsigned long flags = 0;
1200262306a36Sopenharmony_ci	int i;
1200362306a36Sopenharmony_ci
1200462306a36Sopenharmony_ci	/* Shutdown the mailbox command sub-system */
1200562306a36Sopenharmony_ci	lpfc_sli_mbox_sys_shutdown(phba, LPFC_MBX_WAIT);
1200662306a36Sopenharmony_ci
1200762306a36Sopenharmony_ci	lpfc_hba_down_prep(phba);
1200862306a36Sopenharmony_ci
1200962306a36Sopenharmony_ci	/* Disable softirqs, including timers from obtaining phba->hbalock */
1201062306a36Sopenharmony_ci	local_bh_disable();
1201162306a36Sopenharmony_ci
1201262306a36Sopenharmony_ci	lpfc_fabric_abort_hba(phba);
1201362306a36Sopenharmony_ci
1201462306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, flags);
1201562306a36Sopenharmony_ci
1201662306a36Sopenharmony_ci	/*
1201762306a36Sopenharmony_ci	 * Error everything on the txq since these iocbs
1201862306a36Sopenharmony_ci	 * have not been given to the FW yet.
1201962306a36Sopenharmony_ci	 */
1202062306a36Sopenharmony_ci	if (phba->sli_rev != LPFC_SLI_REV4) {
1202162306a36Sopenharmony_ci		for (i = 0; i < psli->num_rings; i++) {
1202262306a36Sopenharmony_ci			pring = &psli->sli3_ring[i];
1202362306a36Sopenharmony_ci			/* Only slow rings */
1202462306a36Sopenharmony_ci			if (pring->ringno == LPFC_ELS_RING) {
1202562306a36Sopenharmony_ci				pring->flag |= LPFC_DEFERRED_RING_EVENT;
1202662306a36Sopenharmony_ci				/* Set the lpfc data pending flag */
1202762306a36Sopenharmony_ci				set_bit(LPFC_DATA_READY, &phba->data_flags);
1202862306a36Sopenharmony_ci			}
1202962306a36Sopenharmony_ci			list_splice_init(&pring->txq, &completions);
1203062306a36Sopenharmony_ci		}
1203162306a36Sopenharmony_ci	} else {
1203262306a36Sopenharmony_ci		list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) {
1203362306a36Sopenharmony_ci			pring = qp->pring;
1203462306a36Sopenharmony_ci			if (!pring)
1203562306a36Sopenharmony_ci				continue;
1203662306a36Sopenharmony_ci			spin_lock(&pring->ring_lock);
1203762306a36Sopenharmony_ci			list_splice_init(&pring->txq, &completions);
1203862306a36Sopenharmony_ci			spin_unlock(&pring->ring_lock);
1203962306a36Sopenharmony_ci			if (pring == phba->sli4_hba.els_wq->pring) {
1204062306a36Sopenharmony_ci				pring->flag |= LPFC_DEFERRED_RING_EVENT;
1204162306a36Sopenharmony_ci				/* Set the lpfc data pending flag */
1204262306a36Sopenharmony_ci				set_bit(LPFC_DATA_READY, &phba->data_flags);
1204362306a36Sopenharmony_ci			}
1204462306a36Sopenharmony_ci		}
1204562306a36Sopenharmony_ci	}
1204662306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, flags);
1204762306a36Sopenharmony_ci
1204862306a36Sopenharmony_ci	/* Cancel all the IOCBs from the completions list */
1204962306a36Sopenharmony_ci	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
1205062306a36Sopenharmony_ci			      IOERR_SLI_DOWN);
1205162306a36Sopenharmony_ci
1205262306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, flags);
1205362306a36Sopenharmony_ci	list_splice_init(&phba->elsbuf, &completions);
1205462306a36Sopenharmony_ci	phba->elsbuf_cnt = 0;
1205562306a36Sopenharmony_ci	phba->elsbuf_prev_cnt = 0;
1205662306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, flags);
1205762306a36Sopenharmony_ci
1205862306a36Sopenharmony_ci	while (!list_empty(&completions)) {
1205962306a36Sopenharmony_ci		list_remove_head(&completions, buf_ptr,
1206062306a36Sopenharmony_ci			struct lpfc_dmabuf, list);
1206162306a36Sopenharmony_ci		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
1206262306a36Sopenharmony_ci		kfree(buf_ptr);
1206362306a36Sopenharmony_ci	}
1206462306a36Sopenharmony_ci
1206562306a36Sopenharmony_ci	/* Enable softirqs again, done with phba->hbalock */
1206662306a36Sopenharmony_ci	local_bh_enable();
1206762306a36Sopenharmony_ci
1206862306a36Sopenharmony_ci	/* Return any active mbox cmds */
1206962306a36Sopenharmony_ci	del_timer_sync(&psli->mbox_tmo);
1207062306a36Sopenharmony_ci
1207162306a36Sopenharmony_ci	spin_lock_irqsave(&phba->pport->work_port_lock, flags);
1207262306a36Sopenharmony_ci	phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
1207362306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
1207462306a36Sopenharmony_ci
1207562306a36Sopenharmony_ci	return 1;
1207662306a36Sopenharmony_ci}
1207762306a36Sopenharmony_ci
1207862306a36Sopenharmony_ci/**
1207962306a36Sopenharmony_ci * lpfc_sli_pcimem_bcopy - SLI memory copy function
1208062306a36Sopenharmony_ci * @srcp: Source memory pointer.
1208162306a36Sopenharmony_ci * @destp: Destination memory pointer.
1208262306a36Sopenharmony_ci * @cnt: Number of words required to be copied.
1208362306a36Sopenharmony_ci *
1208462306a36Sopenharmony_ci * This function is used for copying data between driver memory
1208562306a36Sopenharmony_ci * and the SLI memory. This function also changes the endianness
1208662306a36Sopenharmony_ci * of each word if native endianness is different from SLI
1208762306a36Sopenharmony_ci * endianness. This function can be called with or without
1208862306a36Sopenharmony_ci * lock.
1208962306a36Sopenharmony_ci **/
1209062306a36Sopenharmony_civoid
1209162306a36Sopenharmony_cilpfc_sli_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt)
1209262306a36Sopenharmony_ci{
1209362306a36Sopenharmony_ci	uint32_t *src = srcp;
1209462306a36Sopenharmony_ci	uint32_t *dest = destp;
1209562306a36Sopenharmony_ci	uint32_t ldata;
1209662306a36Sopenharmony_ci	int i;
1209762306a36Sopenharmony_ci
1209862306a36Sopenharmony_ci	for (i = 0; i < (int)cnt; i += sizeof (uint32_t)) {
1209962306a36Sopenharmony_ci		ldata = *src;
1210062306a36Sopenharmony_ci		ldata = le32_to_cpu(ldata);
1210162306a36Sopenharmony_ci		*dest = ldata;
1210262306a36Sopenharmony_ci		src++;
1210362306a36Sopenharmony_ci		dest++;
1210462306a36Sopenharmony_ci	}
1210562306a36Sopenharmony_ci}
1210662306a36Sopenharmony_ci
1210762306a36Sopenharmony_ci
1210862306a36Sopenharmony_ci/**
1210962306a36Sopenharmony_ci * lpfc_sli_bemem_bcopy - SLI memory copy function
1211062306a36Sopenharmony_ci * @srcp: Source memory pointer.
1211162306a36Sopenharmony_ci * @destp: Destination memory pointer.
1211262306a36Sopenharmony_ci * @cnt: Number of words required to be copied.
1211362306a36Sopenharmony_ci *
1211462306a36Sopenharmony_ci * This function is used for copying data between a data structure
1211562306a36Sopenharmony_ci * with big endian representation to local endianness.
1211662306a36Sopenharmony_ci * This function can be called with or without lock.
1211762306a36Sopenharmony_ci **/
1211862306a36Sopenharmony_civoid
1211962306a36Sopenharmony_cilpfc_sli_bemem_bcopy(void *srcp, void *destp, uint32_t cnt)
1212062306a36Sopenharmony_ci{
1212162306a36Sopenharmony_ci	uint32_t *src = srcp;
1212262306a36Sopenharmony_ci	uint32_t *dest = destp;
1212362306a36Sopenharmony_ci	uint32_t ldata;
1212462306a36Sopenharmony_ci	int i;
1212562306a36Sopenharmony_ci
1212662306a36Sopenharmony_ci	for (i = 0; i < (int)cnt; i += sizeof(uint32_t)) {
1212762306a36Sopenharmony_ci		ldata = *src;
1212862306a36Sopenharmony_ci		ldata = be32_to_cpu(ldata);
1212962306a36Sopenharmony_ci		*dest = ldata;
1213062306a36Sopenharmony_ci		src++;
1213162306a36Sopenharmony_ci		dest++;
1213262306a36Sopenharmony_ci	}
1213362306a36Sopenharmony_ci}
1213462306a36Sopenharmony_ci
1213562306a36Sopenharmony_ci/**
1213662306a36Sopenharmony_ci * lpfc_sli_ringpostbuf_put - Function to add a buffer to postbufq
1213762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1213862306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
1213962306a36Sopenharmony_ci * @mp: Pointer to driver buffer object.
1214062306a36Sopenharmony_ci *
1214162306a36Sopenharmony_ci * This function is called with no lock held.
1214262306a36Sopenharmony_ci * It always return zero after adding the buffer to the postbufq
1214362306a36Sopenharmony_ci * buffer list.
1214462306a36Sopenharmony_ci **/
1214562306a36Sopenharmony_ciint
1214662306a36Sopenharmony_cilpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
1214762306a36Sopenharmony_ci			 struct lpfc_dmabuf *mp)
1214862306a36Sopenharmony_ci{
1214962306a36Sopenharmony_ci	/* Stick struct lpfc_dmabuf at end of postbufq so driver can look it up
1215062306a36Sopenharmony_ci	   later */
1215162306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
1215262306a36Sopenharmony_ci	list_add_tail(&mp->list, &pring->postbufq);
1215362306a36Sopenharmony_ci	pring->postbufq_cnt++;
1215462306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
1215562306a36Sopenharmony_ci	return 0;
1215662306a36Sopenharmony_ci}
1215762306a36Sopenharmony_ci
1215862306a36Sopenharmony_ci/**
1215962306a36Sopenharmony_ci * lpfc_sli_get_buffer_tag - allocates a tag for a CMD_QUE_XRI64_CX buffer
1216062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1216162306a36Sopenharmony_ci *
1216262306a36Sopenharmony_ci * When HBQ is enabled, buffers are searched based on tags. This function
1216362306a36Sopenharmony_ci * allocates a tag for buffer posted using CMD_QUE_XRI64_CX iocb. The
1216462306a36Sopenharmony_ci * tag is bit wise or-ed with QUE_BUFTAG_BIT to make sure that the tag
1216562306a36Sopenharmony_ci * does not conflict with tags of buffer posted for unsolicited events.
1216662306a36Sopenharmony_ci * The function returns the allocated tag. The function is called with
1216762306a36Sopenharmony_ci * no locks held.
1216862306a36Sopenharmony_ci **/
1216962306a36Sopenharmony_ciuint32_t
1217062306a36Sopenharmony_cilpfc_sli_get_buffer_tag(struct lpfc_hba *phba)
1217162306a36Sopenharmony_ci{
1217262306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
1217362306a36Sopenharmony_ci	phba->buffer_tag_count++;
1217462306a36Sopenharmony_ci	/*
1217562306a36Sopenharmony_ci	 * Always set the QUE_BUFTAG_BIT to distiguish between
1217662306a36Sopenharmony_ci	 * a tag assigned by HBQ.
1217762306a36Sopenharmony_ci	 */
1217862306a36Sopenharmony_ci	phba->buffer_tag_count |= QUE_BUFTAG_BIT;
1217962306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
1218062306a36Sopenharmony_ci	return phba->buffer_tag_count;
1218162306a36Sopenharmony_ci}
1218262306a36Sopenharmony_ci
1218362306a36Sopenharmony_ci/**
1218462306a36Sopenharmony_ci * lpfc_sli_ring_taggedbuf_get - find HBQ buffer associated with given tag
1218562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1218662306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
1218762306a36Sopenharmony_ci * @tag: Buffer tag.
1218862306a36Sopenharmony_ci *
1218962306a36Sopenharmony_ci * Buffers posted using CMD_QUE_XRI64_CX iocb are in pring->postbufq
1219062306a36Sopenharmony_ci * list. After HBA DMA data to these buffers, CMD_IOCB_RET_XRI64_CX
1219162306a36Sopenharmony_ci * iocb is posted to the response ring with the tag of the buffer.
1219262306a36Sopenharmony_ci * This function searches the pring->postbufq list using the tag
1219362306a36Sopenharmony_ci * to find buffer associated with CMD_IOCB_RET_XRI64_CX
1219462306a36Sopenharmony_ci * iocb. If the buffer is found then lpfc_dmabuf object of the
1219562306a36Sopenharmony_ci * buffer is returned to the caller else NULL is returned.
1219662306a36Sopenharmony_ci * This function is called with no lock held.
1219762306a36Sopenharmony_ci **/
1219862306a36Sopenharmony_cistruct lpfc_dmabuf *
1219962306a36Sopenharmony_cilpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
1220062306a36Sopenharmony_ci			uint32_t tag)
1220162306a36Sopenharmony_ci{
1220262306a36Sopenharmony_ci	struct lpfc_dmabuf *mp, *next_mp;
1220362306a36Sopenharmony_ci	struct list_head *slp = &pring->postbufq;
1220462306a36Sopenharmony_ci
1220562306a36Sopenharmony_ci	/* Search postbufq, from the beginning, looking for a match on tag */
1220662306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
1220762306a36Sopenharmony_ci	list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
1220862306a36Sopenharmony_ci		if (mp->buffer_tag == tag) {
1220962306a36Sopenharmony_ci			list_del_init(&mp->list);
1221062306a36Sopenharmony_ci			pring->postbufq_cnt--;
1221162306a36Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
1221262306a36Sopenharmony_ci			return mp;
1221362306a36Sopenharmony_ci		}
1221462306a36Sopenharmony_ci	}
1221562306a36Sopenharmony_ci
1221662306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
1221762306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1221862306a36Sopenharmony_ci			"0402 Cannot find virtual addr for buffer tag on "
1221962306a36Sopenharmony_ci			"ring %d Data x%lx x%px x%px x%x\n",
1222062306a36Sopenharmony_ci			pring->ringno, (unsigned long) tag,
1222162306a36Sopenharmony_ci			slp->next, slp->prev, pring->postbufq_cnt);
1222262306a36Sopenharmony_ci
1222362306a36Sopenharmony_ci	return NULL;
1222462306a36Sopenharmony_ci}
1222562306a36Sopenharmony_ci
1222662306a36Sopenharmony_ci/**
1222762306a36Sopenharmony_ci * lpfc_sli_ringpostbuf_get - search buffers for unsolicited CT and ELS events
1222862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1222962306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
1223062306a36Sopenharmony_ci * @phys: DMA address of the buffer.
1223162306a36Sopenharmony_ci *
1223262306a36Sopenharmony_ci * This function searches the buffer list using the dma_address
1223362306a36Sopenharmony_ci * of unsolicited event to find the driver's lpfc_dmabuf object
1223462306a36Sopenharmony_ci * corresponding to the dma_address. The function returns the
1223562306a36Sopenharmony_ci * lpfc_dmabuf object if a buffer is found else it returns NULL.
1223662306a36Sopenharmony_ci * This function is called by the ct and els unsolicited event
1223762306a36Sopenharmony_ci * handlers to get the buffer associated with the unsolicited
1223862306a36Sopenharmony_ci * event.
1223962306a36Sopenharmony_ci *
1224062306a36Sopenharmony_ci * This function is called with no lock held.
1224162306a36Sopenharmony_ci **/
1224262306a36Sopenharmony_cistruct lpfc_dmabuf *
1224362306a36Sopenharmony_cilpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
1224462306a36Sopenharmony_ci			 dma_addr_t phys)
1224562306a36Sopenharmony_ci{
1224662306a36Sopenharmony_ci	struct lpfc_dmabuf *mp, *next_mp;
1224762306a36Sopenharmony_ci	struct list_head *slp = &pring->postbufq;
1224862306a36Sopenharmony_ci
1224962306a36Sopenharmony_ci	/* Search postbufq, from the beginning, looking for a match on phys */
1225062306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
1225162306a36Sopenharmony_ci	list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
1225262306a36Sopenharmony_ci		if (mp->phys == phys) {
1225362306a36Sopenharmony_ci			list_del_init(&mp->list);
1225462306a36Sopenharmony_ci			pring->postbufq_cnt--;
1225562306a36Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
1225662306a36Sopenharmony_ci			return mp;
1225762306a36Sopenharmony_ci		}
1225862306a36Sopenharmony_ci	}
1225962306a36Sopenharmony_ci
1226062306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
1226162306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1226262306a36Sopenharmony_ci			"0410 Cannot find virtual addr for mapped buf on "
1226362306a36Sopenharmony_ci			"ring %d Data x%llx x%px x%px x%x\n",
1226462306a36Sopenharmony_ci			pring->ringno, (unsigned long long)phys,
1226562306a36Sopenharmony_ci			slp->next, slp->prev, pring->postbufq_cnt);
1226662306a36Sopenharmony_ci	return NULL;
1226762306a36Sopenharmony_ci}
1226862306a36Sopenharmony_ci
1226962306a36Sopenharmony_ci/**
1227062306a36Sopenharmony_ci * lpfc_sli_abort_els_cmpl - Completion handler for the els abort iocbs
1227162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1227262306a36Sopenharmony_ci * @cmdiocb: Pointer to driver command iocb object.
1227362306a36Sopenharmony_ci * @rspiocb: Pointer to driver response iocb object.
1227462306a36Sopenharmony_ci *
1227562306a36Sopenharmony_ci * This function is the completion handler for the abort iocbs for
1227662306a36Sopenharmony_ci * ELS commands. This function is called from the ELS ring event
1227762306a36Sopenharmony_ci * handler with no lock held. This function frees memory resources
1227862306a36Sopenharmony_ci * associated with the abort iocb.
1227962306a36Sopenharmony_ci **/
1228062306a36Sopenharmony_cistatic void
1228162306a36Sopenharmony_cilpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1228262306a36Sopenharmony_ci			struct lpfc_iocbq *rspiocb)
1228362306a36Sopenharmony_ci{
1228462306a36Sopenharmony_ci	u32 ulp_status = get_job_ulpstatus(phba, rspiocb);
1228562306a36Sopenharmony_ci	u32 ulp_word4 = get_job_word4(phba, rspiocb);
1228662306a36Sopenharmony_ci	u8 cmnd = get_job_cmnd(phba, cmdiocb);
1228762306a36Sopenharmony_ci
1228862306a36Sopenharmony_ci	if (ulp_status) {
1228962306a36Sopenharmony_ci		/*
1229062306a36Sopenharmony_ci		 * Assume that the port already completed and returned, or
1229162306a36Sopenharmony_ci		 * will return the iocb. Just Log the message.
1229262306a36Sopenharmony_ci		 */
1229362306a36Sopenharmony_ci		if (phba->sli_rev < LPFC_SLI_REV4) {
1229462306a36Sopenharmony_ci			if (cmnd == CMD_ABORT_XRI_CX &&
1229562306a36Sopenharmony_ci			    ulp_status == IOSTAT_LOCAL_REJECT &&
1229662306a36Sopenharmony_ci			    ulp_word4 == IOERR_ABORT_REQUESTED) {
1229762306a36Sopenharmony_ci				goto release_iocb;
1229862306a36Sopenharmony_ci			}
1229962306a36Sopenharmony_ci		}
1230062306a36Sopenharmony_ci
1230162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_SLI,
1230262306a36Sopenharmony_ci				"0327 Cannot abort els iocb x%px "
1230362306a36Sopenharmony_ci				"with io cmd xri %x abort tag : x%x, "
1230462306a36Sopenharmony_ci				"abort status %x abort code %x\n",
1230562306a36Sopenharmony_ci				cmdiocb, get_job_abtsiotag(phba, cmdiocb),
1230662306a36Sopenharmony_ci				(phba->sli_rev == LPFC_SLI_REV4) ?
1230762306a36Sopenharmony_ci				get_wqe_reqtag(cmdiocb) :
1230862306a36Sopenharmony_ci				cmdiocb->iocb.un.acxri.abortContextTag,
1230962306a36Sopenharmony_ci				ulp_status, ulp_word4);
1231062306a36Sopenharmony_ci
1231162306a36Sopenharmony_ci	}
1231262306a36Sopenharmony_cirelease_iocb:
1231362306a36Sopenharmony_ci	lpfc_sli_release_iocbq(phba, cmdiocb);
1231462306a36Sopenharmony_ci	return;
1231562306a36Sopenharmony_ci}
1231662306a36Sopenharmony_ci
1231762306a36Sopenharmony_ci/**
1231862306a36Sopenharmony_ci * lpfc_ignore_els_cmpl - Completion handler for aborted ELS command
1231962306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1232062306a36Sopenharmony_ci * @cmdiocb: Pointer to driver command iocb object.
1232162306a36Sopenharmony_ci * @rspiocb: Pointer to driver response iocb object.
1232262306a36Sopenharmony_ci *
1232362306a36Sopenharmony_ci * The function is called from SLI ring event handler with no
1232462306a36Sopenharmony_ci * lock held. This function is the completion handler for ELS commands
1232562306a36Sopenharmony_ci * which are aborted. The function frees memory resources used for
1232662306a36Sopenharmony_ci * the aborted ELS commands.
1232762306a36Sopenharmony_ci **/
1232862306a36Sopenharmony_civoid
1232962306a36Sopenharmony_cilpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1233062306a36Sopenharmony_ci		     struct lpfc_iocbq *rspiocb)
1233162306a36Sopenharmony_ci{
1233262306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
1233362306a36Sopenharmony_ci	IOCB_t *irsp;
1233462306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1233562306a36Sopenharmony_ci	u32 ulp_command, ulp_status, ulp_word4, iotag;
1233662306a36Sopenharmony_ci
1233762306a36Sopenharmony_ci	ulp_command = get_job_cmnd(phba, cmdiocb);
1233862306a36Sopenharmony_ci	ulp_status = get_job_ulpstatus(phba, rspiocb);
1233962306a36Sopenharmony_ci	ulp_word4 = get_job_word4(phba, rspiocb);
1234062306a36Sopenharmony_ci
1234162306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4) {
1234262306a36Sopenharmony_ci		iotag = get_wqe_reqtag(cmdiocb);
1234362306a36Sopenharmony_ci	} else {
1234462306a36Sopenharmony_ci		irsp = &rspiocb->iocb;
1234562306a36Sopenharmony_ci		iotag = irsp->ulpIoTag;
1234662306a36Sopenharmony_ci
1234762306a36Sopenharmony_ci		/* It is possible a PLOGI_RJT for NPIV ports to get aborted.
1234862306a36Sopenharmony_ci		 * The MBX_REG_LOGIN64 mbox command is freed back to the
1234962306a36Sopenharmony_ci		 * mbox_mem_pool here.
1235062306a36Sopenharmony_ci		 */
1235162306a36Sopenharmony_ci		if (cmdiocb->context_un.mbox) {
1235262306a36Sopenharmony_ci			mbox = cmdiocb->context_un.mbox;
1235362306a36Sopenharmony_ci			lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
1235462306a36Sopenharmony_ci			cmdiocb->context_un.mbox = NULL;
1235562306a36Sopenharmony_ci		}
1235662306a36Sopenharmony_ci	}
1235762306a36Sopenharmony_ci
1235862306a36Sopenharmony_ci	/* ELS cmd tag <ulpIoTag> completes */
1235962306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
1236062306a36Sopenharmony_ci			"0139 Ignoring ELS cmd code x%x completion Data: "
1236162306a36Sopenharmony_ci			"x%x x%x x%x x%px\n",
1236262306a36Sopenharmony_ci			ulp_command, ulp_status, ulp_word4, iotag,
1236362306a36Sopenharmony_ci			cmdiocb->ndlp);
1236462306a36Sopenharmony_ci	/*
1236562306a36Sopenharmony_ci	 * Deref the ndlp after free_iocb. sli_release_iocb will access the ndlp
1236662306a36Sopenharmony_ci	 * if exchange is busy.
1236762306a36Sopenharmony_ci	 */
1236862306a36Sopenharmony_ci	if (ulp_command == CMD_GEN_REQUEST64_CR)
1236962306a36Sopenharmony_ci		lpfc_ct_free_iocb(phba, cmdiocb);
1237062306a36Sopenharmony_ci	else
1237162306a36Sopenharmony_ci		lpfc_els_free_iocb(phba, cmdiocb);
1237262306a36Sopenharmony_ci
1237362306a36Sopenharmony_ci	lpfc_nlp_put(ndlp);
1237462306a36Sopenharmony_ci}
1237562306a36Sopenharmony_ci
1237662306a36Sopenharmony_ci/**
1237762306a36Sopenharmony_ci * lpfc_sli_issue_abort_iotag - Abort function for a command iocb
1237862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1237962306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
1238062306a36Sopenharmony_ci * @cmdiocb: Pointer to driver command iocb object.
1238162306a36Sopenharmony_ci * @cmpl: completion function.
1238262306a36Sopenharmony_ci *
1238362306a36Sopenharmony_ci * This function issues an abort iocb for the provided command iocb. In case
1238462306a36Sopenharmony_ci * of unloading, the abort iocb will not be issued to commands on the ELS
1238562306a36Sopenharmony_ci * ring. Instead, the callback function shall be changed to those commands
1238662306a36Sopenharmony_ci * so that nothing happens when them finishes. This function is called with
1238762306a36Sopenharmony_ci * hbalock held andno ring_lock held (SLI4). The function returns IOCB_SUCCESS
1238862306a36Sopenharmony_ci * when the command iocb is an abort request.
1238962306a36Sopenharmony_ci *
1239062306a36Sopenharmony_ci **/
1239162306a36Sopenharmony_ciint
1239262306a36Sopenharmony_cilpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
1239362306a36Sopenharmony_ci			   struct lpfc_iocbq *cmdiocb, void *cmpl)
1239462306a36Sopenharmony_ci{
1239562306a36Sopenharmony_ci	struct lpfc_vport *vport = cmdiocb->vport;
1239662306a36Sopenharmony_ci	struct lpfc_iocbq *abtsiocbp;
1239762306a36Sopenharmony_ci	int retval = IOCB_ERROR;
1239862306a36Sopenharmony_ci	unsigned long iflags;
1239962306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp = NULL;
1240062306a36Sopenharmony_ci	u32 ulp_command = get_job_cmnd(phba, cmdiocb);
1240162306a36Sopenharmony_ci	u16 ulp_context, iotag;
1240262306a36Sopenharmony_ci	bool ia;
1240362306a36Sopenharmony_ci
1240462306a36Sopenharmony_ci	/*
1240562306a36Sopenharmony_ci	 * There are certain command types we don't want to abort.  And we
1240662306a36Sopenharmony_ci	 * don't want to abort commands that are already in the process of
1240762306a36Sopenharmony_ci	 * being aborted.
1240862306a36Sopenharmony_ci	 */
1240962306a36Sopenharmony_ci	if (ulp_command == CMD_ABORT_XRI_WQE ||
1241062306a36Sopenharmony_ci	    ulp_command == CMD_ABORT_XRI_CN ||
1241162306a36Sopenharmony_ci	    ulp_command == CMD_CLOSE_XRI_CN ||
1241262306a36Sopenharmony_ci	    cmdiocb->cmd_flag & LPFC_DRIVER_ABORTED)
1241362306a36Sopenharmony_ci		return IOCB_ABORTING;
1241462306a36Sopenharmony_ci
1241562306a36Sopenharmony_ci	if (!pring) {
1241662306a36Sopenharmony_ci		if (cmdiocb->cmd_flag & LPFC_IO_FABRIC)
1241762306a36Sopenharmony_ci			cmdiocb->fabric_cmd_cmpl = lpfc_ignore_els_cmpl;
1241862306a36Sopenharmony_ci		else
1241962306a36Sopenharmony_ci			cmdiocb->cmd_cmpl = lpfc_ignore_els_cmpl;
1242062306a36Sopenharmony_ci		return retval;
1242162306a36Sopenharmony_ci	}
1242262306a36Sopenharmony_ci
1242362306a36Sopenharmony_ci	/*
1242462306a36Sopenharmony_ci	 * If we're unloading, don't abort iocb on the ELS ring, but change
1242562306a36Sopenharmony_ci	 * the callback so that nothing happens when it finishes.
1242662306a36Sopenharmony_ci	 */
1242762306a36Sopenharmony_ci	if ((vport->load_flag & FC_UNLOADING) &&
1242862306a36Sopenharmony_ci	    pring->ringno == LPFC_ELS_RING) {
1242962306a36Sopenharmony_ci		if (cmdiocb->cmd_flag & LPFC_IO_FABRIC)
1243062306a36Sopenharmony_ci			cmdiocb->fabric_cmd_cmpl = lpfc_ignore_els_cmpl;
1243162306a36Sopenharmony_ci		else
1243262306a36Sopenharmony_ci			cmdiocb->cmd_cmpl = lpfc_ignore_els_cmpl;
1243362306a36Sopenharmony_ci		return retval;
1243462306a36Sopenharmony_ci	}
1243562306a36Sopenharmony_ci
1243662306a36Sopenharmony_ci	/* issue ABTS for this IOCB based on iotag */
1243762306a36Sopenharmony_ci	abtsiocbp = __lpfc_sli_get_iocbq(phba);
1243862306a36Sopenharmony_ci	if (abtsiocbp == NULL)
1243962306a36Sopenharmony_ci		return IOCB_NORESOURCE;
1244062306a36Sopenharmony_ci
1244162306a36Sopenharmony_ci	/* This signals the response to set the correct status
1244262306a36Sopenharmony_ci	 * before calling the completion handler
1244362306a36Sopenharmony_ci	 */
1244462306a36Sopenharmony_ci	cmdiocb->cmd_flag |= LPFC_DRIVER_ABORTED;
1244562306a36Sopenharmony_ci
1244662306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4) {
1244762306a36Sopenharmony_ci		ulp_context = cmdiocb->sli4_xritag;
1244862306a36Sopenharmony_ci		iotag = abtsiocbp->iotag;
1244962306a36Sopenharmony_ci	} else {
1245062306a36Sopenharmony_ci		iotag = cmdiocb->iocb.ulpIoTag;
1245162306a36Sopenharmony_ci		if (pring->ringno == LPFC_ELS_RING) {
1245262306a36Sopenharmony_ci			ndlp = cmdiocb->ndlp;
1245362306a36Sopenharmony_ci			ulp_context = ndlp->nlp_rpi;
1245462306a36Sopenharmony_ci		} else {
1245562306a36Sopenharmony_ci			ulp_context = cmdiocb->iocb.ulpContext;
1245662306a36Sopenharmony_ci		}
1245762306a36Sopenharmony_ci	}
1245862306a36Sopenharmony_ci
1245962306a36Sopenharmony_ci	if (phba->link_state < LPFC_LINK_UP ||
1246062306a36Sopenharmony_ci	    (phba->sli_rev == LPFC_SLI_REV4 &&
1246162306a36Sopenharmony_ci	     phba->sli4_hba.link_state.status == LPFC_FC_LA_TYPE_LINK_DOWN) ||
1246262306a36Sopenharmony_ci	    (phba->link_flag & LS_EXTERNAL_LOOPBACK))
1246362306a36Sopenharmony_ci		ia = true;
1246462306a36Sopenharmony_ci	else
1246562306a36Sopenharmony_ci		ia = false;
1246662306a36Sopenharmony_ci
1246762306a36Sopenharmony_ci	lpfc_sli_prep_abort_xri(phba, abtsiocbp, ulp_context, iotag,
1246862306a36Sopenharmony_ci				cmdiocb->iocb.ulpClass,
1246962306a36Sopenharmony_ci				LPFC_WQE_CQ_ID_DEFAULT, ia, false);
1247062306a36Sopenharmony_ci
1247162306a36Sopenharmony_ci	abtsiocbp->vport = vport;
1247262306a36Sopenharmony_ci
1247362306a36Sopenharmony_ci	/* ABTS WQE must go to the same WQ as the WQE to be aborted */
1247462306a36Sopenharmony_ci	abtsiocbp->hba_wqidx = cmdiocb->hba_wqidx;
1247562306a36Sopenharmony_ci	if (cmdiocb->cmd_flag & LPFC_IO_FCP)
1247662306a36Sopenharmony_ci		abtsiocbp->cmd_flag |= (LPFC_IO_FCP | LPFC_USE_FCPWQIDX);
1247762306a36Sopenharmony_ci
1247862306a36Sopenharmony_ci	if (cmdiocb->cmd_flag & LPFC_IO_FOF)
1247962306a36Sopenharmony_ci		abtsiocbp->cmd_flag |= LPFC_IO_FOF;
1248062306a36Sopenharmony_ci
1248162306a36Sopenharmony_ci	if (cmpl)
1248262306a36Sopenharmony_ci		abtsiocbp->cmd_cmpl = cmpl;
1248362306a36Sopenharmony_ci	else
1248462306a36Sopenharmony_ci		abtsiocbp->cmd_cmpl = lpfc_sli_abort_els_cmpl;
1248562306a36Sopenharmony_ci	abtsiocbp->vport = vport;
1248662306a36Sopenharmony_ci
1248762306a36Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4) {
1248862306a36Sopenharmony_ci		pring = lpfc_sli4_calc_ring(phba, abtsiocbp);
1248962306a36Sopenharmony_ci		if (unlikely(pring == NULL))
1249062306a36Sopenharmony_ci			goto abort_iotag_exit;
1249162306a36Sopenharmony_ci		/* Note: both hbalock and ring_lock need to be set here */
1249262306a36Sopenharmony_ci		spin_lock_irqsave(&pring->ring_lock, iflags);
1249362306a36Sopenharmony_ci		retval = __lpfc_sli_issue_iocb(phba, pring->ringno,
1249462306a36Sopenharmony_ci			abtsiocbp, 0);
1249562306a36Sopenharmony_ci		spin_unlock_irqrestore(&pring->ring_lock, iflags);
1249662306a36Sopenharmony_ci	} else {
1249762306a36Sopenharmony_ci		retval = __lpfc_sli_issue_iocb(phba, pring->ringno,
1249862306a36Sopenharmony_ci			abtsiocbp, 0);
1249962306a36Sopenharmony_ci	}
1250062306a36Sopenharmony_ci
1250162306a36Sopenharmony_ciabort_iotag_exit:
1250262306a36Sopenharmony_ci
1250362306a36Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
1250462306a36Sopenharmony_ci			 "0339 Abort IO XRI x%x, Original iotag x%x, "
1250562306a36Sopenharmony_ci			 "abort tag x%x Cmdjob : x%px Abortjob : x%px "
1250662306a36Sopenharmony_ci			 "retval x%x\n",
1250762306a36Sopenharmony_ci			 ulp_context, (phba->sli_rev == LPFC_SLI_REV4) ?
1250862306a36Sopenharmony_ci			 cmdiocb->iotag : iotag, iotag, cmdiocb, abtsiocbp,
1250962306a36Sopenharmony_ci			 retval);
1251062306a36Sopenharmony_ci	if (retval) {
1251162306a36Sopenharmony_ci		cmdiocb->cmd_flag &= ~LPFC_DRIVER_ABORTED;
1251262306a36Sopenharmony_ci		__lpfc_sli_release_iocbq(phba, abtsiocbp);
1251362306a36Sopenharmony_ci	}
1251462306a36Sopenharmony_ci
1251562306a36Sopenharmony_ci	/*
1251662306a36Sopenharmony_ci	 * Caller to this routine should check for IOCB_ERROR
1251762306a36Sopenharmony_ci	 * and handle it properly.  This routine no longer removes
1251862306a36Sopenharmony_ci	 * iocb off txcmplq and call compl in case of IOCB_ERROR.
1251962306a36Sopenharmony_ci	 */
1252062306a36Sopenharmony_ci	return retval;
1252162306a36Sopenharmony_ci}
1252262306a36Sopenharmony_ci
1252362306a36Sopenharmony_ci/**
1252462306a36Sopenharmony_ci * lpfc_sli_hba_iocb_abort - Abort all iocbs to an hba.
1252562306a36Sopenharmony_ci * @phba: pointer to lpfc HBA data structure.
1252662306a36Sopenharmony_ci *
1252762306a36Sopenharmony_ci * This routine will abort all pending and outstanding iocbs to an HBA.
1252862306a36Sopenharmony_ci **/
1252962306a36Sopenharmony_civoid
1253062306a36Sopenharmony_cilpfc_sli_hba_iocb_abort(struct lpfc_hba *phba)
1253162306a36Sopenharmony_ci{
1253262306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
1253362306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1253462306a36Sopenharmony_ci	struct lpfc_queue *qp = NULL;
1253562306a36Sopenharmony_ci	int i;
1253662306a36Sopenharmony_ci
1253762306a36Sopenharmony_ci	if (phba->sli_rev != LPFC_SLI_REV4) {
1253862306a36Sopenharmony_ci		for (i = 0; i < psli->num_rings; i++) {
1253962306a36Sopenharmony_ci			pring = &psli->sli3_ring[i];
1254062306a36Sopenharmony_ci			lpfc_sli_abort_iocb_ring(phba, pring);
1254162306a36Sopenharmony_ci		}
1254262306a36Sopenharmony_ci		return;
1254362306a36Sopenharmony_ci	}
1254462306a36Sopenharmony_ci	list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) {
1254562306a36Sopenharmony_ci		pring = qp->pring;
1254662306a36Sopenharmony_ci		if (!pring)
1254762306a36Sopenharmony_ci			continue;
1254862306a36Sopenharmony_ci		lpfc_sli_abort_iocb_ring(phba, pring);
1254962306a36Sopenharmony_ci	}
1255062306a36Sopenharmony_ci}
1255162306a36Sopenharmony_ci
1255262306a36Sopenharmony_ci/**
1255362306a36Sopenharmony_ci * lpfc_sli_validate_fcp_iocb_for_abort - filter iocbs appropriate for FCP aborts
1255462306a36Sopenharmony_ci * @iocbq: Pointer to iocb object.
1255562306a36Sopenharmony_ci * @vport: Pointer to driver virtual port object.
1255662306a36Sopenharmony_ci *
1255762306a36Sopenharmony_ci * This function acts as an iocb filter for functions which abort FCP iocbs.
1255862306a36Sopenharmony_ci *
1255962306a36Sopenharmony_ci * Return values
1256062306a36Sopenharmony_ci * -ENODEV, if a null iocb or vport ptr is encountered
1256162306a36Sopenharmony_ci * -EINVAL, if the iocb is not an FCP I/O, not on the TX cmpl queue, premarked as
1256262306a36Sopenharmony_ci *          driver already started the abort process, or is an abort iocb itself
1256362306a36Sopenharmony_ci * 0, passes criteria for aborting the FCP I/O iocb
1256462306a36Sopenharmony_ci **/
1256562306a36Sopenharmony_cistatic int
1256662306a36Sopenharmony_cilpfc_sli_validate_fcp_iocb_for_abort(struct lpfc_iocbq *iocbq,
1256762306a36Sopenharmony_ci				     struct lpfc_vport *vport)
1256862306a36Sopenharmony_ci{
1256962306a36Sopenharmony_ci	u8 ulp_command;
1257062306a36Sopenharmony_ci
1257162306a36Sopenharmony_ci	/* No null ptr vports */
1257262306a36Sopenharmony_ci	if (!iocbq || iocbq->vport != vport)
1257362306a36Sopenharmony_ci		return -ENODEV;
1257462306a36Sopenharmony_ci
1257562306a36Sopenharmony_ci	/* iocb must be for FCP IO, already exists on the TX cmpl queue,
1257662306a36Sopenharmony_ci	 * can't be premarked as driver aborted, nor be an ABORT iocb itself
1257762306a36Sopenharmony_ci	 */
1257862306a36Sopenharmony_ci	ulp_command = get_job_cmnd(vport->phba, iocbq);
1257962306a36Sopenharmony_ci	if (!(iocbq->cmd_flag & LPFC_IO_FCP) ||
1258062306a36Sopenharmony_ci	    !(iocbq->cmd_flag & LPFC_IO_ON_TXCMPLQ) ||
1258162306a36Sopenharmony_ci	    (iocbq->cmd_flag & LPFC_DRIVER_ABORTED) ||
1258262306a36Sopenharmony_ci	    (ulp_command == CMD_ABORT_XRI_CN ||
1258362306a36Sopenharmony_ci	     ulp_command == CMD_CLOSE_XRI_CN ||
1258462306a36Sopenharmony_ci	     ulp_command == CMD_ABORT_XRI_WQE))
1258562306a36Sopenharmony_ci		return -EINVAL;
1258662306a36Sopenharmony_ci
1258762306a36Sopenharmony_ci	return 0;
1258862306a36Sopenharmony_ci}
1258962306a36Sopenharmony_ci
1259062306a36Sopenharmony_ci/**
1259162306a36Sopenharmony_ci * lpfc_sli_validate_fcp_iocb - validate commands associated with a SCSI target
1259262306a36Sopenharmony_ci * @iocbq: Pointer to driver iocb object.
1259362306a36Sopenharmony_ci * @vport: Pointer to driver virtual port object.
1259462306a36Sopenharmony_ci * @tgt_id: SCSI ID of the target.
1259562306a36Sopenharmony_ci * @lun_id: LUN ID of the scsi device.
1259662306a36Sopenharmony_ci * @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST
1259762306a36Sopenharmony_ci *
1259862306a36Sopenharmony_ci * This function acts as an iocb filter for validating a lun/SCSI target/SCSI
1259962306a36Sopenharmony_ci * host.
1260062306a36Sopenharmony_ci *
1260162306a36Sopenharmony_ci * It will return
1260262306a36Sopenharmony_ci * 0 if the filtering criteria is met for the given iocb and will return
1260362306a36Sopenharmony_ci * 1 if the filtering criteria is not met.
1260462306a36Sopenharmony_ci * If ctx_cmd == LPFC_CTX_LUN, the function returns 0 only if the
1260562306a36Sopenharmony_ci * given iocb is for the SCSI device specified by vport, tgt_id and
1260662306a36Sopenharmony_ci * lun_id parameter.
1260762306a36Sopenharmony_ci * If ctx_cmd == LPFC_CTX_TGT,  the function returns 0 only if the
1260862306a36Sopenharmony_ci * given iocb is for the SCSI target specified by vport and tgt_id
1260962306a36Sopenharmony_ci * parameters.
1261062306a36Sopenharmony_ci * If ctx_cmd == LPFC_CTX_HOST, the function returns 0 only if the
1261162306a36Sopenharmony_ci * given iocb is for the SCSI host associated with the given vport.
1261262306a36Sopenharmony_ci * This function is called with no locks held.
1261362306a36Sopenharmony_ci **/
1261462306a36Sopenharmony_cistatic int
1261562306a36Sopenharmony_cilpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport,
1261662306a36Sopenharmony_ci			   uint16_t tgt_id, uint64_t lun_id,
1261762306a36Sopenharmony_ci			   lpfc_ctx_cmd ctx_cmd)
1261862306a36Sopenharmony_ci{
1261962306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_cmd;
1262062306a36Sopenharmony_ci	int rc = 1;
1262162306a36Sopenharmony_ci
1262262306a36Sopenharmony_ci	lpfc_cmd = container_of(iocbq, struct lpfc_io_buf, cur_iocbq);
1262362306a36Sopenharmony_ci
1262462306a36Sopenharmony_ci	if (lpfc_cmd->pCmd == NULL)
1262562306a36Sopenharmony_ci		return rc;
1262662306a36Sopenharmony_ci
1262762306a36Sopenharmony_ci	switch (ctx_cmd) {
1262862306a36Sopenharmony_ci	case LPFC_CTX_LUN:
1262962306a36Sopenharmony_ci		if ((lpfc_cmd->rdata) && (lpfc_cmd->rdata->pnode) &&
1263062306a36Sopenharmony_ci		    (lpfc_cmd->rdata->pnode->nlp_sid == tgt_id) &&
1263162306a36Sopenharmony_ci		    (scsilun_to_int(&lpfc_cmd->fcp_cmnd->fcp_lun) == lun_id))
1263262306a36Sopenharmony_ci			rc = 0;
1263362306a36Sopenharmony_ci		break;
1263462306a36Sopenharmony_ci	case LPFC_CTX_TGT:
1263562306a36Sopenharmony_ci		if ((lpfc_cmd->rdata) && (lpfc_cmd->rdata->pnode) &&
1263662306a36Sopenharmony_ci		    (lpfc_cmd->rdata->pnode->nlp_sid == tgt_id))
1263762306a36Sopenharmony_ci			rc = 0;
1263862306a36Sopenharmony_ci		break;
1263962306a36Sopenharmony_ci	case LPFC_CTX_HOST:
1264062306a36Sopenharmony_ci		rc = 0;
1264162306a36Sopenharmony_ci		break;
1264262306a36Sopenharmony_ci	default:
1264362306a36Sopenharmony_ci		printk(KERN_ERR "%s: Unknown context cmd type, value %d\n",
1264462306a36Sopenharmony_ci			__func__, ctx_cmd);
1264562306a36Sopenharmony_ci		break;
1264662306a36Sopenharmony_ci	}
1264762306a36Sopenharmony_ci
1264862306a36Sopenharmony_ci	return rc;
1264962306a36Sopenharmony_ci}
1265062306a36Sopenharmony_ci
1265162306a36Sopenharmony_ci/**
1265262306a36Sopenharmony_ci * lpfc_sli_sum_iocb - Function to count the number of FCP iocbs pending
1265362306a36Sopenharmony_ci * @vport: Pointer to virtual port.
1265462306a36Sopenharmony_ci * @tgt_id: SCSI ID of the target.
1265562306a36Sopenharmony_ci * @lun_id: LUN ID of the scsi device.
1265662306a36Sopenharmony_ci * @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST.
1265762306a36Sopenharmony_ci *
1265862306a36Sopenharmony_ci * This function returns number of FCP commands pending for the vport.
1265962306a36Sopenharmony_ci * When ctx_cmd == LPFC_CTX_LUN, the function returns number of FCP
1266062306a36Sopenharmony_ci * commands pending on the vport associated with SCSI device specified
1266162306a36Sopenharmony_ci * by tgt_id and lun_id parameters.
1266262306a36Sopenharmony_ci * When ctx_cmd == LPFC_CTX_TGT, the function returns number of FCP
1266362306a36Sopenharmony_ci * commands pending on the vport associated with SCSI target specified
1266462306a36Sopenharmony_ci * by tgt_id parameter.
1266562306a36Sopenharmony_ci * When ctx_cmd == LPFC_CTX_HOST, the function returns number of FCP
1266662306a36Sopenharmony_ci * commands pending on the vport.
1266762306a36Sopenharmony_ci * This function returns the number of iocbs which satisfy the filter.
1266862306a36Sopenharmony_ci * This function is called without any lock held.
1266962306a36Sopenharmony_ci **/
1267062306a36Sopenharmony_ciint
1267162306a36Sopenharmony_cilpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id,
1267262306a36Sopenharmony_ci		  lpfc_ctx_cmd ctx_cmd)
1267362306a36Sopenharmony_ci{
1267462306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
1267562306a36Sopenharmony_ci	struct lpfc_iocbq *iocbq;
1267662306a36Sopenharmony_ci	int sum, i;
1267762306a36Sopenharmony_ci	unsigned long iflags;
1267862306a36Sopenharmony_ci	u8 ulp_command;
1267962306a36Sopenharmony_ci
1268062306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1268162306a36Sopenharmony_ci	for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) {
1268262306a36Sopenharmony_ci		iocbq = phba->sli.iocbq_lookup[i];
1268362306a36Sopenharmony_ci
1268462306a36Sopenharmony_ci		if (!iocbq || iocbq->vport != vport)
1268562306a36Sopenharmony_ci			continue;
1268662306a36Sopenharmony_ci		if (!(iocbq->cmd_flag & LPFC_IO_FCP) ||
1268762306a36Sopenharmony_ci		    !(iocbq->cmd_flag & LPFC_IO_ON_TXCMPLQ))
1268862306a36Sopenharmony_ci			continue;
1268962306a36Sopenharmony_ci
1269062306a36Sopenharmony_ci		/* Include counting outstanding aborts */
1269162306a36Sopenharmony_ci		ulp_command = get_job_cmnd(phba, iocbq);
1269262306a36Sopenharmony_ci		if (ulp_command == CMD_ABORT_XRI_CN ||
1269362306a36Sopenharmony_ci		    ulp_command == CMD_CLOSE_XRI_CN ||
1269462306a36Sopenharmony_ci		    ulp_command == CMD_ABORT_XRI_WQE) {
1269562306a36Sopenharmony_ci			sum++;
1269662306a36Sopenharmony_ci			continue;
1269762306a36Sopenharmony_ci		}
1269862306a36Sopenharmony_ci
1269962306a36Sopenharmony_ci		if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id,
1270062306a36Sopenharmony_ci					       ctx_cmd) == 0)
1270162306a36Sopenharmony_ci			sum++;
1270262306a36Sopenharmony_ci	}
1270362306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1270462306a36Sopenharmony_ci
1270562306a36Sopenharmony_ci	return sum;
1270662306a36Sopenharmony_ci}
1270762306a36Sopenharmony_ci
1270862306a36Sopenharmony_ci/**
1270962306a36Sopenharmony_ci * lpfc_sli_abort_fcp_cmpl - Completion handler function for aborted FCP IOCBs
1271062306a36Sopenharmony_ci * @phba: Pointer to HBA context object
1271162306a36Sopenharmony_ci * @cmdiocb: Pointer to command iocb object.
1271262306a36Sopenharmony_ci * @rspiocb: Pointer to response iocb object.
1271362306a36Sopenharmony_ci *
1271462306a36Sopenharmony_ci * This function is called when an aborted FCP iocb completes. This
1271562306a36Sopenharmony_ci * function is called by the ring event handler with no lock held.
1271662306a36Sopenharmony_ci * This function frees the iocb.
1271762306a36Sopenharmony_ci **/
1271862306a36Sopenharmony_civoid
1271962306a36Sopenharmony_cilpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1272062306a36Sopenharmony_ci			struct lpfc_iocbq *rspiocb)
1272162306a36Sopenharmony_ci{
1272262306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
1272362306a36Sopenharmony_ci			"3096 ABORT_XRI_CX completing on rpi x%x "
1272462306a36Sopenharmony_ci			"original iotag x%x, abort cmd iotag x%x "
1272562306a36Sopenharmony_ci			"status 0x%x, reason 0x%x\n",
1272662306a36Sopenharmony_ci			(phba->sli_rev == LPFC_SLI_REV4) ?
1272762306a36Sopenharmony_ci			cmdiocb->sli4_xritag :
1272862306a36Sopenharmony_ci			cmdiocb->iocb.un.acxri.abortContextTag,
1272962306a36Sopenharmony_ci			get_job_abtsiotag(phba, cmdiocb),
1273062306a36Sopenharmony_ci			cmdiocb->iotag, get_job_ulpstatus(phba, rspiocb),
1273162306a36Sopenharmony_ci			get_job_word4(phba, rspiocb));
1273262306a36Sopenharmony_ci	lpfc_sli_release_iocbq(phba, cmdiocb);
1273362306a36Sopenharmony_ci	return;
1273462306a36Sopenharmony_ci}
1273562306a36Sopenharmony_ci
1273662306a36Sopenharmony_ci/**
1273762306a36Sopenharmony_ci * lpfc_sli_abort_iocb - issue abort for all commands on a host/target/LUN
1273862306a36Sopenharmony_ci * @vport: Pointer to virtual port.
1273962306a36Sopenharmony_ci * @tgt_id: SCSI ID of the target.
1274062306a36Sopenharmony_ci * @lun_id: LUN ID of the scsi device.
1274162306a36Sopenharmony_ci * @abort_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST.
1274262306a36Sopenharmony_ci *
1274362306a36Sopenharmony_ci * This function sends an abort command for every SCSI command
1274462306a36Sopenharmony_ci * associated with the given virtual port pending on the ring
1274562306a36Sopenharmony_ci * filtered by lpfc_sli_validate_fcp_iocb_for_abort and then
1274662306a36Sopenharmony_ci * lpfc_sli_validate_fcp_iocb function.  The ordering for validation before
1274762306a36Sopenharmony_ci * submitting abort iocbs must be lpfc_sli_validate_fcp_iocb_for_abort
1274862306a36Sopenharmony_ci * followed by lpfc_sli_validate_fcp_iocb.
1274962306a36Sopenharmony_ci *
1275062306a36Sopenharmony_ci * When abort_cmd == LPFC_CTX_LUN, the function sends abort only to the
1275162306a36Sopenharmony_ci * FCP iocbs associated with lun specified by tgt_id and lun_id
1275262306a36Sopenharmony_ci * parameters
1275362306a36Sopenharmony_ci * When abort_cmd == LPFC_CTX_TGT, the function sends abort only to the
1275462306a36Sopenharmony_ci * FCP iocbs associated with SCSI target specified by tgt_id parameter.
1275562306a36Sopenharmony_ci * When abort_cmd == LPFC_CTX_HOST, the function sends abort to all
1275662306a36Sopenharmony_ci * FCP iocbs associated with virtual port.
1275762306a36Sopenharmony_ci * The pring used for SLI3 is sli3_ring[LPFC_FCP_RING], for SLI4
1275862306a36Sopenharmony_ci * lpfc_sli4_calc_ring is used.
1275962306a36Sopenharmony_ci * This function returns number of iocbs it failed to abort.
1276062306a36Sopenharmony_ci * This function is called with no locks held.
1276162306a36Sopenharmony_ci **/
1276262306a36Sopenharmony_ciint
1276362306a36Sopenharmony_cilpfc_sli_abort_iocb(struct lpfc_vport *vport, u16 tgt_id, u64 lun_id,
1276462306a36Sopenharmony_ci		    lpfc_ctx_cmd abort_cmd)
1276562306a36Sopenharmony_ci{
1276662306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
1276762306a36Sopenharmony_ci	struct lpfc_sli_ring *pring = NULL;
1276862306a36Sopenharmony_ci	struct lpfc_iocbq *iocbq;
1276962306a36Sopenharmony_ci	int errcnt = 0, ret_val = 0;
1277062306a36Sopenharmony_ci	unsigned long iflags;
1277162306a36Sopenharmony_ci	int i;
1277262306a36Sopenharmony_ci
1277362306a36Sopenharmony_ci	/* all I/Os are in process of being flushed */
1277462306a36Sopenharmony_ci	if (phba->hba_flag & HBA_IOQ_FLUSH)
1277562306a36Sopenharmony_ci		return errcnt;
1277662306a36Sopenharmony_ci
1277762306a36Sopenharmony_ci	for (i = 1; i <= phba->sli.last_iotag; i++) {
1277862306a36Sopenharmony_ci		iocbq = phba->sli.iocbq_lookup[i];
1277962306a36Sopenharmony_ci
1278062306a36Sopenharmony_ci		if (lpfc_sli_validate_fcp_iocb_for_abort(iocbq, vport))
1278162306a36Sopenharmony_ci			continue;
1278262306a36Sopenharmony_ci
1278362306a36Sopenharmony_ci		if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id,
1278462306a36Sopenharmony_ci					       abort_cmd) != 0)
1278562306a36Sopenharmony_ci			continue;
1278662306a36Sopenharmony_ci
1278762306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1278862306a36Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV3) {
1278962306a36Sopenharmony_ci			pring = &phba->sli.sli3_ring[LPFC_FCP_RING];
1279062306a36Sopenharmony_ci		} else if (phba->sli_rev == LPFC_SLI_REV4) {
1279162306a36Sopenharmony_ci			pring = lpfc_sli4_calc_ring(phba, iocbq);
1279262306a36Sopenharmony_ci		}
1279362306a36Sopenharmony_ci		ret_val = lpfc_sli_issue_abort_iotag(phba, pring, iocbq,
1279462306a36Sopenharmony_ci						     lpfc_sli_abort_fcp_cmpl);
1279562306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1279662306a36Sopenharmony_ci		if (ret_val != IOCB_SUCCESS)
1279762306a36Sopenharmony_ci			errcnt++;
1279862306a36Sopenharmony_ci	}
1279962306a36Sopenharmony_ci
1280062306a36Sopenharmony_ci	return errcnt;
1280162306a36Sopenharmony_ci}
1280262306a36Sopenharmony_ci
1280362306a36Sopenharmony_ci/**
1280462306a36Sopenharmony_ci * lpfc_sli_abort_taskmgmt - issue abort for all commands on a host/target/LUN
1280562306a36Sopenharmony_ci * @vport: Pointer to virtual port.
1280662306a36Sopenharmony_ci * @pring: Pointer to driver SLI ring object.
1280762306a36Sopenharmony_ci * @tgt_id: SCSI ID of the target.
1280862306a36Sopenharmony_ci * @lun_id: LUN ID of the scsi device.
1280962306a36Sopenharmony_ci * @cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST.
1281062306a36Sopenharmony_ci *
1281162306a36Sopenharmony_ci * This function sends an abort command for every SCSI command
1281262306a36Sopenharmony_ci * associated with the given virtual port pending on the ring
1281362306a36Sopenharmony_ci * filtered by lpfc_sli_validate_fcp_iocb_for_abort and then
1281462306a36Sopenharmony_ci * lpfc_sli_validate_fcp_iocb function.  The ordering for validation before
1281562306a36Sopenharmony_ci * submitting abort iocbs must be lpfc_sli_validate_fcp_iocb_for_abort
1281662306a36Sopenharmony_ci * followed by lpfc_sli_validate_fcp_iocb.
1281762306a36Sopenharmony_ci *
1281862306a36Sopenharmony_ci * When taskmgmt_cmd == LPFC_CTX_LUN, the function sends abort only to the
1281962306a36Sopenharmony_ci * FCP iocbs associated with lun specified by tgt_id and lun_id
1282062306a36Sopenharmony_ci * parameters
1282162306a36Sopenharmony_ci * When taskmgmt_cmd == LPFC_CTX_TGT, the function sends abort only to the
1282262306a36Sopenharmony_ci * FCP iocbs associated with SCSI target specified by tgt_id parameter.
1282362306a36Sopenharmony_ci * When taskmgmt_cmd == LPFC_CTX_HOST, the function sends abort to all
1282462306a36Sopenharmony_ci * FCP iocbs associated with virtual port.
1282562306a36Sopenharmony_ci * This function returns number of iocbs it aborted .
1282662306a36Sopenharmony_ci * This function is called with no locks held right after a taskmgmt
1282762306a36Sopenharmony_ci * command is sent.
1282862306a36Sopenharmony_ci **/
1282962306a36Sopenharmony_ciint
1283062306a36Sopenharmony_cilpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
1283162306a36Sopenharmony_ci			uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd cmd)
1283262306a36Sopenharmony_ci{
1283362306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
1283462306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_cmd;
1283562306a36Sopenharmony_ci	struct lpfc_iocbq *abtsiocbq;
1283662306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp = NULL;
1283762306a36Sopenharmony_ci	struct lpfc_iocbq *iocbq;
1283862306a36Sopenharmony_ci	int sum, i, ret_val;
1283962306a36Sopenharmony_ci	unsigned long iflags;
1284062306a36Sopenharmony_ci	struct lpfc_sli_ring *pring_s4 = NULL;
1284162306a36Sopenharmony_ci	u16 ulp_context, iotag, cqid = LPFC_WQE_CQ_ID_DEFAULT;
1284262306a36Sopenharmony_ci	bool ia;
1284362306a36Sopenharmony_ci
1284462306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1284562306a36Sopenharmony_ci
1284662306a36Sopenharmony_ci	/* all I/Os are in process of being flushed */
1284762306a36Sopenharmony_ci	if (phba->hba_flag & HBA_IOQ_FLUSH) {
1284862306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1284962306a36Sopenharmony_ci		return 0;
1285062306a36Sopenharmony_ci	}
1285162306a36Sopenharmony_ci	sum = 0;
1285262306a36Sopenharmony_ci
1285362306a36Sopenharmony_ci	for (i = 1; i <= phba->sli.last_iotag; i++) {
1285462306a36Sopenharmony_ci		iocbq = phba->sli.iocbq_lookup[i];
1285562306a36Sopenharmony_ci
1285662306a36Sopenharmony_ci		if (lpfc_sli_validate_fcp_iocb_for_abort(iocbq, vport))
1285762306a36Sopenharmony_ci			continue;
1285862306a36Sopenharmony_ci
1285962306a36Sopenharmony_ci		if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id,
1286062306a36Sopenharmony_ci					       cmd) != 0)
1286162306a36Sopenharmony_ci			continue;
1286262306a36Sopenharmony_ci
1286362306a36Sopenharmony_ci		/* Guard against IO completion being called at same time */
1286462306a36Sopenharmony_ci		lpfc_cmd = container_of(iocbq, struct lpfc_io_buf, cur_iocbq);
1286562306a36Sopenharmony_ci		spin_lock(&lpfc_cmd->buf_lock);
1286662306a36Sopenharmony_ci
1286762306a36Sopenharmony_ci		if (!lpfc_cmd->pCmd) {
1286862306a36Sopenharmony_ci			spin_unlock(&lpfc_cmd->buf_lock);
1286962306a36Sopenharmony_ci			continue;
1287062306a36Sopenharmony_ci		}
1287162306a36Sopenharmony_ci
1287262306a36Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4) {
1287362306a36Sopenharmony_ci			pring_s4 =
1287462306a36Sopenharmony_ci			    phba->sli4_hba.hdwq[iocbq->hba_wqidx].io_wq->pring;
1287562306a36Sopenharmony_ci			if (!pring_s4) {
1287662306a36Sopenharmony_ci				spin_unlock(&lpfc_cmd->buf_lock);
1287762306a36Sopenharmony_ci				continue;
1287862306a36Sopenharmony_ci			}
1287962306a36Sopenharmony_ci			/* Note: both hbalock and ring_lock must be set here */
1288062306a36Sopenharmony_ci			spin_lock(&pring_s4->ring_lock);
1288162306a36Sopenharmony_ci		}
1288262306a36Sopenharmony_ci
1288362306a36Sopenharmony_ci		/*
1288462306a36Sopenharmony_ci		 * If the iocbq is already being aborted, don't take a second
1288562306a36Sopenharmony_ci		 * action, but do count it.
1288662306a36Sopenharmony_ci		 */
1288762306a36Sopenharmony_ci		if ((iocbq->cmd_flag & LPFC_DRIVER_ABORTED) ||
1288862306a36Sopenharmony_ci		    !(iocbq->cmd_flag & LPFC_IO_ON_TXCMPLQ)) {
1288962306a36Sopenharmony_ci			if (phba->sli_rev == LPFC_SLI_REV4)
1289062306a36Sopenharmony_ci				spin_unlock(&pring_s4->ring_lock);
1289162306a36Sopenharmony_ci			spin_unlock(&lpfc_cmd->buf_lock);
1289262306a36Sopenharmony_ci			continue;
1289362306a36Sopenharmony_ci		}
1289462306a36Sopenharmony_ci
1289562306a36Sopenharmony_ci		/* issue ABTS for this IOCB based on iotag */
1289662306a36Sopenharmony_ci		abtsiocbq = __lpfc_sli_get_iocbq(phba);
1289762306a36Sopenharmony_ci		if (!abtsiocbq) {
1289862306a36Sopenharmony_ci			if (phba->sli_rev == LPFC_SLI_REV4)
1289962306a36Sopenharmony_ci				spin_unlock(&pring_s4->ring_lock);
1290062306a36Sopenharmony_ci			spin_unlock(&lpfc_cmd->buf_lock);
1290162306a36Sopenharmony_ci			continue;
1290262306a36Sopenharmony_ci		}
1290362306a36Sopenharmony_ci
1290462306a36Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4) {
1290562306a36Sopenharmony_ci			iotag = abtsiocbq->iotag;
1290662306a36Sopenharmony_ci			ulp_context = iocbq->sli4_xritag;
1290762306a36Sopenharmony_ci			cqid = lpfc_cmd->hdwq->io_cq_map;
1290862306a36Sopenharmony_ci		} else {
1290962306a36Sopenharmony_ci			iotag = iocbq->iocb.ulpIoTag;
1291062306a36Sopenharmony_ci			if (pring->ringno == LPFC_ELS_RING) {
1291162306a36Sopenharmony_ci				ndlp = iocbq->ndlp;
1291262306a36Sopenharmony_ci				ulp_context = ndlp->nlp_rpi;
1291362306a36Sopenharmony_ci			} else {
1291462306a36Sopenharmony_ci				ulp_context = iocbq->iocb.ulpContext;
1291562306a36Sopenharmony_ci			}
1291662306a36Sopenharmony_ci		}
1291762306a36Sopenharmony_ci
1291862306a36Sopenharmony_ci		ndlp = lpfc_cmd->rdata->pnode;
1291962306a36Sopenharmony_ci
1292062306a36Sopenharmony_ci		if (lpfc_is_link_up(phba) &&
1292162306a36Sopenharmony_ci		    (ndlp && ndlp->nlp_state == NLP_STE_MAPPED_NODE) &&
1292262306a36Sopenharmony_ci		    !(phba->link_flag & LS_EXTERNAL_LOOPBACK))
1292362306a36Sopenharmony_ci			ia = false;
1292462306a36Sopenharmony_ci		else
1292562306a36Sopenharmony_ci			ia = true;
1292662306a36Sopenharmony_ci
1292762306a36Sopenharmony_ci		lpfc_sli_prep_abort_xri(phba, abtsiocbq, ulp_context, iotag,
1292862306a36Sopenharmony_ci					iocbq->iocb.ulpClass, cqid,
1292962306a36Sopenharmony_ci					ia, false);
1293062306a36Sopenharmony_ci
1293162306a36Sopenharmony_ci		abtsiocbq->vport = vport;
1293262306a36Sopenharmony_ci
1293362306a36Sopenharmony_ci		/* ABTS WQE must go to the same WQ as the WQE to be aborted */
1293462306a36Sopenharmony_ci		abtsiocbq->hba_wqidx = iocbq->hba_wqidx;
1293562306a36Sopenharmony_ci		if (iocbq->cmd_flag & LPFC_IO_FCP)
1293662306a36Sopenharmony_ci			abtsiocbq->cmd_flag |= LPFC_USE_FCPWQIDX;
1293762306a36Sopenharmony_ci		if (iocbq->cmd_flag & LPFC_IO_FOF)
1293862306a36Sopenharmony_ci			abtsiocbq->cmd_flag |= LPFC_IO_FOF;
1293962306a36Sopenharmony_ci
1294062306a36Sopenharmony_ci		/* Setup callback routine and issue the command. */
1294162306a36Sopenharmony_ci		abtsiocbq->cmd_cmpl = lpfc_sli_abort_fcp_cmpl;
1294262306a36Sopenharmony_ci
1294362306a36Sopenharmony_ci		/*
1294462306a36Sopenharmony_ci		 * Indicate the IO is being aborted by the driver and set
1294562306a36Sopenharmony_ci		 * the caller's flag into the aborted IO.
1294662306a36Sopenharmony_ci		 */
1294762306a36Sopenharmony_ci		iocbq->cmd_flag |= LPFC_DRIVER_ABORTED;
1294862306a36Sopenharmony_ci
1294962306a36Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4) {
1295062306a36Sopenharmony_ci			ret_val = __lpfc_sli_issue_iocb(phba, pring_s4->ringno,
1295162306a36Sopenharmony_ci							abtsiocbq, 0);
1295262306a36Sopenharmony_ci			spin_unlock(&pring_s4->ring_lock);
1295362306a36Sopenharmony_ci		} else {
1295462306a36Sopenharmony_ci			ret_val = __lpfc_sli_issue_iocb(phba, pring->ringno,
1295562306a36Sopenharmony_ci							abtsiocbq, 0);
1295662306a36Sopenharmony_ci		}
1295762306a36Sopenharmony_ci
1295862306a36Sopenharmony_ci		spin_unlock(&lpfc_cmd->buf_lock);
1295962306a36Sopenharmony_ci
1296062306a36Sopenharmony_ci		if (ret_val == IOCB_ERROR)
1296162306a36Sopenharmony_ci			__lpfc_sli_release_iocbq(phba, abtsiocbq);
1296262306a36Sopenharmony_ci		else
1296362306a36Sopenharmony_ci			sum++;
1296462306a36Sopenharmony_ci	}
1296562306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1296662306a36Sopenharmony_ci	return sum;
1296762306a36Sopenharmony_ci}
1296862306a36Sopenharmony_ci
1296962306a36Sopenharmony_ci/**
1297062306a36Sopenharmony_ci * lpfc_sli_wake_iocb_wait - lpfc_sli_issue_iocb_wait's completion handler
1297162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1297262306a36Sopenharmony_ci * @cmdiocbq: Pointer to command iocb.
1297362306a36Sopenharmony_ci * @rspiocbq: Pointer to response iocb.
1297462306a36Sopenharmony_ci *
1297562306a36Sopenharmony_ci * This function is the completion handler for iocbs issued using
1297662306a36Sopenharmony_ci * lpfc_sli_issue_iocb_wait function. This function is called by the
1297762306a36Sopenharmony_ci * ring event handler function without any lock held. This function
1297862306a36Sopenharmony_ci * can be called from both worker thread context and interrupt
1297962306a36Sopenharmony_ci * context. This function also can be called from other thread which
1298062306a36Sopenharmony_ci * cleans up the SLI layer objects.
1298162306a36Sopenharmony_ci * This function copy the contents of the response iocb to the
1298262306a36Sopenharmony_ci * response iocb memory object provided by the caller of
1298362306a36Sopenharmony_ci * lpfc_sli_issue_iocb_wait and then wakes up the thread which
1298462306a36Sopenharmony_ci * sleeps for the iocb completion.
1298562306a36Sopenharmony_ci **/
1298662306a36Sopenharmony_cistatic void
1298762306a36Sopenharmony_cilpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
1298862306a36Sopenharmony_ci			struct lpfc_iocbq *cmdiocbq,
1298962306a36Sopenharmony_ci			struct lpfc_iocbq *rspiocbq)
1299062306a36Sopenharmony_ci{
1299162306a36Sopenharmony_ci	wait_queue_head_t *pdone_q;
1299262306a36Sopenharmony_ci	unsigned long iflags;
1299362306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_cmd;
1299462306a36Sopenharmony_ci	size_t offset = offsetof(struct lpfc_iocbq, wqe);
1299562306a36Sopenharmony_ci
1299662306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1299762306a36Sopenharmony_ci	if (cmdiocbq->cmd_flag & LPFC_IO_WAKE_TMO) {
1299862306a36Sopenharmony_ci
1299962306a36Sopenharmony_ci		/*
1300062306a36Sopenharmony_ci		 * A time out has occurred for the iocb.  If a time out
1300162306a36Sopenharmony_ci		 * completion handler has been supplied, call it.  Otherwise,
1300262306a36Sopenharmony_ci		 * just free the iocbq.
1300362306a36Sopenharmony_ci		 */
1300462306a36Sopenharmony_ci
1300562306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1300662306a36Sopenharmony_ci		cmdiocbq->cmd_cmpl = cmdiocbq->wait_cmd_cmpl;
1300762306a36Sopenharmony_ci		cmdiocbq->wait_cmd_cmpl = NULL;
1300862306a36Sopenharmony_ci		if (cmdiocbq->cmd_cmpl)
1300962306a36Sopenharmony_ci			cmdiocbq->cmd_cmpl(phba, cmdiocbq, NULL);
1301062306a36Sopenharmony_ci		else
1301162306a36Sopenharmony_ci			lpfc_sli_release_iocbq(phba, cmdiocbq);
1301262306a36Sopenharmony_ci		return;
1301362306a36Sopenharmony_ci	}
1301462306a36Sopenharmony_ci
1301562306a36Sopenharmony_ci	/* Copy the contents of the local rspiocb into the caller's buffer. */
1301662306a36Sopenharmony_ci	cmdiocbq->cmd_flag |= LPFC_IO_WAKE;
1301762306a36Sopenharmony_ci	if (cmdiocbq->rsp_iocb && rspiocbq)
1301862306a36Sopenharmony_ci		memcpy((char *)cmdiocbq->rsp_iocb + offset,
1301962306a36Sopenharmony_ci		       (char *)rspiocbq + offset, sizeof(*rspiocbq) - offset);
1302062306a36Sopenharmony_ci
1302162306a36Sopenharmony_ci	/* Set the exchange busy flag for task management commands */
1302262306a36Sopenharmony_ci	if ((cmdiocbq->cmd_flag & LPFC_IO_FCP) &&
1302362306a36Sopenharmony_ci	    !(cmdiocbq->cmd_flag & LPFC_IO_LIBDFC)) {
1302462306a36Sopenharmony_ci		lpfc_cmd = container_of(cmdiocbq, struct lpfc_io_buf,
1302562306a36Sopenharmony_ci					cur_iocbq);
1302662306a36Sopenharmony_ci		if (rspiocbq && (rspiocbq->cmd_flag & LPFC_EXCHANGE_BUSY))
1302762306a36Sopenharmony_ci			lpfc_cmd->flags |= LPFC_SBUF_XBUSY;
1302862306a36Sopenharmony_ci		else
1302962306a36Sopenharmony_ci			lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
1303062306a36Sopenharmony_ci	}
1303162306a36Sopenharmony_ci
1303262306a36Sopenharmony_ci	pdone_q = cmdiocbq->context_un.wait_queue;
1303362306a36Sopenharmony_ci	if (pdone_q)
1303462306a36Sopenharmony_ci		wake_up(pdone_q);
1303562306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1303662306a36Sopenharmony_ci	return;
1303762306a36Sopenharmony_ci}
1303862306a36Sopenharmony_ci
1303962306a36Sopenharmony_ci/**
1304062306a36Sopenharmony_ci * lpfc_chk_iocb_flg - Test IOCB flag with lock held.
1304162306a36Sopenharmony_ci * @phba: Pointer to HBA context object..
1304262306a36Sopenharmony_ci * @piocbq: Pointer to command iocb.
1304362306a36Sopenharmony_ci * @flag: Flag to test.
1304462306a36Sopenharmony_ci *
1304562306a36Sopenharmony_ci * This routine grabs the hbalock and then test the cmd_flag to
1304662306a36Sopenharmony_ci * see if the passed in flag is set.
1304762306a36Sopenharmony_ci * Returns:
1304862306a36Sopenharmony_ci * 1 if flag is set.
1304962306a36Sopenharmony_ci * 0 if flag is not set.
1305062306a36Sopenharmony_ci **/
1305162306a36Sopenharmony_cistatic int
1305262306a36Sopenharmony_cilpfc_chk_iocb_flg(struct lpfc_hba *phba,
1305362306a36Sopenharmony_ci		 struct lpfc_iocbq *piocbq, uint32_t flag)
1305462306a36Sopenharmony_ci{
1305562306a36Sopenharmony_ci	unsigned long iflags;
1305662306a36Sopenharmony_ci	int ret;
1305762306a36Sopenharmony_ci
1305862306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1305962306a36Sopenharmony_ci	ret = piocbq->cmd_flag & flag;
1306062306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1306162306a36Sopenharmony_ci	return ret;
1306262306a36Sopenharmony_ci
1306362306a36Sopenharmony_ci}
1306462306a36Sopenharmony_ci
1306562306a36Sopenharmony_ci/**
1306662306a36Sopenharmony_ci * lpfc_sli_issue_iocb_wait - Synchronous function to issue iocb commands
1306762306a36Sopenharmony_ci * @phba: Pointer to HBA context object..
1306862306a36Sopenharmony_ci * @ring_number: Ring number
1306962306a36Sopenharmony_ci * @piocb: Pointer to command iocb.
1307062306a36Sopenharmony_ci * @prspiocbq: Pointer to response iocb.
1307162306a36Sopenharmony_ci * @timeout: Timeout in number of seconds.
1307262306a36Sopenharmony_ci *
1307362306a36Sopenharmony_ci * This function issues the iocb to firmware and waits for the
1307462306a36Sopenharmony_ci * iocb to complete. The cmd_cmpl field of the shall be used
1307562306a36Sopenharmony_ci * to handle iocbs which time out. If the field is NULL, the
1307662306a36Sopenharmony_ci * function shall free the iocbq structure.  If more clean up is
1307762306a36Sopenharmony_ci * needed, the caller is expected to provide a completion function
1307862306a36Sopenharmony_ci * that will provide the needed clean up.  If the iocb command is
1307962306a36Sopenharmony_ci * not completed within timeout seconds, the function will either
1308062306a36Sopenharmony_ci * free the iocbq structure (if cmd_cmpl == NULL) or execute the
1308162306a36Sopenharmony_ci * completion function set in the cmd_cmpl field and then return
1308262306a36Sopenharmony_ci * a status of IOCB_TIMEDOUT.  The caller should not free the iocb
1308362306a36Sopenharmony_ci * resources if this function returns IOCB_TIMEDOUT.
1308462306a36Sopenharmony_ci * The function waits for the iocb completion using an
1308562306a36Sopenharmony_ci * non-interruptible wait.
1308662306a36Sopenharmony_ci * This function will sleep while waiting for iocb completion.
1308762306a36Sopenharmony_ci * So, this function should not be called from any context which
1308862306a36Sopenharmony_ci * does not allow sleeping. Due to the same reason, this function
1308962306a36Sopenharmony_ci * cannot be called with interrupt disabled.
1309062306a36Sopenharmony_ci * This function assumes that the iocb completions occur while
1309162306a36Sopenharmony_ci * this function sleep. So, this function cannot be called from
1309262306a36Sopenharmony_ci * the thread which process iocb completion for this ring.
1309362306a36Sopenharmony_ci * This function clears the cmd_flag of the iocb object before
1309462306a36Sopenharmony_ci * issuing the iocb and the iocb completion handler sets this
1309562306a36Sopenharmony_ci * flag and wakes this thread when the iocb completes.
1309662306a36Sopenharmony_ci * The contents of the response iocb will be copied to prspiocbq
1309762306a36Sopenharmony_ci * by the completion handler when the command completes.
1309862306a36Sopenharmony_ci * This function returns IOCB_SUCCESS when success.
1309962306a36Sopenharmony_ci * This function is called with no lock held.
1310062306a36Sopenharmony_ci **/
1310162306a36Sopenharmony_ciint
1310262306a36Sopenharmony_cilpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
1310362306a36Sopenharmony_ci			 uint32_t ring_number,
1310462306a36Sopenharmony_ci			 struct lpfc_iocbq *piocb,
1310562306a36Sopenharmony_ci			 struct lpfc_iocbq *prspiocbq,
1310662306a36Sopenharmony_ci			 uint32_t timeout)
1310762306a36Sopenharmony_ci{
1310862306a36Sopenharmony_ci	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
1310962306a36Sopenharmony_ci	long timeleft, timeout_req = 0;
1311062306a36Sopenharmony_ci	int retval = IOCB_SUCCESS;
1311162306a36Sopenharmony_ci	uint32_t creg_val;
1311262306a36Sopenharmony_ci	struct lpfc_iocbq *iocb;
1311362306a36Sopenharmony_ci	int txq_cnt = 0;
1311462306a36Sopenharmony_ci	int txcmplq_cnt = 0;
1311562306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1311662306a36Sopenharmony_ci	unsigned long iflags;
1311762306a36Sopenharmony_ci	bool iocb_completed = true;
1311862306a36Sopenharmony_ci
1311962306a36Sopenharmony_ci	if (phba->sli_rev >= LPFC_SLI_REV4) {
1312062306a36Sopenharmony_ci		lpfc_sli_prep_wqe(phba, piocb);
1312162306a36Sopenharmony_ci
1312262306a36Sopenharmony_ci		pring = lpfc_sli4_calc_ring(phba, piocb);
1312362306a36Sopenharmony_ci	} else
1312462306a36Sopenharmony_ci		pring = &phba->sli.sli3_ring[ring_number];
1312562306a36Sopenharmony_ci	/*
1312662306a36Sopenharmony_ci	 * If the caller has provided a response iocbq buffer, then rsp_iocb
1312762306a36Sopenharmony_ci	 * is NULL or its an error.
1312862306a36Sopenharmony_ci	 */
1312962306a36Sopenharmony_ci	if (prspiocbq) {
1313062306a36Sopenharmony_ci		if (piocb->rsp_iocb)
1313162306a36Sopenharmony_ci			return IOCB_ERROR;
1313262306a36Sopenharmony_ci		piocb->rsp_iocb = prspiocbq;
1313362306a36Sopenharmony_ci	}
1313462306a36Sopenharmony_ci
1313562306a36Sopenharmony_ci	piocb->wait_cmd_cmpl = piocb->cmd_cmpl;
1313662306a36Sopenharmony_ci	piocb->cmd_cmpl = lpfc_sli_wake_iocb_wait;
1313762306a36Sopenharmony_ci	piocb->context_un.wait_queue = &done_q;
1313862306a36Sopenharmony_ci	piocb->cmd_flag &= ~(LPFC_IO_WAKE | LPFC_IO_WAKE_TMO);
1313962306a36Sopenharmony_ci
1314062306a36Sopenharmony_ci	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
1314162306a36Sopenharmony_ci		if (lpfc_readl(phba->HCregaddr, &creg_val))
1314262306a36Sopenharmony_ci			return IOCB_ERROR;
1314362306a36Sopenharmony_ci		creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING);
1314462306a36Sopenharmony_ci		writel(creg_val, phba->HCregaddr);
1314562306a36Sopenharmony_ci		readl(phba->HCregaddr); /* flush */
1314662306a36Sopenharmony_ci	}
1314762306a36Sopenharmony_ci
1314862306a36Sopenharmony_ci	retval = lpfc_sli_issue_iocb(phba, ring_number, piocb,
1314962306a36Sopenharmony_ci				     SLI_IOCB_RET_IOCB);
1315062306a36Sopenharmony_ci	if (retval == IOCB_SUCCESS) {
1315162306a36Sopenharmony_ci		timeout_req = msecs_to_jiffies(timeout * 1000);
1315262306a36Sopenharmony_ci		timeleft = wait_event_timeout(done_q,
1315362306a36Sopenharmony_ci				lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE),
1315462306a36Sopenharmony_ci				timeout_req);
1315562306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1315662306a36Sopenharmony_ci		if (!(piocb->cmd_flag & LPFC_IO_WAKE)) {
1315762306a36Sopenharmony_ci
1315862306a36Sopenharmony_ci			/*
1315962306a36Sopenharmony_ci			 * IOCB timed out.  Inform the wake iocb wait
1316062306a36Sopenharmony_ci			 * completion function and set local status
1316162306a36Sopenharmony_ci			 */
1316262306a36Sopenharmony_ci
1316362306a36Sopenharmony_ci			iocb_completed = false;
1316462306a36Sopenharmony_ci			piocb->cmd_flag |= LPFC_IO_WAKE_TMO;
1316562306a36Sopenharmony_ci		}
1316662306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1316762306a36Sopenharmony_ci		if (iocb_completed) {
1316862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
1316962306a36Sopenharmony_ci					"0331 IOCB wake signaled\n");
1317062306a36Sopenharmony_ci			/* Note: we are not indicating if the IOCB has a success
1317162306a36Sopenharmony_ci			 * status or not - that's for the caller to check.
1317262306a36Sopenharmony_ci			 * IOCB_SUCCESS means just that the command was sent and
1317362306a36Sopenharmony_ci			 * completed. Not that it completed successfully.
1317462306a36Sopenharmony_ci			 * */
1317562306a36Sopenharmony_ci		} else if (timeleft == 0) {
1317662306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1317762306a36Sopenharmony_ci					"0338 IOCB wait timeout error - no "
1317862306a36Sopenharmony_ci					"wake response Data x%x\n", timeout);
1317962306a36Sopenharmony_ci			retval = IOCB_TIMEDOUT;
1318062306a36Sopenharmony_ci		} else {
1318162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1318262306a36Sopenharmony_ci					"0330 IOCB wake NOT set, "
1318362306a36Sopenharmony_ci					"Data x%x x%lx\n",
1318462306a36Sopenharmony_ci					timeout, (timeleft / jiffies));
1318562306a36Sopenharmony_ci			retval = IOCB_TIMEDOUT;
1318662306a36Sopenharmony_ci		}
1318762306a36Sopenharmony_ci	} else if (retval == IOCB_BUSY) {
1318862306a36Sopenharmony_ci		if (phba->cfg_log_verbose & LOG_SLI) {
1318962306a36Sopenharmony_ci			list_for_each_entry(iocb, &pring->txq, list) {
1319062306a36Sopenharmony_ci				txq_cnt++;
1319162306a36Sopenharmony_ci			}
1319262306a36Sopenharmony_ci			list_for_each_entry(iocb, &pring->txcmplq, list) {
1319362306a36Sopenharmony_ci				txcmplq_cnt++;
1319462306a36Sopenharmony_ci			}
1319562306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
1319662306a36Sopenharmony_ci				"2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n",
1319762306a36Sopenharmony_ci				phba->iocb_cnt, txq_cnt, txcmplq_cnt);
1319862306a36Sopenharmony_ci		}
1319962306a36Sopenharmony_ci		return retval;
1320062306a36Sopenharmony_ci	} else {
1320162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
1320262306a36Sopenharmony_ci				"0332 IOCB wait issue failed, Data x%x\n",
1320362306a36Sopenharmony_ci				retval);
1320462306a36Sopenharmony_ci		retval = IOCB_ERROR;
1320562306a36Sopenharmony_ci	}
1320662306a36Sopenharmony_ci
1320762306a36Sopenharmony_ci	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
1320862306a36Sopenharmony_ci		if (lpfc_readl(phba->HCregaddr, &creg_val))
1320962306a36Sopenharmony_ci			return IOCB_ERROR;
1321062306a36Sopenharmony_ci		creg_val &= ~(HC_R0INT_ENA << LPFC_FCP_RING);
1321162306a36Sopenharmony_ci		writel(creg_val, phba->HCregaddr);
1321262306a36Sopenharmony_ci		readl(phba->HCregaddr); /* flush */
1321362306a36Sopenharmony_ci	}
1321462306a36Sopenharmony_ci
1321562306a36Sopenharmony_ci	if (prspiocbq)
1321662306a36Sopenharmony_ci		piocb->rsp_iocb = NULL;
1321762306a36Sopenharmony_ci
1321862306a36Sopenharmony_ci	piocb->context_un.wait_queue = NULL;
1321962306a36Sopenharmony_ci	piocb->cmd_cmpl = NULL;
1322062306a36Sopenharmony_ci	return retval;
1322162306a36Sopenharmony_ci}
1322262306a36Sopenharmony_ci
1322362306a36Sopenharmony_ci/**
1322462306a36Sopenharmony_ci * lpfc_sli_issue_mbox_wait - Synchronous function to issue mailbox
1322562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1322662306a36Sopenharmony_ci * @pmboxq: Pointer to driver mailbox object.
1322762306a36Sopenharmony_ci * @timeout: Timeout in number of seconds.
1322862306a36Sopenharmony_ci *
1322962306a36Sopenharmony_ci * This function issues the mailbox to firmware and waits for the
1323062306a36Sopenharmony_ci * mailbox command to complete. If the mailbox command is not
1323162306a36Sopenharmony_ci * completed within timeout seconds, it returns MBX_TIMEOUT.
1323262306a36Sopenharmony_ci * The function waits for the mailbox completion using an
1323362306a36Sopenharmony_ci * interruptible wait. If the thread is woken up due to a
1323462306a36Sopenharmony_ci * signal, MBX_TIMEOUT error is returned to the caller. Caller
1323562306a36Sopenharmony_ci * should not free the mailbox resources, if this function returns
1323662306a36Sopenharmony_ci * MBX_TIMEOUT.
1323762306a36Sopenharmony_ci * This function will sleep while waiting for mailbox completion.
1323862306a36Sopenharmony_ci * So, this function should not be called from any context which
1323962306a36Sopenharmony_ci * does not allow sleeping. Due to the same reason, this function
1324062306a36Sopenharmony_ci * cannot be called with interrupt disabled.
1324162306a36Sopenharmony_ci * This function assumes that the mailbox completion occurs while
1324262306a36Sopenharmony_ci * this function sleep. So, this function cannot be called from
1324362306a36Sopenharmony_ci * the worker thread which processes mailbox completion.
1324462306a36Sopenharmony_ci * This function is called in the context of HBA management
1324562306a36Sopenharmony_ci * applications.
1324662306a36Sopenharmony_ci * This function returns MBX_SUCCESS when successful.
1324762306a36Sopenharmony_ci * This function is called with no lock held.
1324862306a36Sopenharmony_ci **/
1324962306a36Sopenharmony_ciint
1325062306a36Sopenharmony_cilpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
1325162306a36Sopenharmony_ci			 uint32_t timeout)
1325262306a36Sopenharmony_ci{
1325362306a36Sopenharmony_ci	struct completion mbox_done;
1325462306a36Sopenharmony_ci	int retval;
1325562306a36Sopenharmony_ci	unsigned long flag;
1325662306a36Sopenharmony_ci
1325762306a36Sopenharmony_ci	pmboxq->mbox_flag &= ~LPFC_MBX_WAKE;
1325862306a36Sopenharmony_ci	/* setup wake call as IOCB callback */
1325962306a36Sopenharmony_ci	pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait;
1326062306a36Sopenharmony_ci
1326162306a36Sopenharmony_ci	/* setup context3 field to pass wait_queue pointer to wake function  */
1326262306a36Sopenharmony_ci	init_completion(&mbox_done);
1326362306a36Sopenharmony_ci	pmboxq->context3 = &mbox_done;
1326462306a36Sopenharmony_ci	/* now issue the command */
1326562306a36Sopenharmony_ci	retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
1326662306a36Sopenharmony_ci	if (retval == MBX_BUSY || retval == MBX_SUCCESS) {
1326762306a36Sopenharmony_ci		wait_for_completion_timeout(&mbox_done,
1326862306a36Sopenharmony_ci					    msecs_to_jiffies(timeout * 1000));
1326962306a36Sopenharmony_ci
1327062306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, flag);
1327162306a36Sopenharmony_ci		pmboxq->context3 = NULL;
1327262306a36Sopenharmony_ci		/*
1327362306a36Sopenharmony_ci		 * if LPFC_MBX_WAKE flag is set the mailbox is completed
1327462306a36Sopenharmony_ci		 * else do not free the resources.
1327562306a36Sopenharmony_ci		 */
1327662306a36Sopenharmony_ci		if (pmboxq->mbox_flag & LPFC_MBX_WAKE) {
1327762306a36Sopenharmony_ci			retval = MBX_SUCCESS;
1327862306a36Sopenharmony_ci		} else {
1327962306a36Sopenharmony_ci			retval = MBX_TIMEOUT;
1328062306a36Sopenharmony_ci			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
1328162306a36Sopenharmony_ci		}
1328262306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, flag);
1328362306a36Sopenharmony_ci	}
1328462306a36Sopenharmony_ci	return retval;
1328562306a36Sopenharmony_ci}
1328662306a36Sopenharmony_ci
1328762306a36Sopenharmony_ci/**
1328862306a36Sopenharmony_ci * lpfc_sli_mbox_sys_shutdown - shutdown mailbox command sub-system
1328962306a36Sopenharmony_ci * @phba: Pointer to HBA context.
1329062306a36Sopenharmony_ci * @mbx_action: Mailbox shutdown options.
1329162306a36Sopenharmony_ci *
1329262306a36Sopenharmony_ci * This function is called to shutdown the driver's mailbox sub-system.
1329362306a36Sopenharmony_ci * It first marks the mailbox sub-system is in a block state to prevent
1329462306a36Sopenharmony_ci * the asynchronous mailbox command from issued off the pending mailbox
1329562306a36Sopenharmony_ci * command queue. If the mailbox command sub-system shutdown is due to
1329662306a36Sopenharmony_ci * HBA error conditions such as EEH or ERATT, this routine shall invoke
1329762306a36Sopenharmony_ci * the mailbox sub-system flush routine to forcefully bring down the
1329862306a36Sopenharmony_ci * mailbox sub-system. Otherwise, if it is due to normal condition (such
1329962306a36Sopenharmony_ci * as with offline or HBA function reset), this routine will wait for the
1330062306a36Sopenharmony_ci * outstanding mailbox command to complete before invoking the mailbox
1330162306a36Sopenharmony_ci * sub-system flush routine to gracefully bring down mailbox sub-system.
1330262306a36Sopenharmony_ci **/
1330362306a36Sopenharmony_civoid
1330462306a36Sopenharmony_cilpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action)
1330562306a36Sopenharmony_ci{
1330662306a36Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
1330762306a36Sopenharmony_ci	unsigned long timeout;
1330862306a36Sopenharmony_ci
1330962306a36Sopenharmony_ci	if (mbx_action == LPFC_MBX_NO_WAIT) {
1331062306a36Sopenharmony_ci		/* delay 100ms for port state */
1331162306a36Sopenharmony_ci		msleep(100);
1331262306a36Sopenharmony_ci		lpfc_sli_mbox_sys_flush(phba);
1331362306a36Sopenharmony_ci		return;
1331462306a36Sopenharmony_ci	}
1331562306a36Sopenharmony_ci	timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies;
1331662306a36Sopenharmony_ci
1331762306a36Sopenharmony_ci	/* Disable softirqs, including timers from obtaining phba->hbalock */
1331862306a36Sopenharmony_ci	local_bh_disable();
1331962306a36Sopenharmony_ci
1332062306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
1332162306a36Sopenharmony_ci	psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK;
1332262306a36Sopenharmony_ci
1332362306a36Sopenharmony_ci	if (psli->sli_flag & LPFC_SLI_ACTIVE) {
1332462306a36Sopenharmony_ci		/* Determine how long we might wait for the active mailbox
1332562306a36Sopenharmony_ci		 * command to be gracefully completed by firmware.
1332662306a36Sopenharmony_ci		 */
1332762306a36Sopenharmony_ci		if (phba->sli.mbox_active)
1332862306a36Sopenharmony_ci			timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba,
1332962306a36Sopenharmony_ci						phba->sli.mbox_active) *
1333062306a36Sopenharmony_ci						1000) + jiffies;
1333162306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
1333262306a36Sopenharmony_ci
1333362306a36Sopenharmony_ci		/* Enable softirqs again, done with phba->hbalock */
1333462306a36Sopenharmony_ci		local_bh_enable();
1333562306a36Sopenharmony_ci
1333662306a36Sopenharmony_ci		while (phba->sli.mbox_active) {
1333762306a36Sopenharmony_ci			/* Check active mailbox complete status every 2ms */
1333862306a36Sopenharmony_ci			msleep(2);
1333962306a36Sopenharmony_ci			if (time_after(jiffies, timeout))
1334062306a36Sopenharmony_ci				/* Timeout, let the mailbox flush routine to
1334162306a36Sopenharmony_ci				 * forcefully release active mailbox command
1334262306a36Sopenharmony_ci				 */
1334362306a36Sopenharmony_ci				break;
1334462306a36Sopenharmony_ci		}
1334562306a36Sopenharmony_ci	} else {
1334662306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
1334762306a36Sopenharmony_ci
1334862306a36Sopenharmony_ci		/* Enable softirqs again, done with phba->hbalock */
1334962306a36Sopenharmony_ci		local_bh_enable();
1335062306a36Sopenharmony_ci	}
1335162306a36Sopenharmony_ci
1335262306a36Sopenharmony_ci	lpfc_sli_mbox_sys_flush(phba);
1335362306a36Sopenharmony_ci}
1335462306a36Sopenharmony_ci
1335562306a36Sopenharmony_ci/**
1335662306a36Sopenharmony_ci * lpfc_sli_eratt_read - read sli-3 error attention events
1335762306a36Sopenharmony_ci * @phba: Pointer to HBA context.
1335862306a36Sopenharmony_ci *
1335962306a36Sopenharmony_ci * This function is called to read the SLI3 device error attention registers
1336062306a36Sopenharmony_ci * for possible error attention events. The caller must hold the hostlock
1336162306a36Sopenharmony_ci * with spin_lock_irq().
1336262306a36Sopenharmony_ci *
1336362306a36Sopenharmony_ci * This function returns 1 when there is Error Attention in the Host Attention
1336462306a36Sopenharmony_ci * Register and returns 0 otherwise.
1336562306a36Sopenharmony_ci **/
1336662306a36Sopenharmony_cistatic int
1336762306a36Sopenharmony_cilpfc_sli_eratt_read(struct lpfc_hba *phba)
1336862306a36Sopenharmony_ci{
1336962306a36Sopenharmony_ci	uint32_t ha_copy;
1337062306a36Sopenharmony_ci
1337162306a36Sopenharmony_ci	/* Read chip Host Attention (HA) register */
1337262306a36Sopenharmony_ci	if (lpfc_readl(phba->HAregaddr, &ha_copy))
1337362306a36Sopenharmony_ci		goto unplug_err;
1337462306a36Sopenharmony_ci
1337562306a36Sopenharmony_ci	if (ha_copy & HA_ERATT) {
1337662306a36Sopenharmony_ci		/* Read host status register to retrieve error event */
1337762306a36Sopenharmony_ci		if (lpfc_sli_read_hs(phba))
1337862306a36Sopenharmony_ci			goto unplug_err;
1337962306a36Sopenharmony_ci
1338062306a36Sopenharmony_ci		/* Check if there is a deferred error condition is active */
1338162306a36Sopenharmony_ci		if ((HS_FFER1 & phba->work_hs) &&
1338262306a36Sopenharmony_ci		    ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 |
1338362306a36Sopenharmony_ci		      HS_FFER6 | HS_FFER7 | HS_FFER8) & phba->work_hs)) {
1338462306a36Sopenharmony_ci			phba->hba_flag |= DEFER_ERATT;
1338562306a36Sopenharmony_ci			/* Clear all interrupt enable conditions */
1338662306a36Sopenharmony_ci			writel(0, phba->HCregaddr);
1338762306a36Sopenharmony_ci			readl(phba->HCregaddr);
1338862306a36Sopenharmony_ci		}
1338962306a36Sopenharmony_ci
1339062306a36Sopenharmony_ci		/* Set the driver HA work bitmap */
1339162306a36Sopenharmony_ci		phba->work_ha |= HA_ERATT;
1339262306a36Sopenharmony_ci		/* Indicate polling handles this ERATT */
1339362306a36Sopenharmony_ci		phba->hba_flag |= HBA_ERATT_HANDLED;
1339462306a36Sopenharmony_ci		return 1;
1339562306a36Sopenharmony_ci	}
1339662306a36Sopenharmony_ci	return 0;
1339762306a36Sopenharmony_ci
1339862306a36Sopenharmony_ciunplug_err:
1339962306a36Sopenharmony_ci	/* Set the driver HS work bitmap */
1340062306a36Sopenharmony_ci	phba->work_hs |= UNPLUG_ERR;
1340162306a36Sopenharmony_ci	/* Set the driver HA work bitmap */
1340262306a36Sopenharmony_ci	phba->work_ha |= HA_ERATT;
1340362306a36Sopenharmony_ci	/* Indicate polling handles this ERATT */
1340462306a36Sopenharmony_ci	phba->hba_flag |= HBA_ERATT_HANDLED;
1340562306a36Sopenharmony_ci	return 1;
1340662306a36Sopenharmony_ci}
1340762306a36Sopenharmony_ci
1340862306a36Sopenharmony_ci/**
1340962306a36Sopenharmony_ci * lpfc_sli4_eratt_read - read sli-4 error attention events
1341062306a36Sopenharmony_ci * @phba: Pointer to HBA context.
1341162306a36Sopenharmony_ci *
1341262306a36Sopenharmony_ci * This function is called to read the SLI4 device error attention registers
1341362306a36Sopenharmony_ci * for possible error attention events. The caller must hold the hostlock
1341462306a36Sopenharmony_ci * with spin_lock_irq().
1341562306a36Sopenharmony_ci *
1341662306a36Sopenharmony_ci * This function returns 1 when there is Error Attention in the Host Attention
1341762306a36Sopenharmony_ci * Register and returns 0 otherwise.
1341862306a36Sopenharmony_ci **/
1341962306a36Sopenharmony_cistatic int
1342062306a36Sopenharmony_cilpfc_sli4_eratt_read(struct lpfc_hba *phba)
1342162306a36Sopenharmony_ci{
1342262306a36Sopenharmony_ci	uint32_t uerr_sta_hi, uerr_sta_lo;
1342362306a36Sopenharmony_ci	uint32_t if_type, portsmphr;
1342462306a36Sopenharmony_ci	struct lpfc_register portstat_reg;
1342562306a36Sopenharmony_ci	u32 logmask;
1342662306a36Sopenharmony_ci
1342762306a36Sopenharmony_ci	/*
1342862306a36Sopenharmony_ci	 * For now, use the SLI4 device internal unrecoverable error
1342962306a36Sopenharmony_ci	 * registers for error attention. This can be changed later.
1343062306a36Sopenharmony_ci	 */
1343162306a36Sopenharmony_ci	if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
1343262306a36Sopenharmony_ci	switch (if_type) {
1343362306a36Sopenharmony_ci	case LPFC_SLI_INTF_IF_TYPE_0:
1343462306a36Sopenharmony_ci		if (lpfc_readl(phba->sli4_hba.u.if_type0.UERRLOregaddr,
1343562306a36Sopenharmony_ci			&uerr_sta_lo) ||
1343662306a36Sopenharmony_ci			lpfc_readl(phba->sli4_hba.u.if_type0.UERRHIregaddr,
1343762306a36Sopenharmony_ci			&uerr_sta_hi)) {
1343862306a36Sopenharmony_ci			phba->work_hs |= UNPLUG_ERR;
1343962306a36Sopenharmony_ci			phba->work_ha |= HA_ERATT;
1344062306a36Sopenharmony_ci			phba->hba_flag |= HBA_ERATT_HANDLED;
1344162306a36Sopenharmony_ci			return 1;
1344262306a36Sopenharmony_ci		}
1344362306a36Sopenharmony_ci		if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) ||
1344462306a36Sopenharmony_ci		    (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) {
1344562306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1344662306a36Sopenharmony_ci					"1423 HBA Unrecoverable error: "
1344762306a36Sopenharmony_ci					"uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
1344862306a36Sopenharmony_ci					"ue_mask_lo_reg=0x%x, "
1344962306a36Sopenharmony_ci					"ue_mask_hi_reg=0x%x\n",
1345062306a36Sopenharmony_ci					uerr_sta_lo, uerr_sta_hi,
1345162306a36Sopenharmony_ci					phba->sli4_hba.ue_mask_lo,
1345262306a36Sopenharmony_ci					phba->sli4_hba.ue_mask_hi);
1345362306a36Sopenharmony_ci			phba->work_status[0] = uerr_sta_lo;
1345462306a36Sopenharmony_ci			phba->work_status[1] = uerr_sta_hi;
1345562306a36Sopenharmony_ci			phba->work_ha |= HA_ERATT;
1345662306a36Sopenharmony_ci			phba->hba_flag |= HBA_ERATT_HANDLED;
1345762306a36Sopenharmony_ci			return 1;
1345862306a36Sopenharmony_ci		}
1345962306a36Sopenharmony_ci		break;
1346062306a36Sopenharmony_ci	case LPFC_SLI_INTF_IF_TYPE_2:
1346162306a36Sopenharmony_ci	case LPFC_SLI_INTF_IF_TYPE_6:
1346262306a36Sopenharmony_ci		if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
1346362306a36Sopenharmony_ci			&portstat_reg.word0) ||
1346462306a36Sopenharmony_ci			lpfc_readl(phba->sli4_hba.PSMPHRregaddr,
1346562306a36Sopenharmony_ci			&portsmphr)){
1346662306a36Sopenharmony_ci			phba->work_hs |= UNPLUG_ERR;
1346762306a36Sopenharmony_ci			phba->work_ha |= HA_ERATT;
1346862306a36Sopenharmony_ci			phba->hba_flag |= HBA_ERATT_HANDLED;
1346962306a36Sopenharmony_ci			return 1;
1347062306a36Sopenharmony_ci		}
1347162306a36Sopenharmony_ci		if (bf_get(lpfc_sliport_status_err, &portstat_reg)) {
1347262306a36Sopenharmony_ci			phba->work_status[0] =
1347362306a36Sopenharmony_ci				readl(phba->sli4_hba.u.if_type2.ERR1regaddr);
1347462306a36Sopenharmony_ci			phba->work_status[1] =
1347562306a36Sopenharmony_ci				readl(phba->sli4_hba.u.if_type2.ERR2regaddr);
1347662306a36Sopenharmony_ci			logmask = LOG_TRACE_EVENT;
1347762306a36Sopenharmony_ci			if (phba->work_status[0] ==
1347862306a36Sopenharmony_ci				SLIPORT_ERR1_REG_ERR_CODE_2 &&
1347962306a36Sopenharmony_ci			    phba->work_status[1] == SLIPORT_ERR2_REG_FW_RESTART)
1348062306a36Sopenharmony_ci				logmask = LOG_SLI;
1348162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, logmask,
1348262306a36Sopenharmony_ci					"2885 Port Status Event: "
1348362306a36Sopenharmony_ci					"port status reg 0x%x, "
1348462306a36Sopenharmony_ci					"port smphr reg 0x%x, "
1348562306a36Sopenharmony_ci					"error 1=0x%x, error 2=0x%x\n",
1348662306a36Sopenharmony_ci					portstat_reg.word0,
1348762306a36Sopenharmony_ci					portsmphr,
1348862306a36Sopenharmony_ci					phba->work_status[0],
1348962306a36Sopenharmony_ci					phba->work_status[1]);
1349062306a36Sopenharmony_ci			phba->work_ha |= HA_ERATT;
1349162306a36Sopenharmony_ci			phba->hba_flag |= HBA_ERATT_HANDLED;
1349262306a36Sopenharmony_ci			return 1;
1349362306a36Sopenharmony_ci		}
1349462306a36Sopenharmony_ci		break;
1349562306a36Sopenharmony_ci	case LPFC_SLI_INTF_IF_TYPE_1:
1349662306a36Sopenharmony_ci	default:
1349762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1349862306a36Sopenharmony_ci				"2886 HBA Error Attention on unsupported "
1349962306a36Sopenharmony_ci				"if type %d.", if_type);
1350062306a36Sopenharmony_ci		return 1;
1350162306a36Sopenharmony_ci	}
1350262306a36Sopenharmony_ci
1350362306a36Sopenharmony_ci	return 0;
1350462306a36Sopenharmony_ci}
1350562306a36Sopenharmony_ci
1350662306a36Sopenharmony_ci/**
1350762306a36Sopenharmony_ci * lpfc_sli_check_eratt - check error attention events
1350862306a36Sopenharmony_ci * @phba: Pointer to HBA context.
1350962306a36Sopenharmony_ci *
1351062306a36Sopenharmony_ci * This function is called from timer soft interrupt context to check HBA's
1351162306a36Sopenharmony_ci * error attention register bit for error attention events.
1351262306a36Sopenharmony_ci *
1351362306a36Sopenharmony_ci * This function returns 1 when there is Error Attention in the Host Attention
1351462306a36Sopenharmony_ci * Register and returns 0 otherwise.
1351562306a36Sopenharmony_ci **/
1351662306a36Sopenharmony_ciint
1351762306a36Sopenharmony_cilpfc_sli_check_eratt(struct lpfc_hba *phba)
1351862306a36Sopenharmony_ci{
1351962306a36Sopenharmony_ci	uint32_t ha_copy;
1352062306a36Sopenharmony_ci
1352162306a36Sopenharmony_ci	/* If somebody is waiting to handle an eratt, don't process it
1352262306a36Sopenharmony_ci	 * here. The brdkill function will do this.
1352362306a36Sopenharmony_ci	 */
1352462306a36Sopenharmony_ci	if (phba->link_flag & LS_IGNORE_ERATT)
1352562306a36Sopenharmony_ci		return 0;
1352662306a36Sopenharmony_ci
1352762306a36Sopenharmony_ci	/* Check if interrupt handler handles this ERATT */
1352862306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
1352962306a36Sopenharmony_ci	if (phba->hba_flag & HBA_ERATT_HANDLED) {
1353062306a36Sopenharmony_ci		/* Interrupt handler has handled ERATT */
1353162306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
1353262306a36Sopenharmony_ci		return 0;
1353362306a36Sopenharmony_ci	}
1353462306a36Sopenharmony_ci
1353562306a36Sopenharmony_ci	/*
1353662306a36Sopenharmony_ci	 * If there is deferred error attention, do not check for error
1353762306a36Sopenharmony_ci	 * attention
1353862306a36Sopenharmony_ci	 */
1353962306a36Sopenharmony_ci	if (unlikely(phba->hba_flag & DEFER_ERATT)) {
1354062306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
1354162306a36Sopenharmony_ci		return 0;
1354262306a36Sopenharmony_ci	}
1354362306a36Sopenharmony_ci
1354462306a36Sopenharmony_ci	/* If PCI channel is offline, don't process it */
1354562306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(phba->pcidev))) {
1354662306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
1354762306a36Sopenharmony_ci		return 0;
1354862306a36Sopenharmony_ci	}
1354962306a36Sopenharmony_ci
1355062306a36Sopenharmony_ci	switch (phba->sli_rev) {
1355162306a36Sopenharmony_ci	case LPFC_SLI_REV2:
1355262306a36Sopenharmony_ci	case LPFC_SLI_REV3:
1355362306a36Sopenharmony_ci		/* Read chip Host Attention (HA) register */
1355462306a36Sopenharmony_ci		ha_copy = lpfc_sli_eratt_read(phba);
1355562306a36Sopenharmony_ci		break;
1355662306a36Sopenharmony_ci	case LPFC_SLI_REV4:
1355762306a36Sopenharmony_ci		/* Read device Uncoverable Error (UERR) registers */
1355862306a36Sopenharmony_ci		ha_copy = lpfc_sli4_eratt_read(phba);
1355962306a36Sopenharmony_ci		break;
1356062306a36Sopenharmony_ci	default:
1356162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1356262306a36Sopenharmony_ci				"0299 Invalid SLI revision (%d)\n",
1356362306a36Sopenharmony_ci				phba->sli_rev);
1356462306a36Sopenharmony_ci		ha_copy = 0;
1356562306a36Sopenharmony_ci		break;
1356662306a36Sopenharmony_ci	}
1356762306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
1356862306a36Sopenharmony_ci
1356962306a36Sopenharmony_ci	return ha_copy;
1357062306a36Sopenharmony_ci}
1357162306a36Sopenharmony_ci
1357262306a36Sopenharmony_ci/**
1357362306a36Sopenharmony_ci * lpfc_intr_state_check - Check device state for interrupt handling
1357462306a36Sopenharmony_ci * @phba: Pointer to HBA context.
1357562306a36Sopenharmony_ci *
1357662306a36Sopenharmony_ci * This inline routine checks whether a device or its PCI slot is in a state
1357762306a36Sopenharmony_ci * that the interrupt should be handled.
1357862306a36Sopenharmony_ci *
1357962306a36Sopenharmony_ci * This function returns 0 if the device or the PCI slot is in a state that
1358062306a36Sopenharmony_ci * interrupt should be handled, otherwise -EIO.
1358162306a36Sopenharmony_ci */
1358262306a36Sopenharmony_cistatic inline int
1358362306a36Sopenharmony_cilpfc_intr_state_check(struct lpfc_hba *phba)
1358462306a36Sopenharmony_ci{
1358562306a36Sopenharmony_ci	/* If the pci channel is offline, ignore all the interrupts */
1358662306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(phba->pcidev)))
1358762306a36Sopenharmony_ci		return -EIO;
1358862306a36Sopenharmony_ci
1358962306a36Sopenharmony_ci	/* Update device level interrupt statistics */
1359062306a36Sopenharmony_ci	phba->sli.slistat.sli_intr++;
1359162306a36Sopenharmony_ci
1359262306a36Sopenharmony_ci	/* Ignore all interrupts during initialization. */
1359362306a36Sopenharmony_ci	if (unlikely(phba->link_state < LPFC_LINK_DOWN))
1359462306a36Sopenharmony_ci		return -EIO;
1359562306a36Sopenharmony_ci
1359662306a36Sopenharmony_ci	return 0;
1359762306a36Sopenharmony_ci}
1359862306a36Sopenharmony_ci
1359962306a36Sopenharmony_ci/**
1360062306a36Sopenharmony_ci * lpfc_sli_sp_intr_handler - Slow-path interrupt handler to SLI-3 device
1360162306a36Sopenharmony_ci * @irq: Interrupt number.
1360262306a36Sopenharmony_ci * @dev_id: The device context pointer.
1360362306a36Sopenharmony_ci *
1360462306a36Sopenharmony_ci * This function is directly called from the PCI layer as an interrupt
1360562306a36Sopenharmony_ci * service routine when device with SLI-3 interface spec is enabled with
1360662306a36Sopenharmony_ci * MSI-X multi-message interrupt mode and there are slow-path events in
1360762306a36Sopenharmony_ci * the HBA. However, when the device is enabled with either MSI or Pin-IRQ
1360862306a36Sopenharmony_ci * interrupt mode, this function is called as part of the device-level
1360962306a36Sopenharmony_ci * interrupt handler. When the PCI slot is in error recovery or the HBA
1361062306a36Sopenharmony_ci * is undergoing initialization, the interrupt handler will not process
1361162306a36Sopenharmony_ci * the interrupt. The link attention and ELS ring attention events are
1361262306a36Sopenharmony_ci * handled by the worker thread. The interrupt handler signals the worker
1361362306a36Sopenharmony_ci * thread and returns for these events. This function is called without
1361462306a36Sopenharmony_ci * any lock held. It gets the hbalock to access and update SLI data
1361562306a36Sopenharmony_ci * structures.
1361662306a36Sopenharmony_ci *
1361762306a36Sopenharmony_ci * This function returns IRQ_HANDLED when interrupt is handled else it
1361862306a36Sopenharmony_ci * returns IRQ_NONE.
1361962306a36Sopenharmony_ci **/
1362062306a36Sopenharmony_ciirqreturn_t
1362162306a36Sopenharmony_cilpfc_sli_sp_intr_handler(int irq, void *dev_id)
1362262306a36Sopenharmony_ci{
1362362306a36Sopenharmony_ci	struct lpfc_hba  *phba;
1362462306a36Sopenharmony_ci	uint32_t ha_copy, hc_copy;
1362562306a36Sopenharmony_ci	uint32_t work_ha_copy;
1362662306a36Sopenharmony_ci	unsigned long status;
1362762306a36Sopenharmony_ci	unsigned long iflag;
1362862306a36Sopenharmony_ci	uint32_t control;
1362962306a36Sopenharmony_ci
1363062306a36Sopenharmony_ci	MAILBOX_t *mbox, *pmbox;
1363162306a36Sopenharmony_ci	struct lpfc_vport *vport;
1363262306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp;
1363362306a36Sopenharmony_ci	struct lpfc_dmabuf *mp;
1363462306a36Sopenharmony_ci	LPFC_MBOXQ_t *pmb;
1363562306a36Sopenharmony_ci	int rc;
1363662306a36Sopenharmony_ci
1363762306a36Sopenharmony_ci	/*
1363862306a36Sopenharmony_ci	 * Get the driver's phba structure from the dev_id and
1363962306a36Sopenharmony_ci	 * assume the HBA is not interrupting.
1364062306a36Sopenharmony_ci	 */
1364162306a36Sopenharmony_ci	phba = (struct lpfc_hba *)dev_id;
1364262306a36Sopenharmony_ci
1364362306a36Sopenharmony_ci	if (unlikely(!phba))
1364462306a36Sopenharmony_ci		return IRQ_NONE;
1364562306a36Sopenharmony_ci
1364662306a36Sopenharmony_ci	/*
1364762306a36Sopenharmony_ci	 * Stuff needs to be attented to when this function is invoked as an
1364862306a36Sopenharmony_ci	 * individual interrupt handler in MSI-X multi-message interrupt mode
1364962306a36Sopenharmony_ci	 */
1365062306a36Sopenharmony_ci	if (phba->intr_type == MSIX) {
1365162306a36Sopenharmony_ci		/* Check device state for handling interrupt */
1365262306a36Sopenharmony_ci		if (lpfc_intr_state_check(phba))
1365362306a36Sopenharmony_ci			return IRQ_NONE;
1365462306a36Sopenharmony_ci		/* Need to read HA REG for slow-path events */
1365562306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflag);
1365662306a36Sopenharmony_ci		if (lpfc_readl(phba->HAregaddr, &ha_copy))
1365762306a36Sopenharmony_ci			goto unplug_error;
1365862306a36Sopenharmony_ci		/* If somebody is waiting to handle an eratt don't process it
1365962306a36Sopenharmony_ci		 * here. The brdkill function will do this.
1366062306a36Sopenharmony_ci		 */
1366162306a36Sopenharmony_ci		if (phba->link_flag & LS_IGNORE_ERATT)
1366262306a36Sopenharmony_ci			ha_copy &= ~HA_ERATT;
1366362306a36Sopenharmony_ci		/* Check the need for handling ERATT in interrupt handler */
1366462306a36Sopenharmony_ci		if (ha_copy & HA_ERATT) {
1366562306a36Sopenharmony_ci			if (phba->hba_flag & HBA_ERATT_HANDLED)
1366662306a36Sopenharmony_ci				/* ERATT polling has handled ERATT */
1366762306a36Sopenharmony_ci				ha_copy &= ~HA_ERATT;
1366862306a36Sopenharmony_ci			else
1366962306a36Sopenharmony_ci				/* Indicate interrupt handler handles ERATT */
1367062306a36Sopenharmony_ci				phba->hba_flag |= HBA_ERATT_HANDLED;
1367162306a36Sopenharmony_ci		}
1367262306a36Sopenharmony_ci
1367362306a36Sopenharmony_ci		/*
1367462306a36Sopenharmony_ci		 * If there is deferred error attention, do not check for any
1367562306a36Sopenharmony_ci		 * interrupt.
1367662306a36Sopenharmony_ci		 */
1367762306a36Sopenharmony_ci		if (unlikely(phba->hba_flag & DEFER_ERATT)) {
1367862306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflag);
1367962306a36Sopenharmony_ci			return IRQ_NONE;
1368062306a36Sopenharmony_ci		}
1368162306a36Sopenharmony_ci
1368262306a36Sopenharmony_ci		/* Clear up only attention source related to slow-path */
1368362306a36Sopenharmony_ci		if (lpfc_readl(phba->HCregaddr, &hc_copy))
1368462306a36Sopenharmony_ci			goto unplug_error;
1368562306a36Sopenharmony_ci
1368662306a36Sopenharmony_ci		writel(hc_copy & ~(HC_MBINT_ENA | HC_R2INT_ENA |
1368762306a36Sopenharmony_ci			HC_LAINT_ENA | HC_ERINT_ENA),
1368862306a36Sopenharmony_ci			phba->HCregaddr);
1368962306a36Sopenharmony_ci		writel((ha_copy & (HA_MBATT | HA_R2_CLR_MSK)),
1369062306a36Sopenharmony_ci			phba->HAregaddr);
1369162306a36Sopenharmony_ci		writel(hc_copy, phba->HCregaddr);
1369262306a36Sopenharmony_ci		readl(phba->HAregaddr); /* flush */
1369362306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
1369462306a36Sopenharmony_ci	} else
1369562306a36Sopenharmony_ci		ha_copy = phba->ha_copy;
1369662306a36Sopenharmony_ci
1369762306a36Sopenharmony_ci	work_ha_copy = ha_copy & phba->work_ha_mask;
1369862306a36Sopenharmony_ci
1369962306a36Sopenharmony_ci	if (work_ha_copy) {
1370062306a36Sopenharmony_ci		if (work_ha_copy & HA_LATT) {
1370162306a36Sopenharmony_ci			if (phba->sli.sli_flag & LPFC_PROCESS_LA) {
1370262306a36Sopenharmony_ci				/*
1370362306a36Sopenharmony_ci				 * Turn off Link Attention interrupts
1370462306a36Sopenharmony_ci				 * until CLEAR_LA done
1370562306a36Sopenharmony_ci				 */
1370662306a36Sopenharmony_ci				spin_lock_irqsave(&phba->hbalock, iflag);
1370762306a36Sopenharmony_ci				phba->sli.sli_flag &= ~LPFC_PROCESS_LA;
1370862306a36Sopenharmony_ci				if (lpfc_readl(phba->HCregaddr, &control))
1370962306a36Sopenharmony_ci					goto unplug_error;
1371062306a36Sopenharmony_ci				control &= ~HC_LAINT_ENA;
1371162306a36Sopenharmony_ci				writel(control, phba->HCregaddr);
1371262306a36Sopenharmony_ci				readl(phba->HCregaddr); /* flush */
1371362306a36Sopenharmony_ci				spin_unlock_irqrestore(&phba->hbalock, iflag);
1371462306a36Sopenharmony_ci			}
1371562306a36Sopenharmony_ci			else
1371662306a36Sopenharmony_ci				work_ha_copy &= ~HA_LATT;
1371762306a36Sopenharmony_ci		}
1371862306a36Sopenharmony_ci
1371962306a36Sopenharmony_ci		if (work_ha_copy & ~(HA_ERATT | HA_MBATT | HA_LATT)) {
1372062306a36Sopenharmony_ci			/*
1372162306a36Sopenharmony_ci			 * Turn off Slow Rings interrupts, LPFC_ELS_RING is
1372262306a36Sopenharmony_ci			 * the only slow ring.
1372362306a36Sopenharmony_ci			 */
1372462306a36Sopenharmony_ci			status = (work_ha_copy &
1372562306a36Sopenharmony_ci				(HA_RXMASK  << (4*LPFC_ELS_RING)));
1372662306a36Sopenharmony_ci			status >>= (4*LPFC_ELS_RING);
1372762306a36Sopenharmony_ci			if (status & HA_RXMASK) {
1372862306a36Sopenharmony_ci				spin_lock_irqsave(&phba->hbalock, iflag);
1372962306a36Sopenharmony_ci				if (lpfc_readl(phba->HCregaddr, &control))
1373062306a36Sopenharmony_ci					goto unplug_error;
1373162306a36Sopenharmony_ci
1373262306a36Sopenharmony_ci				lpfc_debugfs_slow_ring_trc(phba,
1373362306a36Sopenharmony_ci				"ISR slow ring:   ctl:x%x stat:x%x isrcnt:x%x",
1373462306a36Sopenharmony_ci				control, status,
1373562306a36Sopenharmony_ci				(uint32_t)phba->sli.slistat.sli_intr);
1373662306a36Sopenharmony_ci
1373762306a36Sopenharmony_ci				if (control & (HC_R0INT_ENA << LPFC_ELS_RING)) {
1373862306a36Sopenharmony_ci					lpfc_debugfs_slow_ring_trc(phba,
1373962306a36Sopenharmony_ci						"ISR Disable ring:"
1374062306a36Sopenharmony_ci						"pwork:x%x hawork:x%x wait:x%x",
1374162306a36Sopenharmony_ci						phba->work_ha, work_ha_copy,
1374262306a36Sopenharmony_ci						(uint32_t)((unsigned long)
1374362306a36Sopenharmony_ci						&phba->work_waitq));
1374462306a36Sopenharmony_ci
1374562306a36Sopenharmony_ci					control &=
1374662306a36Sopenharmony_ci					    ~(HC_R0INT_ENA << LPFC_ELS_RING);
1374762306a36Sopenharmony_ci					writel(control, phba->HCregaddr);
1374862306a36Sopenharmony_ci					readl(phba->HCregaddr); /* flush */
1374962306a36Sopenharmony_ci				}
1375062306a36Sopenharmony_ci				else {
1375162306a36Sopenharmony_ci					lpfc_debugfs_slow_ring_trc(phba,
1375262306a36Sopenharmony_ci						"ISR slow ring:   pwork:"
1375362306a36Sopenharmony_ci						"x%x hawork:x%x wait:x%x",
1375462306a36Sopenharmony_ci						phba->work_ha, work_ha_copy,
1375562306a36Sopenharmony_ci						(uint32_t)((unsigned long)
1375662306a36Sopenharmony_ci						&phba->work_waitq));
1375762306a36Sopenharmony_ci				}
1375862306a36Sopenharmony_ci				spin_unlock_irqrestore(&phba->hbalock, iflag);
1375962306a36Sopenharmony_ci			}
1376062306a36Sopenharmony_ci		}
1376162306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflag);
1376262306a36Sopenharmony_ci		if (work_ha_copy & HA_ERATT) {
1376362306a36Sopenharmony_ci			if (lpfc_sli_read_hs(phba))
1376462306a36Sopenharmony_ci				goto unplug_error;
1376562306a36Sopenharmony_ci			/*
1376662306a36Sopenharmony_ci			 * Check if there is a deferred error condition
1376762306a36Sopenharmony_ci			 * is active
1376862306a36Sopenharmony_ci			 */
1376962306a36Sopenharmony_ci			if ((HS_FFER1 & phba->work_hs) &&
1377062306a36Sopenharmony_ci				((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 |
1377162306a36Sopenharmony_ci				  HS_FFER6 | HS_FFER7 | HS_FFER8) &
1377262306a36Sopenharmony_ci				  phba->work_hs)) {
1377362306a36Sopenharmony_ci				phba->hba_flag |= DEFER_ERATT;
1377462306a36Sopenharmony_ci				/* Clear all interrupt enable conditions */
1377562306a36Sopenharmony_ci				writel(0, phba->HCregaddr);
1377662306a36Sopenharmony_ci				readl(phba->HCregaddr);
1377762306a36Sopenharmony_ci			}
1377862306a36Sopenharmony_ci		}
1377962306a36Sopenharmony_ci
1378062306a36Sopenharmony_ci		if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) {
1378162306a36Sopenharmony_ci			pmb = phba->sli.mbox_active;
1378262306a36Sopenharmony_ci			pmbox = &pmb->u.mb;
1378362306a36Sopenharmony_ci			mbox = phba->mbox;
1378462306a36Sopenharmony_ci			vport = pmb->vport;
1378562306a36Sopenharmony_ci
1378662306a36Sopenharmony_ci			/* First check out the status word */
1378762306a36Sopenharmony_ci			lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof(uint32_t));
1378862306a36Sopenharmony_ci			if (pmbox->mbxOwner != OWN_HOST) {
1378962306a36Sopenharmony_ci				spin_unlock_irqrestore(&phba->hbalock, iflag);
1379062306a36Sopenharmony_ci				/*
1379162306a36Sopenharmony_ci				 * Stray Mailbox Interrupt, mbxCommand <cmd>
1379262306a36Sopenharmony_ci				 * mbxStatus <status>
1379362306a36Sopenharmony_ci				 */
1379462306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1379562306a36Sopenharmony_ci						"(%d):0304 Stray Mailbox "
1379662306a36Sopenharmony_ci						"Interrupt mbxCommand x%x "
1379762306a36Sopenharmony_ci						"mbxStatus x%x\n",
1379862306a36Sopenharmony_ci						(vport ? vport->vpi : 0),
1379962306a36Sopenharmony_ci						pmbox->mbxCommand,
1380062306a36Sopenharmony_ci						pmbox->mbxStatus);
1380162306a36Sopenharmony_ci				/* clear mailbox attention bit */
1380262306a36Sopenharmony_ci				work_ha_copy &= ~HA_MBATT;
1380362306a36Sopenharmony_ci			} else {
1380462306a36Sopenharmony_ci				phba->sli.mbox_active = NULL;
1380562306a36Sopenharmony_ci				spin_unlock_irqrestore(&phba->hbalock, iflag);
1380662306a36Sopenharmony_ci				phba->last_completion_time = jiffies;
1380762306a36Sopenharmony_ci				del_timer(&phba->sli.mbox_tmo);
1380862306a36Sopenharmony_ci				if (pmb->mbox_cmpl) {
1380962306a36Sopenharmony_ci					lpfc_sli_pcimem_bcopy(mbox, pmbox,
1381062306a36Sopenharmony_ci							MAILBOX_CMD_SIZE);
1381162306a36Sopenharmony_ci					if (pmb->out_ext_byte_len &&
1381262306a36Sopenharmony_ci						pmb->ctx_buf)
1381362306a36Sopenharmony_ci						lpfc_sli_pcimem_bcopy(
1381462306a36Sopenharmony_ci						phba->mbox_ext,
1381562306a36Sopenharmony_ci						pmb->ctx_buf,
1381662306a36Sopenharmony_ci						pmb->out_ext_byte_len);
1381762306a36Sopenharmony_ci				}
1381862306a36Sopenharmony_ci				if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
1381962306a36Sopenharmony_ci					pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
1382062306a36Sopenharmony_ci
1382162306a36Sopenharmony_ci					lpfc_debugfs_disc_trc(vport,
1382262306a36Sopenharmony_ci						LPFC_DISC_TRC_MBOX_VPORT,
1382362306a36Sopenharmony_ci						"MBOX dflt rpi: : "
1382462306a36Sopenharmony_ci						"status:x%x rpi:x%x",
1382562306a36Sopenharmony_ci						(uint32_t)pmbox->mbxStatus,
1382662306a36Sopenharmony_ci						pmbox->un.varWords[0], 0);
1382762306a36Sopenharmony_ci
1382862306a36Sopenharmony_ci					if (!pmbox->mbxStatus) {
1382962306a36Sopenharmony_ci						mp = (struct lpfc_dmabuf *)
1383062306a36Sopenharmony_ci							(pmb->ctx_buf);
1383162306a36Sopenharmony_ci						ndlp = (struct lpfc_nodelist *)
1383262306a36Sopenharmony_ci							pmb->ctx_ndlp;
1383362306a36Sopenharmony_ci
1383462306a36Sopenharmony_ci						/* Reg_LOGIN of dflt RPI was
1383562306a36Sopenharmony_ci						 * successful. new lets get
1383662306a36Sopenharmony_ci						 * rid of the RPI using the
1383762306a36Sopenharmony_ci						 * same mbox buffer.
1383862306a36Sopenharmony_ci						 */
1383962306a36Sopenharmony_ci						lpfc_unreg_login(phba,
1384062306a36Sopenharmony_ci							vport->vpi,
1384162306a36Sopenharmony_ci							pmbox->un.varWords[0],
1384262306a36Sopenharmony_ci							pmb);
1384362306a36Sopenharmony_ci						pmb->mbox_cmpl =
1384462306a36Sopenharmony_ci							lpfc_mbx_cmpl_dflt_rpi;
1384562306a36Sopenharmony_ci						pmb->ctx_buf = mp;
1384662306a36Sopenharmony_ci						pmb->ctx_ndlp = ndlp;
1384762306a36Sopenharmony_ci						pmb->vport = vport;
1384862306a36Sopenharmony_ci						rc = lpfc_sli_issue_mbox(phba,
1384962306a36Sopenharmony_ci								pmb,
1385062306a36Sopenharmony_ci								MBX_NOWAIT);
1385162306a36Sopenharmony_ci						if (rc != MBX_BUSY)
1385262306a36Sopenharmony_ci							lpfc_printf_log(phba,
1385362306a36Sopenharmony_ci							KERN_ERR,
1385462306a36Sopenharmony_ci							LOG_TRACE_EVENT,
1385562306a36Sopenharmony_ci							"0350 rc should have"
1385662306a36Sopenharmony_ci							"been MBX_BUSY\n");
1385762306a36Sopenharmony_ci						if (rc != MBX_NOT_FINISHED)
1385862306a36Sopenharmony_ci							goto send_current_mbox;
1385962306a36Sopenharmony_ci					}
1386062306a36Sopenharmony_ci				}
1386162306a36Sopenharmony_ci				spin_lock_irqsave(
1386262306a36Sopenharmony_ci						&phba->pport->work_port_lock,
1386362306a36Sopenharmony_ci						iflag);
1386462306a36Sopenharmony_ci				phba->pport->work_port_events &=
1386562306a36Sopenharmony_ci					~WORKER_MBOX_TMO;
1386662306a36Sopenharmony_ci				spin_unlock_irqrestore(
1386762306a36Sopenharmony_ci						&phba->pport->work_port_lock,
1386862306a36Sopenharmony_ci						iflag);
1386962306a36Sopenharmony_ci
1387062306a36Sopenharmony_ci				/* Do NOT queue MBX_HEARTBEAT to the worker
1387162306a36Sopenharmony_ci				 * thread for processing.
1387262306a36Sopenharmony_ci				 */
1387362306a36Sopenharmony_ci				if (pmbox->mbxCommand == MBX_HEARTBEAT) {
1387462306a36Sopenharmony_ci					/* Process mbox now */
1387562306a36Sopenharmony_ci					phba->sli.mbox_active = NULL;
1387662306a36Sopenharmony_ci					phba->sli.sli_flag &=
1387762306a36Sopenharmony_ci						~LPFC_SLI_MBOX_ACTIVE;
1387862306a36Sopenharmony_ci					if (pmb->mbox_cmpl)
1387962306a36Sopenharmony_ci						pmb->mbox_cmpl(phba, pmb);
1388062306a36Sopenharmony_ci				} else {
1388162306a36Sopenharmony_ci					/* Queue to worker thread to process */
1388262306a36Sopenharmony_ci					lpfc_mbox_cmpl_put(phba, pmb);
1388362306a36Sopenharmony_ci				}
1388462306a36Sopenharmony_ci			}
1388562306a36Sopenharmony_ci		} else
1388662306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflag);
1388762306a36Sopenharmony_ci
1388862306a36Sopenharmony_ci		if ((work_ha_copy & HA_MBATT) &&
1388962306a36Sopenharmony_ci		    (phba->sli.mbox_active == NULL)) {
1389062306a36Sopenharmony_cisend_current_mbox:
1389162306a36Sopenharmony_ci			/* Process next mailbox command if there is one */
1389262306a36Sopenharmony_ci			do {
1389362306a36Sopenharmony_ci				rc = lpfc_sli_issue_mbox(phba, NULL,
1389462306a36Sopenharmony_ci							 MBX_NOWAIT);
1389562306a36Sopenharmony_ci			} while (rc == MBX_NOT_FINISHED);
1389662306a36Sopenharmony_ci			if (rc != MBX_SUCCESS)
1389762306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR,
1389862306a36Sopenharmony_ci						LOG_TRACE_EVENT,
1389962306a36Sopenharmony_ci						"0349 rc should be "
1390062306a36Sopenharmony_ci						"MBX_SUCCESS\n");
1390162306a36Sopenharmony_ci		}
1390262306a36Sopenharmony_ci
1390362306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflag);
1390462306a36Sopenharmony_ci		phba->work_ha |= work_ha_copy;
1390562306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
1390662306a36Sopenharmony_ci		lpfc_worker_wake_up(phba);
1390762306a36Sopenharmony_ci	}
1390862306a36Sopenharmony_ci	return IRQ_HANDLED;
1390962306a36Sopenharmony_ciunplug_error:
1391062306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflag);
1391162306a36Sopenharmony_ci	return IRQ_HANDLED;
1391262306a36Sopenharmony_ci
1391362306a36Sopenharmony_ci} /* lpfc_sli_sp_intr_handler */
1391462306a36Sopenharmony_ci
1391562306a36Sopenharmony_ci/**
1391662306a36Sopenharmony_ci * lpfc_sli_fp_intr_handler - Fast-path interrupt handler to SLI-3 device.
1391762306a36Sopenharmony_ci * @irq: Interrupt number.
1391862306a36Sopenharmony_ci * @dev_id: The device context pointer.
1391962306a36Sopenharmony_ci *
1392062306a36Sopenharmony_ci * This function is directly called from the PCI layer as an interrupt
1392162306a36Sopenharmony_ci * service routine when device with SLI-3 interface spec is enabled with
1392262306a36Sopenharmony_ci * MSI-X multi-message interrupt mode and there is a fast-path FCP IOCB
1392362306a36Sopenharmony_ci * ring event in the HBA. However, when the device is enabled with either
1392462306a36Sopenharmony_ci * MSI or Pin-IRQ interrupt mode, this function is called as part of the
1392562306a36Sopenharmony_ci * device-level interrupt handler. When the PCI slot is in error recovery
1392662306a36Sopenharmony_ci * or the HBA is undergoing initialization, the interrupt handler will not
1392762306a36Sopenharmony_ci * process the interrupt. The SCSI FCP fast-path ring event are handled in
1392862306a36Sopenharmony_ci * the intrrupt context. This function is called without any lock held.
1392962306a36Sopenharmony_ci * It gets the hbalock to access and update SLI data structures.
1393062306a36Sopenharmony_ci *
1393162306a36Sopenharmony_ci * This function returns IRQ_HANDLED when interrupt is handled else it
1393262306a36Sopenharmony_ci * returns IRQ_NONE.
1393362306a36Sopenharmony_ci **/
1393462306a36Sopenharmony_ciirqreturn_t
1393562306a36Sopenharmony_cilpfc_sli_fp_intr_handler(int irq, void *dev_id)
1393662306a36Sopenharmony_ci{
1393762306a36Sopenharmony_ci	struct lpfc_hba  *phba;
1393862306a36Sopenharmony_ci	uint32_t ha_copy;
1393962306a36Sopenharmony_ci	unsigned long status;
1394062306a36Sopenharmony_ci	unsigned long iflag;
1394162306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1394262306a36Sopenharmony_ci
1394362306a36Sopenharmony_ci	/* Get the driver's phba structure from the dev_id and
1394462306a36Sopenharmony_ci	 * assume the HBA is not interrupting.
1394562306a36Sopenharmony_ci	 */
1394662306a36Sopenharmony_ci	phba = (struct lpfc_hba *) dev_id;
1394762306a36Sopenharmony_ci
1394862306a36Sopenharmony_ci	if (unlikely(!phba))
1394962306a36Sopenharmony_ci		return IRQ_NONE;
1395062306a36Sopenharmony_ci
1395162306a36Sopenharmony_ci	/*
1395262306a36Sopenharmony_ci	 * Stuff needs to be attented to when this function is invoked as an
1395362306a36Sopenharmony_ci	 * individual interrupt handler in MSI-X multi-message interrupt mode
1395462306a36Sopenharmony_ci	 */
1395562306a36Sopenharmony_ci	if (phba->intr_type == MSIX) {
1395662306a36Sopenharmony_ci		/* Check device state for handling interrupt */
1395762306a36Sopenharmony_ci		if (lpfc_intr_state_check(phba))
1395862306a36Sopenharmony_ci			return IRQ_NONE;
1395962306a36Sopenharmony_ci		/* Need to read HA REG for FCP ring and other ring events */
1396062306a36Sopenharmony_ci		if (lpfc_readl(phba->HAregaddr, &ha_copy))
1396162306a36Sopenharmony_ci			return IRQ_HANDLED;
1396262306a36Sopenharmony_ci		/* Clear up only attention source related to fast-path */
1396362306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflag);
1396462306a36Sopenharmony_ci		/*
1396562306a36Sopenharmony_ci		 * If there is deferred error attention, do not check for
1396662306a36Sopenharmony_ci		 * any interrupt.
1396762306a36Sopenharmony_ci		 */
1396862306a36Sopenharmony_ci		if (unlikely(phba->hba_flag & DEFER_ERATT)) {
1396962306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflag);
1397062306a36Sopenharmony_ci			return IRQ_NONE;
1397162306a36Sopenharmony_ci		}
1397262306a36Sopenharmony_ci		writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)),
1397362306a36Sopenharmony_ci			phba->HAregaddr);
1397462306a36Sopenharmony_ci		readl(phba->HAregaddr); /* flush */
1397562306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
1397662306a36Sopenharmony_ci	} else
1397762306a36Sopenharmony_ci		ha_copy = phba->ha_copy;
1397862306a36Sopenharmony_ci
1397962306a36Sopenharmony_ci	/*
1398062306a36Sopenharmony_ci	 * Process all events on FCP ring. Take the optimized path for FCP IO.
1398162306a36Sopenharmony_ci	 */
1398262306a36Sopenharmony_ci	ha_copy &= ~(phba->work_ha_mask);
1398362306a36Sopenharmony_ci
1398462306a36Sopenharmony_ci	status = (ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING)));
1398562306a36Sopenharmony_ci	status >>= (4*LPFC_FCP_RING);
1398662306a36Sopenharmony_ci	pring = &phba->sli.sli3_ring[LPFC_FCP_RING];
1398762306a36Sopenharmony_ci	if (status & HA_RXMASK)
1398862306a36Sopenharmony_ci		lpfc_sli_handle_fast_ring_event(phba, pring, status);
1398962306a36Sopenharmony_ci
1399062306a36Sopenharmony_ci	if (phba->cfg_multi_ring_support == 2) {
1399162306a36Sopenharmony_ci		/*
1399262306a36Sopenharmony_ci		 * Process all events on extra ring. Take the optimized path
1399362306a36Sopenharmony_ci		 * for extra ring IO.
1399462306a36Sopenharmony_ci		 */
1399562306a36Sopenharmony_ci		status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING)));
1399662306a36Sopenharmony_ci		status >>= (4*LPFC_EXTRA_RING);
1399762306a36Sopenharmony_ci		if (status & HA_RXMASK) {
1399862306a36Sopenharmony_ci			lpfc_sli_handle_fast_ring_event(phba,
1399962306a36Sopenharmony_ci					&phba->sli.sli3_ring[LPFC_EXTRA_RING],
1400062306a36Sopenharmony_ci					status);
1400162306a36Sopenharmony_ci		}
1400262306a36Sopenharmony_ci	}
1400362306a36Sopenharmony_ci	return IRQ_HANDLED;
1400462306a36Sopenharmony_ci}  /* lpfc_sli_fp_intr_handler */
1400562306a36Sopenharmony_ci
1400662306a36Sopenharmony_ci/**
1400762306a36Sopenharmony_ci * lpfc_sli_intr_handler - Device-level interrupt handler to SLI-3 device
1400862306a36Sopenharmony_ci * @irq: Interrupt number.
1400962306a36Sopenharmony_ci * @dev_id: The device context pointer.
1401062306a36Sopenharmony_ci *
1401162306a36Sopenharmony_ci * This function is the HBA device-level interrupt handler to device with
1401262306a36Sopenharmony_ci * SLI-3 interface spec, called from the PCI layer when either MSI or
1401362306a36Sopenharmony_ci * Pin-IRQ interrupt mode is enabled and there is an event in the HBA which
1401462306a36Sopenharmony_ci * requires driver attention. This function invokes the slow-path interrupt
1401562306a36Sopenharmony_ci * attention handling function and fast-path interrupt attention handling
1401662306a36Sopenharmony_ci * function in turn to process the relevant HBA attention events. This
1401762306a36Sopenharmony_ci * function is called without any lock held. It gets the hbalock to access
1401862306a36Sopenharmony_ci * and update SLI data structures.
1401962306a36Sopenharmony_ci *
1402062306a36Sopenharmony_ci * This function returns IRQ_HANDLED when interrupt is handled, else it
1402162306a36Sopenharmony_ci * returns IRQ_NONE.
1402262306a36Sopenharmony_ci **/
1402362306a36Sopenharmony_ciirqreturn_t
1402462306a36Sopenharmony_cilpfc_sli_intr_handler(int irq, void *dev_id)
1402562306a36Sopenharmony_ci{
1402662306a36Sopenharmony_ci	struct lpfc_hba  *phba;
1402762306a36Sopenharmony_ci	irqreturn_t sp_irq_rc, fp_irq_rc;
1402862306a36Sopenharmony_ci	unsigned long status1, status2;
1402962306a36Sopenharmony_ci	uint32_t hc_copy;
1403062306a36Sopenharmony_ci
1403162306a36Sopenharmony_ci	/*
1403262306a36Sopenharmony_ci	 * Get the driver's phba structure from the dev_id and
1403362306a36Sopenharmony_ci	 * assume the HBA is not interrupting.
1403462306a36Sopenharmony_ci	 */
1403562306a36Sopenharmony_ci	phba = (struct lpfc_hba *) dev_id;
1403662306a36Sopenharmony_ci
1403762306a36Sopenharmony_ci	if (unlikely(!phba))
1403862306a36Sopenharmony_ci		return IRQ_NONE;
1403962306a36Sopenharmony_ci
1404062306a36Sopenharmony_ci	/* Check device state for handling interrupt */
1404162306a36Sopenharmony_ci	if (lpfc_intr_state_check(phba))
1404262306a36Sopenharmony_ci		return IRQ_NONE;
1404362306a36Sopenharmony_ci
1404462306a36Sopenharmony_ci	spin_lock(&phba->hbalock);
1404562306a36Sopenharmony_ci	if (lpfc_readl(phba->HAregaddr, &phba->ha_copy)) {
1404662306a36Sopenharmony_ci		spin_unlock(&phba->hbalock);
1404762306a36Sopenharmony_ci		return IRQ_HANDLED;
1404862306a36Sopenharmony_ci	}
1404962306a36Sopenharmony_ci
1405062306a36Sopenharmony_ci	if (unlikely(!phba->ha_copy)) {
1405162306a36Sopenharmony_ci		spin_unlock(&phba->hbalock);
1405262306a36Sopenharmony_ci		return IRQ_NONE;
1405362306a36Sopenharmony_ci	} else if (phba->ha_copy & HA_ERATT) {
1405462306a36Sopenharmony_ci		if (phba->hba_flag & HBA_ERATT_HANDLED)
1405562306a36Sopenharmony_ci			/* ERATT polling has handled ERATT */
1405662306a36Sopenharmony_ci			phba->ha_copy &= ~HA_ERATT;
1405762306a36Sopenharmony_ci		else
1405862306a36Sopenharmony_ci			/* Indicate interrupt handler handles ERATT */
1405962306a36Sopenharmony_ci			phba->hba_flag |= HBA_ERATT_HANDLED;
1406062306a36Sopenharmony_ci	}
1406162306a36Sopenharmony_ci
1406262306a36Sopenharmony_ci	/*
1406362306a36Sopenharmony_ci	 * If there is deferred error attention, do not check for any interrupt.
1406462306a36Sopenharmony_ci	 */
1406562306a36Sopenharmony_ci	if (unlikely(phba->hba_flag & DEFER_ERATT)) {
1406662306a36Sopenharmony_ci		spin_unlock(&phba->hbalock);
1406762306a36Sopenharmony_ci		return IRQ_NONE;
1406862306a36Sopenharmony_ci	}
1406962306a36Sopenharmony_ci
1407062306a36Sopenharmony_ci	/* Clear attention sources except link and error attentions */
1407162306a36Sopenharmony_ci	if (lpfc_readl(phba->HCregaddr, &hc_copy)) {
1407262306a36Sopenharmony_ci		spin_unlock(&phba->hbalock);
1407362306a36Sopenharmony_ci		return IRQ_HANDLED;
1407462306a36Sopenharmony_ci	}
1407562306a36Sopenharmony_ci	writel(hc_copy & ~(HC_MBINT_ENA | HC_R0INT_ENA | HC_R1INT_ENA
1407662306a36Sopenharmony_ci		| HC_R2INT_ENA | HC_LAINT_ENA | HC_ERINT_ENA),
1407762306a36Sopenharmony_ci		phba->HCregaddr);
1407862306a36Sopenharmony_ci	writel((phba->ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
1407962306a36Sopenharmony_ci	writel(hc_copy, phba->HCregaddr);
1408062306a36Sopenharmony_ci	readl(phba->HAregaddr); /* flush */
1408162306a36Sopenharmony_ci	spin_unlock(&phba->hbalock);
1408262306a36Sopenharmony_ci
1408362306a36Sopenharmony_ci	/*
1408462306a36Sopenharmony_ci	 * Invokes slow-path host attention interrupt handling as appropriate.
1408562306a36Sopenharmony_ci	 */
1408662306a36Sopenharmony_ci
1408762306a36Sopenharmony_ci	/* status of events with mailbox and link attention */
1408862306a36Sopenharmony_ci	status1 = phba->ha_copy & (HA_MBATT | HA_LATT | HA_ERATT);
1408962306a36Sopenharmony_ci
1409062306a36Sopenharmony_ci	/* status of events with ELS ring */
1409162306a36Sopenharmony_ci	status2 = (phba->ha_copy & (HA_RXMASK  << (4*LPFC_ELS_RING)));
1409262306a36Sopenharmony_ci	status2 >>= (4*LPFC_ELS_RING);
1409362306a36Sopenharmony_ci
1409462306a36Sopenharmony_ci	if (status1 || (status2 & HA_RXMASK))
1409562306a36Sopenharmony_ci		sp_irq_rc = lpfc_sli_sp_intr_handler(irq, dev_id);
1409662306a36Sopenharmony_ci	else
1409762306a36Sopenharmony_ci		sp_irq_rc = IRQ_NONE;
1409862306a36Sopenharmony_ci
1409962306a36Sopenharmony_ci	/*
1410062306a36Sopenharmony_ci	 * Invoke fast-path host attention interrupt handling as appropriate.
1410162306a36Sopenharmony_ci	 */
1410262306a36Sopenharmony_ci
1410362306a36Sopenharmony_ci	/* status of events with FCP ring */
1410462306a36Sopenharmony_ci	status1 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING)));
1410562306a36Sopenharmony_ci	status1 >>= (4*LPFC_FCP_RING);
1410662306a36Sopenharmony_ci
1410762306a36Sopenharmony_ci	/* status of events with extra ring */
1410862306a36Sopenharmony_ci	if (phba->cfg_multi_ring_support == 2) {
1410962306a36Sopenharmony_ci		status2 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING)));
1411062306a36Sopenharmony_ci		status2 >>= (4*LPFC_EXTRA_RING);
1411162306a36Sopenharmony_ci	} else
1411262306a36Sopenharmony_ci		status2 = 0;
1411362306a36Sopenharmony_ci
1411462306a36Sopenharmony_ci	if ((status1 & HA_RXMASK) || (status2 & HA_RXMASK))
1411562306a36Sopenharmony_ci		fp_irq_rc = lpfc_sli_fp_intr_handler(irq, dev_id);
1411662306a36Sopenharmony_ci	else
1411762306a36Sopenharmony_ci		fp_irq_rc = IRQ_NONE;
1411862306a36Sopenharmony_ci
1411962306a36Sopenharmony_ci	/* Return device-level interrupt handling status */
1412062306a36Sopenharmony_ci	return (sp_irq_rc == IRQ_HANDLED) ? sp_irq_rc : fp_irq_rc;
1412162306a36Sopenharmony_ci}  /* lpfc_sli_intr_handler */
1412262306a36Sopenharmony_ci
1412362306a36Sopenharmony_ci/**
1412462306a36Sopenharmony_ci * lpfc_sli4_els_xri_abort_event_proc - Process els xri abort event
1412562306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1412662306a36Sopenharmony_ci *
1412762306a36Sopenharmony_ci * This routine is invoked by the worker thread to process all the pending
1412862306a36Sopenharmony_ci * SLI4 els abort xri events.
1412962306a36Sopenharmony_ci **/
1413062306a36Sopenharmony_civoid lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba)
1413162306a36Sopenharmony_ci{
1413262306a36Sopenharmony_ci	struct lpfc_cq_event *cq_event;
1413362306a36Sopenharmony_ci	unsigned long iflags;
1413462306a36Sopenharmony_ci
1413562306a36Sopenharmony_ci	/* First, declare the els xri abort event has been handled */
1413662306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1413762306a36Sopenharmony_ci	phba->hba_flag &= ~ELS_XRI_ABORT_EVENT;
1413862306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1413962306a36Sopenharmony_ci
1414062306a36Sopenharmony_ci	/* Now, handle all the els xri abort events */
1414162306a36Sopenharmony_ci	spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, iflags);
1414262306a36Sopenharmony_ci	while (!list_empty(&phba->sli4_hba.sp_els_xri_aborted_work_queue)) {
1414362306a36Sopenharmony_ci		/* Get the first event from the head of the event queue */
1414462306a36Sopenharmony_ci		list_remove_head(&phba->sli4_hba.sp_els_xri_aborted_work_queue,
1414562306a36Sopenharmony_ci				 cq_event, struct lpfc_cq_event, list);
1414662306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock,
1414762306a36Sopenharmony_ci				       iflags);
1414862306a36Sopenharmony_ci		/* Notify aborted XRI for ELS work queue */
1414962306a36Sopenharmony_ci		lpfc_sli4_els_xri_aborted(phba, &cq_event->cqe.wcqe_axri);
1415062306a36Sopenharmony_ci
1415162306a36Sopenharmony_ci		/* Free the event processed back to the free pool */
1415262306a36Sopenharmony_ci		lpfc_sli4_cq_event_release(phba, cq_event);
1415362306a36Sopenharmony_ci		spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock,
1415462306a36Sopenharmony_ci				  iflags);
1415562306a36Sopenharmony_ci	}
1415662306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, iflags);
1415762306a36Sopenharmony_ci}
1415862306a36Sopenharmony_ci
1415962306a36Sopenharmony_ci/**
1416062306a36Sopenharmony_ci * lpfc_sli4_els_preprocess_rspiocbq - Get response iocbq from els wcqe
1416162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1416262306a36Sopenharmony_ci * @irspiocbq: Pointer to work-queue completion queue entry.
1416362306a36Sopenharmony_ci *
1416462306a36Sopenharmony_ci * This routine handles an ELS work-queue completion event and construct
1416562306a36Sopenharmony_ci * a pseudo response ELS IOCBQ from the SLI4 ELS WCQE for the common
1416662306a36Sopenharmony_ci * discovery engine to handle.
1416762306a36Sopenharmony_ci *
1416862306a36Sopenharmony_ci * Return: Pointer to the receive IOCBQ, NULL otherwise.
1416962306a36Sopenharmony_ci **/
1417062306a36Sopenharmony_cistatic struct lpfc_iocbq *
1417162306a36Sopenharmony_cilpfc_sli4_els_preprocess_rspiocbq(struct lpfc_hba *phba,
1417262306a36Sopenharmony_ci				  struct lpfc_iocbq *irspiocbq)
1417362306a36Sopenharmony_ci{
1417462306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
1417562306a36Sopenharmony_ci	struct lpfc_iocbq *cmdiocbq;
1417662306a36Sopenharmony_ci	struct lpfc_wcqe_complete *wcqe;
1417762306a36Sopenharmony_ci	unsigned long iflags;
1417862306a36Sopenharmony_ci
1417962306a36Sopenharmony_ci	pring = lpfc_phba_elsring(phba);
1418062306a36Sopenharmony_ci	if (unlikely(!pring))
1418162306a36Sopenharmony_ci		return NULL;
1418262306a36Sopenharmony_ci
1418362306a36Sopenharmony_ci	wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl;
1418462306a36Sopenharmony_ci	spin_lock_irqsave(&pring->ring_lock, iflags);
1418562306a36Sopenharmony_ci	pring->stats.iocb_event++;
1418662306a36Sopenharmony_ci	/* Look up the ELS command IOCB and create pseudo response IOCB */
1418762306a36Sopenharmony_ci	cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
1418862306a36Sopenharmony_ci				bf_get(lpfc_wcqe_c_request_tag, wcqe));
1418962306a36Sopenharmony_ci	if (unlikely(!cmdiocbq)) {
1419062306a36Sopenharmony_ci		spin_unlock_irqrestore(&pring->ring_lock, iflags);
1419162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
1419262306a36Sopenharmony_ci				"0386 ELS complete with no corresponding "
1419362306a36Sopenharmony_ci				"cmdiocb: 0x%x 0x%x 0x%x 0x%x\n",
1419462306a36Sopenharmony_ci				wcqe->word0, wcqe->total_data_placed,
1419562306a36Sopenharmony_ci				wcqe->parameter, wcqe->word3);
1419662306a36Sopenharmony_ci		lpfc_sli_release_iocbq(phba, irspiocbq);
1419762306a36Sopenharmony_ci		return NULL;
1419862306a36Sopenharmony_ci	}
1419962306a36Sopenharmony_ci
1420062306a36Sopenharmony_ci	memcpy(&irspiocbq->wqe, &cmdiocbq->wqe, sizeof(union lpfc_wqe128));
1420162306a36Sopenharmony_ci	memcpy(&irspiocbq->wcqe_cmpl, wcqe, sizeof(*wcqe));
1420262306a36Sopenharmony_ci
1420362306a36Sopenharmony_ci	/* Put the iocb back on the txcmplq */
1420462306a36Sopenharmony_ci	lpfc_sli_ringtxcmpl_put(phba, pring, cmdiocbq);
1420562306a36Sopenharmony_ci	spin_unlock_irqrestore(&pring->ring_lock, iflags);
1420662306a36Sopenharmony_ci
1420762306a36Sopenharmony_ci	if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
1420862306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1420962306a36Sopenharmony_ci		irspiocbq->cmd_flag |= LPFC_EXCHANGE_BUSY;
1421062306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1421162306a36Sopenharmony_ci	}
1421262306a36Sopenharmony_ci
1421362306a36Sopenharmony_ci	return irspiocbq;
1421462306a36Sopenharmony_ci}
1421562306a36Sopenharmony_ci
1421662306a36Sopenharmony_ciinline struct lpfc_cq_event *
1421762306a36Sopenharmony_cilpfc_cq_event_setup(struct lpfc_hba *phba, void *entry, int size)
1421862306a36Sopenharmony_ci{
1421962306a36Sopenharmony_ci	struct lpfc_cq_event *cq_event;
1422062306a36Sopenharmony_ci
1422162306a36Sopenharmony_ci	/* Allocate a new internal CQ_EVENT entry */
1422262306a36Sopenharmony_ci	cq_event = lpfc_sli4_cq_event_alloc(phba);
1422362306a36Sopenharmony_ci	if (!cq_event) {
1422462306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1422562306a36Sopenharmony_ci				"0602 Failed to alloc CQ_EVENT entry\n");
1422662306a36Sopenharmony_ci		return NULL;
1422762306a36Sopenharmony_ci	}
1422862306a36Sopenharmony_ci
1422962306a36Sopenharmony_ci	/* Move the CQE into the event */
1423062306a36Sopenharmony_ci	memcpy(&cq_event->cqe, entry, size);
1423162306a36Sopenharmony_ci	return cq_event;
1423262306a36Sopenharmony_ci}
1423362306a36Sopenharmony_ci
1423462306a36Sopenharmony_ci/**
1423562306a36Sopenharmony_ci * lpfc_sli4_sp_handle_async_event - Handle an asynchronous event
1423662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1423762306a36Sopenharmony_ci * @mcqe: Pointer to mailbox completion queue entry.
1423862306a36Sopenharmony_ci *
1423962306a36Sopenharmony_ci * This routine process a mailbox completion queue entry with asynchronous
1424062306a36Sopenharmony_ci * event.
1424162306a36Sopenharmony_ci *
1424262306a36Sopenharmony_ci * Return: true if work posted to worker thread, otherwise false.
1424362306a36Sopenharmony_ci **/
1424462306a36Sopenharmony_cistatic bool
1424562306a36Sopenharmony_cilpfc_sli4_sp_handle_async_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe)
1424662306a36Sopenharmony_ci{
1424762306a36Sopenharmony_ci	struct lpfc_cq_event *cq_event;
1424862306a36Sopenharmony_ci	unsigned long iflags;
1424962306a36Sopenharmony_ci
1425062306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
1425162306a36Sopenharmony_ci			"0392 Async Event: word0:x%x, word1:x%x, "
1425262306a36Sopenharmony_ci			"word2:x%x, word3:x%x\n", mcqe->word0,
1425362306a36Sopenharmony_ci			mcqe->mcqe_tag0, mcqe->mcqe_tag1, mcqe->trailer);
1425462306a36Sopenharmony_ci
1425562306a36Sopenharmony_ci	cq_event = lpfc_cq_event_setup(phba, mcqe, sizeof(struct lpfc_mcqe));
1425662306a36Sopenharmony_ci	if (!cq_event)
1425762306a36Sopenharmony_ci		return false;
1425862306a36Sopenharmony_ci
1425962306a36Sopenharmony_ci	spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags);
1426062306a36Sopenharmony_ci	list_add_tail(&cq_event->list, &phba->sli4_hba.sp_asynce_work_queue);
1426162306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, iflags);
1426262306a36Sopenharmony_ci
1426362306a36Sopenharmony_ci	/* Set the async event flag */
1426462306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1426562306a36Sopenharmony_ci	phba->hba_flag |= ASYNC_EVENT;
1426662306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1426762306a36Sopenharmony_ci
1426862306a36Sopenharmony_ci	return true;
1426962306a36Sopenharmony_ci}
1427062306a36Sopenharmony_ci
1427162306a36Sopenharmony_ci/**
1427262306a36Sopenharmony_ci * lpfc_sli4_sp_handle_mbox_event - Handle a mailbox completion event
1427362306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1427462306a36Sopenharmony_ci * @mcqe: Pointer to mailbox completion queue entry.
1427562306a36Sopenharmony_ci *
1427662306a36Sopenharmony_ci * This routine process a mailbox completion queue entry with mailbox
1427762306a36Sopenharmony_ci * completion event.
1427862306a36Sopenharmony_ci *
1427962306a36Sopenharmony_ci * Return: true if work posted to worker thread, otherwise false.
1428062306a36Sopenharmony_ci **/
1428162306a36Sopenharmony_cistatic bool
1428262306a36Sopenharmony_cilpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe)
1428362306a36Sopenharmony_ci{
1428462306a36Sopenharmony_ci	uint32_t mcqe_status;
1428562306a36Sopenharmony_ci	MAILBOX_t *mbox, *pmbox;
1428662306a36Sopenharmony_ci	struct lpfc_mqe *mqe;
1428762306a36Sopenharmony_ci	struct lpfc_vport *vport;
1428862306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp;
1428962306a36Sopenharmony_ci	struct lpfc_dmabuf *mp;
1429062306a36Sopenharmony_ci	unsigned long iflags;
1429162306a36Sopenharmony_ci	LPFC_MBOXQ_t *pmb;
1429262306a36Sopenharmony_ci	bool workposted = false;
1429362306a36Sopenharmony_ci	int rc;
1429462306a36Sopenharmony_ci
1429562306a36Sopenharmony_ci	/* If not a mailbox complete MCQE, out by checking mailbox consume */
1429662306a36Sopenharmony_ci	if (!bf_get(lpfc_trailer_completed, mcqe))
1429762306a36Sopenharmony_ci		goto out_no_mqe_complete;
1429862306a36Sopenharmony_ci
1429962306a36Sopenharmony_ci	/* Get the reference to the active mbox command */
1430062306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1430162306a36Sopenharmony_ci	pmb = phba->sli.mbox_active;
1430262306a36Sopenharmony_ci	if (unlikely(!pmb)) {
1430362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1430462306a36Sopenharmony_ci				"1832 No pending MBOX command to handle\n");
1430562306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1430662306a36Sopenharmony_ci		goto out_no_mqe_complete;
1430762306a36Sopenharmony_ci	}
1430862306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1430962306a36Sopenharmony_ci	mqe = &pmb->u.mqe;
1431062306a36Sopenharmony_ci	pmbox = (MAILBOX_t *)&pmb->u.mqe;
1431162306a36Sopenharmony_ci	mbox = phba->mbox;
1431262306a36Sopenharmony_ci	vport = pmb->vport;
1431362306a36Sopenharmony_ci
1431462306a36Sopenharmony_ci	/* Reset heartbeat timer */
1431562306a36Sopenharmony_ci	phba->last_completion_time = jiffies;
1431662306a36Sopenharmony_ci	del_timer(&phba->sli.mbox_tmo);
1431762306a36Sopenharmony_ci
1431862306a36Sopenharmony_ci	/* Move mbox data to caller's mailbox region, do endian swapping */
1431962306a36Sopenharmony_ci	if (pmb->mbox_cmpl && mbox)
1432062306a36Sopenharmony_ci		lpfc_sli4_pcimem_bcopy(mbox, mqe, sizeof(struct lpfc_mqe));
1432162306a36Sopenharmony_ci
1432262306a36Sopenharmony_ci	/*
1432362306a36Sopenharmony_ci	 * For mcqe errors, conditionally move a modified error code to
1432462306a36Sopenharmony_ci	 * the mbox so that the error will not be missed.
1432562306a36Sopenharmony_ci	 */
1432662306a36Sopenharmony_ci	mcqe_status = bf_get(lpfc_mcqe_status, mcqe);
1432762306a36Sopenharmony_ci	if (mcqe_status != MB_CQE_STATUS_SUCCESS) {
1432862306a36Sopenharmony_ci		if (bf_get(lpfc_mqe_status, mqe) == MBX_SUCCESS)
1432962306a36Sopenharmony_ci			bf_set(lpfc_mqe_status, mqe,
1433062306a36Sopenharmony_ci			       (LPFC_MBX_ERROR_RANGE | mcqe_status));
1433162306a36Sopenharmony_ci	}
1433262306a36Sopenharmony_ci	if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
1433362306a36Sopenharmony_ci		pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
1433462306a36Sopenharmony_ci		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_MBOX_VPORT,
1433562306a36Sopenharmony_ci				      "MBOX dflt rpi: status:x%x rpi:x%x",
1433662306a36Sopenharmony_ci				      mcqe_status,
1433762306a36Sopenharmony_ci				      pmbox->un.varWords[0], 0);
1433862306a36Sopenharmony_ci		if (mcqe_status == MB_CQE_STATUS_SUCCESS) {
1433962306a36Sopenharmony_ci			mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
1434062306a36Sopenharmony_ci			ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
1434162306a36Sopenharmony_ci
1434262306a36Sopenharmony_ci			/* Reg_LOGIN of dflt RPI was successful. Mark the
1434362306a36Sopenharmony_ci			 * node as having an UNREG_LOGIN in progress to stop
1434462306a36Sopenharmony_ci			 * an unsolicited PLOGI from the same NPortId from
1434562306a36Sopenharmony_ci			 * starting another mailbox transaction.
1434662306a36Sopenharmony_ci			 */
1434762306a36Sopenharmony_ci			spin_lock_irqsave(&ndlp->lock, iflags);
1434862306a36Sopenharmony_ci			ndlp->nlp_flag |= NLP_UNREG_INP;
1434962306a36Sopenharmony_ci			spin_unlock_irqrestore(&ndlp->lock, iflags);
1435062306a36Sopenharmony_ci			lpfc_unreg_login(phba, vport->vpi,
1435162306a36Sopenharmony_ci					 pmbox->un.varWords[0], pmb);
1435262306a36Sopenharmony_ci			pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
1435362306a36Sopenharmony_ci			pmb->ctx_buf = mp;
1435462306a36Sopenharmony_ci
1435562306a36Sopenharmony_ci			/* No reference taken here.  This is a default
1435662306a36Sopenharmony_ci			 * RPI reg/immediate unreg cycle. The reference was
1435762306a36Sopenharmony_ci			 * taken in the reg rpi path and is released when
1435862306a36Sopenharmony_ci			 * this mailbox completes.
1435962306a36Sopenharmony_ci			 */
1436062306a36Sopenharmony_ci			pmb->ctx_ndlp = ndlp;
1436162306a36Sopenharmony_ci			pmb->vport = vport;
1436262306a36Sopenharmony_ci			rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
1436362306a36Sopenharmony_ci			if (rc != MBX_BUSY)
1436462306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR,
1436562306a36Sopenharmony_ci						LOG_TRACE_EVENT,
1436662306a36Sopenharmony_ci						"0385 rc should "
1436762306a36Sopenharmony_ci						"have been MBX_BUSY\n");
1436862306a36Sopenharmony_ci			if (rc != MBX_NOT_FINISHED)
1436962306a36Sopenharmony_ci				goto send_current_mbox;
1437062306a36Sopenharmony_ci		}
1437162306a36Sopenharmony_ci	}
1437262306a36Sopenharmony_ci	spin_lock_irqsave(&phba->pport->work_port_lock, iflags);
1437362306a36Sopenharmony_ci	phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
1437462306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags);
1437562306a36Sopenharmony_ci
1437662306a36Sopenharmony_ci	/* Do NOT queue MBX_HEARTBEAT to the worker thread for processing. */
1437762306a36Sopenharmony_ci	if (pmbox->mbxCommand == MBX_HEARTBEAT) {
1437862306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1437962306a36Sopenharmony_ci		/* Release the mailbox command posting token */
1438062306a36Sopenharmony_ci		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
1438162306a36Sopenharmony_ci		phba->sli.mbox_active = NULL;
1438262306a36Sopenharmony_ci		if (bf_get(lpfc_trailer_consumed, mcqe))
1438362306a36Sopenharmony_ci			lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
1438462306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1438562306a36Sopenharmony_ci
1438662306a36Sopenharmony_ci		/* Post the next mbox command, if there is one */
1438762306a36Sopenharmony_ci		lpfc_sli4_post_async_mbox(phba);
1438862306a36Sopenharmony_ci
1438962306a36Sopenharmony_ci		/* Process cmpl now */
1439062306a36Sopenharmony_ci		if (pmb->mbox_cmpl)
1439162306a36Sopenharmony_ci			pmb->mbox_cmpl(phba, pmb);
1439262306a36Sopenharmony_ci		return false;
1439362306a36Sopenharmony_ci	}
1439462306a36Sopenharmony_ci
1439562306a36Sopenharmony_ci	/* There is mailbox completion work to queue to the worker thread */
1439662306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1439762306a36Sopenharmony_ci	__lpfc_mbox_cmpl_put(phba, pmb);
1439862306a36Sopenharmony_ci	phba->work_ha |= HA_MBATT;
1439962306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1440062306a36Sopenharmony_ci	workposted = true;
1440162306a36Sopenharmony_ci
1440262306a36Sopenharmony_cisend_current_mbox:
1440362306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1440462306a36Sopenharmony_ci	/* Release the mailbox command posting token */
1440562306a36Sopenharmony_ci	phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
1440662306a36Sopenharmony_ci	/* Setting active mailbox pointer need to be in sync to flag clear */
1440762306a36Sopenharmony_ci	phba->sli.mbox_active = NULL;
1440862306a36Sopenharmony_ci	if (bf_get(lpfc_trailer_consumed, mcqe))
1440962306a36Sopenharmony_ci		lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
1441062306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1441162306a36Sopenharmony_ci	/* Wake up worker thread to post the next pending mailbox command */
1441262306a36Sopenharmony_ci	lpfc_worker_wake_up(phba);
1441362306a36Sopenharmony_ci	return workposted;
1441462306a36Sopenharmony_ci
1441562306a36Sopenharmony_ciout_no_mqe_complete:
1441662306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1441762306a36Sopenharmony_ci	if (bf_get(lpfc_trailer_consumed, mcqe))
1441862306a36Sopenharmony_ci		lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
1441962306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1442062306a36Sopenharmony_ci	return false;
1442162306a36Sopenharmony_ci}
1442262306a36Sopenharmony_ci
1442362306a36Sopenharmony_ci/**
1442462306a36Sopenharmony_ci * lpfc_sli4_sp_handle_mcqe - Process a mailbox completion queue entry
1442562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1442662306a36Sopenharmony_ci * @cq: Pointer to associated CQ
1442762306a36Sopenharmony_ci * @cqe: Pointer to mailbox completion queue entry.
1442862306a36Sopenharmony_ci *
1442962306a36Sopenharmony_ci * This routine process a mailbox completion queue entry, it invokes the
1443062306a36Sopenharmony_ci * proper mailbox complete handling or asynchronous event handling routine
1443162306a36Sopenharmony_ci * according to the MCQE's async bit.
1443262306a36Sopenharmony_ci *
1443362306a36Sopenharmony_ci * Return: true if work posted to worker thread, otherwise false.
1443462306a36Sopenharmony_ci **/
1443562306a36Sopenharmony_cistatic bool
1443662306a36Sopenharmony_cilpfc_sli4_sp_handle_mcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
1443762306a36Sopenharmony_ci			 struct lpfc_cqe *cqe)
1443862306a36Sopenharmony_ci{
1443962306a36Sopenharmony_ci	struct lpfc_mcqe mcqe;
1444062306a36Sopenharmony_ci	bool workposted;
1444162306a36Sopenharmony_ci
1444262306a36Sopenharmony_ci	cq->CQ_mbox++;
1444362306a36Sopenharmony_ci
1444462306a36Sopenharmony_ci	/* Copy the mailbox MCQE and convert endian order as needed */
1444562306a36Sopenharmony_ci	lpfc_sli4_pcimem_bcopy(cqe, &mcqe, sizeof(struct lpfc_mcqe));
1444662306a36Sopenharmony_ci
1444762306a36Sopenharmony_ci	/* Invoke the proper event handling routine */
1444862306a36Sopenharmony_ci	if (!bf_get(lpfc_trailer_async, &mcqe))
1444962306a36Sopenharmony_ci		workposted = lpfc_sli4_sp_handle_mbox_event(phba, &mcqe);
1445062306a36Sopenharmony_ci	else
1445162306a36Sopenharmony_ci		workposted = lpfc_sli4_sp_handle_async_event(phba, &mcqe);
1445262306a36Sopenharmony_ci	return workposted;
1445362306a36Sopenharmony_ci}
1445462306a36Sopenharmony_ci
1445562306a36Sopenharmony_ci/**
1445662306a36Sopenharmony_ci * lpfc_sli4_sp_handle_els_wcqe - Handle els work-queue completion event
1445762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1445862306a36Sopenharmony_ci * @cq: Pointer to associated CQ
1445962306a36Sopenharmony_ci * @wcqe: Pointer to work-queue completion queue entry.
1446062306a36Sopenharmony_ci *
1446162306a36Sopenharmony_ci * This routine handles an ELS work-queue completion event.
1446262306a36Sopenharmony_ci *
1446362306a36Sopenharmony_ci * Return: true if work posted to worker thread, otherwise false.
1446462306a36Sopenharmony_ci **/
1446562306a36Sopenharmony_cistatic bool
1446662306a36Sopenharmony_cilpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
1446762306a36Sopenharmony_ci			     struct lpfc_wcqe_complete *wcqe)
1446862306a36Sopenharmony_ci{
1446962306a36Sopenharmony_ci	struct lpfc_iocbq *irspiocbq;
1447062306a36Sopenharmony_ci	unsigned long iflags;
1447162306a36Sopenharmony_ci	struct lpfc_sli_ring *pring = cq->pring;
1447262306a36Sopenharmony_ci	int txq_cnt = 0;
1447362306a36Sopenharmony_ci	int txcmplq_cnt = 0;
1447462306a36Sopenharmony_ci
1447562306a36Sopenharmony_ci	/* Check for response status */
1447662306a36Sopenharmony_ci	if (unlikely(bf_get(lpfc_wcqe_c_status, wcqe))) {
1447762306a36Sopenharmony_ci		/* Log the error status */
1447862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
1447962306a36Sopenharmony_ci				"0357 ELS CQE error: status=x%x: "
1448062306a36Sopenharmony_ci				"CQE: %08x %08x %08x %08x\n",
1448162306a36Sopenharmony_ci				bf_get(lpfc_wcqe_c_status, wcqe),
1448262306a36Sopenharmony_ci				wcqe->word0, wcqe->total_data_placed,
1448362306a36Sopenharmony_ci				wcqe->parameter, wcqe->word3);
1448462306a36Sopenharmony_ci	}
1448562306a36Sopenharmony_ci
1448662306a36Sopenharmony_ci	/* Get an irspiocbq for later ELS response processing use */
1448762306a36Sopenharmony_ci	irspiocbq = lpfc_sli_get_iocbq(phba);
1448862306a36Sopenharmony_ci	if (!irspiocbq) {
1448962306a36Sopenharmony_ci		if (!list_empty(&pring->txq))
1449062306a36Sopenharmony_ci			txq_cnt++;
1449162306a36Sopenharmony_ci		if (!list_empty(&pring->txcmplq))
1449262306a36Sopenharmony_ci			txcmplq_cnt++;
1449362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1449462306a36Sopenharmony_ci			"0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d "
1449562306a36Sopenharmony_ci			"els_txcmplq_cnt=%d\n",
1449662306a36Sopenharmony_ci			txq_cnt, phba->iocb_cnt,
1449762306a36Sopenharmony_ci			txcmplq_cnt);
1449862306a36Sopenharmony_ci		return false;
1449962306a36Sopenharmony_ci	}
1450062306a36Sopenharmony_ci
1450162306a36Sopenharmony_ci	/* Save off the slow-path queue event for work thread to process */
1450262306a36Sopenharmony_ci	memcpy(&irspiocbq->cq_event.cqe.wcqe_cmpl, wcqe, sizeof(*wcqe));
1450362306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1450462306a36Sopenharmony_ci	list_add_tail(&irspiocbq->cq_event.list,
1450562306a36Sopenharmony_ci		      &phba->sli4_hba.sp_queue_event);
1450662306a36Sopenharmony_ci	phba->hba_flag |= HBA_SP_QUEUE_EVT;
1450762306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1450862306a36Sopenharmony_ci
1450962306a36Sopenharmony_ci	return true;
1451062306a36Sopenharmony_ci}
1451162306a36Sopenharmony_ci
1451262306a36Sopenharmony_ci/**
1451362306a36Sopenharmony_ci * lpfc_sli4_sp_handle_rel_wcqe - Handle slow-path WQ entry consumed event
1451462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1451562306a36Sopenharmony_ci * @wcqe: Pointer to work-queue completion queue entry.
1451662306a36Sopenharmony_ci *
1451762306a36Sopenharmony_ci * This routine handles slow-path WQ entry consumed event by invoking the
1451862306a36Sopenharmony_ci * proper WQ release routine to the slow-path WQ.
1451962306a36Sopenharmony_ci **/
1452062306a36Sopenharmony_cistatic void
1452162306a36Sopenharmony_cilpfc_sli4_sp_handle_rel_wcqe(struct lpfc_hba *phba,
1452262306a36Sopenharmony_ci			     struct lpfc_wcqe_release *wcqe)
1452362306a36Sopenharmony_ci{
1452462306a36Sopenharmony_ci	/* sanity check on queue memory */
1452562306a36Sopenharmony_ci	if (unlikely(!phba->sli4_hba.els_wq))
1452662306a36Sopenharmony_ci		return;
1452762306a36Sopenharmony_ci	/* Check for the slow-path ELS work queue */
1452862306a36Sopenharmony_ci	if (bf_get(lpfc_wcqe_r_wq_id, wcqe) == phba->sli4_hba.els_wq->queue_id)
1452962306a36Sopenharmony_ci		lpfc_sli4_wq_release(phba->sli4_hba.els_wq,
1453062306a36Sopenharmony_ci				     bf_get(lpfc_wcqe_r_wqe_index, wcqe));
1453162306a36Sopenharmony_ci	else
1453262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
1453362306a36Sopenharmony_ci				"2579 Slow-path wqe consume event carries "
1453462306a36Sopenharmony_ci				"miss-matched qid: wcqe-qid=x%x, sp-qid=x%x\n",
1453562306a36Sopenharmony_ci				bf_get(lpfc_wcqe_r_wqe_index, wcqe),
1453662306a36Sopenharmony_ci				phba->sli4_hba.els_wq->queue_id);
1453762306a36Sopenharmony_ci}
1453862306a36Sopenharmony_ci
1453962306a36Sopenharmony_ci/**
1454062306a36Sopenharmony_ci * lpfc_sli4_sp_handle_abort_xri_wcqe - Handle a xri abort event
1454162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1454262306a36Sopenharmony_ci * @cq: Pointer to a WQ completion queue.
1454362306a36Sopenharmony_ci * @wcqe: Pointer to work-queue completion queue entry.
1454462306a36Sopenharmony_ci *
1454562306a36Sopenharmony_ci * This routine handles an XRI abort event.
1454662306a36Sopenharmony_ci *
1454762306a36Sopenharmony_ci * Return: true if work posted to worker thread, otherwise false.
1454862306a36Sopenharmony_ci **/
1454962306a36Sopenharmony_cistatic bool
1455062306a36Sopenharmony_cilpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba,
1455162306a36Sopenharmony_ci				   struct lpfc_queue *cq,
1455262306a36Sopenharmony_ci				   struct sli4_wcqe_xri_aborted *wcqe)
1455362306a36Sopenharmony_ci{
1455462306a36Sopenharmony_ci	bool workposted = false;
1455562306a36Sopenharmony_ci	struct lpfc_cq_event *cq_event;
1455662306a36Sopenharmony_ci	unsigned long iflags;
1455762306a36Sopenharmony_ci
1455862306a36Sopenharmony_ci	switch (cq->subtype) {
1455962306a36Sopenharmony_ci	case LPFC_IO:
1456062306a36Sopenharmony_ci		lpfc_sli4_io_xri_aborted(phba, wcqe, cq->hdwq);
1456162306a36Sopenharmony_ci		if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
1456262306a36Sopenharmony_ci			/* Notify aborted XRI for NVME work queue */
1456362306a36Sopenharmony_ci			if (phba->nvmet_support)
1456462306a36Sopenharmony_ci				lpfc_sli4_nvmet_xri_aborted(phba, wcqe);
1456562306a36Sopenharmony_ci		}
1456662306a36Sopenharmony_ci		workposted = false;
1456762306a36Sopenharmony_ci		break;
1456862306a36Sopenharmony_ci	case LPFC_NVME_LS: /* NVME LS uses ELS resources */
1456962306a36Sopenharmony_ci	case LPFC_ELS:
1457062306a36Sopenharmony_ci		cq_event = lpfc_cq_event_setup(phba, wcqe, sizeof(*wcqe));
1457162306a36Sopenharmony_ci		if (!cq_event) {
1457262306a36Sopenharmony_ci			workposted = false;
1457362306a36Sopenharmony_ci			break;
1457462306a36Sopenharmony_ci		}
1457562306a36Sopenharmony_ci		cq_event->hdwq = cq->hdwq;
1457662306a36Sopenharmony_ci		spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock,
1457762306a36Sopenharmony_ci				  iflags);
1457862306a36Sopenharmony_ci		list_add_tail(&cq_event->list,
1457962306a36Sopenharmony_ci			      &phba->sli4_hba.sp_els_xri_aborted_work_queue);
1458062306a36Sopenharmony_ci		/* Set the els xri abort event flag */
1458162306a36Sopenharmony_ci		phba->hba_flag |= ELS_XRI_ABORT_EVENT;
1458262306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock,
1458362306a36Sopenharmony_ci				       iflags);
1458462306a36Sopenharmony_ci		workposted = true;
1458562306a36Sopenharmony_ci		break;
1458662306a36Sopenharmony_ci	default:
1458762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1458862306a36Sopenharmony_ci				"0603 Invalid CQ subtype %d: "
1458962306a36Sopenharmony_ci				"%08x %08x %08x %08x\n",
1459062306a36Sopenharmony_ci				cq->subtype, wcqe->word0, wcqe->parameter,
1459162306a36Sopenharmony_ci				wcqe->word2, wcqe->word3);
1459262306a36Sopenharmony_ci		workposted = false;
1459362306a36Sopenharmony_ci		break;
1459462306a36Sopenharmony_ci	}
1459562306a36Sopenharmony_ci	return workposted;
1459662306a36Sopenharmony_ci}
1459762306a36Sopenharmony_ci
1459862306a36Sopenharmony_ci#define FC_RCTL_MDS_DIAGS	0xF4
1459962306a36Sopenharmony_ci
1460062306a36Sopenharmony_ci/**
1460162306a36Sopenharmony_ci * lpfc_sli4_sp_handle_rcqe - Process a receive-queue completion queue entry
1460262306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1460362306a36Sopenharmony_ci * @rcqe: Pointer to receive-queue completion queue entry.
1460462306a36Sopenharmony_ci *
1460562306a36Sopenharmony_ci * This routine process a receive-queue completion queue entry.
1460662306a36Sopenharmony_ci *
1460762306a36Sopenharmony_ci * Return: true if work posted to worker thread, otherwise false.
1460862306a36Sopenharmony_ci **/
1460962306a36Sopenharmony_cistatic bool
1461062306a36Sopenharmony_cilpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)
1461162306a36Sopenharmony_ci{
1461262306a36Sopenharmony_ci	bool workposted = false;
1461362306a36Sopenharmony_ci	struct fc_frame_header *fc_hdr;
1461462306a36Sopenharmony_ci	struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq;
1461562306a36Sopenharmony_ci	struct lpfc_queue *drq = phba->sli4_hba.dat_rq;
1461662306a36Sopenharmony_ci	struct lpfc_nvmet_tgtport *tgtp;
1461762306a36Sopenharmony_ci	struct hbq_dmabuf *dma_buf;
1461862306a36Sopenharmony_ci	uint32_t status, rq_id;
1461962306a36Sopenharmony_ci	unsigned long iflags;
1462062306a36Sopenharmony_ci
1462162306a36Sopenharmony_ci	/* sanity check on queue memory */
1462262306a36Sopenharmony_ci	if (unlikely(!hrq) || unlikely(!drq))
1462362306a36Sopenharmony_ci		return workposted;
1462462306a36Sopenharmony_ci
1462562306a36Sopenharmony_ci	if (bf_get(lpfc_cqe_code, rcqe) == CQE_CODE_RECEIVE_V1)
1462662306a36Sopenharmony_ci		rq_id = bf_get(lpfc_rcqe_rq_id_v1, rcqe);
1462762306a36Sopenharmony_ci	else
1462862306a36Sopenharmony_ci		rq_id = bf_get(lpfc_rcqe_rq_id, rcqe);
1462962306a36Sopenharmony_ci	if (rq_id != hrq->queue_id)
1463062306a36Sopenharmony_ci		goto out;
1463162306a36Sopenharmony_ci
1463262306a36Sopenharmony_ci	status = bf_get(lpfc_rcqe_status, rcqe);
1463362306a36Sopenharmony_ci	switch (status) {
1463462306a36Sopenharmony_ci	case FC_STATUS_RQ_BUF_LEN_EXCEEDED:
1463562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1463662306a36Sopenharmony_ci				"2537 Receive Frame Truncated!!\n");
1463762306a36Sopenharmony_ci		fallthrough;
1463862306a36Sopenharmony_ci	case FC_STATUS_RQ_SUCCESS:
1463962306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1464062306a36Sopenharmony_ci		lpfc_sli4_rq_release(hrq, drq);
1464162306a36Sopenharmony_ci		dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list);
1464262306a36Sopenharmony_ci		if (!dma_buf) {
1464362306a36Sopenharmony_ci			hrq->RQ_no_buf_found++;
1464462306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflags);
1464562306a36Sopenharmony_ci			goto out;
1464662306a36Sopenharmony_ci		}
1464762306a36Sopenharmony_ci		hrq->RQ_rcv_buf++;
1464862306a36Sopenharmony_ci		hrq->RQ_buf_posted--;
1464962306a36Sopenharmony_ci		memcpy(&dma_buf->cq_event.cqe.rcqe_cmpl, rcqe, sizeof(*rcqe));
1465062306a36Sopenharmony_ci
1465162306a36Sopenharmony_ci		fc_hdr = (struct fc_frame_header *)dma_buf->hbuf.virt;
1465262306a36Sopenharmony_ci
1465362306a36Sopenharmony_ci		if (fc_hdr->fh_r_ctl == FC_RCTL_MDS_DIAGS ||
1465462306a36Sopenharmony_ci		    fc_hdr->fh_r_ctl == FC_RCTL_DD_UNSOL_DATA) {
1465562306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflags);
1465662306a36Sopenharmony_ci			/* Handle MDS Loopback frames */
1465762306a36Sopenharmony_ci			if  (!(phba->pport->load_flag & FC_UNLOADING))
1465862306a36Sopenharmony_ci				lpfc_sli4_handle_mds_loopback(phba->pport,
1465962306a36Sopenharmony_ci							      dma_buf);
1466062306a36Sopenharmony_ci			else
1466162306a36Sopenharmony_ci				lpfc_in_buf_free(phba, &dma_buf->dbuf);
1466262306a36Sopenharmony_ci			break;
1466362306a36Sopenharmony_ci		}
1466462306a36Sopenharmony_ci
1466562306a36Sopenharmony_ci		/* save off the frame for the work thread to process */
1466662306a36Sopenharmony_ci		list_add_tail(&dma_buf->cq_event.list,
1466762306a36Sopenharmony_ci			      &phba->sli4_hba.sp_queue_event);
1466862306a36Sopenharmony_ci		/* Frame received */
1466962306a36Sopenharmony_ci		phba->hba_flag |= HBA_SP_QUEUE_EVT;
1467062306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1467162306a36Sopenharmony_ci		workposted = true;
1467262306a36Sopenharmony_ci		break;
1467362306a36Sopenharmony_ci	case FC_STATUS_INSUFF_BUF_FRM_DISC:
1467462306a36Sopenharmony_ci		if (phba->nvmet_support) {
1467562306a36Sopenharmony_ci			tgtp = phba->targetport->private;
1467662306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1467762306a36Sopenharmony_ci					"6402 RQE Error x%x, posted %d err_cnt "
1467862306a36Sopenharmony_ci					"%d: %x %x %x\n",
1467962306a36Sopenharmony_ci					status, hrq->RQ_buf_posted,
1468062306a36Sopenharmony_ci					hrq->RQ_no_posted_buf,
1468162306a36Sopenharmony_ci					atomic_read(&tgtp->rcv_fcp_cmd_in),
1468262306a36Sopenharmony_ci					atomic_read(&tgtp->rcv_fcp_cmd_out),
1468362306a36Sopenharmony_ci					atomic_read(&tgtp->xmt_fcp_release));
1468462306a36Sopenharmony_ci		}
1468562306a36Sopenharmony_ci		fallthrough;
1468662306a36Sopenharmony_ci
1468762306a36Sopenharmony_ci	case FC_STATUS_INSUFF_BUF_NEED_BUF:
1468862306a36Sopenharmony_ci		hrq->RQ_no_posted_buf++;
1468962306a36Sopenharmony_ci		/* Post more buffers if possible */
1469062306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1469162306a36Sopenharmony_ci		phba->hba_flag |= HBA_POST_RECEIVE_BUFFER;
1469262306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1469362306a36Sopenharmony_ci		workposted = true;
1469462306a36Sopenharmony_ci		break;
1469562306a36Sopenharmony_ci	case FC_STATUS_RQ_DMA_FAILURE:
1469662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1469762306a36Sopenharmony_ci				"2564 RQE DMA Error x%x, x%08x x%08x x%08x "
1469862306a36Sopenharmony_ci				"x%08x\n",
1469962306a36Sopenharmony_ci				status, rcqe->word0, rcqe->word1,
1470062306a36Sopenharmony_ci				rcqe->word2, rcqe->word3);
1470162306a36Sopenharmony_ci
1470262306a36Sopenharmony_ci		/* If IV set, no further recovery */
1470362306a36Sopenharmony_ci		if (bf_get(lpfc_rcqe_iv, rcqe))
1470462306a36Sopenharmony_ci			break;
1470562306a36Sopenharmony_ci
1470662306a36Sopenharmony_ci		/* recycle consumed resource */
1470762306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1470862306a36Sopenharmony_ci		lpfc_sli4_rq_release(hrq, drq);
1470962306a36Sopenharmony_ci		dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list);
1471062306a36Sopenharmony_ci		if (!dma_buf) {
1471162306a36Sopenharmony_ci			hrq->RQ_no_buf_found++;
1471262306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflags);
1471362306a36Sopenharmony_ci			break;
1471462306a36Sopenharmony_ci		}
1471562306a36Sopenharmony_ci		hrq->RQ_rcv_buf++;
1471662306a36Sopenharmony_ci		hrq->RQ_buf_posted--;
1471762306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1471862306a36Sopenharmony_ci		lpfc_in_buf_free(phba, &dma_buf->dbuf);
1471962306a36Sopenharmony_ci		break;
1472062306a36Sopenharmony_ci	default:
1472162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1472262306a36Sopenharmony_ci				"2565 Unexpected RQE Status x%x, w0-3 x%08x "
1472362306a36Sopenharmony_ci				"x%08x x%08x x%08x\n",
1472462306a36Sopenharmony_ci				status, rcqe->word0, rcqe->word1,
1472562306a36Sopenharmony_ci				rcqe->word2, rcqe->word3);
1472662306a36Sopenharmony_ci		break;
1472762306a36Sopenharmony_ci	}
1472862306a36Sopenharmony_ciout:
1472962306a36Sopenharmony_ci	return workposted;
1473062306a36Sopenharmony_ci}
1473162306a36Sopenharmony_ci
1473262306a36Sopenharmony_ci/**
1473362306a36Sopenharmony_ci * lpfc_sli4_sp_handle_cqe - Process a slow path completion queue entry
1473462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1473562306a36Sopenharmony_ci * @cq: Pointer to the completion queue.
1473662306a36Sopenharmony_ci * @cqe: Pointer to a completion queue entry.
1473762306a36Sopenharmony_ci *
1473862306a36Sopenharmony_ci * This routine process a slow-path work-queue or receive queue completion queue
1473962306a36Sopenharmony_ci * entry.
1474062306a36Sopenharmony_ci *
1474162306a36Sopenharmony_ci * Return: true if work posted to worker thread, otherwise false.
1474262306a36Sopenharmony_ci **/
1474362306a36Sopenharmony_cistatic bool
1474462306a36Sopenharmony_cilpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
1474562306a36Sopenharmony_ci			 struct lpfc_cqe *cqe)
1474662306a36Sopenharmony_ci{
1474762306a36Sopenharmony_ci	struct lpfc_cqe cqevt;
1474862306a36Sopenharmony_ci	bool workposted = false;
1474962306a36Sopenharmony_ci
1475062306a36Sopenharmony_ci	/* Copy the work queue CQE and convert endian order if needed */
1475162306a36Sopenharmony_ci	lpfc_sli4_pcimem_bcopy(cqe, &cqevt, sizeof(struct lpfc_cqe));
1475262306a36Sopenharmony_ci
1475362306a36Sopenharmony_ci	/* Check and process for different type of WCQE and dispatch */
1475462306a36Sopenharmony_ci	switch (bf_get(lpfc_cqe_code, &cqevt)) {
1475562306a36Sopenharmony_ci	case CQE_CODE_COMPL_WQE:
1475662306a36Sopenharmony_ci		/* Process the WQ/RQ complete event */
1475762306a36Sopenharmony_ci		phba->last_completion_time = jiffies;
1475862306a36Sopenharmony_ci		workposted = lpfc_sli4_sp_handle_els_wcqe(phba, cq,
1475962306a36Sopenharmony_ci				(struct lpfc_wcqe_complete *)&cqevt);
1476062306a36Sopenharmony_ci		break;
1476162306a36Sopenharmony_ci	case CQE_CODE_RELEASE_WQE:
1476262306a36Sopenharmony_ci		/* Process the WQ release event */
1476362306a36Sopenharmony_ci		lpfc_sli4_sp_handle_rel_wcqe(phba,
1476462306a36Sopenharmony_ci				(struct lpfc_wcqe_release *)&cqevt);
1476562306a36Sopenharmony_ci		break;
1476662306a36Sopenharmony_ci	case CQE_CODE_XRI_ABORTED:
1476762306a36Sopenharmony_ci		/* Process the WQ XRI abort event */
1476862306a36Sopenharmony_ci		phba->last_completion_time = jiffies;
1476962306a36Sopenharmony_ci		workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq,
1477062306a36Sopenharmony_ci				(struct sli4_wcqe_xri_aborted *)&cqevt);
1477162306a36Sopenharmony_ci		break;
1477262306a36Sopenharmony_ci	case CQE_CODE_RECEIVE:
1477362306a36Sopenharmony_ci	case CQE_CODE_RECEIVE_V1:
1477462306a36Sopenharmony_ci		/* Process the RQ event */
1477562306a36Sopenharmony_ci		phba->last_completion_time = jiffies;
1477662306a36Sopenharmony_ci		workposted = lpfc_sli4_sp_handle_rcqe(phba,
1477762306a36Sopenharmony_ci				(struct lpfc_rcqe *)&cqevt);
1477862306a36Sopenharmony_ci		break;
1477962306a36Sopenharmony_ci	default:
1478062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1478162306a36Sopenharmony_ci				"0388 Not a valid WCQE code: x%x\n",
1478262306a36Sopenharmony_ci				bf_get(lpfc_cqe_code, &cqevt));
1478362306a36Sopenharmony_ci		break;
1478462306a36Sopenharmony_ci	}
1478562306a36Sopenharmony_ci	return workposted;
1478662306a36Sopenharmony_ci}
1478762306a36Sopenharmony_ci
1478862306a36Sopenharmony_ci/**
1478962306a36Sopenharmony_ci * lpfc_sli4_sp_handle_eqe - Process a slow-path event queue entry
1479062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1479162306a36Sopenharmony_ci * @eqe: Pointer to fast-path event queue entry.
1479262306a36Sopenharmony_ci * @speq: Pointer to slow-path event queue.
1479362306a36Sopenharmony_ci *
1479462306a36Sopenharmony_ci * This routine process a event queue entry from the slow-path event queue.
1479562306a36Sopenharmony_ci * It will check the MajorCode and MinorCode to determine this is for a
1479662306a36Sopenharmony_ci * completion event on a completion queue, if not, an error shall be logged
1479762306a36Sopenharmony_ci * and just return. Otherwise, it will get to the corresponding completion
1479862306a36Sopenharmony_ci * queue and process all the entries on that completion queue, rearm the
1479962306a36Sopenharmony_ci * completion queue, and then return.
1480062306a36Sopenharmony_ci *
1480162306a36Sopenharmony_ci **/
1480262306a36Sopenharmony_cistatic void
1480362306a36Sopenharmony_cilpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
1480462306a36Sopenharmony_ci	struct lpfc_queue *speq)
1480562306a36Sopenharmony_ci{
1480662306a36Sopenharmony_ci	struct lpfc_queue *cq = NULL, *childq;
1480762306a36Sopenharmony_ci	uint16_t cqid;
1480862306a36Sopenharmony_ci	int ret = 0;
1480962306a36Sopenharmony_ci
1481062306a36Sopenharmony_ci	/* Get the reference to the corresponding CQ */
1481162306a36Sopenharmony_ci	cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
1481262306a36Sopenharmony_ci
1481362306a36Sopenharmony_ci	list_for_each_entry(childq, &speq->child_list, list) {
1481462306a36Sopenharmony_ci		if (childq->queue_id == cqid) {
1481562306a36Sopenharmony_ci			cq = childq;
1481662306a36Sopenharmony_ci			break;
1481762306a36Sopenharmony_ci		}
1481862306a36Sopenharmony_ci	}
1481962306a36Sopenharmony_ci	if (unlikely(!cq)) {
1482062306a36Sopenharmony_ci		if (phba->sli.sli_flag & LPFC_SLI_ACTIVE)
1482162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1482262306a36Sopenharmony_ci					"0365 Slow-path CQ identifier "
1482362306a36Sopenharmony_ci					"(%d) does not exist\n", cqid);
1482462306a36Sopenharmony_ci		return;
1482562306a36Sopenharmony_ci	}
1482662306a36Sopenharmony_ci
1482762306a36Sopenharmony_ci	/* Save EQ associated with this CQ */
1482862306a36Sopenharmony_ci	cq->assoc_qp = speq;
1482962306a36Sopenharmony_ci
1483062306a36Sopenharmony_ci	if (is_kdump_kernel())
1483162306a36Sopenharmony_ci		ret = queue_work(phba->wq, &cq->spwork);
1483262306a36Sopenharmony_ci	else
1483362306a36Sopenharmony_ci		ret = queue_work_on(cq->chann, phba->wq, &cq->spwork);
1483462306a36Sopenharmony_ci
1483562306a36Sopenharmony_ci	if (!ret)
1483662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1483762306a36Sopenharmony_ci				"0390 Cannot schedule queue work "
1483862306a36Sopenharmony_ci				"for CQ eqcqid=%d, cqid=%d on CPU %d\n",
1483962306a36Sopenharmony_ci				cqid, cq->queue_id, raw_smp_processor_id());
1484062306a36Sopenharmony_ci}
1484162306a36Sopenharmony_ci
1484262306a36Sopenharmony_ci/**
1484362306a36Sopenharmony_ci * __lpfc_sli4_process_cq - Process elements of a CQ
1484462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1484562306a36Sopenharmony_ci * @cq: Pointer to CQ to be processed
1484662306a36Sopenharmony_ci * @handler: Routine to process each cqe
1484762306a36Sopenharmony_ci * @delay: Pointer to usdelay to set in case of rescheduling of the handler
1484862306a36Sopenharmony_ci *
1484962306a36Sopenharmony_ci * This routine processes completion queue entries in a CQ. While a valid
1485062306a36Sopenharmony_ci * queue element is found, the handler is called. During processing checks
1485162306a36Sopenharmony_ci * are made for periodic doorbell writes to let the hardware know of
1485262306a36Sopenharmony_ci * element consumption.
1485362306a36Sopenharmony_ci *
1485462306a36Sopenharmony_ci * If the max limit on cqes to process is hit, or there are no more valid
1485562306a36Sopenharmony_ci * entries, the loop stops. If we processed a sufficient number of elements,
1485662306a36Sopenharmony_ci * meaning there is sufficient load, rather than rearming and generating
1485762306a36Sopenharmony_ci * another interrupt, a cq rescheduling delay will be set. A delay of 0
1485862306a36Sopenharmony_ci * indicates no rescheduling.
1485962306a36Sopenharmony_ci *
1486062306a36Sopenharmony_ci * Returns True if work scheduled, False otherwise.
1486162306a36Sopenharmony_ci **/
1486262306a36Sopenharmony_cistatic bool
1486362306a36Sopenharmony_ci__lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
1486462306a36Sopenharmony_ci	bool (*handler)(struct lpfc_hba *, struct lpfc_queue *,
1486562306a36Sopenharmony_ci			struct lpfc_cqe *), unsigned long *delay)
1486662306a36Sopenharmony_ci{
1486762306a36Sopenharmony_ci	struct lpfc_cqe *cqe;
1486862306a36Sopenharmony_ci	bool workposted = false;
1486962306a36Sopenharmony_ci	int count = 0, consumed = 0;
1487062306a36Sopenharmony_ci	bool arm = true;
1487162306a36Sopenharmony_ci
1487262306a36Sopenharmony_ci	/* default - no reschedule */
1487362306a36Sopenharmony_ci	*delay = 0;
1487462306a36Sopenharmony_ci
1487562306a36Sopenharmony_ci	if (cmpxchg(&cq->queue_claimed, 0, 1) != 0)
1487662306a36Sopenharmony_ci		goto rearm_and_exit;
1487762306a36Sopenharmony_ci
1487862306a36Sopenharmony_ci	/* Process all the entries to the CQ */
1487962306a36Sopenharmony_ci	cq->q_flag = 0;
1488062306a36Sopenharmony_ci	cqe = lpfc_sli4_cq_get(cq);
1488162306a36Sopenharmony_ci	while (cqe) {
1488262306a36Sopenharmony_ci		workposted |= handler(phba, cq, cqe);
1488362306a36Sopenharmony_ci		__lpfc_sli4_consume_cqe(phba, cq, cqe);
1488462306a36Sopenharmony_ci
1488562306a36Sopenharmony_ci		consumed++;
1488662306a36Sopenharmony_ci		if (!(++count % cq->max_proc_limit))
1488762306a36Sopenharmony_ci			break;
1488862306a36Sopenharmony_ci
1488962306a36Sopenharmony_ci		if (!(count % cq->notify_interval)) {
1489062306a36Sopenharmony_ci			phba->sli4_hba.sli4_write_cq_db(phba, cq, consumed,
1489162306a36Sopenharmony_ci						LPFC_QUEUE_NOARM);
1489262306a36Sopenharmony_ci			consumed = 0;
1489362306a36Sopenharmony_ci			cq->assoc_qp->q_flag |= HBA_EQ_DELAY_CHK;
1489462306a36Sopenharmony_ci		}
1489562306a36Sopenharmony_ci
1489662306a36Sopenharmony_ci		if (count == LPFC_NVMET_CQ_NOTIFY)
1489762306a36Sopenharmony_ci			cq->q_flag |= HBA_NVMET_CQ_NOTIFY;
1489862306a36Sopenharmony_ci
1489962306a36Sopenharmony_ci		cqe = lpfc_sli4_cq_get(cq);
1490062306a36Sopenharmony_ci	}
1490162306a36Sopenharmony_ci	if (count >= phba->cfg_cq_poll_threshold) {
1490262306a36Sopenharmony_ci		*delay = 1;
1490362306a36Sopenharmony_ci		arm = false;
1490462306a36Sopenharmony_ci	}
1490562306a36Sopenharmony_ci
1490662306a36Sopenharmony_ci	/* Track the max number of CQEs processed in 1 EQ */
1490762306a36Sopenharmony_ci	if (count > cq->CQ_max_cqe)
1490862306a36Sopenharmony_ci		cq->CQ_max_cqe = count;
1490962306a36Sopenharmony_ci
1491062306a36Sopenharmony_ci	cq->assoc_qp->EQ_cqe_cnt += count;
1491162306a36Sopenharmony_ci
1491262306a36Sopenharmony_ci	/* Catch the no cq entry condition */
1491362306a36Sopenharmony_ci	if (unlikely(count == 0))
1491462306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
1491562306a36Sopenharmony_ci				"0369 No entry from completion queue "
1491662306a36Sopenharmony_ci				"qid=%d\n", cq->queue_id);
1491762306a36Sopenharmony_ci
1491862306a36Sopenharmony_ci	xchg(&cq->queue_claimed, 0);
1491962306a36Sopenharmony_ci
1492062306a36Sopenharmony_cirearm_and_exit:
1492162306a36Sopenharmony_ci	phba->sli4_hba.sli4_write_cq_db(phba, cq, consumed,
1492262306a36Sopenharmony_ci			arm ?  LPFC_QUEUE_REARM : LPFC_QUEUE_NOARM);
1492362306a36Sopenharmony_ci
1492462306a36Sopenharmony_ci	return workposted;
1492562306a36Sopenharmony_ci}
1492662306a36Sopenharmony_ci
1492762306a36Sopenharmony_ci/**
1492862306a36Sopenharmony_ci * __lpfc_sli4_sp_process_cq - Process a slow-path event queue entry
1492962306a36Sopenharmony_ci * @cq: pointer to CQ to process
1493062306a36Sopenharmony_ci *
1493162306a36Sopenharmony_ci * This routine calls the cq processing routine with a handler specific
1493262306a36Sopenharmony_ci * to the type of queue bound to it.
1493362306a36Sopenharmony_ci *
1493462306a36Sopenharmony_ci * The CQ routine returns two values: the first is the calling status,
1493562306a36Sopenharmony_ci * which indicates whether work was queued to the  background discovery
1493662306a36Sopenharmony_ci * thread. If true, the routine should wakeup the discovery thread;
1493762306a36Sopenharmony_ci * the second is the delay parameter. If non-zero, rather than rearming
1493862306a36Sopenharmony_ci * the CQ and yet another interrupt, the CQ handler should be queued so
1493962306a36Sopenharmony_ci * that it is processed in a subsequent polling action. The value of
1494062306a36Sopenharmony_ci * the delay indicates when to reschedule it.
1494162306a36Sopenharmony_ci **/
1494262306a36Sopenharmony_cistatic void
1494362306a36Sopenharmony_ci__lpfc_sli4_sp_process_cq(struct lpfc_queue *cq)
1494462306a36Sopenharmony_ci{
1494562306a36Sopenharmony_ci	struct lpfc_hba *phba = cq->phba;
1494662306a36Sopenharmony_ci	unsigned long delay;
1494762306a36Sopenharmony_ci	bool workposted = false;
1494862306a36Sopenharmony_ci	int ret = 0;
1494962306a36Sopenharmony_ci
1495062306a36Sopenharmony_ci	/* Process and rearm the CQ */
1495162306a36Sopenharmony_ci	switch (cq->type) {
1495262306a36Sopenharmony_ci	case LPFC_MCQ:
1495362306a36Sopenharmony_ci		workposted |= __lpfc_sli4_process_cq(phba, cq,
1495462306a36Sopenharmony_ci						lpfc_sli4_sp_handle_mcqe,
1495562306a36Sopenharmony_ci						&delay);
1495662306a36Sopenharmony_ci		break;
1495762306a36Sopenharmony_ci	case LPFC_WCQ:
1495862306a36Sopenharmony_ci		if (cq->subtype == LPFC_IO)
1495962306a36Sopenharmony_ci			workposted |= __lpfc_sli4_process_cq(phba, cq,
1496062306a36Sopenharmony_ci						lpfc_sli4_fp_handle_cqe,
1496162306a36Sopenharmony_ci						&delay);
1496262306a36Sopenharmony_ci		else
1496362306a36Sopenharmony_ci			workposted |= __lpfc_sli4_process_cq(phba, cq,
1496462306a36Sopenharmony_ci						lpfc_sli4_sp_handle_cqe,
1496562306a36Sopenharmony_ci						&delay);
1496662306a36Sopenharmony_ci		break;
1496762306a36Sopenharmony_ci	default:
1496862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1496962306a36Sopenharmony_ci				"0370 Invalid completion queue type (%d)\n",
1497062306a36Sopenharmony_ci				cq->type);
1497162306a36Sopenharmony_ci		return;
1497262306a36Sopenharmony_ci	}
1497362306a36Sopenharmony_ci
1497462306a36Sopenharmony_ci	if (delay) {
1497562306a36Sopenharmony_ci		if (is_kdump_kernel())
1497662306a36Sopenharmony_ci			ret = queue_delayed_work(phba->wq, &cq->sched_spwork,
1497762306a36Sopenharmony_ci						delay);
1497862306a36Sopenharmony_ci		else
1497962306a36Sopenharmony_ci			ret = queue_delayed_work_on(cq->chann, phba->wq,
1498062306a36Sopenharmony_ci						&cq->sched_spwork, delay);
1498162306a36Sopenharmony_ci		if (!ret)
1498262306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1498362306a36Sopenharmony_ci				"0394 Cannot schedule queue work "
1498462306a36Sopenharmony_ci				"for cqid=%d on CPU %d\n",
1498562306a36Sopenharmony_ci				cq->queue_id, cq->chann);
1498662306a36Sopenharmony_ci	}
1498762306a36Sopenharmony_ci
1498862306a36Sopenharmony_ci	/* wake up worker thread if there are works to be done */
1498962306a36Sopenharmony_ci	if (workposted)
1499062306a36Sopenharmony_ci		lpfc_worker_wake_up(phba);
1499162306a36Sopenharmony_ci}
1499262306a36Sopenharmony_ci
1499362306a36Sopenharmony_ci/**
1499462306a36Sopenharmony_ci * lpfc_sli4_sp_process_cq - slow-path work handler when started by
1499562306a36Sopenharmony_ci *   interrupt
1499662306a36Sopenharmony_ci * @work: pointer to work element
1499762306a36Sopenharmony_ci *
1499862306a36Sopenharmony_ci * translates from the work handler and calls the slow-path handler.
1499962306a36Sopenharmony_ci **/
1500062306a36Sopenharmony_cistatic void
1500162306a36Sopenharmony_cilpfc_sli4_sp_process_cq(struct work_struct *work)
1500262306a36Sopenharmony_ci{
1500362306a36Sopenharmony_ci	struct lpfc_queue *cq = container_of(work, struct lpfc_queue, spwork);
1500462306a36Sopenharmony_ci
1500562306a36Sopenharmony_ci	__lpfc_sli4_sp_process_cq(cq);
1500662306a36Sopenharmony_ci}
1500762306a36Sopenharmony_ci
1500862306a36Sopenharmony_ci/**
1500962306a36Sopenharmony_ci * lpfc_sli4_dly_sp_process_cq - slow-path work handler when started by timer
1501062306a36Sopenharmony_ci * @work: pointer to work element
1501162306a36Sopenharmony_ci *
1501262306a36Sopenharmony_ci * translates from the work handler and calls the slow-path handler.
1501362306a36Sopenharmony_ci **/
1501462306a36Sopenharmony_cistatic void
1501562306a36Sopenharmony_cilpfc_sli4_dly_sp_process_cq(struct work_struct *work)
1501662306a36Sopenharmony_ci{
1501762306a36Sopenharmony_ci	struct lpfc_queue *cq = container_of(to_delayed_work(work),
1501862306a36Sopenharmony_ci					struct lpfc_queue, sched_spwork);
1501962306a36Sopenharmony_ci
1502062306a36Sopenharmony_ci	__lpfc_sli4_sp_process_cq(cq);
1502162306a36Sopenharmony_ci}
1502262306a36Sopenharmony_ci
1502362306a36Sopenharmony_ci/**
1502462306a36Sopenharmony_ci * lpfc_sli4_fp_handle_fcp_wcqe - Process fast-path work queue completion entry
1502562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1502662306a36Sopenharmony_ci * @cq: Pointer to associated CQ
1502762306a36Sopenharmony_ci * @wcqe: Pointer to work-queue completion queue entry.
1502862306a36Sopenharmony_ci *
1502962306a36Sopenharmony_ci * This routine process a fast-path work queue completion entry from fast-path
1503062306a36Sopenharmony_ci * event queue for FCP command response completion.
1503162306a36Sopenharmony_ci **/
1503262306a36Sopenharmony_cistatic void
1503362306a36Sopenharmony_cilpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
1503462306a36Sopenharmony_ci			     struct lpfc_wcqe_complete *wcqe)
1503562306a36Sopenharmony_ci{
1503662306a36Sopenharmony_ci	struct lpfc_sli_ring *pring = cq->pring;
1503762306a36Sopenharmony_ci	struct lpfc_iocbq *cmdiocbq;
1503862306a36Sopenharmony_ci	unsigned long iflags;
1503962306a36Sopenharmony_ci
1504062306a36Sopenharmony_ci	/* Check for response status */
1504162306a36Sopenharmony_ci	if (unlikely(bf_get(lpfc_wcqe_c_status, wcqe))) {
1504262306a36Sopenharmony_ci		/* If resource errors reported from HBA, reduce queue
1504362306a36Sopenharmony_ci		 * depth of the SCSI device.
1504462306a36Sopenharmony_ci		 */
1504562306a36Sopenharmony_ci		if (((bf_get(lpfc_wcqe_c_status, wcqe) ==
1504662306a36Sopenharmony_ci		     IOSTAT_LOCAL_REJECT)) &&
1504762306a36Sopenharmony_ci		    ((wcqe->parameter & IOERR_PARAM_MASK) ==
1504862306a36Sopenharmony_ci		     IOERR_NO_RESOURCES))
1504962306a36Sopenharmony_ci			phba->lpfc_rampdown_queue_depth(phba);
1505062306a36Sopenharmony_ci
1505162306a36Sopenharmony_ci		/* Log the cmpl status */
1505262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
1505362306a36Sopenharmony_ci				"0373 FCP CQE cmpl: status=x%x: "
1505462306a36Sopenharmony_ci				"CQE: %08x %08x %08x %08x\n",
1505562306a36Sopenharmony_ci				bf_get(lpfc_wcqe_c_status, wcqe),
1505662306a36Sopenharmony_ci				wcqe->word0, wcqe->total_data_placed,
1505762306a36Sopenharmony_ci				wcqe->parameter, wcqe->word3);
1505862306a36Sopenharmony_ci	}
1505962306a36Sopenharmony_ci
1506062306a36Sopenharmony_ci	/* Look up the FCP command IOCB and create pseudo response IOCB */
1506162306a36Sopenharmony_ci	spin_lock_irqsave(&pring->ring_lock, iflags);
1506262306a36Sopenharmony_ci	pring->stats.iocb_event++;
1506362306a36Sopenharmony_ci	cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
1506462306a36Sopenharmony_ci				bf_get(lpfc_wcqe_c_request_tag, wcqe));
1506562306a36Sopenharmony_ci	spin_unlock_irqrestore(&pring->ring_lock, iflags);
1506662306a36Sopenharmony_ci	if (unlikely(!cmdiocbq)) {
1506762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
1506862306a36Sopenharmony_ci				"0374 FCP complete with no corresponding "
1506962306a36Sopenharmony_ci				"cmdiocb: iotag (%d)\n",
1507062306a36Sopenharmony_ci				bf_get(lpfc_wcqe_c_request_tag, wcqe));
1507162306a36Sopenharmony_ci		return;
1507262306a36Sopenharmony_ci	}
1507362306a36Sopenharmony_ci#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
1507462306a36Sopenharmony_ci	cmdiocbq->isr_timestamp = cq->isr_timestamp;
1507562306a36Sopenharmony_ci#endif
1507662306a36Sopenharmony_ci	if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
1507762306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1507862306a36Sopenharmony_ci		cmdiocbq->cmd_flag |= LPFC_EXCHANGE_BUSY;
1507962306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1508062306a36Sopenharmony_ci	}
1508162306a36Sopenharmony_ci
1508262306a36Sopenharmony_ci	if (cmdiocbq->cmd_cmpl) {
1508362306a36Sopenharmony_ci		/* For FCP the flag is cleared in cmd_cmpl */
1508462306a36Sopenharmony_ci		if (!(cmdiocbq->cmd_flag & LPFC_IO_FCP) &&
1508562306a36Sopenharmony_ci		    cmdiocbq->cmd_flag & LPFC_DRIVER_ABORTED) {
1508662306a36Sopenharmony_ci			spin_lock_irqsave(&phba->hbalock, iflags);
1508762306a36Sopenharmony_ci			cmdiocbq->cmd_flag &= ~LPFC_DRIVER_ABORTED;
1508862306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflags);
1508962306a36Sopenharmony_ci		}
1509062306a36Sopenharmony_ci
1509162306a36Sopenharmony_ci		/* Pass the cmd_iocb and the wcqe to the upper layer */
1509262306a36Sopenharmony_ci		memcpy(&cmdiocbq->wcqe_cmpl, wcqe,
1509362306a36Sopenharmony_ci		       sizeof(struct lpfc_wcqe_complete));
1509462306a36Sopenharmony_ci		cmdiocbq->cmd_cmpl(phba, cmdiocbq, cmdiocbq);
1509562306a36Sopenharmony_ci	} else {
1509662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
1509762306a36Sopenharmony_ci				"0375 FCP cmdiocb not callback function "
1509862306a36Sopenharmony_ci				"iotag: (%d)\n",
1509962306a36Sopenharmony_ci				bf_get(lpfc_wcqe_c_request_tag, wcqe));
1510062306a36Sopenharmony_ci	}
1510162306a36Sopenharmony_ci}
1510262306a36Sopenharmony_ci
1510362306a36Sopenharmony_ci/**
1510462306a36Sopenharmony_ci * lpfc_sli4_fp_handle_rel_wcqe - Handle fast-path WQ entry consumed event
1510562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1510662306a36Sopenharmony_ci * @cq: Pointer to completion queue.
1510762306a36Sopenharmony_ci * @wcqe: Pointer to work-queue completion queue entry.
1510862306a36Sopenharmony_ci *
1510962306a36Sopenharmony_ci * This routine handles an fast-path WQ entry consumed event by invoking the
1511062306a36Sopenharmony_ci * proper WQ release routine to the slow-path WQ.
1511162306a36Sopenharmony_ci **/
1511262306a36Sopenharmony_cistatic void
1511362306a36Sopenharmony_cilpfc_sli4_fp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
1511462306a36Sopenharmony_ci			     struct lpfc_wcqe_release *wcqe)
1511562306a36Sopenharmony_ci{
1511662306a36Sopenharmony_ci	struct lpfc_queue *childwq;
1511762306a36Sopenharmony_ci	bool wqid_matched = false;
1511862306a36Sopenharmony_ci	uint16_t hba_wqid;
1511962306a36Sopenharmony_ci
1512062306a36Sopenharmony_ci	/* Check for fast-path FCP work queue release */
1512162306a36Sopenharmony_ci	hba_wqid = bf_get(lpfc_wcqe_r_wq_id, wcqe);
1512262306a36Sopenharmony_ci	list_for_each_entry(childwq, &cq->child_list, list) {
1512362306a36Sopenharmony_ci		if (childwq->queue_id == hba_wqid) {
1512462306a36Sopenharmony_ci			lpfc_sli4_wq_release(childwq,
1512562306a36Sopenharmony_ci					bf_get(lpfc_wcqe_r_wqe_index, wcqe));
1512662306a36Sopenharmony_ci			if (childwq->q_flag & HBA_NVMET_WQFULL)
1512762306a36Sopenharmony_ci				lpfc_nvmet_wqfull_process(phba, childwq);
1512862306a36Sopenharmony_ci			wqid_matched = true;
1512962306a36Sopenharmony_ci			break;
1513062306a36Sopenharmony_ci		}
1513162306a36Sopenharmony_ci	}
1513262306a36Sopenharmony_ci	/* Report warning log message if no match found */
1513362306a36Sopenharmony_ci	if (wqid_matched != true)
1513462306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
1513562306a36Sopenharmony_ci				"2580 Fast-path wqe consume event carries "
1513662306a36Sopenharmony_ci				"miss-matched qid: wcqe-qid=x%x\n", hba_wqid);
1513762306a36Sopenharmony_ci}
1513862306a36Sopenharmony_ci
1513962306a36Sopenharmony_ci/**
1514062306a36Sopenharmony_ci * lpfc_sli4_nvmet_handle_rcqe - Process a receive-queue completion queue entry
1514162306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1514262306a36Sopenharmony_ci * @cq: Pointer to completion queue.
1514362306a36Sopenharmony_ci * @rcqe: Pointer to receive-queue completion queue entry.
1514462306a36Sopenharmony_ci *
1514562306a36Sopenharmony_ci * This routine process a receive-queue completion queue entry.
1514662306a36Sopenharmony_ci *
1514762306a36Sopenharmony_ci * Return: true if work posted to worker thread, otherwise false.
1514862306a36Sopenharmony_ci **/
1514962306a36Sopenharmony_cistatic bool
1515062306a36Sopenharmony_cilpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
1515162306a36Sopenharmony_ci			    struct lpfc_rcqe *rcqe)
1515262306a36Sopenharmony_ci{
1515362306a36Sopenharmony_ci	bool workposted = false;
1515462306a36Sopenharmony_ci	struct lpfc_queue *hrq;
1515562306a36Sopenharmony_ci	struct lpfc_queue *drq;
1515662306a36Sopenharmony_ci	struct rqb_dmabuf *dma_buf;
1515762306a36Sopenharmony_ci	struct fc_frame_header *fc_hdr;
1515862306a36Sopenharmony_ci	struct lpfc_nvmet_tgtport *tgtp;
1515962306a36Sopenharmony_ci	uint32_t status, rq_id;
1516062306a36Sopenharmony_ci	unsigned long iflags;
1516162306a36Sopenharmony_ci	uint32_t fctl, idx;
1516262306a36Sopenharmony_ci
1516362306a36Sopenharmony_ci	if ((phba->nvmet_support == 0) ||
1516462306a36Sopenharmony_ci	    (phba->sli4_hba.nvmet_cqset == NULL))
1516562306a36Sopenharmony_ci		return workposted;
1516662306a36Sopenharmony_ci
1516762306a36Sopenharmony_ci	idx = cq->queue_id - phba->sli4_hba.nvmet_cqset[0]->queue_id;
1516862306a36Sopenharmony_ci	hrq = phba->sli4_hba.nvmet_mrq_hdr[idx];
1516962306a36Sopenharmony_ci	drq = phba->sli4_hba.nvmet_mrq_data[idx];
1517062306a36Sopenharmony_ci
1517162306a36Sopenharmony_ci	/* sanity check on queue memory */
1517262306a36Sopenharmony_ci	if (unlikely(!hrq) || unlikely(!drq))
1517362306a36Sopenharmony_ci		return workposted;
1517462306a36Sopenharmony_ci
1517562306a36Sopenharmony_ci	if (bf_get(lpfc_cqe_code, rcqe) == CQE_CODE_RECEIVE_V1)
1517662306a36Sopenharmony_ci		rq_id = bf_get(lpfc_rcqe_rq_id_v1, rcqe);
1517762306a36Sopenharmony_ci	else
1517862306a36Sopenharmony_ci		rq_id = bf_get(lpfc_rcqe_rq_id, rcqe);
1517962306a36Sopenharmony_ci
1518062306a36Sopenharmony_ci	if ((phba->nvmet_support == 0) ||
1518162306a36Sopenharmony_ci	    (rq_id != hrq->queue_id))
1518262306a36Sopenharmony_ci		return workposted;
1518362306a36Sopenharmony_ci
1518462306a36Sopenharmony_ci	status = bf_get(lpfc_rcqe_status, rcqe);
1518562306a36Sopenharmony_ci	switch (status) {
1518662306a36Sopenharmony_ci	case FC_STATUS_RQ_BUF_LEN_EXCEEDED:
1518762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1518862306a36Sopenharmony_ci				"6126 Receive Frame Truncated!!\n");
1518962306a36Sopenharmony_ci		fallthrough;
1519062306a36Sopenharmony_ci	case FC_STATUS_RQ_SUCCESS:
1519162306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1519262306a36Sopenharmony_ci		lpfc_sli4_rq_release(hrq, drq);
1519362306a36Sopenharmony_ci		dma_buf = lpfc_sli_rqbuf_get(phba, hrq);
1519462306a36Sopenharmony_ci		if (!dma_buf) {
1519562306a36Sopenharmony_ci			hrq->RQ_no_buf_found++;
1519662306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflags);
1519762306a36Sopenharmony_ci			goto out;
1519862306a36Sopenharmony_ci		}
1519962306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1520062306a36Sopenharmony_ci		hrq->RQ_rcv_buf++;
1520162306a36Sopenharmony_ci		hrq->RQ_buf_posted--;
1520262306a36Sopenharmony_ci		fc_hdr = (struct fc_frame_header *)dma_buf->hbuf.virt;
1520362306a36Sopenharmony_ci
1520462306a36Sopenharmony_ci		/* Just some basic sanity checks on FCP Command frame */
1520562306a36Sopenharmony_ci		fctl = (fc_hdr->fh_f_ctl[0] << 16 |
1520662306a36Sopenharmony_ci			fc_hdr->fh_f_ctl[1] << 8 |
1520762306a36Sopenharmony_ci			fc_hdr->fh_f_ctl[2]);
1520862306a36Sopenharmony_ci		if (((fctl &
1520962306a36Sopenharmony_ci		    (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT)) !=
1521062306a36Sopenharmony_ci		    (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT)) ||
1521162306a36Sopenharmony_ci		    (fc_hdr->fh_seq_cnt != 0)) /* 0 byte swapped is still 0 */
1521262306a36Sopenharmony_ci			goto drop;
1521362306a36Sopenharmony_ci
1521462306a36Sopenharmony_ci		if (fc_hdr->fh_type == FC_TYPE_FCP) {
1521562306a36Sopenharmony_ci			dma_buf->bytes_recv = bf_get(lpfc_rcqe_length, rcqe);
1521662306a36Sopenharmony_ci			lpfc_nvmet_unsol_fcp_event(
1521762306a36Sopenharmony_ci				phba, idx, dma_buf, cq->isr_timestamp,
1521862306a36Sopenharmony_ci				cq->q_flag & HBA_NVMET_CQ_NOTIFY);
1521962306a36Sopenharmony_ci			return false;
1522062306a36Sopenharmony_ci		}
1522162306a36Sopenharmony_cidrop:
1522262306a36Sopenharmony_ci		lpfc_rq_buf_free(phba, &dma_buf->hbuf);
1522362306a36Sopenharmony_ci		break;
1522462306a36Sopenharmony_ci	case FC_STATUS_INSUFF_BUF_FRM_DISC:
1522562306a36Sopenharmony_ci		if (phba->nvmet_support) {
1522662306a36Sopenharmony_ci			tgtp = phba->targetport->private;
1522762306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1522862306a36Sopenharmony_ci					"6401 RQE Error x%x, posted %d err_cnt "
1522962306a36Sopenharmony_ci					"%d: %x %x %x\n",
1523062306a36Sopenharmony_ci					status, hrq->RQ_buf_posted,
1523162306a36Sopenharmony_ci					hrq->RQ_no_posted_buf,
1523262306a36Sopenharmony_ci					atomic_read(&tgtp->rcv_fcp_cmd_in),
1523362306a36Sopenharmony_ci					atomic_read(&tgtp->rcv_fcp_cmd_out),
1523462306a36Sopenharmony_ci					atomic_read(&tgtp->xmt_fcp_release));
1523562306a36Sopenharmony_ci		}
1523662306a36Sopenharmony_ci		fallthrough;
1523762306a36Sopenharmony_ci
1523862306a36Sopenharmony_ci	case FC_STATUS_INSUFF_BUF_NEED_BUF:
1523962306a36Sopenharmony_ci		hrq->RQ_no_posted_buf++;
1524062306a36Sopenharmony_ci		/* Post more buffers if possible */
1524162306a36Sopenharmony_ci		break;
1524262306a36Sopenharmony_ci	case FC_STATUS_RQ_DMA_FAILURE:
1524362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1524462306a36Sopenharmony_ci				"2575 RQE DMA Error x%x, x%08x x%08x x%08x "
1524562306a36Sopenharmony_ci				"x%08x\n",
1524662306a36Sopenharmony_ci				status, rcqe->word0, rcqe->word1,
1524762306a36Sopenharmony_ci				rcqe->word2, rcqe->word3);
1524862306a36Sopenharmony_ci
1524962306a36Sopenharmony_ci		/* If IV set, no further recovery */
1525062306a36Sopenharmony_ci		if (bf_get(lpfc_rcqe_iv, rcqe))
1525162306a36Sopenharmony_ci			break;
1525262306a36Sopenharmony_ci
1525362306a36Sopenharmony_ci		/* recycle consumed resource */
1525462306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1525562306a36Sopenharmony_ci		lpfc_sli4_rq_release(hrq, drq);
1525662306a36Sopenharmony_ci		dma_buf = lpfc_sli_rqbuf_get(phba, hrq);
1525762306a36Sopenharmony_ci		if (!dma_buf) {
1525862306a36Sopenharmony_ci			hrq->RQ_no_buf_found++;
1525962306a36Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflags);
1526062306a36Sopenharmony_ci			break;
1526162306a36Sopenharmony_ci		}
1526262306a36Sopenharmony_ci		hrq->RQ_rcv_buf++;
1526362306a36Sopenharmony_ci		hrq->RQ_buf_posted--;
1526462306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1526562306a36Sopenharmony_ci		lpfc_rq_buf_free(phba, &dma_buf->hbuf);
1526662306a36Sopenharmony_ci		break;
1526762306a36Sopenharmony_ci	default:
1526862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1526962306a36Sopenharmony_ci				"2576 Unexpected RQE Status x%x, w0-3 x%08x "
1527062306a36Sopenharmony_ci				"x%08x x%08x x%08x\n",
1527162306a36Sopenharmony_ci				status, rcqe->word0, rcqe->word1,
1527262306a36Sopenharmony_ci				rcqe->word2, rcqe->word3);
1527362306a36Sopenharmony_ci		break;
1527462306a36Sopenharmony_ci	}
1527562306a36Sopenharmony_ciout:
1527662306a36Sopenharmony_ci	return workposted;
1527762306a36Sopenharmony_ci}
1527862306a36Sopenharmony_ci
1527962306a36Sopenharmony_ci/**
1528062306a36Sopenharmony_ci * lpfc_sli4_fp_handle_cqe - Process fast-path work queue completion entry
1528162306a36Sopenharmony_ci * @phba: adapter with cq
1528262306a36Sopenharmony_ci * @cq: Pointer to the completion queue.
1528362306a36Sopenharmony_ci * @cqe: Pointer to fast-path completion queue entry.
1528462306a36Sopenharmony_ci *
1528562306a36Sopenharmony_ci * This routine process a fast-path work queue completion entry from fast-path
1528662306a36Sopenharmony_ci * event queue for FCP command response completion.
1528762306a36Sopenharmony_ci *
1528862306a36Sopenharmony_ci * Return: true if work posted to worker thread, otherwise false.
1528962306a36Sopenharmony_ci **/
1529062306a36Sopenharmony_cistatic bool
1529162306a36Sopenharmony_cilpfc_sli4_fp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
1529262306a36Sopenharmony_ci			 struct lpfc_cqe *cqe)
1529362306a36Sopenharmony_ci{
1529462306a36Sopenharmony_ci	struct lpfc_wcqe_release wcqe;
1529562306a36Sopenharmony_ci	bool workposted = false;
1529662306a36Sopenharmony_ci
1529762306a36Sopenharmony_ci	/* Copy the work queue CQE and convert endian order if needed */
1529862306a36Sopenharmony_ci	lpfc_sli4_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe));
1529962306a36Sopenharmony_ci
1530062306a36Sopenharmony_ci	/* Check and process for different type of WCQE and dispatch */
1530162306a36Sopenharmony_ci	switch (bf_get(lpfc_wcqe_c_code, &wcqe)) {
1530262306a36Sopenharmony_ci	case CQE_CODE_COMPL_WQE:
1530362306a36Sopenharmony_ci	case CQE_CODE_NVME_ERSP:
1530462306a36Sopenharmony_ci		cq->CQ_wq++;
1530562306a36Sopenharmony_ci		/* Process the WQ complete event */
1530662306a36Sopenharmony_ci		phba->last_completion_time = jiffies;
1530762306a36Sopenharmony_ci		if (cq->subtype == LPFC_IO || cq->subtype == LPFC_NVME_LS)
1530862306a36Sopenharmony_ci			lpfc_sli4_fp_handle_fcp_wcqe(phba, cq,
1530962306a36Sopenharmony_ci				(struct lpfc_wcqe_complete *)&wcqe);
1531062306a36Sopenharmony_ci		break;
1531162306a36Sopenharmony_ci	case CQE_CODE_RELEASE_WQE:
1531262306a36Sopenharmony_ci		cq->CQ_release_wqe++;
1531362306a36Sopenharmony_ci		/* Process the WQ release event */
1531462306a36Sopenharmony_ci		lpfc_sli4_fp_handle_rel_wcqe(phba, cq,
1531562306a36Sopenharmony_ci				(struct lpfc_wcqe_release *)&wcqe);
1531662306a36Sopenharmony_ci		break;
1531762306a36Sopenharmony_ci	case CQE_CODE_XRI_ABORTED:
1531862306a36Sopenharmony_ci		cq->CQ_xri_aborted++;
1531962306a36Sopenharmony_ci		/* Process the WQ XRI abort event */
1532062306a36Sopenharmony_ci		phba->last_completion_time = jiffies;
1532162306a36Sopenharmony_ci		workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq,
1532262306a36Sopenharmony_ci				(struct sli4_wcqe_xri_aborted *)&wcqe);
1532362306a36Sopenharmony_ci		break;
1532462306a36Sopenharmony_ci	case CQE_CODE_RECEIVE_V1:
1532562306a36Sopenharmony_ci	case CQE_CODE_RECEIVE:
1532662306a36Sopenharmony_ci		phba->last_completion_time = jiffies;
1532762306a36Sopenharmony_ci		if (cq->subtype == LPFC_NVMET) {
1532862306a36Sopenharmony_ci			workposted = lpfc_sli4_nvmet_handle_rcqe(
1532962306a36Sopenharmony_ci				phba, cq, (struct lpfc_rcqe *)&wcqe);
1533062306a36Sopenharmony_ci		}
1533162306a36Sopenharmony_ci		break;
1533262306a36Sopenharmony_ci	default:
1533362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1533462306a36Sopenharmony_ci				"0144 Not a valid CQE code: x%x\n",
1533562306a36Sopenharmony_ci				bf_get(lpfc_wcqe_c_code, &wcqe));
1533662306a36Sopenharmony_ci		break;
1533762306a36Sopenharmony_ci	}
1533862306a36Sopenharmony_ci	return workposted;
1533962306a36Sopenharmony_ci}
1534062306a36Sopenharmony_ci
1534162306a36Sopenharmony_ci/**
1534262306a36Sopenharmony_ci * __lpfc_sli4_hba_process_cq - Process a fast-path event queue entry
1534362306a36Sopenharmony_ci * @cq: Pointer to CQ to be processed
1534462306a36Sopenharmony_ci *
1534562306a36Sopenharmony_ci * This routine calls the cq processing routine with the handler for
1534662306a36Sopenharmony_ci * fast path CQEs.
1534762306a36Sopenharmony_ci *
1534862306a36Sopenharmony_ci * The CQ routine returns two values: the first is the calling status,
1534962306a36Sopenharmony_ci * which indicates whether work was queued to the  background discovery
1535062306a36Sopenharmony_ci * thread. If true, the routine should wakeup the discovery thread;
1535162306a36Sopenharmony_ci * the second is the delay parameter. If non-zero, rather than rearming
1535262306a36Sopenharmony_ci * the CQ and yet another interrupt, the CQ handler should be queued so
1535362306a36Sopenharmony_ci * that it is processed in a subsequent polling action. The value of
1535462306a36Sopenharmony_ci * the delay indicates when to reschedule it.
1535562306a36Sopenharmony_ci **/
1535662306a36Sopenharmony_cistatic void
1535762306a36Sopenharmony_ci__lpfc_sli4_hba_process_cq(struct lpfc_queue *cq)
1535862306a36Sopenharmony_ci{
1535962306a36Sopenharmony_ci	struct lpfc_hba *phba = cq->phba;
1536062306a36Sopenharmony_ci	unsigned long delay;
1536162306a36Sopenharmony_ci	bool workposted = false;
1536262306a36Sopenharmony_ci	int ret;
1536362306a36Sopenharmony_ci
1536462306a36Sopenharmony_ci	/* process and rearm the CQ */
1536562306a36Sopenharmony_ci	workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_fp_handle_cqe,
1536662306a36Sopenharmony_ci					     &delay);
1536762306a36Sopenharmony_ci
1536862306a36Sopenharmony_ci	if (delay) {
1536962306a36Sopenharmony_ci		if (is_kdump_kernel())
1537062306a36Sopenharmony_ci			ret = queue_delayed_work(phba->wq, &cq->sched_irqwork,
1537162306a36Sopenharmony_ci						delay);
1537262306a36Sopenharmony_ci		else
1537362306a36Sopenharmony_ci			ret = queue_delayed_work_on(cq->chann, phba->wq,
1537462306a36Sopenharmony_ci						&cq->sched_irqwork, delay);
1537562306a36Sopenharmony_ci		if (!ret)
1537662306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1537762306a36Sopenharmony_ci					"0367 Cannot schedule queue work "
1537862306a36Sopenharmony_ci					"for cqid=%d on CPU %d\n",
1537962306a36Sopenharmony_ci					cq->queue_id, cq->chann);
1538062306a36Sopenharmony_ci	}
1538162306a36Sopenharmony_ci
1538262306a36Sopenharmony_ci	/* wake up worker thread if there are works to be done */
1538362306a36Sopenharmony_ci	if (workposted)
1538462306a36Sopenharmony_ci		lpfc_worker_wake_up(phba);
1538562306a36Sopenharmony_ci}
1538662306a36Sopenharmony_ci
1538762306a36Sopenharmony_ci/**
1538862306a36Sopenharmony_ci * lpfc_sli4_hba_process_cq - fast-path work handler when started by
1538962306a36Sopenharmony_ci *   interrupt
1539062306a36Sopenharmony_ci * @work: pointer to work element
1539162306a36Sopenharmony_ci *
1539262306a36Sopenharmony_ci * translates from the work handler and calls the fast-path handler.
1539362306a36Sopenharmony_ci **/
1539462306a36Sopenharmony_cistatic void
1539562306a36Sopenharmony_cilpfc_sli4_hba_process_cq(struct work_struct *work)
1539662306a36Sopenharmony_ci{
1539762306a36Sopenharmony_ci	struct lpfc_queue *cq = container_of(work, struct lpfc_queue, irqwork);
1539862306a36Sopenharmony_ci
1539962306a36Sopenharmony_ci	__lpfc_sli4_hba_process_cq(cq);
1540062306a36Sopenharmony_ci}
1540162306a36Sopenharmony_ci
1540262306a36Sopenharmony_ci/**
1540362306a36Sopenharmony_ci * lpfc_sli4_hba_handle_eqe - Process a fast-path event queue entry
1540462306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1540562306a36Sopenharmony_ci * @eq: Pointer to the queue structure.
1540662306a36Sopenharmony_ci * @eqe: Pointer to fast-path event queue entry.
1540762306a36Sopenharmony_ci * @poll_mode: poll_mode to execute processing the cq.
1540862306a36Sopenharmony_ci *
1540962306a36Sopenharmony_ci * This routine process a event queue entry from the fast-path event queue.
1541062306a36Sopenharmony_ci * It will check the MajorCode and MinorCode to determine this is for a
1541162306a36Sopenharmony_ci * completion event on a completion queue, if not, an error shall be logged
1541262306a36Sopenharmony_ci * and just return. Otherwise, it will get to the corresponding completion
1541362306a36Sopenharmony_ci * queue and process all the entries on the completion queue, rearm the
1541462306a36Sopenharmony_ci * completion queue, and then return.
1541562306a36Sopenharmony_ci **/
1541662306a36Sopenharmony_cistatic void
1541762306a36Sopenharmony_cilpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_queue *eq,
1541862306a36Sopenharmony_ci			 struct lpfc_eqe *eqe, enum lpfc_poll_mode poll_mode)
1541962306a36Sopenharmony_ci{
1542062306a36Sopenharmony_ci	struct lpfc_queue *cq = NULL;
1542162306a36Sopenharmony_ci	uint32_t qidx = eq->hdwq;
1542262306a36Sopenharmony_ci	uint16_t cqid, id;
1542362306a36Sopenharmony_ci	int ret;
1542462306a36Sopenharmony_ci
1542562306a36Sopenharmony_ci	if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) {
1542662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1542762306a36Sopenharmony_ci				"0366 Not a valid completion "
1542862306a36Sopenharmony_ci				"event: majorcode=x%x, minorcode=x%x\n",
1542962306a36Sopenharmony_ci				bf_get_le32(lpfc_eqe_major_code, eqe),
1543062306a36Sopenharmony_ci				bf_get_le32(lpfc_eqe_minor_code, eqe));
1543162306a36Sopenharmony_ci		return;
1543262306a36Sopenharmony_ci	}
1543362306a36Sopenharmony_ci
1543462306a36Sopenharmony_ci	/* Get the reference to the corresponding CQ */
1543562306a36Sopenharmony_ci	cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
1543662306a36Sopenharmony_ci
1543762306a36Sopenharmony_ci	/* Use the fast lookup method first */
1543862306a36Sopenharmony_ci	if (cqid <= phba->sli4_hba.cq_max) {
1543962306a36Sopenharmony_ci		cq = phba->sli4_hba.cq_lookup[cqid];
1544062306a36Sopenharmony_ci		if (cq)
1544162306a36Sopenharmony_ci			goto  work_cq;
1544262306a36Sopenharmony_ci	}
1544362306a36Sopenharmony_ci
1544462306a36Sopenharmony_ci	/* Next check for NVMET completion */
1544562306a36Sopenharmony_ci	if (phba->cfg_nvmet_mrq && phba->sli4_hba.nvmet_cqset) {
1544662306a36Sopenharmony_ci		id = phba->sli4_hba.nvmet_cqset[0]->queue_id;
1544762306a36Sopenharmony_ci		if ((cqid >= id) && (cqid < (id + phba->cfg_nvmet_mrq))) {
1544862306a36Sopenharmony_ci			/* Process NVMET unsol rcv */
1544962306a36Sopenharmony_ci			cq = phba->sli4_hba.nvmet_cqset[cqid - id];
1545062306a36Sopenharmony_ci			goto  process_cq;
1545162306a36Sopenharmony_ci		}
1545262306a36Sopenharmony_ci	}
1545362306a36Sopenharmony_ci
1545462306a36Sopenharmony_ci	if (phba->sli4_hba.nvmels_cq &&
1545562306a36Sopenharmony_ci	    (cqid == phba->sli4_hba.nvmels_cq->queue_id)) {
1545662306a36Sopenharmony_ci		/* Process NVME unsol rcv */
1545762306a36Sopenharmony_ci		cq = phba->sli4_hba.nvmels_cq;
1545862306a36Sopenharmony_ci	}
1545962306a36Sopenharmony_ci
1546062306a36Sopenharmony_ci	/* Otherwise this is a Slow path event */
1546162306a36Sopenharmony_ci	if (cq == NULL) {
1546262306a36Sopenharmony_ci		lpfc_sli4_sp_handle_eqe(phba, eqe,
1546362306a36Sopenharmony_ci					phba->sli4_hba.hdwq[qidx].hba_eq);
1546462306a36Sopenharmony_ci		return;
1546562306a36Sopenharmony_ci	}
1546662306a36Sopenharmony_ci
1546762306a36Sopenharmony_ciprocess_cq:
1546862306a36Sopenharmony_ci	if (unlikely(cqid != cq->queue_id)) {
1546962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1547062306a36Sopenharmony_ci				"0368 Miss-matched fast-path completion "
1547162306a36Sopenharmony_ci				"queue identifier: eqcqid=%d, fcpcqid=%d\n",
1547262306a36Sopenharmony_ci				cqid, cq->queue_id);
1547362306a36Sopenharmony_ci		return;
1547462306a36Sopenharmony_ci	}
1547562306a36Sopenharmony_ci
1547662306a36Sopenharmony_ciwork_cq:
1547762306a36Sopenharmony_ci#if defined(CONFIG_SCSI_LPFC_DEBUG_FS)
1547862306a36Sopenharmony_ci	if (phba->ktime_on)
1547962306a36Sopenharmony_ci		cq->isr_timestamp = ktime_get_ns();
1548062306a36Sopenharmony_ci	else
1548162306a36Sopenharmony_ci		cq->isr_timestamp = 0;
1548262306a36Sopenharmony_ci#endif
1548362306a36Sopenharmony_ci
1548462306a36Sopenharmony_ci	switch (poll_mode) {
1548562306a36Sopenharmony_ci	case LPFC_THREADED_IRQ:
1548662306a36Sopenharmony_ci		__lpfc_sli4_hba_process_cq(cq);
1548762306a36Sopenharmony_ci		break;
1548862306a36Sopenharmony_ci	case LPFC_QUEUE_WORK:
1548962306a36Sopenharmony_ci	default:
1549062306a36Sopenharmony_ci		if (is_kdump_kernel())
1549162306a36Sopenharmony_ci			ret = queue_work(phba->wq, &cq->irqwork);
1549262306a36Sopenharmony_ci		else
1549362306a36Sopenharmony_ci			ret = queue_work_on(cq->chann, phba->wq, &cq->irqwork);
1549462306a36Sopenharmony_ci		if (!ret)
1549562306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1549662306a36Sopenharmony_ci					"0383 Cannot schedule queue work "
1549762306a36Sopenharmony_ci					"for CQ eqcqid=%d, cqid=%d on CPU %d\n",
1549862306a36Sopenharmony_ci					cqid, cq->queue_id,
1549962306a36Sopenharmony_ci					raw_smp_processor_id());
1550062306a36Sopenharmony_ci		break;
1550162306a36Sopenharmony_ci	}
1550262306a36Sopenharmony_ci}
1550362306a36Sopenharmony_ci
1550462306a36Sopenharmony_ci/**
1550562306a36Sopenharmony_ci * lpfc_sli4_dly_hba_process_cq - fast-path work handler when started by timer
1550662306a36Sopenharmony_ci * @work: pointer to work element
1550762306a36Sopenharmony_ci *
1550862306a36Sopenharmony_ci * translates from the work handler and calls the fast-path handler.
1550962306a36Sopenharmony_ci **/
1551062306a36Sopenharmony_cistatic void
1551162306a36Sopenharmony_cilpfc_sli4_dly_hba_process_cq(struct work_struct *work)
1551262306a36Sopenharmony_ci{
1551362306a36Sopenharmony_ci	struct lpfc_queue *cq = container_of(to_delayed_work(work),
1551462306a36Sopenharmony_ci					struct lpfc_queue, sched_irqwork);
1551562306a36Sopenharmony_ci
1551662306a36Sopenharmony_ci	__lpfc_sli4_hba_process_cq(cq);
1551762306a36Sopenharmony_ci}
1551862306a36Sopenharmony_ci
1551962306a36Sopenharmony_ci/**
1552062306a36Sopenharmony_ci * lpfc_sli4_hba_intr_handler - HBA interrupt handler to SLI-4 device
1552162306a36Sopenharmony_ci * @irq: Interrupt number.
1552262306a36Sopenharmony_ci * @dev_id: The device context pointer.
1552362306a36Sopenharmony_ci *
1552462306a36Sopenharmony_ci * This function is directly called from the PCI layer as an interrupt
1552562306a36Sopenharmony_ci * service routine when device with SLI-4 interface spec is enabled with
1552662306a36Sopenharmony_ci * MSI-X multi-message interrupt mode and there is a fast-path FCP IOCB
1552762306a36Sopenharmony_ci * ring event in the HBA. However, when the device is enabled with either
1552862306a36Sopenharmony_ci * MSI or Pin-IRQ interrupt mode, this function is called as part of the
1552962306a36Sopenharmony_ci * device-level interrupt handler. When the PCI slot is in error recovery
1553062306a36Sopenharmony_ci * or the HBA is undergoing initialization, the interrupt handler will not
1553162306a36Sopenharmony_ci * process the interrupt. The SCSI FCP fast-path ring event are handled in
1553262306a36Sopenharmony_ci * the intrrupt context. This function is called without any lock held.
1553362306a36Sopenharmony_ci * It gets the hbalock to access and update SLI data structures. Note that,
1553462306a36Sopenharmony_ci * the FCP EQ to FCP CQ are one-to-one map such that the FCP EQ index is
1553562306a36Sopenharmony_ci * equal to that of FCP CQ index.
1553662306a36Sopenharmony_ci *
1553762306a36Sopenharmony_ci * The link attention and ELS ring attention events are handled
1553862306a36Sopenharmony_ci * by the worker thread. The interrupt handler signals the worker thread
1553962306a36Sopenharmony_ci * and returns for these events. This function is called without any lock
1554062306a36Sopenharmony_ci * held. It gets the hbalock to access and update SLI data structures.
1554162306a36Sopenharmony_ci *
1554262306a36Sopenharmony_ci * This function returns IRQ_HANDLED when interrupt is handled, IRQ_WAKE_THREAD
1554362306a36Sopenharmony_ci * when interrupt is scheduled to be handled from a threaded irq context, or
1554462306a36Sopenharmony_ci * else returns IRQ_NONE.
1554562306a36Sopenharmony_ci **/
1554662306a36Sopenharmony_ciirqreturn_t
1554762306a36Sopenharmony_cilpfc_sli4_hba_intr_handler(int irq, void *dev_id)
1554862306a36Sopenharmony_ci{
1554962306a36Sopenharmony_ci	struct lpfc_hba *phba;
1555062306a36Sopenharmony_ci	struct lpfc_hba_eq_hdl *hba_eq_hdl;
1555162306a36Sopenharmony_ci	struct lpfc_queue *fpeq;
1555262306a36Sopenharmony_ci	unsigned long iflag;
1555362306a36Sopenharmony_ci	int hba_eqidx;
1555462306a36Sopenharmony_ci	int ecount = 0;
1555562306a36Sopenharmony_ci	struct lpfc_eq_intr_info *eqi;
1555662306a36Sopenharmony_ci
1555762306a36Sopenharmony_ci	/* Get the driver's phba structure from the dev_id */
1555862306a36Sopenharmony_ci	hba_eq_hdl = (struct lpfc_hba_eq_hdl *)dev_id;
1555962306a36Sopenharmony_ci	phba = hba_eq_hdl->phba;
1556062306a36Sopenharmony_ci	hba_eqidx = hba_eq_hdl->idx;
1556162306a36Sopenharmony_ci
1556262306a36Sopenharmony_ci	if (unlikely(!phba))
1556362306a36Sopenharmony_ci		return IRQ_NONE;
1556462306a36Sopenharmony_ci	if (unlikely(!phba->sli4_hba.hdwq))
1556562306a36Sopenharmony_ci		return IRQ_NONE;
1556662306a36Sopenharmony_ci
1556762306a36Sopenharmony_ci	/* Get to the EQ struct associated with this vector */
1556862306a36Sopenharmony_ci	fpeq = phba->sli4_hba.hba_eq_hdl[hba_eqidx].eq;
1556962306a36Sopenharmony_ci	if (unlikely(!fpeq))
1557062306a36Sopenharmony_ci		return IRQ_NONE;
1557162306a36Sopenharmony_ci
1557262306a36Sopenharmony_ci	/* Check device state for handling interrupt */
1557362306a36Sopenharmony_ci	if (unlikely(lpfc_intr_state_check(phba))) {
1557462306a36Sopenharmony_ci		/* Check again for link_state with lock held */
1557562306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflag);
1557662306a36Sopenharmony_ci		if (phba->link_state < LPFC_LINK_DOWN)
1557762306a36Sopenharmony_ci			/* Flush, clear interrupt, and rearm the EQ */
1557862306a36Sopenharmony_ci			lpfc_sli4_eqcq_flush(phba, fpeq);
1557962306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
1558062306a36Sopenharmony_ci		return IRQ_NONE;
1558162306a36Sopenharmony_ci	}
1558262306a36Sopenharmony_ci
1558362306a36Sopenharmony_ci	switch (fpeq->poll_mode) {
1558462306a36Sopenharmony_ci	case LPFC_THREADED_IRQ:
1558562306a36Sopenharmony_ci		/* CGN mgmt is mutually exclusive from irq processing */
1558662306a36Sopenharmony_ci		if (phba->cmf_active_mode == LPFC_CFG_OFF)
1558762306a36Sopenharmony_ci			return IRQ_WAKE_THREAD;
1558862306a36Sopenharmony_ci		fallthrough;
1558962306a36Sopenharmony_ci	case LPFC_QUEUE_WORK:
1559062306a36Sopenharmony_ci	default:
1559162306a36Sopenharmony_ci		eqi = this_cpu_ptr(phba->sli4_hba.eq_info);
1559262306a36Sopenharmony_ci		eqi->icnt++;
1559362306a36Sopenharmony_ci
1559462306a36Sopenharmony_ci		fpeq->last_cpu = raw_smp_processor_id();
1559562306a36Sopenharmony_ci
1559662306a36Sopenharmony_ci		if (eqi->icnt > LPFC_EQD_ISR_TRIGGER &&
1559762306a36Sopenharmony_ci		    fpeq->q_flag & HBA_EQ_DELAY_CHK &&
1559862306a36Sopenharmony_ci		    phba->cfg_auto_imax &&
1559962306a36Sopenharmony_ci		    fpeq->q_mode != LPFC_MAX_AUTO_EQ_DELAY &&
1560062306a36Sopenharmony_ci		    phba->sli.sli_flag & LPFC_SLI_USE_EQDR)
1560162306a36Sopenharmony_ci			lpfc_sli4_mod_hba_eq_delay(phba, fpeq,
1560262306a36Sopenharmony_ci						   LPFC_MAX_AUTO_EQ_DELAY);
1560362306a36Sopenharmony_ci
1560462306a36Sopenharmony_ci		/* process and rearm the EQ */
1560562306a36Sopenharmony_ci		ecount = lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM,
1560662306a36Sopenharmony_ci					      LPFC_QUEUE_WORK);
1560762306a36Sopenharmony_ci
1560862306a36Sopenharmony_ci		if (unlikely(ecount == 0)) {
1560962306a36Sopenharmony_ci			fpeq->EQ_no_entry++;
1561062306a36Sopenharmony_ci			if (phba->intr_type == MSIX)
1561162306a36Sopenharmony_ci				/* MSI-X treated interrupt served as no EQ share INT */
1561262306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
1561362306a36Sopenharmony_ci						"0358 MSI-X interrupt with no EQE\n");
1561462306a36Sopenharmony_ci			else
1561562306a36Sopenharmony_ci				/* Non MSI-X treated on interrupt as EQ share INT */
1561662306a36Sopenharmony_ci				return IRQ_NONE;
1561762306a36Sopenharmony_ci		}
1561862306a36Sopenharmony_ci	}
1561962306a36Sopenharmony_ci
1562062306a36Sopenharmony_ci	return IRQ_HANDLED;
1562162306a36Sopenharmony_ci} /* lpfc_sli4_hba_intr_handler */
1562262306a36Sopenharmony_ci
1562362306a36Sopenharmony_ci/**
1562462306a36Sopenharmony_ci * lpfc_sli4_intr_handler - Device-level interrupt handler for SLI-4 device
1562562306a36Sopenharmony_ci * @irq: Interrupt number.
1562662306a36Sopenharmony_ci * @dev_id: The device context pointer.
1562762306a36Sopenharmony_ci *
1562862306a36Sopenharmony_ci * This function is the device-level interrupt handler to device with SLI-4
1562962306a36Sopenharmony_ci * interface spec, called from the PCI layer when either MSI or Pin-IRQ
1563062306a36Sopenharmony_ci * interrupt mode is enabled and there is an event in the HBA which requires
1563162306a36Sopenharmony_ci * driver attention. This function invokes the slow-path interrupt attention
1563262306a36Sopenharmony_ci * handling function and fast-path interrupt attention handling function in
1563362306a36Sopenharmony_ci * turn to process the relevant HBA attention events. This function is called
1563462306a36Sopenharmony_ci * without any lock held. It gets the hbalock to access and update SLI data
1563562306a36Sopenharmony_ci * structures.
1563662306a36Sopenharmony_ci *
1563762306a36Sopenharmony_ci * This function returns IRQ_HANDLED when interrupt is handled, else it
1563862306a36Sopenharmony_ci * returns IRQ_NONE.
1563962306a36Sopenharmony_ci **/
1564062306a36Sopenharmony_ciirqreturn_t
1564162306a36Sopenharmony_cilpfc_sli4_intr_handler(int irq, void *dev_id)
1564262306a36Sopenharmony_ci{
1564362306a36Sopenharmony_ci	struct lpfc_hba  *phba;
1564462306a36Sopenharmony_ci	irqreturn_t hba_irq_rc;
1564562306a36Sopenharmony_ci	bool hba_handled = false;
1564662306a36Sopenharmony_ci	int qidx;
1564762306a36Sopenharmony_ci
1564862306a36Sopenharmony_ci	/* Get the driver's phba structure from the dev_id */
1564962306a36Sopenharmony_ci	phba = (struct lpfc_hba *)dev_id;
1565062306a36Sopenharmony_ci
1565162306a36Sopenharmony_ci	if (unlikely(!phba))
1565262306a36Sopenharmony_ci		return IRQ_NONE;
1565362306a36Sopenharmony_ci
1565462306a36Sopenharmony_ci	/*
1565562306a36Sopenharmony_ci	 * Invoke fast-path host attention interrupt handling as appropriate.
1565662306a36Sopenharmony_ci	 */
1565762306a36Sopenharmony_ci	for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
1565862306a36Sopenharmony_ci		hba_irq_rc = lpfc_sli4_hba_intr_handler(irq,
1565962306a36Sopenharmony_ci					&phba->sli4_hba.hba_eq_hdl[qidx]);
1566062306a36Sopenharmony_ci		if (hba_irq_rc == IRQ_HANDLED)
1566162306a36Sopenharmony_ci			hba_handled |= true;
1566262306a36Sopenharmony_ci	}
1566362306a36Sopenharmony_ci
1566462306a36Sopenharmony_ci	return (hba_handled == true) ? IRQ_HANDLED : IRQ_NONE;
1566562306a36Sopenharmony_ci} /* lpfc_sli4_intr_handler */
1566662306a36Sopenharmony_ci
1566762306a36Sopenharmony_civoid lpfc_sli4_poll_hbtimer(struct timer_list *t)
1566862306a36Sopenharmony_ci{
1566962306a36Sopenharmony_ci	struct lpfc_hba *phba = from_timer(phba, t, cpuhp_poll_timer);
1567062306a36Sopenharmony_ci	struct lpfc_queue *eq;
1567162306a36Sopenharmony_ci
1567262306a36Sopenharmony_ci	rcu_read_lock();
1567362306a36Sopenharmony_ci
1567462306a36Sopenharmony_ci	list_for_each_entry_rcu(eq, &phba->poll_list, _poll_list)
1567562306a36Sopenharmony_ci		lpfc_sli4_poll_eq(eq);
1567662306a36Sopenharmony_ci	if (!list_empty(&phba->poll_list))
1567762306a36Sopenharmony_ci		mod_timer(&phba->cpuhp_poll_timer,
1567862306a36Sopenharmony_ci			  jiffies + msecs_to_jiffies(LPFC_POLL_HB));
1567962306a36Sopenharmony_ci
1568062306a36Sopenharmony_ci	rcu_read_unlock();
1568162306a36Sopenharmony_ci}
1568262306a36Sopenharmony_ci
1568362306a36Sopenharmony_cistatic inline void lpfc_sli4_add_to_poll_list(struct lpfc_queue *eq)
1568462306a36Sopenharmony_ci{
1568562306a36Sopenharmony_ci	struct lpfc_hba *phba = eq->phba;
1568662306a36Sopenharmony_ci
1568762306a36Sopenharmony_ci	/* kickstart slowpath processing if needed */
1568862306a36Sopenharmony_ci	if (list_empty(&phba->poll_list))
1568962306a36Sopenharmony_ci		mod_timer(&phba->cpuhp_poll_timer,
1569062306a36Sopenharmony_ci			  jiffies + msecs_to_jiffies(LPFC_POLL_HB));
1569162306a36Sopenharmony_ci
1569262306a36Sopenharmony_ci	list_add_rcu(&eq->_poll_list, &phba->poll_list);
1569362306a36Sopenharmony_ci	synchronize_rcu();
1569462306a36Sopenharmony_ci}
1569562306a36Sopenharmony_ci
1569662306a36Sopenharmony_cistatic inline void lpfc_sli4_remove_from_poll_list(struct lpfc_queue *eq)
1569762306a36Sopenharmony_ci{
1569862306a36Sopenharmony_ci	struct lpfc_hba *phba = eq->phba;
1569962306a36Sopenharmony_ci
1570062306a36Sopenharmony_ci	/* Disable slowpath processing for this eq.  Kick start the eq
1570162306a36Sopenharmony_ci	 * by RE-ARMING the eq's ASAP
1570262306a36Sopenharmony_ci	 */
1570362306a36Sopenharmony_ci	list_del_rcu(&eq->_poll_list);
1570462306a36Sopenharmony_ci	synchronize_rcu();
1570562306a36Sopenharmony_ci
1570662306a36Sopenharmony_ci	if (list_empty(&phba->poll_list))
1570762306a36Sopenharmony_ci		del_timer_sync(&phba->cpuhp_poll_timer);
1570862306a36Sopenharmony_ci}
1570962306a36Sopenharmony_ci
1571062306a36Sopenharmony_civoid lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba)
1571162306a36Sopenharmony_ci{
1571262306a36Sopenharmony_ci	struct lpfc_queue *eq, *next;
1571362306a36Sopenharmony_ci
1571462306a36Sopenharmony_ci	list_for_each_entry_safe(eq, next, &phba->poll_list, _poll_list)
1571562306a36Sopenharmony_ci		list_del(&eq->_poll_list);
1571662306a36Sopenharmony_ci
1571762306a36Sopenharmony_ci	INIT_LIST_HEAD(&phba->poll_list);
1571862306a36Sopenharmony_ci	synchronize_rcu();
1571962306a36Sopenharmony_ci}
1572062306a36Sopenharmony_ci
1572162306a36Sopenharmony_cistatic inline void
1572262306a36Sopenharmony_ci__lpfc_sli4_switch_eqmode(struct lpfc_queue *eq, uint8_t mode)
1572362306a36Sopenharmony_ci{
1572462306a36Sopenharmony_ci	if (mode == eq->mode)
1572562306a36Sopenharmony_ci		return;
1572662306a36Sopenharmony_ci	/*
1572762306a36Sopenharmony_ci	 * currently this function is only called during a hotplug
1572862306a36Sopenharmony_ci	 * event and the cpu on which this function is executing
1572962306a36Sopenharmony_ci	 * is going offline.  By now the hotplug has instructed
1573062306a36Sopenharmony_ci	 * the scheduler to remove this cpu from cpu active mask.
1573162306a36Sopenharmony_ci	 * So we don't need to work about being put aside by the
1573262306a36Sopenharmony_ci	 * scheduler for a high priority process.  Yes, the inte-
1573362306a36Sopenharmony_ci	 * rrupts could come but they are known to retire ASAP.
1573462306a36Sopenharmony_ci	 */
1573562306a36Sopenharmony_ci
1573662306a36Sopenharmony_ci	/* Disable polling in the fastpath */
1573762306a36Sopenharmony_ci	WRITE_ONCE(eq->mode, mode);
1573862306a36Sopenharmony_ci	/* flush out the store buffer */
1573962306a36Sopenharmony_ci	smp_wmb();
1574062306a36Sopenharmony_ci
1574162306a36Sopenharmony_ci	/*
1574262306a36Sopenharmony_ci	 * Add this eq to the polling list and start polling. For
1574362306a36Sopenharmony_ci	 * a grace period both interrupt handler and poller will
1574462306a36Sopenharmony_ci	 * try to process the eq _but_ that's fine.  We have a
1574562306a36Sopenharmony_ci	 * synchronization mechanism in place (queue_claimed) to
1574662306a36Sopenharmony_ci	 * deal with it.  This is just a draining phase for int-
1574762306a36Sopenharmony_ci	 * errupt handler (not eq's) as we have guranteed through
1574862306a36Sopenharmony_ci	 * barrier that all the CPUs have seen the new CQ_POLLED
1574962306a36Sopenharmony_ci	 * state. which will effectively disable the REARMING of
1575062306a36Sopenharmony_ci	 * the EQ.  The whole idea is eq's die off eventually as
1575162306a36Sopenharmony_ci	 * we are not rearming EQ's anymore.
1575262306a36Sopenharmony_ci	 */
1575362306a36Sopenharmony_ci	mode ? lpfc_sli4_add_to_poll_list(eq) :
1575462306a36Sopenharmony_ci	       lpfc_sli4_remove_from_poll_list(eq);
1575562306a36Sopenharmony_ci}
1575662306a36Sopenharmony_ci
1575762306a36Sopenharmony_civoid lpfc_sli4_start_polling(struct lpfc_queue *eq)
1575862306a36Sopenharmony_ci{
1575962306a36Sopenharmony_ci	__lpfc_sli4_switch_eqmode(eq, LPFC_EQ_POLL);
1576062306a36Sopenharmony_ci}
1576162306a36Sopenharmony_ci
1576262306a36Sopenharmony_civoid lpfc_sli4_stop_polling(struct lpfc_queue *eq)
1576362306a36Sopenharmony_ci{
1576462306a36Sopenharmony_ci	struct lpfc_hba *phba = eq->phba;
1576562306a36Sopenharmony_ci
1576662306a36Sopenharmony_ci	__lpfc_sli4_switch_eqmode(eq, LPFC_EQ_INTERRUPT);
1576762306a36Sopenharmony_ci
1576862306a36Sopenharmony_ci	/* Kick start for the pending io's in h/w.
1576962306a36Sopenharmony_ci	 * Once we switch back to interrupt processing on a eq
1577062306a36Sopenharmony_ci	 * the io path completion will only arm eq's when it
1577162306a36Sopenharmony_ci	 * receives a completion.  But since eq's are in disa-
1577262306a36Sopenharmony_ci	 * rmed state it doesn't receive a completion.  This
1577362306a36Sopenharmony_ci	 * creates a deadlock scenaro.
1577462306a36Sopenharmony_ci	 */
1577562306a36Sopenharmony_ci	phba->sli4_hba.sli4_write_eq_db(phba, eq, 0, LPFC_QUEUE_REARM);
1577662306a36Sopenharmony_ci}
1577762306a36Sopenharmony_ci
1577862306a36Sopenharmony_ci/**
1577962306a36Sopenharmony_ci * lpfc_sli4_queue_free - free a queue structure and associated memory
1578062306a36Sopenharmony_ci * @queue: The queue structure to free.
1578162306a36Sopenharmony_ci *
1578262306a36Sopenharmony_ci * This function frees a queue structure and the DMAable memory used for
1578362306a36Sopenharmony_ci * the host resident queue. This function must be called after destroying the
1578462306a36Sopenharmony_ci * queue on the HBA.
1578562306a36Sopenharmony_ci **/
1578662306a36Sopenharmony_civoid
1578762306a36Sopenharmony_cilpfc_sli4_queue_free(struct lpfc_queue *queue)
1578862306a36Sopenharmony_ci{
1578962306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
1579062306a36Sopenharmony_ci
1579162306a36Sopenharmony_ci	if (!queue)
1579262306a36Sopenharmony_ci		return;
1579362306a36Sopenharmony_ci
1579462306a36Sopenharmony_ci	if (!list_empty(&queue->wq_list))
1579562306a36Sopenharmony_ci		list_del(&queue->wq_list);
1579662306a36Sopenharmony_ci
1579762306a36Sopenharmony_ci	while (!list_empty(&queue->page_list)) {
1579862306a36Sopenharmony_ci		list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf,
1579962306a36Sopenharmony_ci				 list);
1580062306a36Sopenharmony_ci		dma_free_coherent(&queue->phba->pcidev->dev, queue->page_size,
1580162306a36Sopenharmony_ci				  dmabuf->virt, dmabuf->phys);
1580262306a36Sopenharmony_ci		kfree(dmabuf);
1580362306a36Sopenharmony_ci	}
1580462306a36Sopenharmony_ci	if (queue->rqbp) {
1580562306a36Sopenharmony_ci		lpfc_free_rq_buffer(queue->phba, queue);
1580662306a36Sopenharmony_ci		kfree(queue->rqbp);
1580762306a36Sopenharmony_ci	}
1580862306a36Sopenharmony_ci
1580962306a36Sopenharmony_ci	if (!list_empty(&queue->cpu_list))
1581062306a36Sopenharmony_ci		list_del(&queue->cpu_list);
1581162306a36Sopenharmony_ci
1581262306a36Sopenharmony_ci	kfree(queue);
1581362306a36Sopenharmony_ci	return;
1581462306a36Sopenharmony_ci}
1581562306a36Sopenharmony_ci
1581662306a36Sopenharmony_ci/**
1581762306a36Sopenharmony_ci * lpfc_sli4_queue_alloc - Allocate and initialize a queue structure
1581862306a36Sopenharmony_ci * @phba: The HBA that this queue is being created on.
1581962306a36Sopenharmony_ci * @page_size: The size of a queue page
1582062306a36Sopenharmony_ci * @entry_size: The size of each queue entry for this queue.
1582162306a36Sopenharmony_ci * @entry_count: The number of entries that this queue will handle.
1582262306a36Sopenharmony_ci * @cpu: The cpu that will primarily utilize this queue.
1582362306a36Sopenharmony_ci *
1582462306a36Sopenharmony_ci * This function allocates a queue structure and the DMAable memory used for
1582562306a36Sopenharmony_ci * the host resident queue. This function must be called before creating the
1582662306a36Sopenharmony_ci * queue on the HBA.
1582762306a36Sopenharmony_ci **/
1582862306a36Sopenharmony_cistruct lpfc_queue *
1582962306a36Sopenharmony_cilpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size,
1583062306a36Sopenharmony_ci		      uint32_t entry_size, uint32_t entry_count, int cpu)
1583162306a36Sopenharmony_ci{
1583262306a36Sopenharmony_ci	struct lpfc_queue *queue;
1583362306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
1583462306a36Sopenharmony_ci	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
1583562306a36Sopenharmony_ci	uint16_t x, pgcnt;
1583662306a36Sopenharmony_ci
1583762306a36Sopenharmony_ci	if (!phba->sli4_hba.pc_sli4_params.supported)
1583862306a36Sopenharmony_ci		hw_page_size = page_size;
1583962306a36Sopenharmony_ci
1584062306a36Sopenharmony_ci	pgcnt = ALIGN(entry_size * entry_count, hw_page_size) / hw_page_size;
1584162306a36Sopenharmony_ci
1584262306a36Sopenharmony_ci	/* If needed, Adjust page count to match the max the adapter supports */
1584362306a36Sopenharmony_ci	if (pgcnt > phba->sli4_hba.pc_sli4_params.wqpcnt)
1584462306a36Sopenharmony_ci		pgcnt = phba->sli4_hba.pc_sli4_params.wqpcnt;
1584562306a36Sopenharmony_ci
1584662306a36Sopenharmony_ci	queue = kzalloc_node(sizeof(*queue) + (sizeof(void *) * pgcnt),
1584762306a36Sopenharmony_ci			     GFP_KERNEL, cpu_to_node(cpu));
1584862306a36Sopenharmony_ci	if (!queue)
1584962306a36Sopenharmony_ci		return NULL;
1585062306a36Sopenharmony_ci
1585162306a36Sopenharmony_ci	INIT_LIST_HEAD(&queue->list);
1585262306a36Sopenharmony_ci	INIT_LIST_HEAD(&queue->_poll_list);
1585362306a36Sopenharmony_ci	INIT_LIST_HEAD(&queue->wq_list);
1585462306a36Sopenharmony_ci	INIT_LIST_HEAD(&queue->wqfull_list);
1585562306a36Sopenharmony_ci	INIT_LIST_HEAD(&queue->page_list);
1585662306a36Sopenharmony_ci	INIT_LIST_HEAD(&queue->child_list);
1585762306a36Sopenharmony_ci	INIT_LIST_HEAD(&queue->cpu_list);
1585862306a36Sopenharmony_ci
1585962306a36Sopenharmony_ci	/* Set queue parameters now.  If the system cannot provide memory
1586062306a36Sopenharmony_ci	 * resources, the free routine needs to know what was allocated.
1586162306a36Sopenharmony_ci	 */
1586262306a36Sopenharmony_ci	queue->page_count = pgcnt;
1586362306a36Sopenharmony_ci	queue->q_pgs = (void **)&queue[1];
1586462306a36Sopenharmony_ci	queue->entry_cnt_per_pg = hw_page_size / entry_size;
1586562306a36Sopenharmony_ci	queue->entry_size = entry_size;
1586662306a36Sopenharmony_ci	queue->entry_count = entry_count;
1586762306a36Sopenharmony_ci	queue->page_size = hw_page_size;
1586862306a36Sopenharmony_ci	queue->phba = phba;
1586962306a36Sopenharmony_ci
1587062306a36Sopenharmony_ci	for (x = 0; x < queue->page_count; x++) {
1587162306a36Sopenharmony_ci		dmabuf = kzalloc_node(sizeof(*dmabuf), GFP_KERNEL,
1587262306a36Sopenharmony_ci				      dev_to_node(&phba->pcidev->dev));
1587362306a36Sopenharmony_ci		if (!dmabuf)
1587462306a36Sopenharmony_ci			goto out_fail;
1587562306a36Sopenharmony_ci		dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
1587662306a36Sopenharmony_ci						  hw_page_size, &dmabuf->phys,
1587762306a36Sopenharmony_ci						  GFP_KERNEL);
1587862306a36Sopenharmony_ci		if (!dmabuf->virt) {
1587962306a36Sopenharmony_ci			kfree(dmabuf);
1588062306a36Sopenharmony_ci			goto out_fail;
1588162306a36Sopenharmony_ci		}
1588262306a36Sopenharmony_ci		dmabuf->buffer_tag = x;
1588362306a36Sopenharmony_ci		list_add_tail(&dmabuf->list, &queue->page_list);
1588462306a36Sopenharmony_ci		/* use lpfc_sli4_qe to index a paritcular entry in this page */
1588562306a36Sopenharmony_ci		queue->q_pgs[x] = dmabuf->virt;
1588662306a36Sopenharmony_ci	}
1588762306a36Sopenharmony_ci	INIT_WORK(&queue->irqwork, lpfc_sli4_hba_process_cq);
1588862306a36Sopenharmony_ci	INIT_WORK(&queue->spwork, lpfc_sli4_sp_process_cq);
1588962306a36Sopenharmony_ci	INIT_DELAYED_WORK(&queue->sched_irqwork, lpfc_sli4_dly_hba_process_cq);
1589062306a36Sopenharmony_ci	INIT_DELAYED_WORK(&queue->sched_spwork, lpfc_sli4_dly_sp_process_cq);
1589162306a36Sopenharmony_ci
1589262306a36Sopenharmony_ci	/* notify_interval will be set during q creation */
1589362306a36Sopenharmony_ci
1589462306a36Sopenharmony_ci	return queue;
1589562306a36Sopenharmony_ciout_fail:
1589662306a36Sopenharmony_ci	lpfc_sli4_queue_free(queue);
1589762306a36Sopenharmony_ci	return NULL;
1589862306a36Sopenharmony_ci}
1589962306a36Sopenharmony_ci
1590062306a36Sopenharmony_ci/**
1590162306a36Sopenharmony_ci * lpfc_dual_chute_pci_bar_map - Map pci base address register to host memory
1590262306a36Sopenharmony_ci * @phba: HBA structure that indicates port to create a queue on.
1590362306a36Sopenharmony_ci * @pci_barset: PCI BAR set flag.
1590462306a36Sopenharmony_ci *
1590562306a36Sopenharmony_ci * This function shall perform iomap of the specified PCI BAR address to host
1590662306a36Sopenharmony_ci * memory address if not already done so and return it. The returned host
1590762306a36Sopenharmony_ci * memory address can be NULL.
1590862306a36Sopenharmony_ci */
1590962306a36Sopenharmony_cistatic void __iomem *
1591062306a36Sopenharmony_cilpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset)
1591162306a36Sopenharmony_ci{
1591262306a36Sopenharmony_ci	if (!phba->pcidev)
1591362306a36Sopenharmony_ci		return NULL;
1591462306a36Sopenharmony_ci
1591562306a36Sopenharmony_ci	switch (pci_barset) {
1591662306a36Sopenharmony_ci	case WQ_PCI_BAR_0_AND_1:
1591762306a36Sopenharmony_ci		return phba->pci_bar0_memmap_p;
1591862306a36Sopenharmony_ci	case WQ_PCI_BAR_2_AND_3:
1591962306a36Sopenharmony_ci		return phba->pci_bar2_memmap_p;
1592062306a36Sopenharmony_ci	case WQ_PCI_BAR_4_AND_5:
1592162306a36Sopenharmony_ci		return phba->pci_bar4_memmap_p;
1592262306a36Sopenharmony_ci	default:
1592362306a36Sopenharmony_ci		break;
1592462306a36Sopenharmony_ci	}
1592562306a36Sopenharmony_ci	return NULL;
1592662306a36Sopenharmony_ci}
1592762306a36Sopenharmony_ci
1592862306a36Sopenharmony_ci/**
1592962306a36Sopenharmony_ci * lpfc_modify_hba_eq_delay - Modify Delay Multiplier on EQs
1593062306a36Sopenharmony_ci * @phba: HBA structure that EQs are on.
1593162306a36Sopenharmony_ci * @startq: The starting EQ index to modify
1593262306a36Sopenharmony_ci * @numq: The number of EQs (consecutive indexes) to modify
1593362306a36Sopenharmony_ci * @usdelay: amount of delay
1593462306a36Sopenharmony_ci *
1593562306a36Sopenharmony_ci * This function revises the EQ delay on 1 or more EQs. The EQ delay
1593662306a36Sopenharmony_ci * is set either by writing to a register (if supported by the SLI Port)
1593762306a36Sopenharmony_ci * or by mailbox command. The mailbox command allows several EQs to be
1593862306a36Sopenharmony_ci * updated at once.
1593962306a36Sopenharmony_ci *
1594062306a36Sopenharmony_ci * The @phba struct is used to send a mailbox command to HBA. The @startq
1594162306a36Sopenharmony_ci * is used to get the starting EQ index to change. The @numq value is
1594262306a36Sopenharmony_ci * used to specify how many consecutive EQ indexes, starting at EQ index,
1594362306a36Sopenharmony_ci * are to be changed. This function is asynchronous and will wait for any
1594462306a36Sopenharmony_ci * mailbox commands to finish before returning.
1594562306a36Sopenharmony_ci *
1594662306a36Sopenharmony_ci * On success this function will return a zero. If unable to allocate
1594762306a36Sopenharmony_ci * enough memory this function will return -ENOMEM. If a mailbox command
1594862306a36Sopenharmony_ci * fails this function will return -ENXIO. Note: on ENXIO, some EQs may
1594962306a36Sopenharmony_ci * have had their delay multipler changed.
1595062306a36Sopenharmony_ci **/
1595162306a36Sopenharmony_civoid
1595262306a36Sopenharmony_cilpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
1595362306a36Sopenharmony_ci			 uint32_t numq, uint32_t usdelay)
1595462306a36Sopenharmony_ci{
1595562306a36Sopenharmony_ci	struct lpfc_mbx_modify_eq_delay *eq_delay;
1595662306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1595762306a36Sopenharmony_ci	struct lpfc_queue *eq;
1595862306a36Sopenharmony_ci	int cnt = 0, rc, length;
1595962306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1596062306a36Sopenharmony_ci	uint32_t dmult;
1596162306a36Sopenharmony_ci	int qidx;
1596262306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1596362306a36Sopenharmony_ci
1596462306a36Sopenharmony_ci	if (startq >= phba->cfg_irq_chann)
1596562306a36Sopenharmony_ci		return;
1596662306a36Sopenharmony_ci
1596762306a36Sopenharmony_ci	if (usdelay > 0xFFFF) {
1596862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP | LOG_NVME,
1596962306a36Sopenharmony_ci				"6429 usdelay %d too large. Scaled down to "
1597062306a36Sopenharmony_ci				"0xFFFF.\n", usdelay);
1597162306a36Sopenharmony_ci		usdelay = 0xFFFF;
1597262306a36Sopenharmony_ci	}
1597362306a36Sopenharmony_ci
1597462306a36Sopenharmony_ci	/* set values by EQ_DELAY register if supported */
1597562306a36Sopenharmony_ci	if (phba->sli.sli_flag & LPFC_SLI_USE_EQDR) {
1597662306a36Sopenharmony_ci		for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) {
1597762306a36Sopenharmony_ci			eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
1597862306a36Sopenharmony_ci			if (!eq)
1597962306a36Sopenharmony_ci				continue;
1598062306a36Sopenharmony_ci
1598162306a36Sopenharmony_ci			lpfc_sli4_mod_hba_eq_delay(phba, eq, usdelay);
1598262306a36Sopenharmony_ci
1598362306a36Sopenharmony_ci			if (++cnt >= numq)
1598462306a36Sopenharmony_ci				break;
1598562306a36Sopenharmony_ci		}
1598662306a36Sopenharmony_ci		return;
1598762306a36Sopenharmony_ci	}
1598862306a36Sopenharmony_ci
1598962306a36Sopenharmony_ci	/* Otherwise, set values by mailbox cmd */
1599062306a36Sopenharmony_ci
1599162306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1599262306a36Sopenharmony_ci	if (!mbox) {
1599362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1599462306a36Sopenharmony_ci				"6428 Failed allocating mailbox cmd buffer."
1599562306a36Sopenharmony_ci				" EQ delay was not set.\n");
1599662306a36Sopenharmony_ci		return;
1599762306a36Sopenharmony_ci	}
1599862306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_modify_eq_delay) -
1599962306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1600062306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
1600162306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_MODIFY_EQ_DELAY,
1600262306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1600362306a36Sopenharmony_ci	eq_delay = &mbox->u.mqe.un.eq_delay;
1600462306a36Sopenharmony_ci
1600562306a36Sopenharmony_ci	/* Calculate delay multiper from maximum interrupt per second */
1600662306a36Sopenharmony_ci	dmult = (usdelay * LPFC_DMULT_CONST) / LPFC_SEC_TO_USEC;
1600762306a36Sopenharmony_ci	if (dmult)
1600862306a36Sopenharmony_ci		dmult--;
1600962306a36Sopenharmony_ci	if (dmult > LPFC_DMULT_MAX)
1601062306a36Sopenharmony_ci		dmult = LPFC_DMULT_MAX;
1601162306a36Sopenharmony_ci
1601262306a36Sopenharmony_ci	for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) {
1601362306a36Sopenharmony_ci		eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
1601462306a36Sopenharmony_ci		if (!eq)
1601562306a36Sopenharmony_ci			continue;
1601662306a36Sopenharmony_ci		eq->q_mode = usdelay;
1601762306a36Sopenharmony_ci		eq_delay->u.request.eq[cnt].eq_id = eq->queue_id;
1601862306a36Sopenharmony_ci		eq_delay->u.request.eq[cnt].phase = 0;
1601962306a36Sopenharmony_ci		eq_delay->u.request.eq[cnt].delay_multi = dmult;
1602062306a36Sopenharmony_ci
1602162306a36Sopenharmony_ci		if (++cnt >= numq)
1602262306a36Sopenharmony_ci			break;
1602362306a36Sopenharmony_ci	}
1602462306a36Sopenharmony_ci	eq_delay->u.request.num_eq = cnt;
1602562306a36Sopenharmony_ci
1602662306a36Sopenharmony_ci	mbox->vport = phba->pport;
1602762306a36Sopenharmony_ci	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
1602862306a36Sopenharmony_ci	mbox->ctx_ndlp = NULL;
1602962306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1603062306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *) &eq_delay->header.cfg_shdr;
1603162306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1603262306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1603362306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1603462306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1603562306a36Sopenharmony_ci				"2512 MODIFY_EQ_DELAY mailbox failed with "
1603662306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1603762306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1603862306a36Sopenharmony_ci	}
1603962306a36Sopenharmony_ci	mempool_free(mbox, phba->mbox_mem_pool);
1604062306a36Sopenharmony_ci	return;
1604162306a36Sopenharmony_ci}
1604262306a36Sopenharmony_ci
1604362306a36Sopenharmony_ci/**
1604462306a36Sopenharmony_ci * lpfc_eq_create - Create an Event Queue on the HBA
1604562306a36Sopenharmony_ci * @phba: HBA structure that indicates port to create a queue on.
1604662306a36Sopenharmony_ci * @eq: The queue structure to use to create the event queue.
1604762306a36Sopenharmony_ci * @imax: The maximum interrupt per second limit.
1604862306a36Sopenharmony_ci *
1604962306a36Sopenharmony_ci * This function creates an event queue, as detailed in @eq, on a port,
1605062306a36Sopenharmony_ci * described by @phba by sending an EQ_CREATE mailbox command to the HBA.
1605162306a36Sopenharmony_ci *
1605262306a36Sopenharmony_ci * The @phba struct is used to send mailbox command to HBA. The @eq struct
1605362306a36Sopenharmony_ci * is used to get the entry count and entry size that are necessary to
1605462306a36Sopenharmony_ci * determine the number of pages to allocate and use for this queue. This
1605562306a36Sopenharmony_ci * function will send the EQ_CREATE mailbox command to the HBA to setup the
1605662306a36Sopenharmony_ci * event queue. This function is asynchronous and will wait for the mailbox
1605762306a36Sopenharmony_ci * command to finish before continuing.
1605862306a36Sopenharmony_ci *
1605962306a36Sopenharmony_ci * On success this function will return a zero. If unable to allocate enough
1606062306a36Sopenharmony_ci * memory this function will return -ENOMEM. If the queue create mailbox command
1606162306a36Sopenharmony_ci * fails this function will return -ENXIO.
1606262306a36Sopenharmony_ci **/
1606362306a36Sopenharmony_ciint
1606462306a36Sopenharmony_cilpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
1606562306a36Sopenharmony_ci{
1606662306a36Sopenharmony_ci	struct lpfc_mbx_eq_create *eq_create;
1606762306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1606862306a36Sopenharmony_ci	int rc, length, status = 0;
1606962306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
1607062306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1607162306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1607262306a36Sopenharmony_ci	uint16_t dmult;
1607362306a36Sopenharmony_ci	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
1607462306a36Sopenharmony_ci
1607562306a36Sopenharmony_ci	/* sanity check on queue memory */
1607662306a36Sopenharmony_ci	if (!eq)
1607762306a36Sopenharmony_ci		return -ENODEV;
1607862306a36Sopenharmony_ci	if (!phba->sli4_hba.pc_sli4_params.supported)
1607962306a36Sopenharmony_ci		hw_page_size = SLI4_PAGE_SIZE;
1608062306a36Sopenharmony_ci
1608162306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1608262306a36Sopenharmony_ci	if (!mbox)
1608362306a36Sopenharmony_ci		return -ENOMEM;
1608462306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_eq_create) -
1608562306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1608662306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
1608762306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_EQ_CREATE,
1608862306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1608962306a36Sopenharmony_ci	eq_create = &mbox->u.mqe.un.eq_create;
1609062306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *) &eq_create->header.cfg_shdr;
1609162306a36Sopenharmony_ci	bf_set(lpfc_mbx_eq_create_num_pages, &eq_create->u.request,
1609262306a36Sopenharmony_ci	       eq->page_count);
1609362306a36Sopenharmony_ci	bf_set(lpfc_eq_context_size, &eq_create->u.request.context,
1609462306a36Sopenharmony_ci	       LPFC_EQE_SIZE);
1609562306a36Sopenharmony_ci	bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1);
1609662306a36Sopenharmony_ci
1609762306a36Sopenharmony_ci	/* Use version 2 of CREATE_EQ if eqav is set */
1609862306a36Sopenharmony_ci	if (phba->sli4_hba.pc_sli4_params.eqav) {
1609962306a36Sopenharmony_ci		bf_set(lpfc_mbox_hdr_version, &shdr->request,
1610062306a36Sopenharmony_ci		       LPFC_Q_CREATE_VERSION_2);
1610162306a36Sopenharmony_ci		bf_set(lpfc_eq_context_autovalid, &eq_create->u.request.context,
1610262306a36Sopenharmony_ci		       phba->sli4_hba.pc_sli4_params.eqav);
1610362306a36Sopenharmony_ci	}
1610462306a36Sopenharmony_ci
1610562306a36Sopenharmony_ci	/* don't setup delay multiplier using EQ_CREATE */
1610662306a36Sopenharmony_ci	dmult = 0;
1610762306a36Sopenharmony_ci	bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context,
1610862306a36Sopenharmony_ci	       dmult);
1610962306a36Sopenharmony_ci	switch (eq->entry_count) {
1611062306a36Sopenharmony_ci	default:
1611162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1611262306a36Sopenharmony_ci				"0360 Unsupported EQ count. (%d)\n",
1611362306a36Sopenharmony_ci				eq->entry_count);
1611462306a36Sopenharmony_ci		if (eq->entry_count < 256) {
1611562306a36Sopenharmony_ci			status = -EINVAL;
1611662306a36Sopenharmony_ci			goto out;
1611762306a36Sopenharmony_ci		}
1611862306a36Sopenharmony_ci		fallthrough;	/* otherwise default to smallest count */
1611962306a36Sopenharmony_ci	case 256:
1612062306a36Sopenharmony_ci		bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
1612162306a36Sopenharmony_ci		       LPFC_EQ_CNT_256);
1612262306a36Sopenharmony_ci		break;
1612362306a36Sopenharmony_ci	case 512:
1612462306a36Sopenharmony_ci		bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
1612562306a36Sopenharmony_ci		       LPFC_EQ_CNT_512);
1612662306a36Sopenharmony_ci		break;
1612762306a36Sopenharmony_ci	case 1024:
1612862306a36Sopenharmony_ci		bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
1612962306a36Sopenharmony_ci		       LPFC_EQ_CNT_1024);
1613062306a36Sopenharmony_ci		break;
1613162306a36Sopenharmony_ci	case 2048:
1613262306a36Sopenharmony_ci		bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
1613362306a36Sopenharmony_ci		       LPFC_EQ_CNT_2048);
1613462306a36Sopenharmony_ci		break;
1613562306a36Sopenharmony_ci	case 4096:
1613662306a36Sopenharmony_ci		bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
1613762306a36Sopenharmony_ci		       LPFC_EQ_CNT_4096);
1613862306a36Sopenharmony_ci		break;
1613962306a36Sopenharmony_ci	}
1614062306a36Sopenharmony_ci	list_for_each_entry(dmabuf, &eq->page_list, list) {
1614162306a36Sopenharmony_ci		memset(dmabuf->virt, 0, hw_page_size);
1614262306a36Sopenharmony_ci		eq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
1614362306a36Sopenharmony_ci					putPaddrLow(dmabuf->phys);
1614462306a36Sopenharmony_ci		eq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
1614562306a36Sopenharmony_ci					putPaddrHigh(dmabuf->phys);
1614662306a36Sopenharmony_ci	}
1614762306a36Sopenharmony_ci	mbox->vport = phba->pport;
1614862306a36Sopenharmony_ci	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
1614962306a36Sopenharmony_ci	mbox->ctx_buf = NULL;
1615062306a36Sopenharmony_ci	mbox->ctx_ndlp = NULL;
1615162306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1615262306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1615362306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1615462306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1615562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1615662306a36Sopenharmony_ci				"2500 EQ_CREATE mailbox failed with "
1615762306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1615862306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1615962306a36Sopenharmony_ci		status = -ENXIO;
1616062306a36Sopenharmony_ci	}
1616162306a36Sopenharmony_ci	eq->type = LPFC_EQ;
1616262306a36Sopenharmony_ci	eq->subtype = LPFC_NONE;
1616362306a36Sopenharmony_ci	eq->queue_id = bf_get(lpfc_mbx_eq_create_q_id, &eq_create->u.response);
1616462306a36Sopenharmony_ci	if (eq->queue_id == 0xFFFF)
1616562306a36Sopenharmony_ci		status = -ENXIO;
1616662306a36Sopenharmony_ci	eq->host_index = 0;
1616762306a36Sopenharmony_ci	eq->notify_interval = LPFC_EQ_NOTIFY_INTRVL;
1616862306a36Sopenharmony_ci	eq->max_proc_limit = LPFC_EQ_MAX_PROC_LIMIT;
1616962306a36Sopenharmony_ciout:
1617062306a36Sopenharmony_ci	mempool_free(mbox, phba->mbox_mem_pool);
1617162306a36Sopenharmony_ci	return status;
1617262306a36Sopenharmony_ci}
1617362306a36Sopenharmony_ci
1617462306a36Sopenharmony_ci/**
1617562306a36Sopenharmony_ci * lpfc_sli4_hba_intr_handler_th - SLI4 HBA threaded interrupt handler
1617662306a36Sopenharmony_ci * @irq: Interrupt number.
1617762306a36Sopenharmony_ci * @dev_id: The device context pointer.
1617862306a36Sopenharmony_ci *
1617962306a36Sopenharmony_ci * This routine is a mirror of lpfc_sli4_hba_intr_handler, but executed within
1618062306a36Sopenharmony_ci * threaded irq context.
1618162306a36Sopenharmony_ci *
1618262306a36Sopenharmony_ci * Returns
1618362306a36Sopenharmony_ci * IRQ_HANDLED - interrupt is handled
1618462306a36Sopenharmony_ci * IRQ_NONE - otherwise
1618562306a36Sopenharmony_ci **/
1618662306a36Sopenharmony_ciirqreturn_t lpfc_sli4_hba_intr_handler_th(int irq, void *dev_id)
1618762306a36Sopenharmony_ci{
1618862306a36Sopenharmony_ci	struct lpfc_hba *phba;
1618962306a36Sopenharmony_ci	struct lpfc_hba_eq_hdl *hba_eq_hdl;
1619062306a36Sopenharmony_ci	struct lpfc_queue *fpeq;
1619162306a36Sopenharmony_ci	int ecount = 0;
1619262306a36Sopenharmony_ci	int hba_eqidx;
1619362306a36Sopenharmony_ci	struct lpfc_eq_intr_info *eqi;
1619462306a36Sopenharmony_ci
1619562306a36Sopenharmony_ci	/* Get the driver's phba structure from the dev_id */
1619662306a36Sopenharmony_ci	hba_eq_hdl = (struct lpfc_hba_eq_hdl *)dev_id;
1619762306a36Sopenharmony_ci	phba = hba_eq_hdl->phba;
1619862306a36Sopenharmony_ci	hba_eqidx = hba_eq_hdl->idx;
1619962306a36Sopenharmony_ci
1620062306a36Sopenharmony_ci	if (unlikely(!phba))
1620162306a36Sopenharmony_ci		return IRQ_NONE;
1620262306a36Sopenharmony_ci	if (unlikely(!phba->sli4_hba.hdwq))
1620362306a36Sopenharmony_ci		return IRQ_NONE;
1620462306a36Sopenharmony_ci
1620562306a36Sopenharmony_ci	/* Get to the EQ struct associated with this vector */
1620662306a36Sopenharmony_ci	fpeq = phba->sli4_hba.hba_eq_hdl[hba_eqidx].eq;
1620762306a36Sopenharmony_ci	if (unlikely(!fpeq))
1620862306a36Sopenharmony_ci		return IRQ_NONE;
1620962306a36Sopenharmony_ci
1621062306a36Sopenharmony_ci	eqi = per_cpu_ptr(phba->sli4_hba.eq_info, raw_smp_processor_id());
1621162306a36Sopenharmony_ci	eqi->icnt++;
1621262306a36Sopenharmony_ci
1621362306a36Sopenharmony_ci	fpeq->last_cpu = raw_smp_processor_id();
1621462306a36Sopenharmony_ci
1621562306a36Sopenharmony_ci	if (eqi->icnt > LPFC_EQD_ISR_TRIGGER &&
1621662306a36Sopenharmony_ci	    fpeq->q_flag & HBA_EQ_DELAY_CHK &&
1621762306a36Sopenharmony_ci	    phba->cfg_auto_imax &&
1621862306a36Sopenharmony_ci	    fpeq->q_mode != LPFC_MAX_AUTO_EQ_DELAY &&
1621962306a36Sopenharmony_ci	    phba->sli.sli_flag & LPFC_SLI_USE_EQDR)
1622062306a36Sopenharmony_ci		lpfc_sli4_mod_hba_eq_delay(phba, fpeq, LPFC_MAX_AUTO_EQ_DELAY);
1622162306a36Sopenharmony_ci
1622262306a36Sopenharmony_ci	/* process and rearm the EQ */
1622362306a36Sopenharmony_ci	ecount = lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM,
1622462306a36Sopenharmony_ci				      LPFC_THREADED_IRQ);
1622562306a36Sopenharmony_ci
1622662306a36Sopenharmony_ci	if (unlikely(ecount == 0)) {
1622762306a36Sopenharmony_ci		fpeq->EQ_no_entry++;
1622862306a36Sopenharmony_ci		if (phba->intr_type == MSIX)
1622962306a36Sopenharmony_ci			/* MSI-X treated interrupt served as no EQ share INT */
1623062306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
1623162306a36Sopenharmony_ci					"3358 MSI-X interrupt with no EQE\n");
1623262306a36Sopenharmony_ci		else
1623362306a36Sopenharmony_ci			/* Non MSI-X treated on interrupt as EQ share INT */
1623462306a36Sopenharmony_ci			return IRQ_NONE;
1623562306a36Sopenharmony_ci	}
1623662306a36Sopenharmony_ci	return IRQ_HANDLED;
1623762306a36Sopenharmony_ci}
1623862306a36Sopenharmony_ci
1623962306a36Sopenharmony_ci/**
1624062306a36Sopenharmony_ci * lpfc_cq_create - Create a Completion Queue on the HBA
1624162306a36Sopenharmony_ci * @phba: HBA structure that indicates port to create a queue on.
1624262306a36Sopenharmony_ci * @cq: The queue structure to use to create the completion queue.
1624362306a36Sopenharmony_ci * @eq: The event queue to bind this completion queue to.
1624462306a36Sopenharmony_ci * @type: Type of queue (EQ, GCQ, MCQ, WCQ, etc).
1624562306a36Sopenharmony_ci * @subtype: Functional purpose of the queue (MBOX, IO, ELS, NVMET, etc).
1624662306a36Sopenharmony_ci *
1624762306a36Sopenharmony_ci * This function creates a completion queue, as detailed in @wq, on a port,
1624862306a36Sopenharmony_ci * described by @phba by sending a CQ_CREATE mailbox command to the HBA.
1624962306a36Sopenharmony_ci *
1625062306a36Sopenharmony_ci * The @phba struct is used to send mailbox command to HBA. The @cq struct
1625162306a36Sopenharmony_ci * is used to get the entry count and entry size that are necessary to
1625262306a36Sopenharmony_ci * determine the number of pages to allocate and use for this queue. The @eq
1625362306a36Sopenharmony_ci * is used to indicate which event queue to bind this completion queue to. This
1625462306a36Sopenharmony_ci * function will send the CQ_CREATE mailbox command to the HBA to setup the
1625562306a36Sopenharmony_ci * completion queue. This function is asynchronous and will wait for the mailbox
1625662306a36Sopenharmony_ci * command to finish before continuing.
1625762306a36Sopenharmony_ci *
1625862306a36Sopenharmony_ci * On success this function will return a zero. If unable to allocate enough
1625962306a36Sopenharmony_ci * memory this function will return -ENOMEM. If the queue create mailbox command
1626062306a36Sopenharmony_ci * fails this function will return -ENXIO.
1626162306a36Sopenharmony_ci **/
1626262306a36Sopenharmony_ciint
1626362306a36Sopenharmony_cilpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
1626462306a36Sopenharmony_ci	       struct lpfc_queue *eq, uint32_t type, uint32_t subtype)
1626562306a36Sopenharmony_ci{
1626662306a36Sopenharmony_ci	struct lpfc_mbx_cq_create *cq_create;
1626762306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
1626862306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1626962306a36Sopenharmony_ci	int rc, length, status = 0;
1627062306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1627162306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1627262306a36Sopenharmony_ci
1627362306a36Sopenharmony_ci	/* sanity check on queue memory */
1627462306a36Sopenharmony_ci	if (!cq || !eq)
1627562306a36Sopenharmony_ci		return -ENODEV;
1627662306a36Sopenharmony_ci
1627762306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1627862306a36Sopenharmony_ci	if (!mbox)
1627962306a36Sopenharmony_ci		return -ENOMEM;
1628062306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_cq_create) -
1628162306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1628262306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
1628362306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_CQ_CREATE,
1628462306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1628562306a36Sopenharmony_ci	cq_create = &mbox->u.mqe.un.cq_create;
1628662306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *) &cq_create->header.cfg_shdr;
1628762306a36Sopenharmony_ci	bf_set(lpfc_mbx_cq_create_num_pages, &cq_create->u.request,
1628862306a36Sopenharmony_ci		    cq->page_count);
1628962306a36Sopenharmony_ci	bf_set(lpfc_cq_context_event, &cq_create->u.request.context, 1);
1629062306a36Sopenharmony_ci	bf_set(lpfc_cq_context_valid, &cq_create->u.request.context, 1);
1629162306a36Sopenharmony_ci	bf_set(lpfc_mbox_hdr_version, &shdr->request,
1629262306a36Sopenharmony_ci	       phba->sli4_hba.pc_sli4_params.cqv);
1629362306a36Sopenharmony_ci	if (phba->sli4_hba.pc_sli4_params.cqv == LPFC_Q_CREATE_VERSION_2) {
1629462306a36Sopenharmony_ci		bf_set(lpfc_mbx_cq_create_page_size, &cq_create->u.request,
1629562306a36Sopenharmony_ci		       (cq->page_size / SLI4_PAGE_SIZE));
1629662306a36Sopenharmony_ci		bf_set(lpfc_cq_eq_id_2, &cq_create->u.request.context,
1629762306a36Sopenharmony_ci		       eq->queue_id);
1629862306a36Sopenharmony_ci		bf_set(lpfc_cq_context_autovalid, &cq_create->u.request.context,
1629962306a36Sopenharmony_ci		       phba->sli4_hba.pc_sli4_params.cqav);
1630062306a36Sopenharmony_ci	} else {
1630162306a36Sopenharmony_ci		bf_set(lpfc_cq_eq_id, &cq_create->u.request.context,
1630262306a36Sopenharmony_ci		       eq->queue_id);
1630362306a36Sopenharmony_ci	}
1630462306a36Sopenharmony_ci	switch (cq->entry_count) {
1630562306a36Sopenharmony_ci	case 2048:
1630662306a36Sopenharmony_ci	case 4096:
1630762306a36Sopenharmony_ci		if (phba->sli4_hba.pc_sli4_params.cqv ==
1630862306a36Sopenharmony_ci		    LPFC_Q_CREATE_VERSION_2) {
1630962306a36Sopenharmony_ci			cq_create->u.request.context.lpfc_cq_context_count =
1631062306a36Sopenharmony_ci				cq->entry_count;
1631162306a36Sopenharmony_ci			bf_set(lpfc_cq_context_count,
1631262306a36Sopenharmony_ci			       &cq_create->u.request.context,
1631362306a36Sopenharmony_ci			       LPFC_CQ_CNT_WORD7);
1631462306a36Sopenharmony_ci			break;
1631562306a36Sopenharmony_ci		}
1631662306a36Sopenharmony_ci		fallthrough;
1631762306a36Sopenharmony_ci	default:
1631862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1631962306a36Sopenharmony_ci				"0361 Unsupported CQ count: "
1632062306a36Sopenharmony_ci				"entry cnt %d sz %d pg cnt %d\n",
1632162306a36Sopenharmony_ci				cq->entry_count, cq->entry_size,
1632262306a36Sopenharmony_ci				cq->page_count);
1632362306a36Sopenharmony_ci		if (cq->entry_count < 256) {
1632462306a36Sopenharmony_ci			status = -EINVAL;
1632562306a36Sopenharmony_ci			goto out;
1632662306a36Sopenharmony_ci		}
1632762306a36Sopenharmony_ci		fallthrough;	/* otherwise default to smallest count */
1632862306a36Sopenharmony_ci	case 256:
1632962306a36Sopenharmony_ci		bf_set(lpfc_cq_context_count, &cq_create->u.request.context,
1633062306a36Sopenharmony_ci		       LPFC_CQ_CNT_256);
1633162306a36Sopenharmony_ci		break;
1633262306a36Sopenharmony_ci	case 512:
1633362306a36Sopenharmony_ci		bf_set(lpfc_cq_context_count, &cq_create->u.request.context,
1633462306a36Sopenharmony_ci		       LPFC_CQ_CNT_512);
1633562306a36Sopenharmony_ci		break;
1633662306a36Sopenharmony_ci	case 1024:
1633762306a36Sopenharmony_ci		bf_set(lpfc_cq_context_count, &cq_create->u.request.context,
1633862306a36Sopenharmony_ci		       LPFC_CQ_CNT_1024);
1633962306a36Sopenharmony_ci		break;
1634062306a36Sopenharmony_ci	}
1634162306a36Sopenharmony_ci	list_for_each_entry(dmabuf, &cq->page_list, list) {
1634262306a36Sopenharmony_ci		memset(dmabuf->virt, 0, cq->page_size);
1634362306a36Sopenharmony_ci		cq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
1634462306a36Sopenharmony_ci					putPaddrLow(dmabuf->phys);
1634562306a36Sopenharmony_ci		cq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
1634662306a36Sopenharmony_ci					putPaddrHigh(dmabuf->phys);
1634762306a36Sopenharmony_ci	}
1634862306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1634962306a36Sopenharmony_ci
1635062306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1635162306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1635262306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1635362306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1635462306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1635562306a36Sopenharmony_ci				"2501 CQ_CREATE mailbox failed with "
1635662306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1635762306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1635862306a36Sopenharmony_ci		status = -ENXIO;
1635962306a36Sopenharmony_ci		goto out;
1636062306a36Sopenharmony_ci	}
1636162306a36Sopenharmony_ci	cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response);
1636262306a36Sopenharmony_ci	if (cq->queue_id == 0xFFFF) {
1636362306a36Sopenharmony_ci		status = -ENXIO;
1636462306a36Sopenharmony_ci		goto out;
1636562306a36Sopenharmony_ci	}
1636662306a36Sopenharmony_ci	/* link the cq onto the parent eq child list */
1636762306a36Sopenharmony_ci	list_add_tail(&cq->list, &eq->child_list);
1636862306a36Sopenharmony_ci	/* Set up completion queue's type and subtype */
1636962306a36Sopenharmony_ci	cq->type = type;
1637062306a36Sopenharmony_ci	cq->subtype = subtype;
1637162306a36Sopenharmony_ci	cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response);
1637262306a36Sopenharmony_ci	cq->assoc_qid = eq->queue_id;
1637362306a36Sopenharmony_ci	cq->assoc_qp = eq;
1637462306a36Sopenharmony_ci	cq->host_index = 0;
1637562306a36Sopenharmony_ci	cq->notify_interval = LPFC_CQ_NOTIFY_INTRVL;
1637662306a36Sopenharmony_ci	cq->max_proc_limit = min(phba->cfg_cq_max_proc_limit, cq->entry_count);
1637762306a36Sopenharmony_ci
1637862306a36Sopenharmony_ci	if (cq->queue_id > phba->sli4_hba.cq_max)
1637962306a36Sopenharmony_ci		phba->sli4_hba.cq_max = cq->queue_id;
1638062306a36Sopenharmony_ciout:
1638162306a36Sopenharmony_ci	mempool_free(mbox, phba->mbox_mem_pool);
1638262306a36Sopenharmony_ci	return status;
1638362306a36Sopenharmony_ci}
1638462306a36Sopenharmony_ci
1638562306a36Sopenharmony_ci/**
1638662306a36Sopenharmony_ci * lpfc_cq_create_set - Create a set of Completion Queues on the HBA for MRQ
1638762306a36Sopenharmony_ci * @phba: HBA structure that indicates port to create a queue on.
1638862306a36Sopenharmony_ci * @cqp: The queue structure array to use to create the completion queues.
1638962306a36Sopenharmony_ci * @hdwq: The hardware queue array  with the EQ to bind completion queues to.
1639062306a36Sopenharmony_ci * @type: Type of queue (EQ, GCQ, MCQ, WCQ, etc).
1639162306a36Sopenharmony_ci * @subtype: Functional purpose of the queue (MBOX, IO, ELS, NVMET, etc).
1639262306a36Sopenharmony_ci *
1639362306a36Sopenharmony_ci * This function creates a set of  completion queue, s to support MRQ
1639462306a36Sopenharmony_ci * as detailed in @cqp, on a port,
1639562306a36Sopenharmony_ci * described by @phba by sending a CREATE_CQ_SET mailbox command to the HBA.
1639662306a36Sopenharmony_ci *
1639762306a36Sopenharmony_ci * The @phba struct is used to send mailbox command to HBA. The @cq struct
1639862306a36Sopenharmony_ci * is used to get the entry count and entry size that are necessary to
1639962306a36Sopenharmony_ci * determine the number of pages to allocate and use for this queue. The @eq
1640062306a36Sopenharmony_ci * is used to indicate which event queue to bind this completion queue to. This
1640162306a36Sopenharmony_ci * function will send the CREATE_CQ_SET mailbox command to the HBA to setup the
1640262306a36Sopenharmony_ci * completion queue. This function is asynchronous and will wait for the mailbox
1640362306a36Sopenharmony_ci * command to finish before continuing.
1640462306a36Sopenharmony_ci *
1640562306a36Sopenharmony_ci * On success this function will return a zero. If unable to allocate enough
1640662306a36Sopenharmony_ci * memory this function will return -ENOMEM. If the queue create mailbox command
1640762306a36Sopenharmony_ci * fails this function will return -ENXIO.
1640862306a36Sopenharmony_ci **/
1640962306a36Sopenharmony_ciint
1641062306a36Sopenharmony_cilpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp,
1641162306a36Sopenharmony_ci		   struct lpfc_sli4_hdw_queue *hdwq, uint32_t type,
1641262306a36Sopenharmony_ci		   uint32_t subtype)
1641362306a36Sopenharmony_ci{
1641462306a36Sopenharmony_ci	struct lpfc_queue *cq;
1641562306a36Sopenharmony_ci	struct lpfc_queue *eq;
1641662306a36Sopenharmony_ci	struct lpfc_mbx_cq_create_set *cq_set;
1641762306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
1641862306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1641962306a36Sopenharmony_ci	int rc, length, alloclen, status = 0;
1642062306a36Sopenharmony_ci	int cnt, idx, numcq, page_idx = 0;
1642162306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1642262306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1642362306a36Sopenharmony_ci	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
1642462306a36Sopenharmony_ci
1642562306a36Sopenharmony_ci	/* sanity check on queue memory */
1642662306a36Sopenharmony_ci	numcq = phba->cfg_nvmet_mrq;
1642762306a36Sopenharmony_ci	if (!cqp || !hdwq || !numcq)
1642862306a36Sopenharmony_ci		return -ENODEV;
1642962306a36Sopenharmony_ci
1643062306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1643162306a36Sopenharmony_ci	if (!mbox)
1643262306a36Sopenharmony_ci		return -ENOMEM;
1643362306a36Sopenharmony_ci
1643462306a36Sopenharmony_ci	length = sizeof(struct lpfc_mbx_cq_create_set);
1643562306a36Sopenharmony_ci	length += ((numcq * cqp[0]->page_count) *
1643662306a36Sopenharmony_ci		   sizeof(struct dma_address));
1643762306a36Sopenharmony_ci	alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
1643862306a36Sopenharmony_ci			LPFC_MBOX_OPCODE_FCOE_CQ_CREATE_SET, length,
1643962306a36Sopenharmony_ci			LPFC_SLI4_MBX_NEMBED);
1644062306a36Sopenharmony_ci	if (alloclen < length) {
1644162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1644262306a36Sopenharmony_ci				"3098 Allocated DMA memory size (%d) is "
1644362306a36Sopenharmony_ci				"less than the requested DMA memory size "
1644462306a36Sopenharmony_ci				"(%d)\n", alloclen, length);
1644562306a36Sopenharmony_ci		status = -ENOMEM;
1644662306a36Sopenharmony_ci		goto out;
1644762306a36Sopenharmony_ci	}
1644862306a36Sopenharmony_ci	cq_set = mbox->sge_array->addr[0];
1644962306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)&cq_set->cfg_shdr;
1645062306a36Sopenharmony_ci	bf_set(lpfc_mbox_hdr_version, &shdr->request, 0);
1645162306a36Sopenharmony_ci
1645262306a36Sopenharmony_ci	for (idx = 0; idx < numcq; idx++) {
1645362306a36Sopenharmony_ci		cq = cqp[idx];
1645462306a36Sopenharmony_ci		eq = hdwq[idx].hba_eq;
1645562306a36Sopenharmony_ci		if (!cq || !eq) {
1645662306a36Sopenharmony_ci			status = -ENOMEM;
1645762306a36Sopenharmony_ci			goto out;
1645862306a36Sopenharmony_ci		}
1645962306a36Sopenharmony_ci		if (!phba->sli4_hba.pc_sli4_params.supported)
1646062306a36Sopenharmony_ci			hw_page_size = cq->page_size;
1646162306a36Sopenharmony_ci
1646262306a36Sopenharmony_ci		switch (idx) {
1646362306a36Sopenharmony_ci		case 0:
1646462306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_page_size,
1646562306a36Sopenharmony_ci			       &cq_set->u.request,
1646662306a36Sopenharmony_ci			       (hw_page_size / SLI4_PAGE_SIZE));
1646762306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_num_pages,
1646862306a36Sopenharmony_ci			       &cq_set->u.request, cq->page_count);
1646962306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_evt,
1647062306a36Sopenharmony_ci			       &cq_set->u.request, 1);
1647162306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_valid,
1647262306a36Sopenharmony_ci			       &cq_set->u.request, 1);
1647362306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_cqe_size,
1647462306a36Sopenharmony_ci			       &cq_set->u.request, 0);
1647562306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_num_cq,
1647662306a36Sopenharmony_ci			       &cq_set->u.request, numcq);
1647762306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_autovalid,
1647862306a36Sopenharmony_ci			       &cq_set->u.request,
1647962306a36Sopenharmony_ci			       phba->sli4_hba.pc_sli4_params.cqav);
1648062306a36Sopenharmony_ci			switch (cq->entry_count) {
1648162306a36Sopenharmony_ci			case 2048:
1648262306a36Sopenharmony_ci			case 4096:
1648362306a36Sopenharmony_ci				if (phba->sli4_hba.pc_sli4_params.cqv ==
1648462306a36Sopenharmony_ci				    LPFC_Q_CREATE_VERSION_2) {
1648562306a36Sopenharmony_ci					bf_set(lpfc_mbx_cq_create_set_cqe_cnt,
1648662306a36Sopenharmony_ci					       &cq_set->u.request,
1648762306a36Sopenharmony_ci						cq->entry_count);
1648862306a36Sopenharmony_ci					bf_set(lpfc_mbx_cq_create_set_cqe_cnt,
1648962306a36Sopenharmony_ci					       &cq_set->u.request,
1649062306a36Sopenharmony_ci					       LPFC_CQ_CNT_WORD7);
1649162306a36Sopenharmony_ci					break;
1649262306a36Sopenharmony_ci				}
1649362306a36Sopenharmony_ci				fallthrough;
1649462306a36Sopenharmony_ci			default:
1649562306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1649662306a36Sopenharmony_ci						"3118 Bad CQ count. (%d)\n",
1649762306a36Sopenharmony_ci						cq->entry_count);
1649862306a36Sopenharmony_ci				if (cq->entry_count < 256) {
1649962306a36Sopenharmony_ci					status = -EINVAL;
1650062306a36Sopenharmony_ci					goto out;
1650162306a36Sopenharmony_ci				}
1650262306a36Sopenharmony_ci				fallthrough;	/* otherwise default to smallest */
1650362306a36Sopenharmony_ci			case 256:
1650462306a36Sopenharmony_ci				bf_set(lpfc_mbx_cq_create_set_cqe_cnt,
1650562306a36Sopenharmony_ci				       &cq_set->u.request, LPFC_CQ_CNT_256);
1650662306a36Sopenharmony_ci				break;
1650762306a36Sopenharmony_ci			case 512:
1650862306a36Sopenharmony_ci				bf_set(lpfc_mbx_cq_create_set_cqe_cnt,
1650962306a36Sopenharmony_ci				       &cq_set->u.request, LPFC_CQ_CNT_512);
1651062306a36Sopenharmony_ci				break;
1651162306a36Sopenharmony_ci			case 1024:
1651262306a36Sopenharmony_ci				bf_set(lpfc_mbx_cq_create_set_cqe_cnt,
1651362306a36Sopenharmony_ci				       &cq_set->u.request, LPFC_CQ_CNT_1024);
1651462306a36Sopenharmony_ci				break;
1651562306a36Sopenharmony_ci			}
1651662306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id0,
1651762306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1651862306a36Sopenharmony_ci			break;
1651962306a36Sopenharmony_ci		case 1:
1652062306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id1,
1652162306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1652262306a36Sopenharmony_ci			break;
1652362306a36Sopenharmony_ci		case 2:
1652462306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id2,
1652562306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1652662306a36Sopenharmony_ci			break;
1652762306a36Sopenharmony_ci		case 3:
1652862306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id3,
1652962306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1653062306a36Sopenharmony_ci			break;
1653162306a36Sopenharmony_ci		case 4:
1653262306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id4,
1653362306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1653462306a36Sopenharmony_ci			break;
1653562306a36Sopenharmony_ci		case 5:
1653662306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id5,
1653762306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1653862306a36Sopenharmony_ci			break;
1653962306a36Sopenharmony_ci		case 6:
1654062306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id6,
1654162306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1654262306a36Sopenharmony_ci			break;
1654362306a36Sopenharmony_ci		case 7:
1654462306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id7,
1654562306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1654662306a36Sopenharmony_ci			break;
1654762306a36Sopenharmony_ci		case 8:
1654862306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id8,
1654962306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1655062306a36Sopenharmony_ci			break;
1655162306a36Sopenharmony_ci		case 9:
1655262306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id9,
1655362306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1655462306a36Sopenharmony_ci			break;
1655562306a36Sopenharmony_ci		case 10:
1655662306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id10,
1655762306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1655862306a36Sopenharmony_ci			break;
1655962306a36Sopenharmony_ci		case 11:
1656062306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id11,
1656162306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1656262306a36Sopenharmony_ci			break;
1656362306a36Sopenharmony_ci		case 12:
1656462306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id12,
1656562306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1656662306a36Sopenharmony_ci			break;
1656762306a36Sopenharmony_ci		case 13:
1656862306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id13,
1656962306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1657062306a36Sopenharmony_ci			break;
1657162306a36Sopenharmony_ci		case 14:
1657262306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id14,
1657362306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1657462306a36Sopenharmony_ci			break;
1657562306a36Sopenharmony_ci		case 15:
1657662306a36Sopenharmony_ci			bf_set(lpfc_mbx_cq_create_set_eq_id15,
1657762306a36Sopenharmony_ci			       &cq_set->u.request, eq->queue_id);
1657862306a36Sopenharmony_ci			break;
1657962306a36Sopenharmony_ci		}
1658062306a36Sopenharmony_ci
1658162306a36Sopenharmony_ci		/* link the cq onto the parent eq child list */
1658262306a36Sopenharmony_ci		list_add_tail(&cq->list, &eq->child_list);
1658362306a36Sopenharmony_ci		/* Set up completion queue's type and subtype */
1658462306a36Sopenharmony_ci		cq->type = type;
1658562306a36Sopenharmony_ci		cq->subtype = subtype;
1658662306a36Sopenharmony_ci		cq->assoc_qid = eq->queue_id;
1658762306a36Sopenharmony_ci		cq->assoc_qp = eq;
1658862306a36Sopenharmony_ci		cq->host_index = 0;
1658962306a36Sopenharmony_ci		cq->notify_interval = LPFC_CQ_NOTIFY_INTRVL;
1659062306a36Sopenharmony_ci		cq->max_proc_limit = min(phba->cfg_cq_max_proc_limit,
1659162306a36Sopenharmony_ci					 cq->entry_count);
1659262306a36Sopenharmony_ci		cq->chann = idx;
1659362306a36Sopenharmony_ci
1659462306a36Sopenharmony_ci		rc = 0;
1659562306a36Sopenharmony_ci		list_for_each_entry(dmabuf, &cq->page_list, list) {
1659662306a36Sopenharmony_ci			memset(dmabuf->virt, 0, hw_page_size);
1659762306a36Sopenharmony_ci			cnt = page_idx + dmabuf->buffer_tag;
1659862306a36Sopenharmony_ci			cq_set->u.request.page[cnt].addr_lo =
1659962306a36Sopenharmony_ci					putPaddrLow(dmabuf->phys);
1660062306a36Sopenharmony_ci			cq_set->u.request.page[cnt].addr_hi =
1660162306a36Sopenharmony_ci					putPaddrHigh(dmabuf->phys);
1660262306a36Sopenharmony_ci			rc++;
1660362306a36Sopenharmony_ci		}
1660462306a36Sopenharmony_ci		page_idx += rc;
1660562306a36Sopenharmony_ci	}
1660662306a36Sopenharmony_ci
1660762306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1660862306a36Sopenharmony_ci
1660962306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1661062306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1661162306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1661262306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1661362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1661462306a36Sopenharmony_ci				"3119 CQ_CREATE_SET mailbox failed with "
1661562306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1661662306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1661762306a36Sopenharmony_ci		status = -ENXIO;
1661862306a36Sopenharmony_ci		goto out;
1661962306a36Sopenharmony_ci	}
1662062306a36Sopenharmony_ci	rc = bf_get(lpfc_mbx_cq_create_set_base_id, &cq_set->u.response);
1662162306a36Sopenharmony_ci	if (rc == 0xFFFF) {
1662262306a36Sopenharmony_ci		status = -ENXIO;
1662362306a36Sopenharmony_ci		goto out;
1662462306a36Sopenharmony_ci	}
1662562306a36Sopenharmony_ci
1662662306a36Sopenharmony_ci	for (idx = 0; idx < numcq; idx++) {
1662762306a36Sopenharmony_ci		cq = cqp[idx];
1662862306a36Sopenharmony_ci		cq->queue_id = rc + idx;
1662962306a36Sopenharmony_ci		if (cq->queue_id > phba->sli4_hba.cq_max)
1663062306a36Sopenharmony_ci			phba->sli4_hba.cq_max = cq->queue_id;
1663162306a36Sopenharmony_ci	}
1663262306a36Sopenharmony_ci
1663362306a36Sopenharmony_ciout:
1663462306a36Sopenharmony_ci	lpfc_sli4_mbox_cmd_free(phba, mbox);
1663562306a36Sopenharmony_ci	return status;
1663662306a36Sopenharmony_ci}
1663762306a36Sopenharmony_ci
1663862306a36Sopenharmony_ci/**
1663962306a36Sopenharmony_ci * lpfc_mq_create_fb_init - Send MCC_CREATE without async events registration
1664062306a36Sopenharmony_ci * @phba: HBA structure that indicates port to create a queue on.
1664162306a36Sopenharmony_ci * @mq: The queue structure to use to create the mailbox queue.
1664262306a36Sopenharmony_ci * @mbox: An allocated pointer to type LPFC_MBOXQ_t
1664362306a36Sopenharmony_ci * @cq: The completion queue to associate with this cq.
1664462306a36Sopenharmony_ci *
1664562306a36Sopenharmony_ci * This function provides failback (fb) functionality when the
1664662306a36Sopenharmony_ci * mq_create_ext fails on older FW generations.  It's purpose is identical
1664762306a36Sopenharmony_ci * to mq_create_ext otherwise.
1664862306a36Sopenharmony_ci *
1664962306a36Sopenharmony_ci * This routine cannot fail as all attributes were previously accessed and
1665062306a36Sopenharmony_ci * initialized in mq_create_ext.
1665162306a36Sopenharmony_ci **/
1665262306a36Sopenharmony_cistatic void
1665362306a36Sopenharmony_cilpfc_mq_create_fb_init(struct lpfc_hba *phba, struct lpfc_queue *mq,
1665462306a36Sopenharmony_ci		       LPFC_MBOXQ_t *mbox, struct lpfc_queue *cq)
1665562306a36Sopenharmony_ci{
1665662306a36Sopenharmony_ci	struct lpfc_mbx_mq_create *mq_create;
1665762306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
1665862306a36Sopenharmony_ci	int length;
1665962306a36Sopenharmony_ci
1666062306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_mq_create) -
1666162306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1666262306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
1666362306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_MQ_CREATE,
1666462306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1666562306a36Sopenharmony_ci	mq_create = &mbox->u.mqe.un.mq_create;
1666662306a36Sopenharmony_ci	bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request,
1666762306a36Sopenharmony_ci	       mq->page_count);
1666862306a36Sopenharmony_ci	bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context,
1666962306a36Sopenharmony_ci	       cq->queue_id);
1667062306a36Sopenharmony_ci	bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1);
1667162306a36Sopenharmony_ci	switch (mq->entry_count) {
1667262306a36Sopenharmony_ci	case 16:
1667362306a36Sopenharmony_ci		bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context,
1667462306a36Sopenharmony_ci		       LPFC_MQ_RING_SIZE_16);
1667562306a36Sopenharmony_ci		break;
1667662306a36Sopenharmony_ci	case 32:
1667762306a36Sopenharmony_ci		bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context,
1667862306a36Sopenharmony_ci		       LPFC_MQ_RING_SIZE_32);
1667962306a36Sopenharmony_ci		break;
1668062306a36Sopenharmony_ci	case 64:
1668162306a36Sopenharmony_ci		bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context,
1668262306a36Sopenharmony_ci		       LPFC_MQ_RING_SIZE_64);
1668362306a36Sopenharmony_ci		break;
1668462306a36Sopenharmony_ci	case 128:
1668562306a36Sopenharmony_ci		bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context,
1668662306a36Sopenharmony_ci		       LPFC_MQ_RING_SIZE_128);
1668762306a36Sopenharmony_ci		break;
1668862306a36Sopenharmony_ci	}
1668962306a36Sopenharmony_ci	list_for_each_entry(dmabuf, &mq->page_list, list) {
1669062306a36Sopenharmony_ci		mq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
1669162306a36Sopenharmony_ci			putPaddrLow(dmabuf->phys);
1669262306a36Sopenharmony_ci		mq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
1669362306a36Sopenharmony_ci			putPaddrHigh(dmabuf->phys);
1669462306a36Sopenharmony_ci	}
1669562306a36Sopenharmony_ci}
1669662306a36Sopenharmony_ci
1669762306a36Sopenharmony_ci/**
1669862306a36Sopenharmony_ci * lpfc_mq_create - Create a mailbox Queue on the HBA
1669962306a36Sopenharmony_ci * @phba: HBA structure that indicates port to create a queue on.
1670062306a36Sopenharmony_ci * @mq: The queue structure to use to create the mailbox queue.
1670162306a36Sopenharmony_ci * @cq: The completion queue to associate with this cq.
1670262306a36Sopenharmony_ci * @subtype: The queue's subtype.
1670362306a36Sopenharmony_ci *
1670462306a36Sopenharmony_ci * This function creates a mailbox queue, as detailed in @mq, on a port,
1670562306a36Sopenharmony_ci * described by @phba by sending a MQ_CREATE mailbox command to the HBA.
1670662306a36Sopenharmony_ci *
1670762306a36Sopenharmony_ci * The @phba struct is used to send mailbox command to HBA. The @cq struct
1670862306a36Sopenharmony_ci * is used to get the entry count and entry size that are necessary to
1670962306a36Sopenharmony_ci * determine the number of pages to allocate and use for this queue. This
1671062306a36Sopenharmony_ci * function will send the MQ_CREATE mailbox command to the HBA to setup the
1671162306a36Sopenharmony_ci * mailbox queue. This function is asynchronous and will wait for the mailbox
1671262306a36Sopenharmony_ci * command to finish before continuing.
1671362306a36Sopenharmony_ci *
1671462306a36Sopenharmony_ci * On success this function will return a zero. If unable to allocate enough
1671562306a36Sopenharmony_ci * memory this function will return -ENOMEM. If the queue create mailbox command
1671662306a36Sopenharmony_ci * fails this function will return -ENXIO.
1671762306a36Sopenharmony_ci **/
1671862306a36Sopenharmony_ciint32_t
1671962306a36Sopenharmony_cilpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
1672062306a36Sopenharmony_ci	       struct lpfc_queue *cq, uint32_t subtype)
1672162306a36Sopenharmony_ci{
1672262306a36Sopenharmony_ci	struct lpfc_mbx_mq_create *mq_create;
1672362306a36Sopenharmony_ci	struct lpfc_mbx_mq_create_ext *mq_create_ext;
1672462306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
1672562306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1672662306a36Sopenharmony_ci	int rc, length, status = 0;
1672762306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1672862306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1672962306a36Sopenharmony_ci	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
1673062306a36Sopenharmony_ci
1673162306a36Sopenharmony_ci	/* sanity check on queue memory */
1673262306a36Sopenharmony_ci	if (!mq || !cq)
1673362306a36Sopenharmony_ci		return -ENODEV;
1673462306a36Sopenharmony_ci	if (!phba->sli4_hba.pc_sli4_params.supported)
1673562306a36Sopenharmony_ci		hw_page_size = SLI4_PAGE_SIZE;
1673662306a36Sopenharmony_ci
1673762306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1673862306a36Sopenharmony_ci	if (!mbox)
1673962306a36Sopenharmony_ci		return -ENOMEM;
1674062306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_mq_create_ext) -
1674162306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1674262306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
1674362306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_MQ_CREATE_EXT,
1674462306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1674562306a36Sopenharmony_ci
1674662306a36Sopenharmony_ci	mq_create_ext = &mbox->u.mqe.un.mq_create_ext;
1674762306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *) &mq_create_ext->header.cfg_shdr;
1674862306a36Sopenharmony_ci	bf_set(lpfc_mbx_mq_create_ext_num_pages,
1674962306a36Sopenharmony_ci	       &mq_create_ext->u.request, mq->page_count);
1675062306a36Sopenharmony_ci	bf_set(lpfc_mbx_mq_create_ext_async_evt_link,
1675162306a36Sopenharmony_ci	       &mq_create_ext->u.request, 1);
1675262306a36Sopenharmony_ci	bf_set(lpfc_mbx_mq_create_ext_async_evt_fip,
1675362306a36Sopenharmony_ci	       &mq_create_ext->u.request, 1);
1675462306a36Sopenharmony_ci	bf_set(lpfc_mbx_mq_create_ext_async_evt_group5,
1675562306a36Sopenharmony_ci	       &mq_create_ext->u.request, 1);
1675662306a36Sopenharmony_ci	bf_set(lpfc_mbx_mq_create_ext_async_evt_fc,
1675762306a36Sopenharmony_ci	       &mq_create_ext->u.request, 1);
1675862306a36Sopenharmony_ci	bf_set(lpfc_mbx_mq_create_ext_async_evt_sli,
1675962306a36Sopenharmony_ci	       &mq_create_ext->u.request, 1);
1676062306a36Sopenharmony_ci	bf_set(lpfc_mq_context_valid, &mq_create_ext->u.request.context, 1);
1676162306a36Sopenharmony_ci	bf_set(lpfc_mbox_hdr_version, &shdr->request,
1676262306a36Sopenharmony_ci	       phba->sli4_hba.pc_sli4_params.mqv);
1676362306a36Sopenharmony_ci	if (phba->sli4_hba.pc_sli4_params.mqv == LPFC_Q_CREATE_VERSION_1)
1676462306a36Sopenharmony_ci		bf_set(lpfc_mbx_mq_create_ext_cq_id, &mq_create_ext->u.request,
1676562306a36Sopenharmony_ci		       cq->queue_id);
1676662306a36Sopenharmony_ci	else
1676762306a36Sopenharmony_ci		bf_set(lpfc_mq_context_cq_id, &mq_create_ext->u.request.context,
1676862306a36Sopenharmony_ci		       cq->queue_id);
1676962306a36Sopenharmony_ci	switch (mq->entry_count) {
1677062306a36Sopenharmony_ci	default:
1677162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1677262306a36Sopenharmony_ci				"0362 Unsupported MQ count. (%d)\n",
1677362306a36Sopenharmony_ci				mq->entry_count);
1677462306a36Sopenharmony_ci		if (mq->entry_count < 16) {
1677562306a36Sopenharmony_ci			status = -EINVAL;
1677662306a36Sopenharmony_ci			goto out;
1677762306a36Sopenharmony_ci		}
1677862306a36Sopenharmony_ci		fallthrough;	/* otherwise default to smallest count */
1677962306a36Sopenharmony_ci	case 16:
1678062306a36Sopenharmony_ci		bf_set(lpfc_mq_context_ring_size,
1678162306a36Sopenharmony_ci		       &mq_create_ext->u.request.context,
1678262306a36Sopenharmony_ci		       LPFC_MQ_RING_SIZE_16);
1678362306a36Sopenharmony_ci		break;
1678462306a36Sopenharmony_ci	case 32:
1678562306a36Sopenharmony_ci		bf_set(lpfc_mq_context_ring_size,
1678662306a36Sopenharmony_ci		       &mq_create_ext->u.request.context,
1678762306a36Sopenharmony_ci		       LPFC_MQ_RING_SIZE_32);
1678862306a36Sopenharmony_ci		break;
1678962306a36Sopenharmony_ci	case 64:
1679062306a36Sopenharmony_ci		bf_set(lpfc_mq_context_ring_size,
1679162306a36Sopenharmony_ci		       &mq_create_ext->u.request.context,
1679262306a36Sopenharmony_ci		       LPFC_MQ_RING_SIZE_64);
1679362306a36Sopenharmony_ci		break;
1679462306a36Sopenharmony_ci	case 128:
1679562306a36Sopenharmony_ci		bf_set(lpfc_mq_context_ring_size,
1679662306a36Sopenharmony_ci		       &mq_create_ext->u.request.context,
1679762306a36Sopenharmony_ci		       LPFC_MQ_RING_SIZE_128);
1679862306a36Sopenharmony_ci		break;
1679962306a36Sopenharmony_ci	}
1680062306a36Sopenharmony_ci	list_for_each_entry(dmabuf, &mq->page_list, list) {
1680162306a36Sopenharmony_ci		memset(dmabuf->virt, 0, hw_page_size);
1680262306a36Sopenharmony_ci		mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_lo =
1680362306a36Sopenharmony_ci					putPaddrLow(dmabuf->phys);
1680462306a36Sopenharmony_ci		mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_hi =
1680562306a36Sopenharmony_ci					putPaddrHigh(dmabuf->phys);
1680662306a36Sopenharmony_ci	}
1680762306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1680862306a36Sopenharmony_ci	mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id,
1680962306a36Sopenharmony_ci			      &mq_create_ext->u.response);
1681062306a36Sopenharmony_ci	if (rc != MBX_SUCCESS) {
1681162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
1681262306a36Sopenharmony_ci				"2795 MQ_CREATE_EXT failed with "
1681362306a36Sopenharmony_ci				"status x%x. Failback to MQ_CREATE.\n",
1681462306a36Sopenharmony_ci				rc);
1681562306a36Sopenharmony_ci		lpfc_mq_create_fb_init(phba, mq, mbox, cq);
1681662306a36Sopenharmony_ci		mq_create = &mbox->u.mqe.un.mq_create;
1681762306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1681862306a36Sopenharmony_ci		shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr;
1681962306a36Sopenharmony_ci		mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id,
1682062306a36Sopenharmony_ci				      &mq_create->u.response);
1682162306a36Sopenharmony_ci	}
1682262306a36Sopenharmony_ci
1682362306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1682462306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1682562306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1682662306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1682762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1682862306a36Sopenharmony_ci				"2502 MQ_CREATE mailbox failed with "
1682962306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1683062306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1683162306a36Sopenharmony_ci		status = -ENXIO;
1683262306a36Sopenharmony_ci		goto out;
1683362306a36Sopenharmony_ci	}
1683462306a36Sopenharmony_ci	if (mq->queue_id == 0xFFFF) {
1683562306a36Sopenharmony_ci		status = -ENXIO;
1683662306a36Sopenharmony_ci		goto out;
1683762306a36Sopenharmony_ci	}
1683862306a36Sopenharmony_ci	mq->type = LPFC_MQ;
1683962306a36Sopenharmony_ci	mq->assoc_qid = cq->queue_id;
1684062306a36Sopenharmony_ci	mq->subtype = subtype;
1684162306a36Sopenharmony_ci	mq->host_index = 0;
1684262306a36Sopenharmony_ci	mq->hba_index = 0;
1684362306a36Sopenharmony_ci
1684462306a36Sopenharmony_ci	/* link the mq onto the parent cq child list */
1684562306a36Sopenharmony_ci	list_add_tail(&mq->list, &cq->child_list);
1684662306a36Sopenharmony_ciout:
1684762306a36Sopenharmony_ci	mempool_free(mbox, phba->mbox_mem_pool);
1684862306a36Sopenharmony_ci	return status;
1684962306a36Sopenharmony_ci}
1685062306a36Sopenharmony_ci
1685162306a36Sopenharmony_ci/**
1685262306a36Sopenharmony_ci * lpfc_wq_create - Create a Work Queue on the HBA
1685362306a36Sopenharmony_ci * @phba: HBA structure that indicates port to create a queue on.
1685462306a36Sopenharmony_ci * @wq: The queue structure to use to create the work queue.
1685562306a36Sopenharmony_ci * @cq: The completion queue to bind this work queue to.
1685662306a36Sopenharmony_ci * @subtype: The subtype of the work queue indicating its functionality.
1685762306a36Sopenharmony_ci *
1685862306a36Sopenharmony_ci * This function creates a work queue, as detailed in @wq, on a port, described
1685962306a36Sopenharmony_ci * by @phba by sending a WQ_CREATE mailbox command to the HBA.
1686062306a36Sopenharmony_ci *
1686162306a36Sopenharmony_ci * The @phba struct is used to send mailbox command to HBA. The @wq struct
1686262306a36Sopenharmony_ci * is used to get the entry count and entry size that are necessary to
1686362306a36Sopenharmony_ci * determine the number of pages to allocate and use for this queue. The @cq
1686462306a36Sopenharmony_ci * is used to indicate which completion queue to bind this work queue to. This
1686562306a36Sopenharmony_ci * function will send the WQ_CREATE mailbox command to the HBA to setup the
1686662306a36Sopenharmony_ci * work queue. This function is asynchronous and will wait for the mailbox
1686762306a36Sopenharmony_ci * command to finish before continuing.
1686862306a36Sopenharmony_ci *
1686962306a36Sopenharmony_ci * On success this function will return a zero. If unable to allocate enough
1687062306a36Sopenharmony_ci * memory this function will return -ENOMEM. If the queue create mailbox command
1687162306a36Sopenharmony_ci * fails this function will return -ENXIO.
1687262306a36Sopenharmony_ci **/
1687362306a36Sopenharmony_ciint
1687462306a36Sopenharmony_cilpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
1687562306a36Sopenharmony_ci	       struct lpfc_queue *cq, uint32_t subtype)
1687662306a36Sopenharmony_ci{
1687762306a36Sopenharmony_ci	struct lpfc_mbx_wq_create *wq_create;
1687862306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
1687962306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1688062306a36Sopenharmony_ci	int rc, length, status = 0;
1688162306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1688262306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1688362306a36Sopenharmony_ci	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
1688462306a36Sopenharmony_ci	struct dma_address *page;
1688562306a36Sopenharmony_ci	void __iomem *bar_memmap_p;
1688662306a36Sopenharmony_ci	uint32_t db_offset;
1688762306a36Sopenharmony_ci	uint16_t pci_barset;
1688862306a36Sopenharmony_ci	uint8_t dpp_barset;
1688962306a36Sopenharmony_ci	uint32_t dpp_offset;
1689062306a36Sopenharmony_ci	uint8_t wq_create_version;
1689162306a36Sopenharmony_ci#ifdef CONFIG_X86
1689262306a36Sopenharmony_ci	unsigned long pg_addr;
1689362306a36Sopenharmony_ci#endif
1689462306a36Sopenharmony_ci
1689562306a36Sopenharmony_ci	/* sanity check on queue memory */
1689662306a36Sopenharmony_ci	if (!wq || !cq)
1689762306a36Sopenharmony_ci		return -ENODEV;
1689862306a36Sopenharmony_ci	if (!phba->sli4_hba.pc_sli4_params.supported)
1689962306a36Sopenharmony_ci		hw_page_size = wq->page_size;
1690062306a36Sopenharmony_ci
1690162306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1690262306a36Sopenharmony_ci	if (!mbox)
1690362306a36Sopenharmony_ci		return -ENOMEM;
1690462306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_wq_create) -
1690562306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1690662306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
1690762306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_FCOE_WQ_CREATE,
1690862306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1690962306a36Sopenharmony_ci	wq_create = &mbox->u.mqe.un.wq_create;
1691062306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *) &wq_create->header.cfg_shdr;
1691162306a36Sopenharmony_ci	bf_set(lpfc_mbx_wq_create_num_pages, &wq_create->u.request,
1691262306a36Sopenharmony_ci		    wq->page_count);
1691362306a36Sopenharmony_ci	bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request,
1691462306a36Sopenharmony_ci		    cq->queue_id);
1691562306a36Sopenharmony_ci
1691662306a36Sopenharmony_ci	/* wqv is the earliest version supported, NOT the latest */
1691762306a36Sopenharmony_ci	bf_set(lpfc_mbox_hdr_version, &shdr->request,
1691862306a36Sopenharmony_ci	       phba->sli4_hba.pc_sli4_params.wqv);
1691962306a36Sopenharmony_ci
1692062306a36Sopenharmony_ci	if ((phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT) ||
1692162306a36Sopenharmony_ci	    (wq->page_size > SLI4_PAGE_SIZE))
1692262306a36Sopenharmony_ci		wq_create_version = LPFC_Q_CREATE_VERSION_1;
1692362306a36Sopenharmony_ci	else
1692462306a36Sopenharmony_ci		wq_create_version = LPFC_Q_CREATE_VERSION_0;
1692562306a36Sopenharmony_ci
1692662306a36Sopenharmony_ci	switch (wq_create_version) {
1692762306a36Sopenharmony_ci	case LPFC_Q_CREATE_VERSION_1:
1692862306a36Sopenharmony_ci		bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1,
1692962306a36Sopenharmony_ci		       wq->entry_count);
1693062306a36Sopenharmony_ci		bf_set(lpfc_mbox_hdr_version, &shdr->request,
1693162306a36Sopenharmony_ci		       LPFC_Q_CREATE_VERSION_1);
1693262306a36Sopenharmony_ci
1693362306a36Sopenharmony_ci		switch (wq->entry_size) {
1693462306a36Sopenharmony_ci		default:
1693562306a36Sopenharmony_ci		case 64:
1693662306a36Sopenharmony_ci			bf_set(lpfc_mbx_wq_create_wqe_size,
1693762306a36Sopenharmony_ci			       &wq_create->u.request_1,
1693862306a36Sopenharmony_ci			       LPFC_WQ_WQE_SIZE_64);
1693962306a36Sopenharmony_ci			break;
1694062306a36Sopenharmony_ci		case 128:
1694162306a36Sopenharmony_ci			bf_set(lpfc_mbx_wq_create_wqe_size,
1694262306a36Sopenharmony_ci			       &wq_create->u.request_1,
1694362306a36Sopenharmony_ci			       LPFC_WQ_WQE_SIZE_128);
1694462306a36Sopenharmony_ci			break;
1694562306a36Sopenharmony_ci		}
1694662306a36Sopenharmony_ci		/* Request DPP by default */
1694762306a36Sopenharmony_ci		bf_set(lpfc_mbx_wq_create_dpp_req, &wq_create->u.request_1, 1);
1694862306a36Sopenharmony_ci		bf_set(lpfc_mbx_wq_create_page_size,
1694962306a36Sopenharmony_ci		       &wq_create->u.request_1,
1695062306a36Sopenharmony_ci		       (wq->page_size / SLI4_PAGE_SIZE));
1695162306a36Sopenharmony_ci		page = wq_create->u.request_1.page;
1695262306a36Sopenharmony_ci		break;
1695362306a36Sopenharmony_ci	default:
1695462306a36Sopenharmony_ci		page = wq_create->u.request.page;
1695562306a36Sopenharmony_ci		break;
1695662306a36Sopenharmony_ci	}
1695762306a36Sopenharmony_ci
1695862306a36Sopenharmony_ci	list_for_each_entry(dmabuf, &wq->page_list, list) {
1695962306a36Sopenharmony_ci		memset(dmabuf->virt, 0, hw_page_size);
1696062306a36Sopenharmony_ci		page[dmabuf->buffer_tag].addr_lo = putPaddrLow(dmabuf->phys);
1696162306a36Sopenharmony_ci		page[dmabuf->buffer_tag].addr_hi = putPaddrHigh(dmabuf->phys);
1696262306a36Sopenharmony_ci	}
1696362306a36Sopenharmony_ci
1696462306a36Sopenharmony_ci	if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE)
1696562306a36Sopenharmony_ci		bf_set(lpfc_mbx_wq_create_dua, &wq_create->u.request, 1);
1696662306a36Sopenharmony_ci
1696762306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1696862306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1696962306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1697062306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1697162306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1697262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1697362306a36Sopenharmony_ci				"2503 WQ_CREATE mailbox failed with "
1697462306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1697562306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1697662306a36Sopenharmony_ci		status = -ENXIO;
1697762306a36Sopenharmony_ci		goto out;
1697862306a36Sopenharmony_ci	}
1697962306a36Sopenharmony_ci
1698062306a36Sopenharmony_ci	if (wq_create_version == LPFC_Q_CREATE_VERSION_0)
1698162306a36Sopenharmony_ci		wq->queue_id = bf_get(lpfc_mbx_wq_create_q_id,
1698262306a36Sopenharmony_ci					&wq_create->u.response);
1698362306a36Sopenharmony_ci	else
1698462306a36Sopenharmony_ci		wq->queue_id = bf_get(lpfc_mbx_wq_create_v1_q_id,
1698562306a36Sopenharmony_ci					&wq_create->u.response_1);
1698662306a36Sopenharmony_ci
1698762306a36Sopenharmony_ci	if (wq->queue_id == 0xFFFF) {
1698862306a36Sopenharmony_ci		status = -ENXIO;
1698962306a36Sopenharmony_ci		goto out;
1699062306a36Sopenharmony_ci	}
1699162306a36Sopenharmony_ci
1699262306a36Sopenharmony_ci	wq->db_format = LPFC_DB_LIST_FORMAT;
1699362306a36Sopenharmony_ci	if (wq_create_version == LPFC_Q_CREATE_VERSION_0) {
1699462306a36Sopenharmony_ci		if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) {
1699562306a36Sopenharmony_ci			wq->db_format = bf_get(lpfc_mbx_wq_create_db_format,
1699662306a36Sopenharmony_ci					       &wq_create->u.response);
1699762306a36Sopenharmony_ci			if ((wq->db_format != LPFC_DB_LIST_FORMAT) &&
1699862306a36Sopenharmony_ci			    (wq->db_format != LPFC_DB_RING_FORMAT)) {
1699962306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1700062306a36Sopenharmony_ci						"3265 WQ[%d] doorbell format "
1700162306a36Sopenharmony_ci						"not supported: x%x\n",
1700262306a36Sopenharmony_ci						wq->queue_id, wq->db_format);
1700362306a36Sopenharmony_ci				status = -EINVAL;
1700462306a36Sopenharmony_ci				goto out;
1700562306a36Sopenharmony_ci			}
1700662306a36Sopenharmony_ci			pci_barset = bf_get(lpfc_mbx_wq_create_bar_set,
1700762306a36Sopenharmony_ci					    &wq_create->u.response);
1700862306a36Sopenharmony_ci			bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba,
1700962306a36Sopenharmony_ci								   pci_barset);
1701062306a36Sopenharmony_ci			if (!bar_memmap_p) {
1701162306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1701262306a36Sopenharmony_ci						"3263 WQ[%d] failed to memmap "
1701362306a36Sopenharmony_ci						"pci barset:x%x\n",
1701462306a36Sopenharmony_ci						wq->queue_id, pci_barset);
1701562306a36Sopenharmony_ci				status = -ENOMEM;
1701662306a36Sopenharmony_ci				goto out;
1701762306a36Sopenharmony_ci			}
1701862306a36Sopenharmony_ci			db_offset = wq_create->u.response.doorbell_offset;
1701962306a36Sopenharmony_ci			if ((db_offset != LPFC_ULP0_WQ_DOORBELL) &&
1702062306a36Sopenharmony_ci			    (db_offset != LPFC_ULP1_WQ_DOORBELL)) {
1702162306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1702262306a36Sopenharmony_ci						"3252 WQ[%d] doorbell offset "
1702362306a36Sopenharmony_ci						"not supported: x%x\n",
1702462306a36Sopenharmony_ci						wq->queue_id, db_offset);
1702562306a36Sopenharmony_ci				status = -EINVAL;
1702662306a36Sopenharmony_ci				goto out;
1702762306a36Sopenharmony_ci			}
1702862306a36Sopenharmony_ci			wq->db_regaddr = bar_memmap_p + db_offset;
1702962306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
1703062306a36Sopenharmony_ci					"3264 WQ[%d]: barset:x%x, offset:x%x, "
1703162306a36Sopenharmony_ci					"format:x%x\n", wq->queue_id,
1703262306a36Sopenharmony_ci					pci_barset, db_offset, wq->db_format);
1703362306a36Sopenharmony_ci		} else
1703462306a36Sopenharmony_ci			wq->db_regaddr = phba->sli4_hba.WQDBregaddr;
1703562306a36Sopenharmony_ci	} else {
1703662306a36Sopenharmony_ci		/* Check if DPP was honored by the firmware */
1703762306a36Sopenharmony_ci		wq->dpp_enable = bf_get(lpfc_mbx_wq_create_dpp_rsp,
1703862306a36Sopenharmony_ci				    &wq_create->u.response_1);
1703962306a36Sopenharmony_ci		if (wq->dpp_enable) {
1704062306a36Sopenharmony_ci			pci_barset = bf_get(lpfc_mbx_wq_create_v1_bar_set,
1704162306a36Sopenharmony_ci					    &wq_create->u.response_1);
1704262306a36Sopenharmony_ci			bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba,
1704362306a36Sopenharmony_ci								   pci_barset);
1704462306a36Sopenharmony_ci			if (!bar_memmap_p) {
1704562306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1704662306a36Sopenharmony_ci						"3267 WQ[%d] failed to memmap "
1704762306a36Sopenharmony_ci						"pci barset:x%x\n",
1704862306a36Sopenharmony_ci						wq->queue_id, pci_barset);
1704962306a36Sopenharmony_ci				status = -ENOMEM;
1705062306a36Sopenharmony_ci				goto out;
1705162306a36Sopenharmony_ci			}
1705262306a36Sopenharmony_ci			db_offset = wq_create->u.response_1.doorbell_offset;
1705362306a36Sopenharmony_ci			wq->db_regaddr = bar_memmap_p + db_offset;
1705462306a36Sopenharmony_ci			wq->dpp_id = bf_get(lpfc_mbx_wq_create_dpp_id,
1705562306a36Sopenharmony_ci					    &wq_create->u.response_1);
1705662306a36Sopenharmony_ci			dpp_barset = bf_get(lpfc_mbx_wq_create_dpp_bar,
1705762306a36Sopenharmony_ci					    &wq_create->u.response_1);
1705862306a36Sopenharmony_ci			bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba,
1705962306a36Sopenharmony_ci								   dpp_barset);
1706062306a36Sopenharmony_ci			if (!bar_memmap_p) {
1706162306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1706262306a36Sopenharmony_ci						"3268 WQ[%d] failed to memmap "
1706362306a36Sopenharmony_ci						"pci barset:x%x\n",
1706462306a36Sopenharmony_ci						wq->queue_id, dpp_barset);
1706562306a36Sopenharmony_ci				status = -ENOMEM;
1706662306a36Sopenharmony_ci				goto out;
1706762306a36Sopenharmony_ci			}
1706862306a36Sopenharmony_ci			dpp_offset = wq_create->u.response_1.dpp_offset;
1706962306a36Sopenharmony_ci			wq->dpp_regaddr = bar_memmap_p + dpp_offset;
1707062306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
1707162306a36Sopenharmony_ci					"3271 WQ[%d]: barset:x%x, offset:x%x, "
1707262306a36Sopenharmony_ci					"dpp_id:x%x dpp_barset:x%x "
1707362306a36Sopenharmony_ci					"dpp_offset:x%x\n",
1707462306a36Sopenharmony_ci					wq->queue_id, pci_barset, db_offset,
1707562306a36Sopenharmony_ci					wq->dpp_id, dpp_barset, dpp_offset);
1707662306a36Sopenharmony_ci
1707762306a36Sopenharmony_ci#ifdef CONFIG_X86
1707862306a36Sopenharmony_ci			/* Enable combined writes for DPP aperture */
1707962306a36Sopenharmony_ci			pg_addr = (unsigned long)(wq->dpp_regaddr) & PAGE_MASK;
1708062306a36Sopenharmony_ci			rc = set_memory_wc(pg_addr, 1);
1708162306a36Sopenharmony_ci			if (rc) {
1708262306a36Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
1708362306a36Sopenharmony_ci					"3272 Cannot setup Combined "
1708462306a36Sopenharmony_ci					"Write on WQ[%d] - disable DPP\n",
1708562306a36Sopenharmony_ci					wq->queue_id);
1708662306a36Sopenharmony_ci				phba->cfg_enable_dpp = 0;
1708762306a36Sopenharmony_ci			}
1708862306a36Sopenharmony_ci#else
1708962306a36Sopenharmony_ci			phba->cfg_enable_dpp = 0;
1709062306a36Sopenharmony_ci#endif
1709162306a36Sopenharmony_ci		} else
1709262306a36Sopenharmony_ci			wq->db_regaddr = phba->sli4_hba.WQDBregaddr;
1709362306a36Sopenharmony_ci	}
1709462306a36Sopenharmony_ci	wq->pring = kzalloc(sizeof(struct lpfc_sli_ring), GFP_KERNEL);
1709562306a36Sopenharmony_ci	if (wq->pring == NULL) {
1709662306a36Sopenharmony_ci		status = -ENOMEM;
1709762306a36Sopenharmony_ci		goto out;
1709862306a36Sopenharmony_ci	}
1709962306a36Sopenharmony_ci	wq->type = LPFC_WQ;
1710062306a36Sopenharmony_ci	wq->assoc_qid = cq->queue_id;
1710162306a36Sopenharmony_ci	wq->subtype = subtype;
1710262306a36Sopenharmony_ci	wq->host_index = 0;
1710362306a36Sopenharmony_ci	wq->hba_index = 0;
1710462306a36Sopenharmony_ci	wq->notify_interval = LPFC_WQ_NOTIFY_INTRVL;
1710562306a36Sopenharmony_ci
1710662306a36Sopenharmony_ci	/* link the wq onto the parent cq child list */
1710762306a36Sopenharmony_ci	list_add_tail(&wq->list, &cq->child_list);
1710862306a36Sopenharmony_ciout:
1710962306a36Sopenharmony_ci	mempool_free(mbox, phba->mbox_mem_pool);
1711062306a36Sopenharmony_ci	return status;
1711162306a36Sopenharmony_ci}
1711262306a36Sopenharmony_ci
1711362306a36Sopenharmony_ci/**
1711462306a36Sopenharmony_ci * lpfc_rq_create - Create a Receive Queue on the HBA
1711562306a36Sopenharmony_ci * @phba: HBA structure that indicates port to create a queue on.
1711662306a36Sopenharmony_ci * @hrq: The queue structure to use to create the header receive queue.
1711762306a36Sopenharmony_ci * @drq: The queue structure to use to create the data receive queue.
1711862306a36Sopenharmony_ci * @cq: The completion queue to bind this work queue to.
1711962306a36Sopenharmony_ci * @subtype: The subtype of the work queue indicating its functionality.
1712062306a36Sopenharmony_ci *
1712162306a36Sopenharmony_ci * This function creates a receive buffer queue pair , as detailed in @hrq and
1712262306a36Sopenharmony_ci * @drq, on a port, described by @phba by sending a RQ_CREATE mailbox command
1712362306a36Sopenharmony_ci * to the HBA.
1712462306a36Sopenharmony_ci *
1712562306a36Sopenharmony_ci * The @phba struct is used to send mailbox command to HBA. The @drq and @hrq
1712662306a36Sopenharmony_ci * struct is used to get the entry count that is necessary to determine the
1712762306a36Sopenharmony_ci * number of pages to use for this queue. The @cq is used to indicate which
1712862306a36Sopenharmony_ci * completion queue to bind received buffers that are posted to these queues to.
1712962306a36Sopenharmony_ci * This function will send the RQ_CREATE mailbox command to the HBA to setup the
1713062306a36Sopenharmony_ci * receive queue pair. This function is asynchronous and will wait for the
1713162306a36Sopenharmony_ci * mailbox command to finish before continuing.
1713262306a36Sopenharmony_ci *
1713362306a36Sopenharmony_ci * On success this function will return a zero. If unable to allocate enough
1713462306a36Sopenharmony_ci * memory this function will return -ENOMEM. If the queue create mailbox command
1713562306a36Sopenharmony_ci * fails this function will return -ENXIO.
1713662306a36Sopenharmony_ci **/
1713762306a36Sopenharmony_ciint
1713862306a36Sopenharmony_cilpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
1713962306a36Sopenharmony_ci	       struct lpfc_queue *drq, struct lpfc_queue *cq, uint32_t subtype)
1714062306a36Sopenharmony_ci{
1714162306a36Sopenharmony_ci	struct lpfc_mbx_rq_create *rq_create;
1714262306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
1714362306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1714462306a36Sopenharmony_ci	int rc, length, status = 0;
1714562306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1714662306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1714762306a36Sopenharmony_ci	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
1714862306a36Sopenharmony_ci	void __iomem *bar_memmap_p;
1714962306a36Sopenharmony_ci	uint32_t db_offset;
1715062306a36Sopenharmony_ci	uint16_t pci_barset;
1715162306a36Sopenharmony_ci
1715262306a36Sopenharmony_ci	/* sanity check on queue memory */
1715362306a36Sopenharmony_ci	if (!hrq || !drq || !cq)
1715462306a36Sopenharmony_ci		return -ENODEV;
1715562306a36Sopenharmony_ci	if (!phba->sli4_hba.pc_sli4_params.supported)
1715662306a36Sopenharmony_ci		hw_page_size = SLI4_PAGE_SIZE;
1715762306a36Sopenharmony_ci
1715862306a36Sopenharmony_ci	if (hrq->entry_count != drq->entry_count)
1715962306a36Sopenharmony_ci		return -EINVAL;
1716062306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1716162306a36Sopenharmony_ci	if (!mbox)
1716262306a36Sopenharmony_ci		return -ENOMEM;
1716362306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_rq_create) -
1716462306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1716562306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
1716662306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_FCOE_RQ_CREATE,
1716762306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1716862306a36Sopenharmony_ci	rq_create = &mbox->u.mqe.un.rq_create;
1716962306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr;
1717062306a36Sopenharmony_ci	bf_set(lpfc_mbox_hdr_version, &shdr->request,
1717162306a36Sopenharmony_ci	       phba->sli4_hba.pc_sli4_params.rqv);
1717262306a36Sopenharmony_ci	if (phba->sli4_hba.pc_sli4_params.rqv == LPFC_Q_CREATE_VERSION_1) {
1717362306a36Sopenharmony_ci		bf_set(lpfc_rq_context_rqe_count_1,
1717462306a36Sopenharmony_ci		       &rq_create->u.request.context,
1717562306a36Sopenharmony_ci		       hrq->entry_count);
1717662306a36Sopenharmony_ci		rq_create->u.request.context.buffer_size = LPFC_HDR_BUF_SIZE;
1717762306a36Sopenharmony_ci		bf_set(lpfc_rq_context_rqe_size,
1717862306a36Sopenharmony_ci		       &rq_create->u.request.context,
1717962306a36Sopenharmony_ci		       LPFC_RQE_SIZE_8);
1718062306a36Sopenharmony_ci		bf_set(lpfc_rq_context_page_size,
1718162306a36Sopenharmony_ci		       &rq_create->u.request.context,
1718262306a36Sopenharmony_ci		       LPFC_RQ_PAGE_SIZE_4096);
1718362306a36Sopenharmony_ci	} else {
1718462306a36Sopenharmony_ci		switch (hrq->entry_count) {
1718562306a36Sopenharmony_ci		default:
1718662306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1718762306a36Sopenharmony_ci					"2535 Unsupported RQ count. (%d)\n",
1718862306a36Sopenharmony_ci					hrq->entry_count);
1718962306a36Sopenharmony_ci			if (hrq->entry_count < 512) {
1719062306a36Sopenharmony_ci				status = -EINVAL;
1719162306a36Sopenharmony_ci				goto out;
1719262306a36Sopenharmony_ci			}
1719362306a36Sopenharmony_ci			fallthrough;	/* otherwise default to smallest count */
1719462306a36Sopenharmony_ci		case 512:
1719562306a36Sopenharmony_ci			bf_set(lpfc_rq_context_rqe_count,
1719662306a36Sopenharmony_ci			       &rq_create->u.request.context,
1719762306a36Sopenharmony_ci			       LPFC_RQ_RING_SIZE_512);
1719862306a36Sopenharmony_ci			break;
1719962306a36Sopenharmony_ci		case 1024:
1720062306a36Sopenharmony_ci			bf_set(lpfc_rq_context_rqe_count,
1720162306a36Sopenharmony_ci			       &rq_create->u.request.context,
1720262306a36Sopenharmony_ci			       LPFC_RQ_RING_SIZE_1024);
1720362306a36Sopenharmony_ci			break;
1720462306a36Sopenharmony_ci		case 2048:
1720562306a36Sopenharmony_ci			bf_set(lpfc_rq_context_rqe_count,
1720662306a36Sopenharmony_ci			       &rq_create->u.request.context,
1720762306a36Sopenharmony_ci			       LPFC_RQ_RING_SIZE_2048);
1720862306a36Sopenharmony_ci			break;
1720962306a36Sopenharmony_ci		case 4096:
1721062306a36Sopenharmony_ci			bf_set(lpfc_rq_context_rqe_count,
1721162306a36Sopenharmony_ci			       &rq_create->u.request.context,
1721262306a36Sopenharmony_ci			       LPFC_RQ_RING_SIZE_4096);
1721362306a36Sopenharmony_ci			break;
1721462306a36Sopenharmony_ci		}
1721562306a36Sopenharmony_ci		bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context,
1721662306a36Sopenharmony_ci		       LPFC_HDR_BUF_SIZE);
1721762306a36Sopenharmony_ci	}
1721862306a36Sopenharmony_ci	bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context,
1721962306a36Sopenharmony_ci	       cq->queue_id);
1722062306a36Sopenharmony_ci	bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request,
1722162306a36Sopenharmony_ci	       hrq->page_count);
1722262306a36Sopenharmony_ci	list_for_each_entry(dmabuf, &hrq->page_list, list) {
1722362306a36Sopenharmony_ci		memset(dmabuf->virt, 0, hw_page_size);
1722462306a36Sopenharmony_ci		rq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
1722562306a36Sopenharmony_ci					putPaddrLow(dmabuf->phys);
1722662306a36Sopenharmony_ci		rq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
1722762306a36Sopenharmony_ci					putPaddrHigh(dmabuf->phys);
1722862306a36Sopenharmony_ci	}
1722962306a36Sopenharmony_ci	if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE)
1723062306a36Sopenharmony_ci		bf_set(lpfc_mbx_rq_create_dua, &rq_create->u.request, 1);
1723162306a36Sopenharmony_ci
1723262306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1723362306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1723462306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1723562306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1723662306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1723762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1723862306a36Sopenharmony_ci				"2504 RQ_CREATE mailbox failed with "
1723962306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1724062306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1724162306a36Sopenharmony_ci		status = -ENXIO;
1724262306a36Sopenharmony_ci		goto out;
1724362306a36Sopenharmony_ci	}
1724462306a36Sopenharmony_ci	hrq->queue_id = bf_get(lpfc_mbx_rq_create_q_id, &rq_create->u.response);
1724562306a36Sopenharmony_ci	if (hrq->queue_id == 0xFFFF) {
1724662306a36Sopenharmony_ci		status = -ENXIO;
1724762306a36Sopenharmony_ci		goto out;
1724862306a36Sopenharmony_ci	}
1724962306a36Sopenharmony_ci
1725062306a36Sopenharmony_ci	if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) {
1725162306a36Sopenharmony_ci		hrq->db_format = bf_get(lpfc_mbx_rq_create_db_format,
1725262306a36Sopenharmony_ci					&rq_create->u.response);
1725362306a36Sopenharmony_ci		if ((hrq->db_format != LPFC_DB_LIST_FORMAT) &&
1725462306a36Sopenharmony_ci		    (hrq->db_format != LPFC_DB_RING_FORMAT)) {
1725562306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1725662306a36Sopenharmony_ci					"3262 RQ [%d] doorbell format not "
1725762306a36Sopenharmony_ci					"supported: x%x\n", hrq->queue_id,
1725862306a36Sopenharmony_ci					hrq->db_format);
1725962306a36Sopenharmony_ci			status = -EINVAL;
1726062306a36Sopenharmony_ci			goto out;
1726162306a36Sopenharmony_ci		}
1726262306a36Sopenharmony_ci
1726362306a36Sopenharmony_ci		pci_barset = bf_get(lpfc_mbx_rq_create_bar_set,
1726462306a36Sopenharmony_ci				    &rq_create->u.response);
1726562306a36Sopenharmony_ci		bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset);
1726662306a36Sopenharmony_ci		if (!bar_memmap_p) {
1726762306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1726862306a36Sopenharmony_ci					"3269 RQ[%d] failed to memmap pci "
1726962306a36Sopenharmony_ci					"barset:x%x\n", hrq->queue_id,
1727062306a36Sopenharmony_ci					pci_barset);
1727162306a36Sopenharmony_ci			status = -ENOMEM;
1727262306a36Sopenharmony_ci			goto out;
1727362306a36Sopenharmony_ci		}
1727462306a36Sopenharmony_ci
1727562306a36Sopenharmony_ci		db_offset = rq_create->u.response.doorbell_offset;
1727662306a36Sopenharmony_ci		if ((db_offset != LPFC_ULP0_RQ_DOORBELL) &&
1727762306a36Sopenharmony_ci		    (db_offset != LPFC_ULP1_RQ_DOORBELL)) {
1727862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1727962306a36Sopenharmony_ci					"3270 RQ[%d] doorbell offset not "
1728062306a36Sopenharmony_ci					"supported: x%x\n", hrq->queue_id,
1728162306a36Sopenharmony_ci					db_offset);
1728262306a36Sopenharmony_ci			status = -EINVAL;
1728362306a36Sopenharmony_ci			goto out;
1728462306a36Sopenharmony_ci		}
1728562306a36Sopenharmony_ci		hrq->db_regaddr = bar_memmap_p + db_offset;
1728662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
1728762306a36Sopenharmony_ci				"3266 RQ[qid:%d]: barset:x%x, offset:x%x, "
1728862306a36Sopenharmony_ci				"format:x%x\n", hrq->queue_id, pci_barset,
1728962306a36Sopenharmony_ci				db_offset, hrq->db_format);
1729062306a36Sopenharmony_ci	} else {
1729162306a36Sopenharmony_ci		hrq->db_format = LPFC_DB_RING_FORMAT;
1729262306a36Sopenharmony_ci		hrq->db_regaddr = phba->sli4_hba.RQDBregaddr;
1729362306a36Sopenharmony_ci	}
1729462306a36Sopenharmony_ci	hrq->type = LPFC_HRQ;
1729562306a36Sopenharmony_ci	hrq->assoc_qid = cq->queue_id;
1729662306a36Sopenharmony_ci	hrq->subtype = subtype;
1729762306a36Sopenharmony_ci	hrq->host_index = 0;
1729862306a36Sopenharmony_ci	hrq->hba_index = 0;
1729962306a36Sopenharmony_ci	hrq->notify_interval = LPFC_RQ_NOTIFY_INTRVL;
1730062306a36Sopenharmony_ci
1730162306a36Sopenharmony_ci	/* now create the data queue */
1730262306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
1730362306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_FCOE_RQ_CREATE,
1730462306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1730562306a36Sopenharmony_ci	bf_set(lpfc_mbox_hdr_version, &shdr->request,
1730662306a36Sopenharmony_ci	       phba->sli4_hba.pc_sli4_params.rqv);
1730762306a36Sopenharmony_ci	if (phba->sli4_hba.pc_sli4_params.rqv == LPFC_Q_CREATE_VERSION_1) {
1730862306a36Sopenharmony_ci		bf_set(lpfc_rq_context_rqe_count_1,
1730962306a36Sopenharmony_ci		       &rq_create->u.request.context, hrq->entry_count);
1731062306a36Sopenharmony_ci		if (subtype == LPFC_NVMET)
1731162306a36Sopenharmony_ci			rq_create->u.request.context.buffer_size =
1731262306a36Sopenharmony_ci				LPFC_NVMET_DATA_BUF_SIZE;
1731362306a36Sopenharmony_ci		else
1731462306a36Sopenharmony_ci			rq_create->u.request.context.buffer_size =
1731562306a36Sopenharmony_ci				LPFC_DATA_BUF_SIZE;
1731662306a36Sopenharmony_ci		bf_set(lpfc_rq_context_rqe_size, &rq_create->u.request.context,
1731762306a36Sopenharmony_ci		       LPFC_RQE_SIZE_8);
1731862306a36Sopenharmony_ci		bf_set(lpfc_rq_context_page_size, &rq_create->u.request.context,
1731962306a36Sopenharmony_ci		       (PAGE_SIZE/SLI4_PAGE_SIZE));
1732062306a36Sopenharmony_ci	} else {
1732162306a36Sopenharmony_ci		switch (drq->entry_count) {
1732262306a36Sopenharmony_ci		default:
1732362306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1732462306a36Sopenharmony_ci					"2536 Unsupported RQ count. (%d)\n",
1732562306a36Sopenharmony_ci					drq->entry_count);
1732662306a36Sopenharmony_ci			if (drq->entry_count < 512) {
1732762306a36Sopenharmony_ci				status = -EINVAL;
1732862306a36Sopenharmony_ci				goto out;
1732962306a36Sopenharmony_ci			}
1733062306a36Sopenharmony_ci			fallthrough;	/* otherwise default to smallest count */
1733162306a36Sopenharmony_ci		case 512:
1733262306a36Sopenharmony_ci			bf_set(lpfc_rq_context_rqe_count,
1733362306a36Sopenharmony_ci			       &rq_create->u.request.context,
1733462306a36Sopenharmony_ci			       LPFC_RQ_RING_SIZE_512);
1733562306a36Sopenharmony_ci			break;
1733662306a36Sopenharmony_ci		case 1024:
1733762306a36Sopenharmony_ci			bf_set(lpfc_rq_context_rqe_count,
1733862306a36Sopenharmony_ci			       &rq_create->u.request.context,
1733962306a36Sopenharmony_ci			       LPFC_RQ_RING_SIZE_1024);
1734062306a36Sopenharmony_ci			break;
1734162306a36Sopenharmony_ci		case 2048:
1734262306a36Sopenharmony_ci			bf_set(lpfc_rq_context_rqe_count,
1734362306a36Sopenharmony_ci			       &rq_create->u.request.context,
1734462306a36Sopenharmony_ci			       LPFC_RQ_RING_SIZE_2048);
1734562306a36Sopenharmony_ci			break;
1734662306a36Sopenharmony_ci		case 4096:
1734762306a36Sopenharmony_ci			bf_set(lpfc_rq_context_rqe_count,
1734862306a36Sopenharmony_ci			       &rq_create->u.request.context,
1734962306a36Sopenharmony_ci			       LPFC_RQ_RING_SIZE_4096);
1735062306a36Sopenharmony_ci			break;
1735162306a36Sopenharmony_ci		}
1735262306a36Sopenharmony_ci		if (subtype == LPFC_NVMET)
1735362306a36Sopenharmony_ci			bf_set(lpfc_rq_context_buf_size,
1735462306a36Sopenharmony_ci			       &rq_create->u.request.context,
1735562306a36Sopenharmony_ci			       LPFC_NVMET_DATA_BUF_SIZE);
1735662306a36Sopenharmony_ci		else
1735762306a36Sopenharmony_ci			bf_set(lpfc_rq_context_buf_size,
1735862306a36Sopenharmony_ci			       &rq_create->u.request.context,
1735962306a36Sopenharmony_ci			       LPFC_DATA_BUF_SIZE);
1736062306a36Sopenharmony_ci	}
1736162306a36Sopenharmony_ci	bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context,
1736262306a36Sopenharmony_ci	       cq->queue_id);
1736362306a36Sopenharmony_ci	bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request,
1736462306a36Sopenharmony_ci	       drq->page_count);
1736562306a36Sopenharmony_ci	list_for_each_entry(dmabuf, &drq->page_list, list) {
1736662306a36Sopenharmony_ci		rq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
1736762306a36Sopenharmony_ci					putPaddrLow(dmabuf->phys);
1736862306a36Sopenharmony_ci		rq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
1736962306a36Sopenharmony_ci					putPaddrHigh(dmabuf->phys);
1737062306a36Sopenharmony_ci	}
1737162306a36Sopenharmony_ci	if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE)
1737262306a36Sopenharmony_ci		bf_set(lpfc_mbx_rq_create_dua, &rq_create->u.request, 1);
1737362306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1737462306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1737562306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr;
1737662306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1737762306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1737862306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1737962306a36Sopenharmony_ci		status = -ENXIO;
1738062306a36Sopenharmony_ci		goto out;
1738162306a36Sopenharmony_ci	}
1738262306a36Sopenharmony_ci	drq->queue_id = bf_get(lpfc_mbx_rq_create_q_id, &rq_create->u.response);
1738362306a36Sopenharmony_ci	if (drq->queue_id == 0xFFFF) {
1738462306a36Sopenharmony_ci		status = -ENXIO;
1738562306a36Sopenharmony_ci		goto out;
1738662306a36Sopenharmony_ci	}
1738762306a36Sopenharmony_ci	drq->type = LPFC_DRQ;
1738862306a36Sopenharmony_ci	drq->assoc_qid = cq->queue_id;
1738962306a36Sopenharmony_ci	drq->subtype = subtype;
1739062306a36Sopenharmony_ci	drq->host_index = 0;
1739162306a36Sopenharmony_ci	drq->hba_index = 0;
1739262306a36Sopenharmony_ci	drq->notify_interval = LPFC_RQ_NOTIFY_INTRVL;
1739362306a36Sopenharmony_ci
1739462306a36Sopenharmony_ci	/* link the header and data RQs onto the parent cq child list */
1739562306a36Sopenharmony_ci	list_add_tail(&hrq->list, &cq->child_list);
1739662306a36Sopenharmony_ci	list_add_tail(&drq->list, &cq->child_list);
1739762306a36Sopenharmony_ci
1739862306a36Sopenharmony_ciout:
1739962306a36Sopenharmony_ci	mempool_free(mbox, phba->mbox_mem_pool);
1740062306a36Sopenharmony_ci	return status;
1740162306a36Sopenharmony_ci}
1740262306a36Sopenharmony_ci
1740362306a36Sopenharmony_ci/**
1740462306a36Sopenharmony_ci * lpfc_mrq_create - Create MRQ Receive Queues on the HBA
1740562306a36Sopenharmony_ci * @phba: HBA structure that indicates port to create a queue on.
1740662306a36Sopenharmony_ci * @hrqp: The queue structure array to use to create the header receive queues.
1740762306a36Sopenharmony_ci * @drqp: The queue structure array to use to create the data receive queues.
1740862306a36Sopenharmony_ci * @cqp: The completion queue array to bind these receive queues to.
1740962306a36Sopenharmony_ci * @subtype: Functional purpose of the queue (MBOX, IO, ELS, NVMET, etc).
1741062306a36Sopenharmony_ci *
1741162306a36Sopenharmony_ci * This function creates a receive buffer queue pair , as detailed in @hrq and
1741262306a36Sopenharmony_ci * @drq, on a port, described by @phba by sending a RQ_CREATE mailbox command
1741362306a36Sopenharmony_ci * to the HBA.
1741462306a36Sopenharmony_ci *
1741562306a36Sopenharmony_ci * The @phba struct is used to send mailbox command to HBA. The @drq and @hrq
1741662306a36Sopenharmony_ci * struct is used to get the entry count that is necessary to determine the
1741762306a36Sopenharmony_ci * number of pages to use for this queue. The @cq is used to indicate which
1741862306a36Sopenharmony_ci * completion queue to bind received buffers that are posted to these queues to.
1741962306a36Sopenharmony_ci * This function will send the RQ_CREATE mailbox command to the HBA to setup the
1742062306a36Sopenharmony_ci * receive queue pair. This function is asynchronous and will wait for the
1742162306a36Sopenharmony_ci * mailbox command to finish before continuing.
1742262306a36Sopenharmony_ci *
1742362306a36Sopenharmony_ci * On success this function will return a zero. If unable to allocate enough
1742462306a36Sopenharmony_ci * memory this function will return -ENOMEM. If the queue create mailbox command
1742562306a36Sopenharmony_ci * fails this function will return -ENXIO.
1742662306a36Sopenharmony_ci **/
1742762306a36Sopenharmony_ciint
1742862306a36Sopenharmony_cilpfc_mrq_create(struct lpfc_hba *phba, struct lpfc_queue **hrqp,
1742962306a36Sopenharmony_ci		struct lpfc_queue **drqp, struct lpfc_queue **cqp,
1743062306a36Sopenharmony_ci		uint32_t subtype)
1743162306a36Sopenharmony_ci{
1743262306a36Sopenharmony_ci	struct lpfc_queue *hrq, *drq, *cq;
1743362306a36Sopenharmony_ci	struct lpfc_mbx_rq_create_v2 *rq_create;
1743462306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
1743562306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1743662306a36Sopenharmony_ci	int rc, length, alloclen, status = 0;
1743762306a36Sopenharmony_ci	int cnt, idx, numrq, page_idx = 0;
1743862306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1743962306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1744062306a36Sopenharmony_ci	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
1744162306a36Sopenharmony_ci
1744262306a36Sopenharmony_ci	numrq = phba->cfg_nvmet_mrq;
1744362306a36Sopenharmony_ci	/* sanity check on array memory */
1744462306a36Sopenharmony_ci	if (!hrqp || !drqp || !cqp || !numrq)
1744562306a36Sopenharmony_ci		return -ENODEV;
1744662306a36Sopenharmony_ci	if (!phba->sli4_hba.pc_sli4_params.supported)
1744762306a36Sopenharmony_ci		hw_page_size = SLI4_PAGE_SIZE;
1744862306a36Sopenharmony_ci
1744962306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1745062306a36Sopenharmony_ci	if (!mbox)
1745162306a36Sopenharmony_ci		return -ENOMEM;
1745262306a36Sopenharmony_ci
1745362306a36Sopenharmony_ci	length = sizeof(struct lpfc_mbx_rq_create_v2);
1745462306a36Sopenharmony_ci	length += ((2 * numrq * hrqp[0]->page_count) *
1745562306a36Sopenharmony_ci		   sizeof(struct dma_address));
1745662306a36Sopenharmony_ci
1745762306a36Sopenharmony_ci	alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
1745862306a36Sopenharmony_ci				    LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, length,
1745962306a36Sopenharmony_ci				    LPFC_SLI4_MBX_NEMBED);
1746062306a36Sopenharmony_ci	if (alloclen < length) {
1746162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1746262306a36Sopenharmony_ci				"3099 Allocated DMA memory size (%d) is "
1746362306a36Sopenharmony_ci				"less than the requested DMA memory size "
1746462306a36Sopenharmony_ci				"(%d)\n", alloclen, length);
1746562306a36Sopenharmony_ci		status = -ENOMEM;
1746662306a36Sopenharmony_ci		goto out;
1746762306a36Sopenharmony_ci	}
1746862306a36Sopenharmony_ci
1746962306a36Sopenharmony_ci
1747062306a36Sopenharmony_ci
1747162306a36Sopenharmony_ci	rq_create = mbox->sge_array->addr[0];
1747262306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)&rq_create->cfg_shdr;
1747362306a36Sopenharmony_ci
1747462306a36Sopenharmony_ci	bf_set(lpfc_mbox_hdr_version, &shdr->request, LPFC_Q_CREATE_VERSION_2);
1747562306a36Sopenharmony_ci	cnt = 0;
1747662306a36Sopenharmony_ci
1747762306a36Sopenharmony_ci	for (idx = 0; idx < numrq; idx++) {
1747862306a36Sopenharmony_ci		hrq = hrqp[idx];
1747962306a36Sopenharmony_ci		drq = drqp[idx];
1748062306a36Sopenharmony_ci		cq  = cqp[idx];
1748162306a36Sopenharmony_ci
1748262306a36Sopenharmony_ci		/* sanity check on queue memory */
1748362306a36Sopenharmony_ci		if (!hrq || !drq || !cq) {
1748462306a36Sopenharmony_ci			status = -ENODEV;
1748562306a36Sopenharmony_ci			goto out;
1748662306a36Sopenharmony_ci		}
1748762306a36Sopenharmony_ci
1748862306a36Sopenharmony_ci		if (hrq->entry_count != drq->entry_count) {
1748962306a36Sopenharmony_ci			status = -EINVAL;
1749062306a36Sopenharmony_ci			goto out;
1749162306a36Sopenharmony_ci		}
1749262306a36Sopenharmony_ci
1749362306a36Sopenharmony_ci		if (idx == 0) {
1749462306a36Sopenharmony_ci			bf_set(lpfc_mbx_rq_create_num_pages,
1749562306a36Sopenharmony_ci			       &rq_create->u.request,
1749662306a36Sopenharmony_ci			       hrq->page_count);
1749762306a36Sopenharmony_ci			bf_set(lpfc_mbx_rq_create_rq_cnt,
1749862306a36Sopenharmony_ci			       &rq_create->u.request, (numrq * 2));
1749962306a36Sopenharmony_ci			bf_set(lpfc_mbx_rq_create_dnb, &rq_create->u.request,
1750062306a36Sopenharmony_ci			       1);
1750162306a36Sopenharmony_ci			bf_set(lpfc_rq_context_base_cq,
1750262306a36Sopenharmony_ci			       &rq_create->u.request.context,
1750362306a36Sopenharmony_ci			       cq->queue_id);
1750462306a36Sopenharmony_ci			bf_set(lpfc_rq_context_data_size,
1750562306a36Sopenharmony_ci			       &rq_create->u.request.context,
1750662306a36Sopenharmony_ci			       LPFC_NVMET_DATA_BUF_SIZE);
1750762306a36Sopenharmony_ci			bf_set(lpfc_rq_context_hdr_size,
1750862306a36Sopenharmony_ci			       &rq_create->u.request.context,
1750962306a36Sopenharmony_ci			       LPFC_HDR_BUF_SIZE);
1751062306a36Sopenharmony_ci			bf_set(lpfc_rq_context_rqe_count_1,
1751162306a36Sopenharmony_ci			       &rq_create->u.request.context,
1751262306a36Sopenharmony_ci			       hrq->entry_count);
1751362306a36Sopenharmony_ci			bf_set(lpfc_rq_context_rqe_size,
1751462306a36Sopenharmony_ci			       &rq_create->u.request.context,
1751562306a36Sopenharmony_ci			       LPFC_RQE_SIZE_8);
1751662306a36Sopenharmony_ci			bf_set(lpfc_rq_context_page_size,
1751762306a36Sopenharmony_ci			       &rq_create->u.request.context,
1751862306a36Sopenharmony_ci			       (PAGE_SIZE/SLI4_PAGE_SIZE));
1751962306a36Sopenharmony_ci		}
1752062306a36Sopenharmony_ci		rc = 0;
1752162306a36Sopenharmony_ci		list_for_each_entry(dmabuf, &hrq->page_list, list) {
1752262306a36Sopenharmony_ci			memset(dmabuf->virt, 0, hw_page_size);
1752362306a36Sopenharmony_ci			cnt = page_idx + dmabuf->buffer_tag;
1752462306a36Sopenharmony_ci			rq_create->u.request.page[cnt].addr_lo =
1752562306a36Sopenharmony_ci					putPaddrLow(dmabuf->phys);
1752662306a36Sopenharmony_ci			rq_create->u.request.page[cnt].addr_hi =
1752762306a36Sopenharmony_ci					putPaddrHigh(dmabuf->phys);
1752862306a36Sopenharmony_ci			rc++;
1752962306a36Sopenharmony_ci		}
1753062306a36Sopenharmony_ci		page_idx += rc;
1753162306a36Sopenharmony_ci
1753262306a36Sopenharmony_ci		rc = 0;
1753362306a36Sopenharmony_ci		list_for_each_entry(dmabuf, &drq->page_list, list) {
1753462306a36Sopenharmony_ci			memset(dmabuf->virt, 0, hw_page_size);
1753562306a36Sopenharmony_ci			cnt = page_idx + dmabuf->buffer_tag;
1753662306a36Sopenharmony_ci			rq_create->u.request.page[cnt].addr_lo =
1753762306a36Sopenharmony_ci					putPaddrLow(dmabuf->phys);
1753862306a36Sopenharmony_ci			rq_create->u.request.page[cnt].addr_hi =
1753962306a36Sopenharmony_ci					putPaddrHigh(dmabuf->phys);
1754062306a36Sopenharmony_ci			rc++;
1754162306a36Sopenharmony_ci		}
1754262306a36Sopenharmony_ci		page_idx += rc;
1754362306a36Sopenharmony_ci
1754462306a36Sopenharmony_ci		hrq->db_format = LPFC_DB_RING_FORMAT;
1754562306a36Sopenharmony_ci		hrq->db_regaddr = phba->sli4_hba.RQDBregaddr;
1754662306a36Sopenharmony_ci		hrq->type = LPFC_HRQ;
1754762306a36Sopenharmony_ci		hrq->assoc_qid = cq->queue_id;
1754862306a36Sopenharmony_ci		hrq->subtype = subtype;
1754962306a36Sopenharmony_ci		hrq->host_index = 0;
1755062306a36Sopenharmony_ci		hrq->hba_index = 0;
1755162306a36Sopenharmony_ci		hrq->notify_interval = LPFC_RQ_NOTIFY_INTRVL;
1755262306a36Sopenharmony_ci
1755362306a36Sopenharmony_ci		drq->db_format = LPFC_DB_RING_FORMAT;
1755462306a36Sopenharmony_ci		drq->db_regaddr = phba->sli4_hba.RQDBregaddr;
1755562306a36Sopenharmony_ci		drq->type = LPFC_DRQ;
1755662306a36Sopenharmony_ci		drq->assoc_qid = cq->queue_id;
1755762306a36Sopenharmony_ci		drq->subtype = subtype;
1755862306a36Sopenharmony_ci		drq->host_index = 0;
1755962306a36Sopenharmony_ci		drq->hba_index = 0;
1756062306a36Sopenharmony_ci		drq->notify_interval = LPFC_RQ_NOTIFY_INTRVL;
1756162306a36Sopenharmony_ci
1756262306a36Sopenharmony_ci		list_add_tail(&hrq->list, &cq->child_list);
1756362306a36Sopenharmony_ci		list_add_tail(&drq->list, &cq->child_list);
1756462306a36Sopenharmony_ci	}
1756562306a36Sopenharmony_ci
1756662306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1756762306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1756862306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1756962306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1757062306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1757162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1757262306a36Sopenharmony_ci				"3120 RQ_CREATE mailbox failed with "
1757362306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1757462306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1757562306a36Sopenharmony_ci		status = -ENXIO;
1757662306a36Sopenharmony_ci		goto out;
1757762306a36Sopenharmony_ci	}
1757862306a36Sopenharmony_ci	rc = bf_get(lpfc_mbx_rq_create_q_id, &rq_create->u.response);
1757962306a36Sopenharmony_ci	if (rc == 0xFFFF) {
1758062306a36Sopenharmony_ci		status = -ENXIO;
1758162306a36Sopenharmony_ci		goto out;
1758262306a36Sopenharmony_ci	}
1758362306a36Sopenharmony_ci
1758462306a36Sopenharmony_ci	/* Initialize all RQs with associated queue id */
1758562306a36Sopenharmony_ci	for (idx = 0; idx < numrq; idx++) {
1758662306a36Sopenharmony_ci		hrq = hrqp[idx];
1758762306a36Sopenharmony_ci		hrq->queue_id = rc + (2 * idx);
1758862306a36Sopenharmony_ci		drq = drqp[idx];
1758962306a36Sopenharmony_ci		drq->queue_id = rc + (2 * idx) + 1;
1759062306a36Sopenharmony_ci	}
1759162306a36Sopenharmony_ci
1759262306a36Sopenharmony_ciout:
1759362306a36Sopenharmony_ci	lpfc_sli4_mbox_cmd_free(phba, mbox);
1759462306a36Sopenharmony_ci	return status;
1759562306a36Sopenharmony_ci}
1759662306a36Sopenharmony_ci
1759762306a36Sopenharmony_ci/**
1759862306a36Sopenharmony_ci * lpfc_eq_destroy - Destroy an event Queue on the HBA
1759962306a36Sopenharmony_ci * @phba: HBA structure that indicates port to destroy a queue on.
1760062306a36Sopenharmony_ci * @eq: The queue structure associated with the queue to destroy.
1760162306a36Sopenharmony_ci *
1760262306a36Sopenharmony_ci * This function destroys a queue, as detailed in @eq by sending an mailbox
1760362306a36Sopenharmony_ci * command, specific to the type of queue, to the HBA.
1760462306a36Sopenharmony_ci *
1760562306a36Sopenharmony_ci * The @eq struct is used to get the queue ID of the queue to destroy.
1760662306a36Sopenharmony_ci *
1760762306a36Sopenharmony_ci * On success this function will return a zero. If the queue destroy mailbox
1760862306a36Sopenharmony_ci * command fails this function will return -ENXIO.
1760962306a36Sopenharmony_ci **/
1761062306a36Sopenharmony_ciint
1761162306a36Sopenharmony_cilpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq)
1761262306a36Sopenharmony_ci{
1761362306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1761462306a36Sopenharmony_ci	int rc, length, status = 0;
1761562306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1761662306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1761762306a36Sopenharmony_ci
1761862306a36Sopenharmony_ci	/* sanity check on queue memory */
1761962306a36Sopenharmony_ci	if (!eq)
1762062306a36Sopenharmony_ci		return -ENODEV;
1762162306a36Sopenharmony_ci
1762262306a36Sopenharmony_ci	mbox = mempool_alloc(eq->phba->mbox_mem_pool, GFP_KERNEL);
1762362306a36Sopenharmony_ci	if (!mbox)
1762462306a36Sopenharmony_ci		return -ENOMEM;
1762562306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_eq_destroy) -
1762662306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1762762306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
1762862306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_EQ_DESTROY,
1762962306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1763062306a36Sopenharmony_ci	bf_set(lpfc_mbx_eq_destroy_q_id, &mbox->u.mqe.un.eq_destroy.u.request,
1763162306a36Sopenharmony_ci	       eq->queue_id);
1763262306a36Sopenharmony_ci	mbox->vport = eq->phba->pport;
1763362306a36Sopenharmony_ci	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
1763462306a36Sopenharmony_ci
1763562306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(eq->phba, mbox, MBX_POLL);
1763662306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1763762306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)
1763862306a36Sopenharmony_ci		&mbox->u.mqe.un.eq_destroy.header.cfg_shdr;
1763962306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1764062306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1764162306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1764262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1764362306a36Sopenharmony_ci				"2505 EQ_DESTROY mailbox failed with "
1764462306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1764562306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1764662306a36Sopenharmony_ci		status = -ENXIO;
1764762306a36Sopenharmony_ci	}
1764862306a36Sopenharmony_ci
1764962306a36Sopenharmony_ci	/* Remove eq from any list */
1765062306a36Sopenharmony_ci	list_del_init(&eq->list);
1765162306a36Sopenharmony_ci	mempool_free(mbox, eq->phba->mbox_mem_pool);
1765262306a36Sopenharmony_ci	return status;
1765362306a36Sopenharmony_ci}
1765462306a36Sopenharmony_ci
1765562306a36Sopenharmony_ci/**
1765662306a36Sopenharmony_ci * lpfc_cq_destroy - Destroy a Completion Queue on the HBA
1765762306a36Sopenharmony_ci * @phba: HBA structure that indicates port to destroy a queue on.
1765862306a36Sopenharmony_ci * @cq: The queue structure associated with the queue to destroy.
1765962306a36Sopenharmony_ci *
1766062306a36Sopenharmony_ci * This function destroys a queue, as detailed in @cq by sending an mailbox
1766162306a36Sopenharmony_ci * command, specific to the type of queue, to the HBA.
1766262306a36Sopenharmony_ci *
1766362306a36Sopenharmony_ci * The @cq struct is used to get the queue ID of the queue to destroy.
1766462306a36Sopenharmony_ci *
1766562306a36Sopenharmony_ci * On success this function will return a zero. If the queue destroy mailbox
1766662306a36Sopenharmony_ci * command fails this function will return -ENXIO.
1766762306a36Sopenharmony_ci **/
1766862306a36Sopenharmony_ciint
1766962306a36Sopenharmony_cilpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq)
1767062306a36Sopenharmony_ci{
1767162306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1767262306a36Sopenharmony_ci	int rc, length, status = 0;
1767362306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1767462306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1767562306a36Sopenharmony_ci
1767662306a36Sopenharmony_ci	/* sanity check on queue memory */
1767762306a36Sopenharmony_ci	if (!cq)
1767862306a36Sopenharmony_ci		return -ENODEV;
1767962306a36Sopenharmony_ci	mbox = mempool_alloc(cq->phba->mbox_mem_pool, GFP_KERNEL);
1768062306a36Sopenharmony_ci	if (!mbox)
1768162306a36Sopenharmony_ci		return -ENOMEM;
1768262306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_cq_destroy) -
1768362306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1768462306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
1768562306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_CQ_DESTROY,
1768662306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1768762306a36Sopenharmony_ci	bf_set(lpfc_mbx_cq_destroy_q_id, &mbox->u.mqe.un.cq_destroy.u.request,
1768862306a36Sopenharmony_ci	       cq->queue_id);
1768962306a36Sopenharmony_ci	mbox->vport = cq->phba->pport;
1769062306a36Sopenharmony_ci	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
1769162306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(cq->phba, mbox, MBX_POLL);
1769262306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1769362306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)
1769462306a36Sopenharmony_ci		&mbox->u.mqe.un.wq_create.header.cfg_shdr;
1769562306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1769662306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1769762306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1769862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1769962306a36Sopenharmony_ci				"2506 CQ_DESTROY mailbox failed with "
1770062306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1770162306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1770262306a36Sopenharmony_ci		status = -ENXIO;
1770362306a36Sopenharmony_ci	}
1770462306a36Sopenharmony_ci	/* Remove cq from any list */
1770562306a36Sopenharmony_ci	list_del_init(&cq->list);
1770662306a36Sopenharmony_ci	mempool_free(mbox, cq->phba->mbox_mem_pool);
1770762306a36Sopenharmony_ci	return status;
1770862306a36Sopenharmony_ci}
1770962306a36Sopenharmony_ci
1771062306a36Sopenharmony_ci/**
1771162306a36Sopenharmony_ci * lpfc_mq_destroy - Destroy a Mailbox Queue on the HBA
1771262306a36Sopenharmony_ci * @phba: HBA structure that indicates port to destroy a queue on.
1771362306a36Sopenharmony_ci * @mq: The queue structure associated with the queue to destroy.
1771462306a36Sopenharmony_ci *
1771562306a36Sopenharmony_ci * This function destroys a queue, as detailed in @mq by sending an mailbox
1771662306a36Sopenharmony_ci * command, specific to the type of queue, to the HBA.
1771762306a36Sopenharmony_ci *
1771862306a36Sopenharmony_ci * The @mq struct is used to get the queue ID of the queue to destroy.
1771962306a36Sopenharmony_ci *
1772062306a36Sopenharmony_ci * On success this function will return a zero. If the queue destroy mailbox
1772162306a36Sopenharmony_ci * command fails this function will return -ENXIO.
1772262306a36Sopenharmony_ci **/
1772362306a36Sopenharmony_ciint
1772462306a36Sopenharmony_cilpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq)
1772562306a36Sopenharmony_ci{
1772662306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1772762306a36Sopenharmony_ci	int rc, length, status = 0;
1772862306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1772962306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1773062306a36Sopenharmony_ci
1773162306a36Sopenharmony_ci	/* sanity check on queue memory */
1773262306a36Sopenharmony_ci	if (!mq)
1773362306a36Sopenharmony_ci		return -ENODEV;
1773462306a36Sopenharmony_ci	mbox = mempool_alloc(mq->phba->mbox_mem_pool, GFP_KERNEL);
1773562306a36Sopenharmony_ci	if (!mbox)
1773662306a36Sopenharmony_ci		return -ENOMEM;
1773762306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_mq_destroy) -
1773862306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1773962306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
1774062306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_MQ_DESTROY,
1774162306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1774262306a36Sopenharmony_ci	bf_set(lpfc_mbx_mq_destroy_q_id, &mbox->u.mqe.un.mq_destroy.u.request,
1774362306a36Sopenharmony_ci	       mq->queue_id);
1774462306a36Sopenharmony_ci	mbox->vport = mq->phba->pport;
1774562306a36Sopenharmony_ci	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
1774662306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(mq->phba, mbox, MBX_POLL);
1774762306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1774862306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)
1774962306a36Sopenharmony_ci		&mbox->u.mqe.un.mq_destroy.header.cfg_shdr;
1775062306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1775162306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1775262306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1775362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1775462306a36Sopenharmony_ci				"2507 MQ_DESTROY mailbox failed with "
1775562306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1775662306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1775762306a36Sopenharmony_ci		status = -ENXIO;
1775862306a36Sopenharmony_ci	}
1775962306a36Sopenharmony_ci	/* Remove mq from any list */
1776062306a36Sopenharmony_ci	list_del_init(&mq->list);
1776162306a36Sopenharmony_ci	mempool_free(mbox, mq->phba->mbox_mem_pool);
1776262306a36Sopenharmony_ci	return status;
1776362306a36Sopenharmony_ci}
1776462306a36Sopenharmony_ci
1776562306a36Sopenharmony_ci/**
1776662306a36Sopenharmony_ci * lpfc_wq_destroy - Destroy a Work Queue on the HBA
1776762306a36Sopenharmony_ci * @phba: HBA structure that indicates port to destroy a queue on.
1776862306a36Sopenharmony_ci * @wq: The queue structure associated with the queue to destroy.
1776962306a36Sopenharmony_ci *
1777062306a36Sopenharmony_ci * This function destroys a queue, as detailed in @wq by sending an mailbox
1777162306a36Sopenharmony_ci * command, specific to the type of queue, to the HBA.
1777262306a36Sopenharmony_ci *
1777362306a36Sopenharmony_ci * The @wq struct is used to get the queue ID of the queue to destroy.
1777462306a36Sopenharmony_ci *
1777562306a36Sopenharmony_ci * On success this function will return a zero. If the queue destroy mailbox
1777662306a36Sopenharmony_ci * command fails this function will return -ENXIO.
1777762306a36Sopenharmony_ci **/
1777862306a36Sopenharmony_ciint
1777962306a36Sopenharmony_cilpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq)
1778062306a36Sopenharmony_ci{
1778162306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1778262306a36Sopenharmony_ci	int rc, length, status = 0;
1778362306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1778462306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1778562306a36Sopenharmony_ci
1778662306a36Sopenharmony_ci	/* sanity check on queue memory */
1778762306a36Sopenharmony_ci	if (!wq)
1778862306a36Sopenharmony_ci		return -ENODEV;
1778962306a36Sopenharmony_ci	mbox = mempool_alloc(wq->phba->mbox_mem_pool, GFP_KERNEL);
1779062306a36Sopenharmony_ci	if (!mbox)
1779162306a36Sopenharmony_ci		return -ENOMEM;
1779262306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_wq_destroy) -
1779362306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1779462306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
1779562306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_FCOE_WQ_DESTROY,
1779662306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1779762306a36Sopenharmony_ci	bf_set(lpfc_mbx_wq_destroy_q_id, &mbox->u.mqe.un.wq_destroy.u.request,
1779862306a36Sopenharmony_ci	       wq->queue_id);
1779962306a36Sopenharmony_ci	mbox->vport = wq->phba->pport;
1780062306a36Sopenharmony_ci	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
1780162306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(wq->phba, mbox, MBX_POLL);
1780262306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)
1780362306a36Sopenharmony_ci		&mbox->u.mqe.un.wq_destroy.header.cfg_shdr;
1780462306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1780562306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1780662306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1780762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1780862306a36Sopenharmony_ci				"2508 WQ_DESTROY mailbox failed with "
1780962306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1781062306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1781162306a36Sopenharmony_ci		status = -ENXIO;
1781262306a36Sopenharmony_ci	}
1781362306a36Sopenharmony_ci	/* Remove wq from any list */
1781462306a36Sopenharmony_ci	list_del_init(&wq->list);
1781562306a36Sopenharmony_ci	kfree(wq->pring);
1781662306a36Sopenharmony_ci	wq->pring = NULL;
1781762306a36Sopenharmony_ci	mempool_free(mbox, wq->phba->mbox_mem_pool);
1781862306a36Sopenharmony_ci	return status;
1781962306a36Sopenharmony_ci}
1782062306a36Sopenharmony_ci
1782162306a36Sopenharmony_ci/**
1782262306a36Sopenharmony_ci * lpfc_rq_destroy - Destroy a Receive Queue on the HBA
1782362306a36Sopenharmony_ci * @phba: HBA structure that indicates port to destroy a queue on.
1782462306a36Sopenharmony_ci * @hrq: The queue structure associated with the queue to destroy.
1782562306a36Sopenharmony_ci * @drq: The queue structure associated with the queue to destroy.
1782662306a36Sopenharmony_ci *
1782762306a36Sopenharmony_ci * This function destroys a queue, as detailed in @rq by sending an mailbox
1782862306a36Sopenharmony_ci * command, specific to the type of queue, to the HBA.
1782962306a36Sopenharmony_ci *
1783062306a36Sopenharmony_ci * The @rq struct is used to get the queue ID of the queue to destroy.
1783162306a36Sopenharmony_ci *
1783262306a36Sopenharmony_ci * On success this function will return a zero. If the queue destroy mailbox
1783362306a36Sopenharmony_ci * command fails this function will return -ENXIO.
1783462306a36Sopenharmony_ci **/
1783562306a36Sopenharmony_ciint
1783662306a36Sopenharmony_cilpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq,
1783762306a36Sopenharmony_ci		struct lpfc_queue *drq)
1783862306a36Sopenharmony_ci{
1783962306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1784062306a36Sopenharmony_ci	int rc, length, status = 0;
1784162306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1784262306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1784362306a36Sopenharmony_ci
1784462306a36Sopenharmony_ci	/* sanity check on queue memory */
1784562306a36Sopenharmony_ci	if (!hrq || !drq)
1784662306a36Sopenharmony_ci		return -ENODEV;
1784762306a36Sopenharmony_ci	mbox = mempool_alloc(hrq->phba->mbox_mem_pool, GFP_KERNEL);
1784862306a36Sopenharmony_ci	if (!mbox)
1784962306a36Sopenharmony_ci		return -ENOMEM;
1785062306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_rq_destroy) -
1785162306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
1785262306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
1785362306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_FCOE_RQ_DESTROY,
1785462306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
1785562306a36Sopenharmony_ci	bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request,
1785662306a36Sopenharmony_ci	       hrq->queue_id);
1785762306a36Sopenharmony_ci	mbox->vport = hrq->phba->pport;
1785862306a36Sopenharmony_ci	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
1785962306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(hrq->phba, mbox, MBX_POLL);
1786062306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1786162306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)
1786262306a36Sopenharmony_ci		&mbox->u.mqe.un.rq_destroy.header.cfg_shdr;
1786362306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1786462306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1786562306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1786662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1786762306a36Sopenharmony_ci				"2509 RQ_DESTROY mailbox failed with "
1786862306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1786962306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1787062306a36Sopenharmony_ci		mempool_free(mbox, hrq->phba->mbox_mem_pool);
1787162306a36Sopenharmony_ci		return -ENXIO;
1787262306a36Sopenharmony_ci	}
1787362306a36Sopenharmony_ci	bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request,
1787462306a36Sopenharmony_ci	       drq->queue_id);
1787562306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(drq->phba, mbox, MBX_POLL);
1787662306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)
1787762306a36Sopenharmony_ci		&mbox->u.mqe.un.rq_destroy.header.cfg_shdr;
1787862306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1787962306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1788062306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1788162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1788262306a36Sopenharmony_ci				"2510 RQ_DESTROY mailbox failed with "
1788362306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1788462306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1788562306a36Sopenharmony_ci		status = -ENXIO;
1788662306a36Sopenharmony_ci	}
1788762306a36Sopenharmony_ci	list_del_init(&hrq->list);
1788862306a36Sopenharmony_ci	list_del_init(&drq->list);
1788962306a36Sopenharmony_ci	mempool_free(mbox, hrq->phba->mbox_mem_pool);
1789062306a36Sopenharmony_ci	return status;
1789162306a36Sopenharmony_ci}
1789262306a36Sopenharmony_ci
1789362306a36Sopenharmony_ci/**
1789462306a36Sopenharmony_ci * lpfc_sli4_post_sgl - Post scatter gather list for an XRI to HBA
1789562306a36Sopenharmony_ci * @phba: The virtual port for which this call being executed.
1789662306a36Sopenharmony_ci * @pdma_phys_addr0: Physical address of the 1st SGL page.
1789762306a36Sopenharmony_ci * @pdma_phys_addr1: Physical address of the 2nd SGL page.
1789862306a36Sopenharmony_ci * @xritag: the xritag that ties this io to the SGL pages.
1789962306a36Sopenharmony_ci *
1790062306a36Sopenharmony_ci * This routine will post the sgl pages for the IO that has the xritag
1790162306a36Sopenharmony_ci * that is in the iocbq structure. The xritag is assigned during iocbq
1790262306a36Sopenharmony_ci * creation and persists for as long as the driver is loaded.
1790362306a36Sopenharmony_ci * if the caller has fewer than 256 scatter gather segments to map then
1790462306a36Sopenharmony_ci * pdma_phys_addr1 should be 0.
1790562306a36Sopenharmony_ci * If the caller needs to map more than 256 scatter gather segment then
1790662306a36Sopenharmony_ci * pdma_phys_addr1 should be a valid physical address.
1790762306a36Sopenharmony_ci * physical address for SGLs must be 64 byte aligned.
1790862306a36Sopenharmony_ci * If you are going to map 2 SGL's then the first one must have 256 entries
1790962306a36Sopenharmony_ci * the second sgl can have between 1 and 256 entries.
1791062306a36Sopenharmony_ci *
1791162306a36Sopenharmony_ci * Return codes:
1791262306a36Sopenharmony_ci * 	0 - Success
1791362306a36Sopenharmony_ci * 	-ENXIO, -ENOMEM - Failure
1791462306a36Sopenharmony_ci **/
1791562306a36Sopenharmony_ciint
1791662306a36Sopenharmony_cilpfc_sli4_post_sgl(struct lpfc_hba *phba,
1791762306a36Sopenharmony_ci		dma_addr_t pdma_phys_addr0,
1791862306a36Sopenharmony_ci		dma_addr_t pdma_phys_addr1,
1791962306a36Sopenharmony_ci		uint16_t xritag)
1792062306a36Sopenharmony_ci{
1792162306a36Sopenharmony_ci	struct lpfc_mbx_post_sgl_pages *post_sgl_pages;
1792262306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1792362306a36Sopenharmony_ci	int rc;
1792462306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1792562306a36Sopenharmony_ci	uint32_t mbox_tmo;
1792662306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1792762306a36Sopenharmony_ci
1792862306a36Sopenharmony_ci	if (xritag == NO_XRI) {
1792962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1793062306a36Sopenharmony_ci				"0364 Invalid param:\n");
1793162306a36Sopenharmony_ci		return -EINVAL;
1793262306a36Sopenharmony_ci	}
1793362306a36Sopenharmony_ci
1793462306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1793562306a36Sopenharmony_ci	if (!mbox)
1793662306a36Sopenharmony_ci		return -ENOMEM;
1793762306a36Sopenharmony_ci
1793862306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
1793962306a36Sopenharmony_ci			LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES,
1794062306a36Sopenharmony_ci			sizeof(struct lpfc_mbx_post_sgl_pages) -
1794162306a36Sopenharmony_ci			sizeof(struct lpfc_sli4_cfg_mhdr), LPFC_SLI4_MBX_EMBED);
1794262306a36Sopenharmony_ci
1794362306a36Sopenharmony_ci	post_sgl_pages = (struct lpfc_mbx_post_sgl_pages *)
1794462306a36Sopenharmony_ci				&mbox->u.mqe.un.post_sgl_pages;
1794562306a36Sopenharmony_ci	bf_set(lpfc_post_sgl_pages_xri, post_sgl_pages, xritag);
1794662306a36Sopenharmony_ci	bf_set(lpfc_post_sgl_pages_xricnt, post_sgl_pages, 1);
1794762306a36Sopenharmony_ci
1794862306a36Sopenharmony_ci	post_sgl_pages->sgl_pg_pairs[0].sgl_pg0_addr_lo	=
1794962306a36Sopenharmony_ci				cpu_to_le32(putPaddrLow(pdma_phys_addr0));
1795062306a36Sopenharmony_ci	post_sgl_pages->sgl_pg_pairs[0].sgl_pg0_addr_hi =
1795162306a36Sopenharmony_ci				cpu_to_le32(putPaddrHigh(pdma_phys_addr0));
1795262306a36Sopenharmony_ci
1795362306a36Sopenharmony_ci	post_sgl_pages->sgl_pg_pairs[0].sgl_pg1_addr_lo	=
1795462306a36Sopenharmony_ci				cpu_to_le32(putPaddrLow(pdma_phys_addr1));
1795562306a36Sopenharmony_ci	post_sgl_pages->sgl_pg_pairs[0].sgl_pg1_addr_hi =
1795662306a36Sopenharmony_ci				cpu_to_le32(putPaddrHigh(pdma_phys_addr1));
1795762306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable)
1795862306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1795962306a36Sopenharmony_ci	else {
1796062306a36Sopenharmony_ci		mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
1796162306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
1796262306a36Sopenharmony_ci	}
1796362306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1796462306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *) &post_sgl_pages->header.cfg_shdr;
1796562306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1796662306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1796762306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable)
1796862306a36Sopenharmony_ci		mempool_free(mbox, phba->mbox_mem_pool);
1796962306a36Sopenharmony_ci	else if (rc != MBX_TIMEOUT)
1797062306a36Sopenharmony_ci		mempool_free(mbox, phba->mbox_mem_pool);
1797162306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1797262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1797362306a36Sopenharmony_ci				"2511 POST_SGL mailbox failed with "
1797462306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1797562306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1797662306a36Sopenharmony_ci	}
1797762306a36Sopenharmony_ci	return 0;
1797862306a36Sopenharmony_ci}
1797962306a36Sopenharmony_ci
1798062306a36Sopenharmony_ci/**
1798162306a36Sopenharmony_ci * lpfc_sli4_alloc_xri - Get an available rpi in the device's range
1798262306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1798362306a36Sopenharmony_ci *
1798462306a36Sopenharmony_ci * This routine is invoked to post rpi header templates to the
1798562306a36Sopenharmony_ci * HBA consistent with the SLI-4 interface spec.  This routine
1798662306a36Sopenharmony_ci * posts a SLI4_PAGE_SIZE memory region to the port to hold up to
1798762306a36Sopenharmony_ci * SLI4_PAGE_SIZE modulo 64 rpi context headers.
1798862306a36Sopenharmony_ci *
1798962306a36Sopenharmony_ci * Returns
1799062306a36Sopenharmony_ci *	A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful
1799162306a36Sopenharmony_ci *	LPFC_RPI_ALLOC_ERROR if no rpis are available.
1799262306a36Sopenharmony_ci **/
1799362306a36Sopenharmony_cistatic uint16_t
1799462306a36Sopenharmony_cilpfc_sli4_alloc_xri(struct lpfc_hba *phba)
1799562306a36Sopenharmony_ci{
1799662306a36Sopenharmony_ci	unsigned long xri;
1799762306a36Sopenharmony_ci
1799862306a36Sopenharmony_ci	/*
1799962306a36Sopenharmony_ci	 * Fetch the next logical xri.  Because this index is logical,
1800062306a36Sopenharmony_ci	 * the driver starts at 0 each time.
1800162306a36Sopenharmony_ci	 */
1800262306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
1800362306a36Sopenharmony_ci	xri = find_first_zero_bit(phba->sli4_hba.xri_bmask,
1800462306a36Sopenharmony_ci				 phba->sli4_hba.max_cfg_param.max_xri);
1800562306a36Sopenharmony_ci	if (xri >= phba->sli4_hba.max_cfg_param.max_xri) {
1800662306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
1800762306a36Sopenharmony_ci		return NO_XRI;
1800862306a36Sopenharmony_ci	} else {
1800962306a36Sopenharmony_ci		set_bit(xri, phba->sli4_hba.xri_bmask);
1801062306a36Sopenharmony_ci		phba->sli4_hba.max_cfg_param.xri_used++;
1801162306a36Sopenharmony_ci	}
1801262306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
1801362306a36Sopenharmony_ci	return xri;
1801462306a36Sopenharmony_ci}
1801562306a36Sopenharmony_ci
1801662306a36Sopenharmony_ci/**
1801762306a36Sopenharmony_ci * __lpfc_sli4_free_xri - Release an xri for reuse.
1801862306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1801962306a36Sopenharmony_ci * @xri: xri to release.
1802062306a36Sopenharmony_ci *
1802162306a36Sopenharmony_ci * This routine is invoked to release an xri to the pool of
1802262306a36Sopenharmony_ci * available rpis maintained by the driver.
1802362306a36Sopenharmony_ci **/
1802462306a36Sopenharmony_cistatic void
1802562306a36Sopenharmony_ci__lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri)
1802662306a36Sopenharmony_ci{
1802762306a36Sopenharmony_ci	if (test_and_clear_bit(xri, phba->sli4_hba.xri_bmask)) {
1802862306a36Sopenharmony_ci		phba->sli4_hba.max_cfg_param.xri_used--;
1802962306a36Sopenharmony_ci	}
1803062306a36Sopenharmony_ci}
1803162306a36Sopenharmony_ci
1803262306a36Sopenharmony_ci/**
1803362306a36Sopenharmony_ci * lpfc_sli4_free_xri - Release an xri for reuse.
1803462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1803562306a36Sopenharmony_ci * @xri: xri to release.
1803662306a36Sopenharmony_ci *
1803762306a36Sopenharmony_ci * This routine is invoked to release an xri to the pool of
1803862306a36Sopenharmony_ci * available rpis maintained by the driver.
1803962306a36Sopenharmony_ci **/
1804062306a36Sopenharmony_civoid
1804162306a36Sopenharmony_cilpfc_sli4_free_xri(struct lpfc_hba *phba, int xri)
1804262306a36Sopenharmony_ci{
1804362306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
1804462306a36Sopenharmony_ci	__lpfc_sli4_free_xri(phba, xri);
1804562306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
1804662306a36Sopenharmony_ci}
1804762306a36Sopenharmony_ci
1804862306a36Sopenharmony_ci/**
1804962306a36Sopenharmony_ci * lpfc_sli4_next_xritag - Get an xritag for the io
1805062306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1805162306a36Sopenharmony_ci *
1805262306a36Sopenharmony_ci * This function gets an xritag for the iocb. If there is no unused xritag
1805362306a36Sopenharmony_ci * it will return 0xffff.
1805462306a36Sopenharmony_ci * The function returns the allocated xritag if successful, else returns zero.
1805562306a36Sopenharmony_ci * Zero is not a valid xritag.
1805662306a36Sopenharmony_ci * The caller is not required to hold any lock.
1805762306a36Sopenharmony_ci **/
1805862306a36Sopenharmony_ciuint16_t
1805962306a36Sopenharmony_cilpfc_sli4_next_xritag(struct lpfc_hba *phba)
1806062306a36Sopenharmony_ci{
1806162306a36Sopenharmony_ci	uint16_t xri_index;
1806262306a36Sopenharmony_ci
1806362306a36Sopenharmony_ci	xri_index = lpfc_sli4_alloc_xri(phba);
1806462306a36Sopenharmony_ci	if (xri_index == NO_XRI)
1806562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
1806662306a36Sopenharmony_ci				"2004 Failed to allocate XRI.last XRITAG is %d"
1806762306a36Sopenharmony_ci				" Max XRI is %d, Used XRI is %d\n",
1806862306a36Sopenharmony_ci				xri_index,
1806962306a36Sopenharmony_ci				phba->sli4_hba.max_cfg_param.max_xri,
1807062306a36Sopenharmony_ci				phba->sli4_hba.max_cfg_param.xri_used);
1807162306a36Sopenharmony_ci	return xri_index;
1807262306a36Sopenharmony_ci}
1807362306a36Sopenharmony_ci
1807462306a36Sopenharmony_ci/**
1807562306a36Sopenharmony_ci * lpfc_sli4_post_sgl_list - post a block of ELS sgls to the port.
1807662306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1807762306a36Sopenharmony_ci * @post_sgl_list: pointer to els sgl entry list.
1807862306a36Sopenharmony_ci * @post_cnt: number of els sgl entries on the list.
1807962306a36Sopenharmony_ci *
1808062306a36Sopenharmony_ci * This routine is invoked to post a block of driver's sgl pages to the
1808162306a36Sopenharmony_ci * HBA using non-embedded mailbox command. No Lock is held. This routine
1808262306a36Sopenharmony_ci * is only called when the driver is loading and after all IO has been
1808362306a36Sopenharmony_ci * stopped.
1808462306a36Sopenharmony_ci **/
1808562306a36Sopenharmony_cistatic int
1808662306a36Sopenharmony_cilpfc_sli4_post_sgl_list(struct lpfc_hba *phba,
1808762306a36Sopenharmony_ci			    struct list_head *post_sgl_list,
1808862306a36Sopenharmony_ci			    int post_cnt)
1808962306a36Sopenharmony_ci{
1809062306a36Sopenharmony_ci	struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
1809162306a36Sopenharmony_ci	struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
1809262306a36Sopenharmony_ci	struct sgl_page_pairs *sgl_pg_pairs;
1809362306a36Sopenharmony_ci	void *viraddr;
1809462306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1809562306a36Sopenharmony_ci	uint32_t reqlen, alloclen, pg_pairs;
1809662306a36Sopenharmony_ci	uint32_t mbox_tmo;
1809762306a36Sopenharmony_ci	uint16_t xritag_start = 0;
1809862306a36Sopenharmony_ci	int rc = 0;
1809962306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1810062306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1810162306a36Sopenharmony_ci
1810262306a36Sopenharmony_ci	reqlen = post_cnt * sizeof(struct sgl_page_pairs) +
1810362306a36Sopenharmony_ci		 sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
1810462306a36Sopenharmony_ci	if (reqlen > SLI4_PAGE_SIZE) {
1810562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1810662306a36Sopenharmony_ci				"2559 Block sgl registration required DMA "
1810762306a36Sopenharmony_ci				"size (%d) great than a page\n", reqlen);
1810862306a36Sopenharmony_ci		return -ENOMEM;
1810962306a36Sopenharmony_ci	}
1811062306a36Sopenharmony_ci
1811162306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1811262306a36Sopenharmony_ci	if (!mbox)
1811362306a36Sopenharmony_ci		return -ENOMEM;
1811462306a36Sopenharmony_ci
1811562306a36Sopenharmony_ci	/* Allocate DMA memory and set up the non-embedded mailbox command */
1811662306a36Sopenharmony_ci	alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
1811762306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, reqlen,
1811862306a36Sopenharmony_ci			 LPFC_SLI4_MBX_NEMBED);
1811962306a36Sopenharmony_ci
1812062306a36Sopenharmony_ci	if (alloclen < reqlen) {
1812162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1812262306a36Sopenharmony_ci				"0285 Allocated DMA memory size (%d) is "
1812362306a36Sopenharmony_ci				"less than the requested DMA memory "
1812462306a36Sopenharmony_ci				"size (%d)\n", alloclen, reqlen);
1812562306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mbox);
1812662306a36Sopenharmony_ci		return -ENOMEM;
1812762306a36Sopenharmony_ci	}
1812862306a36Sopenharmony_ci	/* Set up the SGL pages in the non-embedded DMA pages */
1812962306a36Sopenharmony_ci	viraddr = mbox->sge_array->addr[0];
1813062306a36Sopenharmony_ci	sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
1813162306a36Sopenharmony_ci	sgl_pg_pairs = &sgl->sgl_pg_pairs;
1813262306a36Sopenharmony_ci
1813362306a36Sopenharmony_ci	pg_pairs = 0;
1813462306a36Sopenharmony_ci	list_for_each_entry_safe(sglq_entry, sglq_next, post_sgl_list, list) {
1813562306a36Sopenharmony_ci		/* Set up the sge entry */
1813662306a36Sopenharmony_ci		sgl_pg_pairs->sgl_pg0_addr_lo =
1813762306a36Sopenharmony_ci				cpu_to_le32(putPaddrLow(sglq_entry->phys));
1813862306a36Sopenharmony_ci		sgl_pg_pairs->sgl_pg0_addr_hi =
1813962306a36Sopenharmony_ci				cpu_to_le32(putPaddrHigh(sglq_entry->phys));
1814062306a36Sopenharmony_ci		sgl_pg_pairs->sgl_pg1_addr_lo =
1814162306a36Sopenharmony_ci				cpu_to_le32(putPaddrLow(0));
1814262306a36Sopenharmony_ci		sgl_pg_pairs->sgl_pg1_addr_hi =
1814362306a36Sopenharmony_ci				cpu_to_le32(putPaddrHigh(0));
1814462306a36Sopenharmony_ci
1814562306a36Sopenharmony_ci		/* Keep the first xritag on the list */
1814662306a36Sopenharmony_ci		if (pg_pairs == 0)
1814762306a36Sopenharmony_ci			xritag_start = sglq_entry->sli4_xritag;
1814862306a36Sopenharmony_ci		sgl_pg_pairs++;
1814962306a36Sopenharmony_ci		pg_pairs++;
1815062306a36Sopenharmony_ci	}
1815162306a36Sopenharmony_ci
1815262306a36Sopenharmony_ci	/* Complete initialization and perform endian conversion. */
1815362306a36Sopenharmony_ci	bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
1815462306a36Sopenharmony_ci	bf_set(lpfc_post_sgl_pages_xricnt, sgl, post_cnt);
1815562306a36Sopenharmony_ci	sgl->word0 = cpu_to_le32(sgl->word0);
1815662306a36Sopenharmony_ci
1815762306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable)
1815862306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1815962306a36Sopenharmony_ci	else {
1816062306a36Sopenharmony_ci		mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
1816162306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
1816262306a36Sopenharmony_ci	}
1816362306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
1816462306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1816562306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1816662306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable)
1816762306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mbox);
1816862306a36Sopenharmony_ci	else if (rc != MBX_TIMEOUT)
1816962306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mbox);
1817062306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1817162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1817262306a36Sopenharmony_ci				"2513 POST_SGL_BLOCK mailbox command failed "
1817362306a36Sopenharmony_ci				"status x%x add_status x%x mbx status x%x\n",
1817462306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1817562306a36Sopenharmony_ci		rc = -ENXIO;
1817662306a36Sopenharmony_ci	}
1817762306a36Sopenharmony_ci	return rc;
1817862306a36Sopenharmony_ci}
1817962306a36Sopenharmony_ci
1818062306a36Sopenharmony_ci/**
1818162306a36Sopenharmony_ci * lpfc_sli4_post_io_sgl_block - post a block of nvme sgl list to firmware
1818262306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1818362306a36Sopenharmony_ci * @nblist: pointer to nvme buffer list.
1818462306a36Sopenharmony_ci * @count: number of scsi buffers on the list.
1818562306a36Sopenharmony_ci *
1818662306a36Sopenharmony_ci * This routine is invoked to post a block of @count scsi sgl pages from a
1818762306a36Sopenharmony_ci * SCSI buffer list @nblist to the HBA using non-embedded mailbox command.
1818862306a36Sopenharmony_ci * No Lock is held.
1818962306a36Sopenharmony_ci *
1819062306a36Sopenharmony_ci **/
1819162306a36Sopenharmony_cistatic int
1819262306a36Sopenharmony_cilpfc_sli4_post_io_sgl_block(struct lpfc_hba *phba, struct list_head *nblist,
1819362306a36Sopenharmony_ci			    int count)
1819462306a36Sopenharmony_ci{
1819562306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_ncmd;
1819662306a36Sopenharmony_ci	struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
1819762306a36Sopenharmony_ci	struct sgl_page_pairs *sgl_pg_pairs;
1819862306a36Sopenharmony_ci	void *viraddr;
1819962306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
1820062306a36Sopenharmony_ci	uint32_t reqlen, alloclen, pg_pairs;
1820162306a36Sopenharmony_ci	uint32_t mbox_tmo;
1820262306a36Sopenharmony_ci	uint16_t xritag_start = 0;
1820362306a36Sopenharmony_ci	int rc = 0;
1820462306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1820562306a36Sopenharmony_ci	dma_addr_t pdma_phys_bpl1;
1820662306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1820762306a36Sopenharmony_ci
1820862306a36Sopenharmony_ci	/* Calculate the requested length of the dma memory */
1820962306a36Sopenharmony_ci	reqlen = count * sizeof(struct sgl_page_pairs) +
1821062306a36Sopenharmony_ci		 sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
1821162306a36Sopenharmony_ci	if (reqlen > SLI4_PAGE_SIZE) {
1821262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
1821362306a36Sopenharmony_ci				"6118 Block sgl registration required DMA "
1821462306a36Sopenharmony_ci				"size (%d) great than a page\n", reqlen);
1821562306a36Sopenharmony_ci		return -ENOMEM;
1821662306a36Sopenharmony_ci	}
1821762306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1821862306a36Sopenharmony_ci	if (!mbox) {
1821962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1822062306a36Sopenharmony_ci				"6119 Failed to allocate mbox cmd memory\n");
1822162306a36Sopenharmony_ci		return -ENOMEM;
1822262306a36Sopenharmony_ci	}
1822362306a36Sopenharmony_ci
1822462306a36Sopenharmony_ci	/* Allocate DMA memory and set up the non-embedded mailbox command */
1822562306a36Sopenharmony_ci	alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
1822662306a36Sopenharmony_ci				    LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES,
1822762306a36Sopenharmony_ci				    reqlen, LPFC_SLI4_MBX_NEMBED);
1822862306a36Sopenharmony_ci
1822962306a36Sopenharmony_ci	if (alloclen < reqlen) {
1823062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1823162306a36Sopenharmony_ci				"6120 Allocated DMA memory size (%d) is "
1823262306a36Sopenharmony_ci				"less than the requested DMA memory "
1823362306a36Sopenharmony_ci				"size (%d)\n", alloclen, reqlen);
1823462306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mbox);
1823562306a36Sopenharmony_ci		return -ENOMEM;
1823662306a36Sopenharmony_ci	}
1823762306a36Sopenharmony_ci
1823862306a36Sopenharmony_ci	/* Get the first SGE entry from the non-embedded DMA memory */
1823962306a36Sopenharmony_ci	viraddr = mbox->sge_array->addr[0];
1824062306a36Sopenharmony_ci
1824162306a36Sopenharmony_ci	/* Set up the SGL pages in the non-embedded DMA pages */
1824262306a36Sopenharmony_ci	sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
1824362306a36Sopenharmony_ci	sgl_pg_pairs = &sgl->sgl_pg_pairs;
1824462306a36Sopenharmony_ci
1824562306a36Sopenharmony_ci	pg_pairs = 0;
1824662306a36Sopenharmony_ci	list_for_each_entry(lpfc_ncmd, nblist, list) {
1824762306a36Sopenharmony_ci		/* Set up the sge entry */
1824862306a36Sopenharmony_ci		sgl_pg_pairs->sgl_pg0_addr_lo =
1824962306a36Sopenharmony_ci			cpu_to_le32(putPaddrLow(lpfc_ncmd->dma_phys_sgl));
1825062306a36Sopenharmony_ci		sgl_pg_pairs->sgl_pg0_addr_hi =
1825162306a36Sopenharmony_ci			cpu_to_le32(putPaddrHigh(lpfc_ncmd->dma_phys_sgl));
1825262306a36Sopenharmony_ci		if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
1825362306a36Sopenharmony_ci			pdma_phys_bpl1 = lpfc_ncmd->dma_phys_sgl +
1825462306a36Sopenharmony_ci						SGL_PAGE_SIZE;
1825562306a36Sopenharmony_ci		else
1825662306a36Sopenharmony_ci			pdma_phys_bpl1 = 0;
1825762306a36Sopenharmony_ci		sgl_pg_pairs->sgl_pg1_addr_lo =
1825862306a36Sopenharmony_ci			cpu_to_le32(putPaddrLow(pdma_phys_bpl1));
1825962306a36Sopenharmony_ci		sgl_pg_pairs->sgl_pg1_addr_hi =
1826062306a36Sopenharmony_ci			cpu_to_le32(putPaddrHigh(pdma_phys_bpl1));
1826162306a36Sopenharmony_ci		/* Keep the first xritag on the list */
1826262306a36Sopenharmony_ci		if (pg_pairs == 0)
1826362306a36Sopenharmony_ci			xritag_start = lpfc_ncmd->cur_iocbq.sli4_xritag;
1826462306a36Sopenharmony_ci		sgl_pg_pairs++;
1826562306a36Sopenharmony_ci		pg_pairs++;
1826662306a36Sopenharmony_ci	}
1826762306a36Sopenharmony_ci	bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
1826862306a36Sopenharmony_ci	bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs);
1826962306a36Sopenharmony_ci	/* Perform endian conversion if necessary */
1827062306a36Sopenharmony_ci	sgl->word0 = cpu_to_le32(sgl->word0);
1827162306a36Sopenharmony_ci
1827262306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable) {
1827362306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
1827462306a36Sopenharmony_ci	} else {
1827562306a36Sopenharmony_ci		mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
1827662306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
1827762306a36Sopenharmony_ci	}
1827862306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)&sgl->cfg_shdr;
1827962306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1828062306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1828162306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable)
1828262306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mbox);
1828362306a36Sopenharmony_ci	else if (rc != MBX_TIMEOUT)
1828462306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mbox);
1828562306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1828662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1828762306a36Sopenharmony_ci				"6125 POST_SGL_BLOCK mailbox command failed "
1828862306a36Sopenharmony_ci				"status x%x add_status x%x mbx status x%x\n",
1828962306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1829062306a36Sopenharmony_ci		rc = -ENXIO;
1829162306a36Sopenharmony_ci	}
1829262306a36Sopenharmony_ci	return rc;
1829362306a36Sopenharmony_ci}
1829462306a36Sopenharmony_ci
1829562306a36Sopenharmony_ci/**
1829662306a36Sopenharmony_ci * lpfc_sli4_post_io_sgl_list - Post blocks of nvme buffer sgls from a list
1829762306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1829862306a36Sopenharmony_ci * @post_nblist: pointer to the nvme buffer list.
1829962306a36Sopenharmony_ci * @sb_count: number of nvme buffers.
1830062306a36Sopenharmony_ci *
1830162306a36Sopenharmony_ci * This routine walks a list of nvme buffers that was passed in. It attempts
1830262306a36Sopenharmony_ci * to construct blocks of nvme buffer sgls which contains contiguous xris and
1830362306a36Sopenharmony_ci * uses the non-embedded SGL block post mailbox commands to post to the port.
1830462306a36Sopenharmony_ci * For single NVME buffer sgl with non-contiguous xri, if any, it shall use
1830562306a36Sopenharmony_ci * embedded SGL post mailbox command for posting. The @post_nblist passed in
1830662306a36Sopenharmony_ci * must be local list, thus no lock is needed when manipulate the list.
1830762306a36Sopenharmony_ci *
1830862306a36Sopenharmony_ci * Returns: 0 = failure, non-zero number of successfully posted buffers.
1830962306a36Sopenharmony_ci **/
1831062306a36Sopenharmony_ciint
1831162306a36Sopenharmony_cilpfc_sli4_post_io_sgl_list(struct lpfc_hba *phba,
1831262306a36Sopenharmony_ci			   struct list_head *post_nblist, int sb_count)
1831362306a36Sopenharmony_ci{
1831462306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_ncmd, *lpfc_ncmd_next;
1831562306a36Sopenharmony_ci	int status, sgl_size;
1831662306a36Sopenharmony_ci	int post_cnt = 0, block_cnt = 0, num_posting = 0, num_posted = 0;
1831762306a36Sopenharmony_ci	dma_addr_t pdma_phys_sgl1;
1831862306a36Sopenharmony_ci	int last_xritag = NO_XRI;
1831962306a36Sopenharmony_ci	int cur_xritag;
1832062306a36Sopenharmony_ci	LIST_HEAD(prep_nblist);
1832162306a36Sopenharmony_ci	LIST_HEAD(blck_nblist);
1832262306a36Sopenharmony_ci	LIST_HEAD(nvme_nblist);
1832362306a36Sopenharmony_ci
1832462306a36Sopenharmony_ci	/* sanity check */
1832562306a36Sopenharmony_ci	if (sb_count <= 0)
1832662306a36Sopenharmony_ci		return -EINVAL;
1832762306a36Sopenharmony_ci
1832862306a36Sopenharmony_ci	sgl_size = phba->cfg_sg_dma_buf_size;
1832962306a36Sopenharmony_ci	list_for_each_entry_safe(lpfc_ncmd, lpfc_ncmd_next, post_nblist, list) {
1833062306a36Sopenharmony_ci		list_del_init(&lpfc_ncmd->list);
1833162306a36Sopenharmony_ci		block_cnt++;
1833262306a36Sopenharmony_ci		if ((last_xritag != NO_XRI) &&
1833362306a36Sopenharmony_ci		    (lpfc_ncmd->cur_iocbq.sli4_xritag != last_xritag + 1)) {
1833462306a36Sopenharmony_ci			/* a hole in xri block, form a sgl posting block */
1833562306a36Sopenharmony_ci			list_splice_init(&prep_nblist, &blck_nblist);
1833662306a36Sopenharmony_ci			post_cnt = block_cnt - 1;
1833762306a36Sopenharmony_ci			/* prepare list for next posting block */
1833862306a36Sopenharmony_ci			list_add_tail(&lpfc_ncmd->list, &prep_nblist);
1833962306a36Sopenharmony_ci			block_cnt = 1;
1834062306a36Sopenharmony_ci		} else {
1834162306a36Sopenharmony_ci			/* prepare list for next posting block */
1834262306a36Sopenharmony_ci			list_add_tail(&lpfc_ncmd->list, &prep_nblist);
1834362306a36Sopenharmony_ci			/* enough sgls for non-embed sgl mbox command */
1834462306a36Sopenharmony_ci			if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) {
1834562306a36Sopenharmony_ci				list_splice_init(&prep_nblist, &blck_nblist);
1834662306a36Sopenharmony_ci				post_cnt = block_cnt;
1834762306a36Sopenharmony_ci				block_cnt = 0;
1834862306a36Sopenharmony_ci			}
1834962306a36Sopenharmony_ci		}
1835062306a36Sopenharmony_ci		num_posting++;
1835162306a36Sopenharmony_ci		last_xritag = lpfc_ncmd->cur_iocbq.sli4_xritag;
1835262306a36Sopenharmony_ci
1835362306a36Sopenharmony_ci		/* end of repost sgl list condition for NVME buffers */
1835462306a36Sopenharmony_ci		if (num_posting == sb_count) {
1835562306a36Sopenharmony_ci			if (post_cnt == 0) {
1835662306a36Sopenharmony_ci				/* last sgl posting block */
1835762306a36Sopenharmony_ci				list_splice_init(&prep_nblist, &blck_nblist);
1835862306a36Sopenharmony_ci				post_cnt = block_cnt;
1835962306a36Sopenharmony_ci			} else if (block_cnt == 1) {
1836062306a36Sopenharmony_ci				/* last single sgl with non-contiguous xri */
1836162306a36Sopenharmony_ci				if (sgl_size > SGL_PAGE_SIZE)
1836262306a36Sopenharmony_ci					pdma_phys_sgl1 =
1836362306a36Sopenharmony_ci						lpfc_ncmd->dma_phys_sgl +
1836462306a36Sopenharmony_ci						SGL_PAGE_SIZE;
1836562306a36Sopenharmony_ci				else
1836662306a36Sopenharmony_ci					pdma_phys_sgl1 = 0;
1836762306a36Sopenharmony_ci				cur_xritag = lpfc_ncmd->cur_iocbq.sli4_xritag;
1836862306a36Sopenharmony_ci				status = lpfc_sli4_post_sgl(
1836962306a36Sopenharmony_ci						phba, lpfc_ncmd->dma_phys_sgl,
1837062306a36Sopenharmony_ci						pdma_phys_sgl1, cur_xritag);
1837162306a36Sopenharmony_ci				if (status) {
1837262306a36Sopenharmony_ci					/* Post error.  Buffer unavailable. */
1837362306a36Sopenharmony_ci					lpfc_ncmd->flags |=
1837462306a36Sopenharmony_ci						LPFC_SBUF_NOT_POSTED;
1837562306a36Sopenharmony_ci				} else {
1837662306a36Sopenharmony_ci					/* Post success. Bffer available. */
1837762306a36Sopenharmony_ci					lpfc_ncmd->flags &=
1837862306a36Sopenharmony_ci						~LPFC_SBUF_NOT_POSTED;
1837962306a36Sopenharmony_ci					lpfc_ncmd->status = IOSTAT_SUCCESS;
1838062306a36Sopenharmony_ci					num_posted++;
1838162306a36Sopenharmony_ci				}
1838262306a36Sopenharmony_ci				/* success, put on NVME buffer sgl list */
1838362306a36Sopenharmony_ci				list_add_tail(&lpfc_ncmd->list, &nvme_nblist);
1838462306a36Sopenharmony_ci			}
1838562306a36Sopenharmony_ci		}
1838662306a36Sopenharmony_ci
1838762306a36Sopenharmony_ci		/* continue until a nembed page worth of sgls */
1838862306a36Sopenharmony_ci		if (post_cnt == 0)
1838962306a36Sopenharmony_ci			continue;
1839062306a36Sopenharmony_ci
1839162306a36Sopenharmony_ci		/* post block of NVME buffer list sgls */
1839262306a36Sopenharmony_ci		status = lpfc_sli4_post_io_sgl_block(phba, &blck_nblist,
1839362306a36Sopenharmony_ci						     post_cnt);
1839462306a36Sopenharmony_ci
1839562306a36Sopenharmony_ci		/* don't reset xirtag due to hole in xri block */
1839662306a36Sopenharmony_ci		if (block_cnt == 0)
1839762306a36Sopenharmony_ci			last_xritag = NO_XRI;
1839862306a36Sopenharmony_ci
1839962306a36Sopenharmony_ci		/* reset NVME buffer post count for next round of posting */
1840062306a36Sopenharmony_ci		post_cnt = 0;
1840162306a36Sopenharmony_ci
1840262306a36Sopenharmony_ci		/* put posted NVME buffer-sgl posted on NVME buffer sgl list */
1840362306a36Sopenharmony_ci		while (!list_empty(&blck_nblist)) {
1840462306a36Sopenharmony_ci			list_remove_head(&blck_nblist, lpfc_ncmd,
1840562306a36Sopenharmony_ci					 struct lpfc_io_buf, list);
1840662306a36Sopenharmony_ci			if (status) {
1840762306a36Sopenharmony_ci				/* Post error.  Mark buffer unavailable. */
1840862306a36Sopenharmony_ci				lpfc_ncmd->flags |= LPFC_SBUF_NOT_POSTED;
1840962306a36Sopenharmony_ci			} else {
1841062306a36Sopenharmony_ci				/* Post success, Mark buffer available. */
1841162306a36Sopenharmony_ci				lpfc_ncmd->flags &= ~LPFC_SBUF_NOT_POSTED;
1841262306a36Sopenharmony_ci				lpfc_ncmd->status = IOSTAT_SUCCESS;
1841362306a36Sopenharmony_ci				num_posted++;
1841462306a36Sopenharmony_ci			}
1841562306a36Sopenharmony_ci			list_add_tail(&lpfc_ncmd->list, &nvme_nblist);
1841662306a36Sopenharmony_ci		}
1841762306a36Sopenharmony_ci	}
1841862306a36Sopenharmony_ci	/* Push NVME buffers with sgl posted to the available list */
1841962306a36Sopenharmony_ci	lpfc_io_buf_replenish(phba, &nvme_nblist);
1842062306a36Sopenharmony_ci
1842162306a36Sopenharmony_ci	return num_posted;
1842262306a36Sopenharmony_ci}
1842362306a36Sopenharmony_ci
1842462306a36Sopenharmony_ci/**
1842562306a36Sopenharmony_ci * lpfc_fc_frame_check - Check that this frame is a valid frame to handle
1842662306a36Sopenharmony_ci * @phba: pointer to lpfc_hba struct that the frame was received on
1842762306a36Sopenharmony_ci * @fc_hdr: A pointer to the FC Header data (In Big Endian Format)
1842862306a36Sopenharmony_ci *
1842962306a36Sopenharmony_ci * This function checks the fields in the @fc_hdr to see if the FC frame is a
1843062306a36Sopenharmony_ci * valid type of frame that the LPFC driver will handle. This function will
1843162306a36Sopenharmony_ci * return a zero if the frame is a valid frame or a non zero value when the
1843262306a36Sopenharmony_ci * frame does not pass the check.
1843362306a36Sopenharmony_ci **/
1843462306a36Sopenharmony_cistatic int
1843562306a36Sopenharmony_cilpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr)
1843662306a36Sopenharmony_ci{
1843762306a36Sopenharmony_ci	/*  make rctl_names static to save stack space */
1843862306a36Sopenharmony_ci	struct fc_vft_header *fc_vft_hdr;
1843962306a36Sopenharmony_ci	uint32_t *header = (uint32_t *) fc_hdr;
1844062306a36Sopenharmony_ci
1844162306a36Sopenharmony_ci#define FC_RCTL_MDS_DIAGS	0xF4
1844262306a36Sopenharmony_ci
1844362306a36Sopenharmony_ci	switch (fc_hdr->fh_r_ctl) {
1844462306a36Sopenharmony_ci	case FC_RCTL_DD_UNCAT:		/* uncategorized information */
1844562306a36Sopenharmony_ci	case FC_RCTL_DD_SOL_DATA:	/* solicited data */
1844662306a36Sopenharmony_ci	case FC_RCTL_DD_UNSOL_CTL:	/* unsolicited control */
1844762306a36Sopenharmony_ci	case FC_RCTL_DD_SOL_CTL:	/* solicited control or reply */
1844862306a36Sopenharmony_ci	case FC_RCTL_DD_UNSOL_DATA:	/* unsolicited data */
1844962306a36Sopenharmony_ci	case FC_RCTL_DD_DATA_DESC:	/* data descriptor */
1845062306a36Sopenharmony_ci	case FC_RCTL_DD_UNSOL_CMD:	/* unsolicited command */
1845162306a36Sopenharmony_ci	case FC_RCTL_DD_CMD_STATUS:	/* command status */
1845262306a36Sopenharmony_ci	case FC_RCTL_ELS_REQ:	/* extended link services request */
1845362306a36Sopenharmony_ci	case FC_RCTL_ELS_REP:	/* extended link services reply */
1845462306a36Sopenharmony_ci	case FC_RCTL_ELS4_REQ:	/* FC-4 ELS request */
1845562306a36Sopenharmony_ci	case FC_RCTL_ELS4_REP:	/* FC-4 ELS reply */
1845662306a36Sopenharmony_ci	case FC_RCTL_BA_ABTS: 	/* basic link service abort */
1845762306a36Sopenharmony_ci	case FC_RCTL_BA_RMC: 	/* remove connection */
1845862306a36Sopenharmony_ci	case FC_RCTL_BA_ACC:	/* basic accept */
1845962306a36Sopenharmony_ci	case FC_RCTL_BA_RJT:	/* basic reject */
1846062306a36Sopenharmony_ci	case FC_RCTL_BA_PRMT:
1846162306a36Sopenharmony_ci	case FC_RCTL_ACK_1:	/* acknowledge_1 */
1846262306a36Sopenharmony_ci	case FC_RCTL_ACK_0:	/* acknowledge_0 */
1846362306a36Sopenharmony_ci	case FC_RCTL_P_RJT:	/* port reject */
1846462306a36Sopenharmony_ci	case FC_RCTL_F_RJT:	/* fabric reject */
1846562306a36Sopenharmony_ci	case FC_RCTL_P_BSY:	/* port busy */
1846662306a36Sopenharmony_ci	case FC_RCTL_F_BSY:	/* fabric busy to data frame */
1846762306a36Sopenharmony_ci	case FC_RCTL_F_BSYL:	/* fabric busy to link control frame */
1846862306a36Sopenharmony_ci	case FC_RCTL_LCR:	/* link credit reset */
1846962306a36Sopenharmony_ci	case FC_RCTL_MDS_DIAGS: /* MDS Diagnostics */
1847062306a36Sopenharmony_ci	case FC_RCTL_END:	/* end */
1847162306a36Sopenharmony_ci		break;
1847262306a36Sopenharmony_ci	case FC_RCTL_VFTH:	/* Virtual Fabric tagging Header */
1847362306a36Sopenharmony_ci		fc_vft_hdr = (struct fc_vft_header *)fc_hdr;
1847462306a36Sopenharmony_ci		fc_hdr = &((struct fc_frame_header *)fc_vft_hdr)[1];
1847562306a36Sopenharmony_ci		return lpfc_fc_frame_check(phba, fc_hdr);
1847662306a36Sopenharmony_ci	case FC_RCTL_BA_NOP:	/* basic link service NOP */
1847762306a36Sopenharmony_ci	default:
1847862306a36Sopenharmony_ci		goto drop;
1847962306a36Sopenharmony_ci	}
1848062306a36Sopenharmony_ci
1848162306a36Sopenharmony_ci	switch (fc_hdr->fh_type) {
1848262306a36Sopenharmony_ci	case FC_TYPE_BLS:
1848362306a36Sopenharmony_ci	case FC_TYPE_ELS:
1848462306a36Sopenharmony_ci	case FC_TYPE_FCP:
1848562306a36Sopenharmony_ci	case FC_TYPE_CT:
1848662306a36Sopenharmony_ci	case FC_TYPE_NVME:
1848762306a36Sopenharmony_ci		break;
1848862306a36Sopenharmony_ci	case FC_TYPE_IP:
1848962306a36Sopenharmony_ci	case FC_TYPE_ILS:
1849062306a36Sopenharmony_ci	default:
1849162306a36Sopenharmony_ci		goto drop;
1849262306a36Sopenharmony_ci	}
1849362306a36Sopenharmony_ci
1849462306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
1849562306a36Sopenharmony_ci			"2538 Received frame rctl:x%x, type:x%x, "
1849662306a36Sopenharmony_ci			"frame Data:%08x %08x %08x %08x %08x %08x %08x\n",
1849762306a36Sopenharmony_ci			fc_hdr->fh_r_ctl, fc_hdr->fh_type,
1849862306a36Sopenharmony_ci			be32_to_cpu(header[0]), be32_to_cpu(header[1]),
1849962306a36Sopenharmony_ci			be32_to_cpu(header[2]), be32_to_cpu(header[3]),
1850062306a36Sopenharmony_ci			be32_to_cpu(header[4]), be32_to_cpu(header[5]),
1850162306a36Sopenharmony_ci			be32_to_cpu(header[6]));
1850262306a36Sopenharmony_ci	return 0;
1850362306a36Sopenharmony_cidrop:
1850462306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
1850562306a36Sopenharmony_ci			"2539 Dropped frame rctl:x%x type:x%x\n",
1850662306a36Sopenharmony_ci			fc_hdr->fh_r_ctl, fc_hdr->fh_type);
1850762306a36Sopenharmony_ci	return 1;
1850862306a36Sopenharmony_ci}
1850962306a36Sopenharmony_ci
1851062306a36Sopenharmony_ci/**
1851162306a36Sopenharmony_ci * lpfc_fc_hdr_get_vfi - Get the VFI from an FC frame
1851262306a36Sopenharmony_ci * @fc_hdr: A pointer to the FC Header data (In Big Endian Format)
1851362306a36Sopenharmony_ci *
1851462306a36Sopenharmony_ci * This function processes the FC header to retrieve the VFI from the VF
1851562306a36Sopenharmony_ci * header, if one exists. This function will return the VFI if one exists
1851662306a36Sopenharmony_ci * or 0 if no VSAN Header exists.
1851762306a36Sopenharmony_ci **/
1851862306a36Sopenharmony_cistatic uint32_t
1851962306a36Sopenharmony_cilpfc_fc_hdr_get_vfi(struct fc_frame_header *fc_hdr)
1852062306a36Sopenharmony_ci{
1852162306a36Sopenharmony_ci	struct fc_vft_header *fc_vft_hdr = (struct fc_vft_header *)fc_hdr;
1852262306a36Sopenharmony_ci
1852362306a36Sopenharmony_ci	if (fc_hdr->fh_r_ctl != FC_RCTL_VFTH)
1852462306a36Sopenharmony_ci		return 0;
1852562306a36Sopenharmony_ci	return bf_get(fc_vft_hdr_vf_id, fc_vft_hdr);
1852662306a36Sopenharmony_ci}
1852762306a36Sopenharmony_ci
1852862306a36Sopenharmony_ci/**
1852962306a36Sopenharmony_ci * lpfc_fc_frame_to_vport - Finds the vport that a frame is destined to
1853062306a36Sopenharmony_ci * @phba: Pointer to the HBA structure to search for the vport on
1853162306a36Sopenharmony_ci * @fc_hdr: A pointer to the FC Header data (In Big Endian Format)
1853262306a36Sopenharmony_ci * @fcfi: The FC Fabric ID that the frame came from
1853362306a36Sopenharmony_ci * @did: Destination ID to match against
1853462306a36Sopenharmony_ci *
1853562306a36Sopenharmony_ci * This function searches the @phba for a vport that matches the content of the
1853662306a36Sopenharmony_ci * @fc_hdr passed in and the @fcfi. This function uses the @fc_hdr to fetch the
1853762306a36Sopenharmony_ci * VFI, if the Virtual Fabric Tagging Header exists, and the DID. This function
1853862306a36Sopenharmony_ci * returns the matching vport pointer or NULL if unable to match frame to a
1853962306a36Sopenharmony_ci * vport.
1854062306a36Sopenharmony_ci **/
1854162306a36Sopenharmony_cistatic struct lpfc_vport *
1854262306a36Sopenharmony_cilpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr,
1854362306a36Sopenharmony_ci		       uint16_t fcfi, uint32_t did)
1854462306a36Sopenharmony_ci{
1854562306a36Sopenharmony_ci	struct lpfc_vport **vports;
1854662306a36Sopenharmony_ci	struct lpfc_vport *vport = NULL;
1854762306a36Sopenharmony_ci	int i;
1854862306a36Sopenharmony_ci
1854962306a36Sopenharmony_ci	if (did == Fabric_DID)
1855062306a36Sopenharmony_ci		return phba->pport;
1855162306a36Sopenharmony_ci	if ((phba->pport->fc_flag & FC_PT2PT) &&
1855262306a36Sopenharmony_ci		!(phba->link_state == LPFC_HBA_READY))
1855362306a36Sopenharmony_ci		return phba->pport;
1855462306a36Sopenharmony_ci
1855562306a36Sopenharmony_ci	vports = lpfc_create_vport_work_array(phba);
1855662306a36Sopenharmony_ci	if (vports != NULL) {
1855762306a36Sopenharmony_ci		for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
1855862306a36Sopenharmony_ci			if (phba->fcf.fcfi == fcfi &&
1855962306a36Sopenharmony_ci			    vports[i]->vfi == lpfc_fc_hdr_get_vfi(fc_hdr) &&
1856062306a36Sopenharmony_ci			    vports[i]->fc_myDID == did) {
1856162306a36Sopenharmony_ci				vport = vports[i];
1856262306a36Sopenharmony_ci				break;
1856362306a36Sopenharmony_ci			}
1856462306a36Sopenharmony_ci		}
1856562306a36Sopenharmony_ci	}
1856662306a36Sopenharmony_ci	lpfc_destroy_vport_work_array(phba, vports);
1856762306a36Sopenharmony_ci	return vport;
1856862306a36Sopenharmony_ci}
1856962306a36Sopenharmony_ci
1857062306a36Sopenharmony_ci/**
1857162306a36Sopenharmony_ci * lpfc_update_rcv_time_stamp - Update vport's rcv seq time stamp
1857262306a36Sopenharmony_ci * @vport: The vport to work on.
1857362306a36Sopenharmony_ci *
1857462306a36Sopenharmony_ci * This function updates the receive sequence time stamp for this vport. The
1857562306a36Sopenharmony_ci * receive sequence time stamp indicates the time that the last frame of the
1857662306a36Sopenharmony_ci * the sequence that has been idle for the longest amount of time was received.
1857762306a36Sopenharmony_ci * the driver uses this time stamp to indicate if any received sequences have
1857862306a36Sopenharmony_ci * timed out.
1857962306a36Sopenharmony_ci **/
1858062306a36Sopenharmony_cistatic void
1858162306a36Sopenharmony_cilpfc_update_rcv_time_stamp(struct lpfc_vport *vport)
1858262306a36Sopenharmony_ci{
1858362306a36Sopenharmony_ci	struct lpfc_dmabuf *h_buf;
1858462306a36Sopenharmony_ci	struct hbq_dmabuf *dmabuf = NULL;
1858562306a36Sopenharmony_ci
1858662306a36Sopenharmony_ci	/* get the oldest sequence on the rcv list */
1858762306a36Sopenharmony_ci	h_buf = list_get_first(&vport->rcv_buffer_list,
1858862306a36Sopenharmony_ci			       struct lpfc_dmabuf, list);
1858962306a36Sopenharmony_ci	if (!h_buf)
1859062306a36Sopenharmony_ci		return;
1859162306a36Sopenharmony_ci	dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf);
1859262306a36Sopenharmony_ci	vport->rcv_buffer_time_stamp = dmabuf->time_stamp;
1859362306a36Sopenharmony_ci}
1859462306a36Sopenharmony_ci
1859562306a36Sopenharmony_ci/**
1859662306a36Sopenharmony_ci * lpfc_cleanup_rcv_buffers - Cleans up all outstanding receive sequences.
1859762306a36Sopenharmony_ci * @vport: The vport that the received sequences were sent to.
1859862306a36Sopenharmony_ci *
1859962306a36Sopenharmony_ci * This function cleans up all outstanding received sequences. This is called
1860062306a36Sopenharmony_ci * by the driver when a link event or user action invalidates all the received
1860162306a36Sopenharmony_ci * sequences.
1860262306a36Sopenharmony_ci **/
1860362306a36Sopenharmony_civoid
1860462306a36Sopenharmony_cilpfc_cleanup_rcv_buffers(struct lpfc_vport *vport)
1860562306a36Sopenharmony_ci{
1860662306a36Sopenharmony_ci	struct lpfc_dmabuf *h_buf, *hnext;
1860762306a36Sopenharmony_ci	struct lpfc_dmabuf *d_buf, *dnext;
1860862306a36Sopenharmony_ci	struct hbq_dmabuf *dmabuf = NULL;
1860962306a36Sopenharmony_ci
1861062306a36Sopenharmony_ci	/* start with the oldest sequence on the rcv list */
1861162306a36Sopenharmony_ci	list_for_each_entry_safe(h_buf, hnext, &vport->rcv_buffer_list, list) {
1861262306a36Sopenharmony_ci		dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf);
1861362306a36Sopenharmony_ci		list_del_init(&dmabuf->hbuf.list);
1861462306a36Sopenharmony_ci		list_for_each_entry_safe(d_buf, dnext,
1861562306a36Sopenharmony_ci					 &dmabuf->dbuf.list, list) {
1861662306a36Sopenharmony_ci			list_del_init(&d_buf->list);
1861762306a36Sopenharmony_ci			lpfc_in_buf_free(vport->phba, d_buf);
1861862306a36Sopenharmony_ci		}
1861962306a36Sopenharmony_ci		lpfc_in_buf_free(vport->phba, &dmabuf->dbuf);
1862062306a36Sopenharmony_ci	}
1862162306a36Sopenharmony_ci}
1862262306a36Sopenharmony_ci
1862362306a36Sopenharmony_ci/**
1862462306a36Sopenharmony_ci * lpfc_rcv_seq_check_edtov - Cleans up timed out receive sequences.
1862562306a36Sopenharmony_ci * @vport: The vport that the received sequences were sent to.
1862662306a36Sopenharmony_ci *
1862762306a36Sopenharmony_ci * This function determines whether any received sequences have timed out by
1862862306a36Sopenharmony_ci * first checking the vport's rcv_buffer_time_stamp. If this time_stamp
1862962306a36Sopenharmony_ci * indicates that there is at least one timed out sequence this routine will
1863062306a36Sopenharmony_ci * go through the received sequences one at a time from most inactive to most
1863162306a36Sopenharmony_ci * active to determine which ones need to be cleaned up. Once it has determined
1863262306a36Sopenharmony_ci * that a sequence needs to be cleaned up it will simply free up the resources
1863362306a36Sopenharmony_ci * without sending an abort.
1863462306a36Sopenharmony_ci **/
1863562306a36Sopenharmony_civoid
1863662306a36Sopenharmony_cilpfc_rcv_seq_check_edtov(struct lpfc_vport *vport)
1863762306a36Sopenharmony_ci{
1863862306a36Sopenharmony_ci	struct lpfc_dmabuf *h_buf, *hnext;
1863962306a36Sopenharmony_ci	struct lpfc_dmabuf *d_buf, *dnext;
1864062306a36Sopenharmony_ci	struct hbq_dmabuf *dmabuf = NULL;
1864162306a36Sopenharmony_ci	unsigned long timeout;
1864262306a36Sopenharmony_ci	int abort_count = 0;
1864362306a36Sopenharmony_ci
1864462306a36Sopenharmony_ci	timeout = (msecs_to_jiffies(vport->phba->fc_edtov) +
1864562306a36Sopenharmony_ci		   vport->rcv_buffer_time_stamp);
1864662306a36Sopenharmony_ci	if (list_empty(&vport->rcv_buffer_list) ||
1864762306a36Sopenharmony_ci	    time_before(jiffies, timeout))
1864862306a36Sopenharmony_ci		return;
1864962306a36Sopenharmony_ci	/* start with the oldest sequence on the rcv list */
1865062306a36Sopenharmony_ci	list_for_each_entry_safe(h_buf, hnext, &vport->rcv_buffer_list, list) {
1865162306a36Sopenharmony_ci		dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf);
1865262306a36Sopenharmony_ci		timeout = (msecs_to_jiffies(vport->phba->fc_edtov) +
1865362306a36Sopenharmony_ci			   dmabuf->time_stamp);
1865462306a36Sopenharmony_ci		if (time_before(jiffies, timeout))
1865562306a36Sopenharmony_ci			break;
1865662306a36Sopenharmony_ci		abort_count++;
1865762306a36Sopenharmony_ci		list_del_init(&dmabuf->hbuf.list);
1865862306a36Sopenharmony_ci		list_for_each_entry_safe(d_buf, dnext,
1865962306a36Sopenharmony_ci					 &dmabuf->dbuf.list, list) {
1866062306a36Sopenharmony_ci			list_del_init(&d_buf->list);
1866162306a36Sopenharmony_ci			lpfc_in_buf_free(vport->phba, d_buf);
1866262306a36Sopenharmony_ci		}
1866362306a36Sopenharmony_ci		lpfc_in_buf_free(vport->phba, &dmabuf->dbuf);
1866462306a36Sopenharmony_ci	}
1866562306a36Sopenharmony_ci	if (abort_count)
1866662306a36Sopenharmony_ci		lpfc_update_rcv_time_stamp(vport);
1866762306a36Sopenharmony_ci}
1866862306a36Sopenharmony_ci
1866962306a36Sopenharmony_ci/**
1867062306a36Sopenharmony_ci * lpfc_fc_frame_add - Adds a frame to the vport's list of received sequences
1867162306a36Sopenharmony_ci * @vport: pointer to a vitural port
1867262306a36Sopenharmony_ci * @dmabuf: pointer to a dmabuf that describes the hdr and data of the FC frame
1867362306a36Sopenharmony_ci *
1867462306a36Sopenharmony_ci * This function searches through the existing incomplete sequences that have
1867562306a36Sopenharmony_ci * been sent to this @vport. If the frame matches one of the incomplete
1867662306a36Sopenharmony_ci * sequences then the dbuf in the @dmabuf is added to the list of frames that
1867762306a36Sopenharmony_ci * make up that sequence. If no sequence is found that matches this frame then
1867862306a36Sopenharmony_ci * the function will add the hbuf in the @dmabuf to the @vport's rcv_buffer_list
1867962306a36Sopenharmony_ci * This function returns a pointer to the first dmabuf in the sequence list that
1868062306a36Sopenharmony_ci * the frame was linked to.
1868162306a36Sopenharmony_ci **/
1868262306a36Sopenharmony_cistatic struct hbq_dmabuf *
1868362306a36Sopenharmony_cilpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
1868462306a36Sopenharmony_ci{
1868562306a36Sopenharmony_ci	struct fc_frame_header *new_hdr;
1868662306a36Sopenharmony_ci	struct fc_frame_header *temp_hdr;
1868762306a36Sopenharmony_ci	struct lpfc_dmabuf *d_buf;
1868862306a36Sopenharmony_ci	struct lpfc_dmabuf *h_buf;
1868962306a36Sopenharmony_ci	struct hbq_dmabuf *seq_dmabuf = NULL;
1869062306a36Sopenharmony_ci	struct hbq_dmabuf *temp_dmabuf = NULL;
1869162306a36Sopenharmony_ci	uint8_t	found = 0;
1869262306a36Sopenharmony_ci
1869362306a36Sopenharmony_ci	INIT_LIST_HEAD(&dmabuf->dbuf.list);
1869462306a36Sopenharmony_ci	dmabuf->time_stamp = jiffies;
1869562306a36Sopenharmony_ci	new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
1869662306a36Sopenharmony_ci
1869762306a36Sopenharmony_ci	/* Use the hdr_buf to find the sequence that this frame belongs to */
1869862306a36Sopenharmony_ci	list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
1869962306a36Sopenharmony_ci		temp_hdr = (struct fc_frame_header *)h_buf->virt;
1870062306a36Sopenharmony_ci		if ((temp_hdr->fh_seq_id != new_hdr->fh_seq_id) ||
1870162306a36Sopenharmony_ci		    (temp_hdr->fh_ox_id != new_hdr->fh_ox_id) ||
1870262306a36Sopenharmony_ci		    (memcmp(&temp_hdr->fh_s_id, &new_hdr->fh_s_id, 3)))
1870362306a36Sopenharmony_ci			continue;
1870462306a36Sopenharmony_ci		/* found a pending sequence that matches this frame */
1870562306a36Sopenharmony_ci		seq_dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf);
1870662306a36Sopenharmony_ci		break;
1870762306a36Sopenharmony_ci	}
1870862306a36Sopenharmony_ci	if (!seq_dmabuf) {
1870962306a36Sopenharmony_ci		/*
1871062306a36Sopenharmony_ci		 * This indicates first frame received for this sequence.
1871162306a36Sopenharmony_ci		 * Queue the buffer on the vport's rcv_buffer_list.
1871262306a36Sopenharmony_ci		 */
1871362306a36Sopenharmony_ci		list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list);
1871462306a36Sopenharmony_ci		lpfc_update_rcv_time_stamp(vport);
1871562306a36Sopenharmony_ci		return dmabuf;
1871662306a36Sopenharmony_ci	}
1871762306a36Sopenharmony_ci	temp_hdr = seq_dmabuf->hbuf.virt;
1871862306a36Sopenharmony_ci	if (be16_to_cpu(new_hdr->fh_seq_cnt) <
1871962306a36Sopenharmony_ci		be16_to_cpu(temp_hdr->fh_seq_cnt)) {
1872062306a36Sopenharmony_ci		list_del_init(&seq_dmabuf->hbuf.list);
1872162306a36Sopenharmony_ci		list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list);
1872262306a36Sopenharmony_ci		list_add_tail(&dmabuf->dbuf.list, &seq_dmabuf->dbuf.list);
1872362306a36Sopenharmony_ci		lpfc_update_rcv_time_stamp(vport);
1872462306a36Sopenharmony_ci		return dmabuf;
1872562306a36Sopenharmony_ci	}
1872662306a36Sopenharmony_ci	/* move this sequence to the tail to indicate a young sequence */
1872762306a36Sopenharmony_ci	list_move_tail(&seq_dmabuf->hbuf.list, &vport->rcv_buffer_list);
1872862306a36Sopenharmony_ci	seq_dmabuf->time_stamp = jiffies;
1872962306a36Sopenharmony_ci	lpfc_update_rcv_time_stamp(vport);
1873062306a36Sopenharmony_ci	if (list_empty(&seq_dmabuf->dbuf.list)) {
1873162306a36Sopenharmony_ci		list_add_tail(&dmabuf->dbuf.list, &seq_dmabuf->dbuf.list);
1873262306a36Sopenharmony_ci		return seq_dmabuf;
1873362306a36Sopenharmony_ci	}
1873462306a36Sopenharmony_ci	/* find the correct place in the sequence to insert this frame */
1873562306a36Sopenharmony_ci	d_buf = list_entry(seq_dmabuf->dbuf.list.prev, typeof(*d_buf), list);
1873662306a36Sopenharmony_ci	while (!found) {
1873762306a36Sopenharmony_ci		temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
1873862306a36Sopenharmony_ci		temp_hdr = (struct fc_frame_header *)temp_dmabuf->hbuf.virt;
1873962306a36Sopenharmony_ci		/*
1874062306a36Sopenharmony_ci		 * If the frame's sequence count is greater than the frame on
1874162306a36Sopenharmony_ci		 * the list then insert the frame right after this frame
1874262306a36Sopenharmony_ci		 */
1874362306a36Sopenharmony_ci		if (be16_to_cpu(new_hdr->fh_seq_cnt) >
1874462306a36Sopenharmony_ci			be16_to_cpu(temp_hdr->fh_seq_cnt)) {
1874562306a36Sopenharmony_ci			list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list);
1874662306a36Sopenharmony_ci			found = 1;
1874762306a36Sopenharmony_ci			break;
1874862306a36Sopenharmony_ci		}
1874962306a36Sopenharmony_ci
1875062306a36Sopenharmony_ci		if (&d_buf->list == &seq_dmabuf->dbuf.list)
1875162306a36Sopenharmony_ci			break;
1875262306a36Sopenharmony_ci		d_buf = list_entry(d_buf->list.prev, typeof(*d_buf), list);
1875362306a36Sopenharmony_ci	}
1875462306a36Sopenharmony_ci
1875562306a36Sopenharmony_ci	if (found)
1875662306a36Sopenharmony_ci		return seq_dmabuf;
1875762306a36Sopenharmony_ci	return NULL;
1875862306a36Sopenharmony_ci}
1875962306a36Sopenharmony_ci
1876062306a36Sopenharmony_ci/**
1876162306a36Sopenharmony_ci * lpfc_sli4_abort_partial_seq - Abort partially assembled unsol sequence
1876262306a36Sopenharmony_ci * @vport: pointer to a vitural port
1876362306a36Sopenharmony_ci * @dmabuf: pointer to a dmabuf that describes the FC sequence
1876462306a36Sopenharmony_ci *
1876562306a36Sopenharmony_ci * This function tries to abort from the partially assembed sequence, described
1876662306a36Sopenharmony_ci * by the information from basic abbort @dmabuf. It checks to see whether such
1876762306a36Sopenharmony_ci * partially assembled sequence held by the driver. If so, it shall free up all
1876862306a36Sopenharmony_ci * the frames from the partially assembled sequence.
1876962306a36Sopenharmony_ci *
1877062306a36Sopenharmony_ci * Return
1877162306a36Sopenharmony_ci * true  -- if there is matching partially assembled sequence present and all
1877262306a36Sopenharmony_ci *          the frames freed with the sequence;
1877362306a36Sopenharmony_ci * false -- if there is no matching partially assembled sequence present so
1877462306a36Sopenharmony_ci *          nothing got aborted in the lower layer driver
1877562306a36Sopenharmony_ci **/
1877662306a36Sopenharmony_cistatic bool
1877762306a36Sopenharmony_cilpfc_sli4_abort_partial_seq(struct lpfc_vport *vport,
1877862306a36Sopenharmony_ci			    struct hbq_dmabuf *dmabuf)
1877962306a36Sopenharmony_ci{
1878062306a36Sopenharmony_ci	struct fc_frame_header *new_hdr;
1878162306a36Sopenharmony_ci	struct fc_frame_header *temp_hdr;
1878262306a36Sopenharmony_ci	struct lpfc_dmabuf *d_buf, *n_buf, *h_buf;
1878362306a36Sopenharmony_ci	struct hbq_dmabuf *seq_dmabuf = NULL;
1878462306a36Sopenharmony_ci
1878562306a36Sopenharmony_ci	/* Use the hdr_buf to find the sequence that matches this frame */
1878662306a36Sopenharmony_ci	INIT_LIST_HEAD(&dmabuf->dbuf.list);
1878762306a36Sopenharmony_ci	INIT_LIST_HEAD(&dmabuf->hbuf.list);
1878862306a36Sopenharmony_ci	new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
1878962306a36Sopenharmony_ci	list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
1879062306a36Sopenharmony_ci		temp_hdr = (struct fc_frame_header *)h_buf->virt;
1879162306a36Sopenharmony_ci		if ((temp_hdr->fh_seq_id != new_hdr->fh_seq_id) ||
1879262306a36Sopenharmony_ci		    (temp_hdr->fh_ox_id != new_hdr->fh_ox_id) ||
1879362306a36Sopenharmony_ci		    (memcmp(&temp_hdr->fh_s_id, &new_hdr->fh_s_id, 3)))
1879462306a36Sopenharmony_ci			continue;
1879562306a36Sopenharmony_ci		/* found a pending sequence that matches this frame */
1879662306a36Sopenharmony_ci		seq_dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf);
1879762306a36Sopenharmony_ci		break;
1879862306a36Sopenharmony_ci	}
1879962306a36Sopenharmony_ci
1880062306a36Sopenharmony_ci	/* Free up all the frames from the partially assembled sequence */
1880162306a36Sopenharmony_ci	if (seq_dmabuf) {
1880262306a36Sopenharmony_ci		list_for_each_entry_safe(d_buf, n_buf,
1880362306a36Sopenharmony_ci					 &seq_dmabuf->dbuf.list, list) {
1880462306a36Sopenharmony_ci			list_del_init(&d_buf->list);
1880562306a36Sopenharmony_ci			lpfc_in_buf_free(vport->phba, d_buf);
1880662306a36Sopenharmony_ci		}
1880762306a36Sopenharmony_ci		return true;
1880862306a36Sopenharmony_ci	}
1880962306a36Sopenharmony_ci	return false;
1881062306a36Sopenharmony_ci}
1881162306a36Sopenharmony_ci
1881262306a36Sopenharmony_ci/**
1881362306a36Sopenharmony_ci * lpfc_sli4_abort_ulp_seq - Abort assembled unsol sequence from ulp
1881462306a36Sopenharmony_ci * @vport: pointer to a vitural port
1881562306a36Sopenharmony_ci * @dmabuf: pointer to a dmabuf that describes the FC sequence
1881662306a36Sopenharmony_ci *
1881762306a36Sopenharmony_ci * This function tries to abort from the assembed sequence from upper level
1881862306a36Sopenharmony_ci * protocol, described by the information from basic abbort @dmabuf. It
1881962306a36Sopenharmony_ci * checks to see whether such pending context exists at upper level protocol.
1882062306a36Sopenharmony_ci * If so, it shall clean up the pending context.
1882162306a36Sopenharmony_ci *
1882262306a36Sopenharmony_ci * Return
1882362306a36Sopenharmony_ci * true  -- if there is matching pending context of the sequence cleaned
1882462306a36Sopenharmony_ci *          at ulp;
1882562306a36Sopenharmony_ci * false -- if there is no matching pending context of the sequence present
1882662306a36Sopenharmony_ci *          at ulp.
1882762306a36Sopenharmony_ci **/
1882862306a36Sopenharmony_cistatic bool
1882962306a36Sopenharmony_cilpfc_sli4_abort_ulp_seq(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
1883062306a36Sopenharmony_ci{
1883162306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
1883262306a36Sopenharmony_ci	int handled;
1883362306a36Sopenharmony_ci
1883462306a36Sopenharmony_ci	/* Accepting abort at ulp with SLI4 only */
1883562306a36Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
1883662306a36Sopenharmony_ci		return false;
1883762306a36Sopenharmony_ci
1883862306a36Sopenharmony_ci	/* Register all caring upper level protocols to attend abort */
1883962306a36Sopenharmony_ci	handled = lpfc_ct_handle_unsol_abort(phba, dmabuf);
1884062306a36Sopenharmony_ci	if (handled)
1884162306a36Sopenharmony_ci		return true;
1884262306a36Sopenharmony_ci
1884362306a36Sopenharmony_ci	return false;
1884462306a36Sopenharmony_ci}
1884562306a36Sopenharmony_ci
1884662306a36Sopenharmony_ci/**
1884762306a36Sopenharmony_ci * lpfc_sli4_seq_abort_rsp_cmpl - BLS ABORT RSP seq abort iocb complete handler
1884862306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1884962306a36Sopenharmony_ci * @cmd_iocbq: pointer to the command iocbq structure.
1885062306a36Sopenharmony_ci * @rsp_iocbq: pointer to the response iocbq structure.
1885162306a36Sopenharmony_ci *
1885262306a36Sopenharmony_ci * This function handles the sequence abort response iocb command complete
1885362306a36Sopenharmony_ci * event. It properly releases the memory allocated to the sequence abort
1885462306a36Sopenharmony_ci * accept iocb.
1885562306a36Sopenharmony_ci **/
1885662306a36Sopenharmony_cistatic void
1885762306a36Sopenharmony_cilpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba,
1885862306a36Sopenharmony_ci			     struct lpfc_iocbq *cmd_iocbq,
1885962306a36Sopenharmony_ci			     struct lpfc_iocbq *rsp_iocbq)
1886062306a36Sopenharmony_ci{
1886162306a36Sopenharmony_ci	if (cmd_iocbq) {
1886262306a36Sopenharmony_ci		lpfc_nlp_put(cmd_iocbq->ndlp);
1886362306a36Sopenharmony_ci		lpfc_sli_release_iocbq(phba, cmd_iocbq);
1886462306a36Sopenharmony_ci	}
1886562306a36Sopenharmony_ci
1886662306a36Sopenharmony_ci	/* Failure means BLS ABORT RSP did not get delivered to remote node*/
1886762306a36Sopenharmony_ci	if (rsp_iocbq && rsp_iocbq->iocb.ulpStatus)
1886862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1886962306a36Sopenharmony_ci			"3154 BLS ABORT RSP failed, data:  x%x/x%x\n",
1887062306a36Sopenharmony_ci			get_job_ulpstatus(phba, rsp_iocbq),
1887162306a36Sopenharmony_ci			get_job_word4(phba, rsp_iocbq));
1887262306a36Sopenharmony_ci}
1887362306a36Sopenharmony_ci
1887462306a36Sopenharmony_ci/**
1887562306a36Sopenharmony_ci * lpfc_sli4_xri_inrange - check xri is in range of xris owned by driver.
1887662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1887762306a36Sopenharmony_ci * @xri: xri id in transaction.
1887862306a36Sopenharmony_ci *
1887962306a36Sopenharmony_ci * This function validates the xri maps to the known range of XRIs allocated an
1888062306a36Sopenharmony_ci * used by the driver.
1888162306a36Sopenharmony_ci **/
1888262306a36Sopenharmony_ciuint16_t
1888362306a36Sopenharmony_cilpfc_sli4_xri_inrange(struct lpfc_hba *phba,
1888462306a36Sopenharmony_ci		      uint16_t xri)
1888562306a36Sopenharmony_ci{
1888662306a36Sopenharmony_ci	uint16_t i;
1888762306a36Sopenharmony_ci
1888862306a36Sopenharmony_ci	for (i = 0; i < phba->sli4_hba.max_cfg_param.max_xri; i++) {
1888962306a36Sopenharmony_ci		if (xri == phba->sli4_hba.xri_ids[i])
1889062306a36Sopenharmony_ci			return i;
1889162306a36Sopenharmony_ci	}
1889262306a36Sopenharmony_ci	return NO_XRI;
1889362306a36Sopenharmony_ci}
1889462306a36Sopenharmony_ci
1889562306a36Sopenharmony_ci/**
1889662306a36Sopenharmony_ci * lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort
1889762306a36Sopenharmony_ci * @vport: pointer to a virtual port.
1889862306a36Sopenharmony_ci * @fc_hdr: pointer to a FC frame header.
1889962306a36Sopenharmony_ci * @aborted: was the partially assembled receive sequence successfully aborted
1890062306a36Sopenharmony_ci *
1890162306a36Sopenharmony_ci * This function sends a basic response to a previous unsol sequence abort
1890262306a36Sopenharmony_ci * event after aborting the sequence handling.
1890362306a36Sopenharmony_ci **/
1890462306a36Sopenharmony_civoid
1890562306a36Sopenharmony_cilpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport,
1890662306a36Sopenharmony_ci			struct fc_frame_header *fc_hdr, bool aborted)
1890762306a36Sopenharmony_ci{
1890862306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
1890962306a36Sopenharmony_ci	struct lpfc_iocbq *ctiocb = NULL;
1891062306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp;
1891162306a36Sopenharmony_ci	uint16_t oxid, rxid, xri, lxri;
1891262306a36Sopenharmony_ci	uint32_t sid, fctl;
1891362306a36Sopenharmony_ci	union lpfc_wqe128 *icmd;
1891462306a36Sopenharmony_ci	int rc;
1891562306a36Sopenharmony_ci
1891662306a36Sopenharmony_ci	if (!lpfc_is_link_up(phba))
1891762306a36Sopenharmony_ci		return;
1891862306a36Sopenharmony_ci
1891962306a36Sopenharmony_ci	sid = sli4_sid_from_fc_hdr(fc_hdr);
1892062306a36Sopenharmony_ci	oxid = be16_to_cpu(fc_hdr->fh_ox_id);
1892162306a36Sopenharmony_ci	rxid = be16_to_cpu(fc_hdr->fh_rx_id);
1892262306a36Sopenharmony_ci
1892362306a36Sopenharmony_ci	ndlp = lpfc_findnode_did(vport, sid);
1892462306a36Sopenharmony_ci	if (!ndlp) {
1892562306a36Sopenharmony_ci		ndlp = lpfc_nlp_init(vport, sid);
1892662306a36Sopenharmony_ci		if (!ndlp) {
1892762306a36Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS,
1892862306a36Sopenharmony_ci					 "1268 Failed to allocate ndlp for "
1892962306a36Sopenharmony_ci					 "oxid:x%x SID:x%x\n", oxid, sid);
1893062306a36Sopenharmony_ci			return;
1893162306a36Sopenharmony_ci		}
1893262306a36Sopenharmony_ci		/* Put ndlp onto pport node list */
1893362306a36Sopenharmony_ci		lpfc_enqueue_node(vport, ndlp);
1893462306a36Sopenharmony_ci	}
1893562306a36Sopenharmony_ci
1893662306a36Sopenharmony_ci	/* Allocate buffer for rsp iocb */
1893762306a36Sopenharmony_ci	ctiocb = lpfc_sli_get_iocbq(phba);
1893862306a36Sopenharmony_ci	if (!ctiocb)
1893962306a36Sopenharmony_ci		return;
1894062306a36Sopenharmony_ci
1894162306a36Sopenharmony_ci	icmd = &ctiocb->wqe;
1894262306a36Sopenharmony_ci
1894362306a36Sopenharmony_ci	/* Extract the F_CTL field from FC_HDR */
1894462306a36Sopenharmony_ci	fctl = sli4_fctl_from_fc_hdr(fc_hdr);
1894562306a36Sopenharmony_ci
1894662306a36Sopenharmony_ci	ctiocb->ndlp = lpfc_nlp_get(ndlp);
1894762306a36Sopenharmony_ci	if (!ctiocb->ndlp) {
1894862306a36Sopenharmony_ci		lpfc_sli_release_iocbq(phba, ctiocb);
1894962306a36Sopenharmony_ci		return;
1895062306a36Sopenharmony_ci	}
1895162306a36Sopenharmony_ci
1895262306a36Sopenharmony_ci	ctiocb->vport = phba->pport;
1895362306a36Sopenharmony_ci	ctiocb->cmd_cmpl = lpfc_sli4_seq_abort_rsp_cmpl;
1895462306a36Sopenharmony_ci	ctiocb->sli4_lxritag = NO_XRI;
1895562306a36Sopenharmony_ci	ctiocb->sli4_xritag = NO_XRI;
1895662306a36Sopenharmony_ci	ctiocb->abort_rctl = FC_RCTL_BA_ACC;
1895762306a36Sopenharmony_ci
1895862306a36Sopenharmony_ci	if (fctl & FC_FC_EX_CTX)
1895962306a36Sopenharmony_ci		/* Exchange responder sent the abort so we
1896062306a36Sopenharmony_ci		 * own the oxid.
1896162306a36Sopenharmony_ci		 */
1896262306a36Sopenharmony_ci		xri = oxid;
1896362306a36Sopenharmony_ci	else
1896462306a36Sopenharmony_ci		xri = rxid;
1896562306a36Sopenharmony_ci	lxri = lpfc_sli4_xri_inrange(phba, xri);
1896662306a36Sopenharmony_ci	if (lxri != NO_XRI)
1896762306a36Sopenharmony_ci		lpfc_set_rrq_active(phba, ndlp, lxri,
1896862306a36Sopenharmony_ci			(xri == oxid) ? rxid : oxid, 0);
1896962306a36Sopenharmony_ci	/* For BA_ABTS from exchange responder, if the logical xri with
1897062306a36Sopenharmony_ci	 * the oxid maps to the FCP XRI range, the port no longer has
1897162306a36Sopenharmony_ci	 * that exchange context, send a BLS_RJT. Override the IOCB for
1897262306a36Sopenharmony_ci	 * a BA_RJT.
1897362306a36Sopenharmony_ci	 */
1897462306a36Sopenharmony_ci	if ((fctl & FC_FC_EX_CTX) &&
1897562306a36Sopenharmony_ci	    (lxri > lpfc_sli4_get_iocb_cnt(phba))) {
1897662306a36Sopenharmony_ci		ctiocb->abort_rctl = FC_RCTL_BA_RJT;
1897762306a36Sopenharmony_ci		bf_set(xmit_bls_rsp64_rjt_vspec, &icmd->xmit_bls_rsp, 0);
1897862306a36Sopenharmony_ci		bf_set(xmit_bls_rsp64_rjt_expc, &icmd->xmit_bls_rsp,
1897962306a36Sopenharmony_ci		       FC_BA_RJT_INV_XID);
1898062306a36Sopenharmony_ci		bf_set(xmit_bls_rsp64_rjt_rsnc, &icmd->xmit_bls_rsp,
1898162306a36Sopenharmony_ci		       FC_BA_RJT_UNABLE);
1898262306a36Sopenharmony_ci	}
1898362306a36Sopenharmony_ci
1898462306a36Sopenharmony_ci	/* If BA_ABTS failed to abort a partially assembled receive sequence,
1898562306a36Sopenharmony_ci	 * the driver no longer has that exchange, send a BLS_RJT. Override
1898662306a36Sopenharmony_ci	 * the IOCB for a BA_RJT.
1898762306a36Sopenharmony_ci	 */
1898862306a36Sopenharmony_ci	if (aborted == false) {
1898962306a36Sopenharmony_ci		ctiocb->abort_rctl = FC_RCTL_BA_RJT;
1899062306a36Sopenharmony_ci		bf_set(xmit_bls_rsp64_rjt_vspec, &icmd->xmit_bls_rsp, 0);
1899162306a36Sopenharmony_ci		bf_set(xmit_bls_rsp64_rjt_expc, &icmd->xmit_bls_rsp,
1899262306a36Sopenharmony_ci		       FC_BA_RJT_INV_XID);
1899362306a36Sopenharmony_ci		bf_set(xmit_bls_rsp64_rjt_rsnc, &icmd->xmit_bls_rsp,
1899462306a36Sopenharmony_ci		       FC_BA_RJT_UNABLE);
1899562306a36Sopenharmony_ci	}
1899662306a36Sopenharmony_ci
1899762306a36Sopenharmony_ci	if (fctl & FC_FC_EX_CTX) {
1899862306a36Sopenharmony_ci		/* ABTS sent by responder to CT exchange, construction
1899962306a36Sopenharmony_ci		 * of BA_ACC will use OX_ID from ABTS for the XRI_TAG
1900062306a36Sopenharmony_ci		 * field and RX_ID from ABTS for RX_ID field.
1900162306a36Sopenharmony_ci		 */
1900262306a36Sopenharmony_ci		ctiocb->abort_bls = LPFC_ABTS_UNSOL_RSP;
1900362306a36Sopenharmony_ci		bf_set(xmit_bls_rsp64_rxid, &icmd->xmit_bls_rsp, rxid);
1900462306a36Sopenharmony_ci	} else {
1900562306a36Sopenharmony_ci		/* ABTS sent by initiator to CT exchange, construction
1900662306a36Sopenharmony_ci		 * of BA_ACC will need to allocate a new XRI as for the
1900762306a36Sopenharmony_ci		 * XRI_TAG field.
1900862306a36Sopenharmony_ci		 */
1900962306a36Sopenharmony_ci		ctiocb->abort_bls = LPFC_ABTS_UNSOL_INT;
1901062306a36Sopenharmony_ci	}
1901162306a36Sopenharmony_ci
1901262306a36Sopenharmony_ci	/* OX_ID is invariable to who sent ABTS to CT exchange */
1901362306a36Sopenharmony_ci	bf_set(xmit_bls_rsp64_oxid, &icmd->xmit_bls_rsp, oxid);
1901462306a36Sopenharmony_ci	bf_set(xmit_bls_rsp64_oxid, &icmd->xmit_bls_rsp, rxid);
1901562306a36Sopenharmony_ci
1901662306a36Sopenharmony_ci	/* Use CT=VPI */
1901762306a36Sopenharmony_ci	bf_set(wqe_els_did, &icmd->xmit_bls_rsp.wqe_dest,
1901862306a36Sopenharmony_ci	       ndlp->nlp_DID);
1901962306a36Sopenharmony_ci	bf_set(xmit_bls_rsp64_temprpi, &icmd->xmit_bls_rsp,
1902062306a36Sopenharmony_ci	       phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
1902162306a36Sopenharmony_ci	bf_set(wqe_cmnd, &icmd->generic.wqe_com, CMD_XMIT_BLS_RSP64_CX);
1902262306a36Sopenharmony_ci
1902362306a36Sopenharmony_ci	/* Xmit CT abts response on exchange <xid> */
1902462306a36Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1902562306a36Sopenharmony_ci			 "1200 Send BLS cmd x%x on oxid x%x Data: x%x\n",
1902662306a36Sopenharmony_ci			 ctiocb->abort_rctl, oxid, phba->link_state);
1902762306a36Sopenharmony_ci
1902862306a36Sopenharmony_ci	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0);
1902962306a36Sopenharmony_ci	if (rc == IOCB_ERROR) {
1903062306a36Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
1903162306a36Sopenharmony_ci				 "2925 Failed to issue CT ABTS RSP x%x on "
1903262306a36Sopenharmony_ci				 "xri x%x, Data x%x\n",
1903362306a36Sopenharmony_ci				 ctiocb->abort_rctl, oxid,
1903462306a36Sopenharmony_ci				 phba->link_state);
1903562306a36Sopenharmony_ci		lpfc_nlp_put(ndlp);
1903662306a36Sopenharmony_ci		ctiocb->ndlp = NULL;
1903762306a36Sopenharmony_ci		lpfc_sli_release_iocbq(phba, ctiocb);
1903862306a36Sopenharmony_ci	}
1903962306a36Sopenharmony_ci}
1904062306a36Sopenharmony_ci
1904162306a36Sopenharmony_ci/**
1904262306a36Sopenharmony_ci * lpfc_sli4_handle_unsol_abort - Handle sli-4 unsolicited abort event
1904362306a36Sopenharmony_ci * @vport: Pointer to the vport on which this sequence was received
1904462306a36Sopenharmony_ci * @dmabuf: pointer to a dmabuf that describes the FC sequence
1904562306a36Sopenharmony_ci *
1904662306a36Sopenharmony_ci * This function handles an SLI-4 unsolicited abort event. If the unsolicited
1904762306a36Sopenharmony_ci * receive sequence is only partially assembed by the driver, it shall abort
1904862306a36Sopenharmony_ci * the partially assembled frames for the sequence. Otherwise, if the
1904962306a36Sopenharmony_ci * unsolicited receive sequence has been completely assembled and passed to
1905062306a36Sopenharmony_ci * the Upper Layer Protocol (ULP), it then mark the per oxid status for the
1905162306a36Sopenharmony_ci * unsolicited sequence has been aborted. After that, it will issue a basic
1905262306a36Sopenharmony_ci * accept to accept the abort.
1905362306a36Sopenharmony_ci **/
1905462306a36Sopenharmony_cistatic void
1905562306a36Sopenharmony_cilpfc_sli4_handle_unsol_abort(struct lpfc_vport *vport,
1905662306a36Sopenharmony_ci			     struct hbq_dmabuf *dmabuf)
1905762306a36Sopenharmony_ci{
1905862306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
1905962306a36Sopenharmony_ci	struct fc_frame_header fc_hdr;
1906062306a36Sopenharmony_ci	uint32_t fctl;
1906162306a36Sopenharmony_ci	bool aborted;
1906262306a36Sopenharmony_ci
1906362306a36Sopenharmony_ci	/* Make a copy of fc_hdr before the dmabuf being released */
1906462306a36Sopenharmony_ci	memcpy(&fc_hdr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header));
1906562306a36Sopenharmony_ci	fctl = sli4_fctl_from_fc_hdr(&fc_hdr);
1906662306a36Sopenharmony_ci
1906762306a36Sopenharmony_ci	if (fctl & FC_FC_EX_CTX) {
1906862306a36Sopenharmony_ci		/* ABTS by responder to exchange, no cleanup needed */
1906962306a36Sopenharmony_ci		aborted = true;
1907062306a36Sopenharmony_ci	} else {
1907162306a36Sopenharmony_ci		/* ABTS by initiator to exchange, need to do cleanup */
1907262306a36Sopenharmony_ci		aborted = lpfc_sli4_abort_partial_seq(vport, dmabuf);
1907362306a36Sopenharmony_ci		if (aborted == false)
1907462306a36Sopenharmony_ci			aborted = lpfc_sli4_abort_ulp_seq(vport, dmabuf);
1907562306a36Sopenharmony_ci	}
1907662306a36Sopenharmony_ci	lpfc_in_buf_free(phba, &dmabuf->dbuf);
1907762306a36Sopenharmony_ci
1907862306a36Sopenharmony_ci	if (phba->nvmet_support) {
1907962306a36Sopenharmony_ci		lpfc_nvmet_rcv_unsol_abort(vport, &fc_hdr);
1908062306a36Sopenharmony_ci		return;
1908162306a36Sopenharmony_ci	}
1908262306a36Sopenharmony_ci
1908362306a36Sopenharmony_ci	/* Respond with BA_ACC or BA_RJT accordingly */
1908462306a36Sopenharmony_ci	lpfc_sli4_seq_abort_rsp(vport, &fc_hdr, aborted);
1908562306a36Sopenharmony_ci}
1908662306a36Sopenharmony_ci
1908762306a36Sopenharmony_ci/**
1908862306a36Sopenharmony_ci * lpfc_seq_complete - Indicates if a sequence is complete
1908962306a36Sopenharmony_ci * @dmabuf: pointer to a dmabuf that describes the FC sequence
1909062306a36Sopenharmony_ci *
1909162306a36Sopenharmony_ci * This function checks the sequence, starting with the frame described by
1909262306a36Sopenharmony_ci * @dmabuf, to see if all the frames associated with this sequence are present.
1909362306a36Sopenharmony_ci * the frames associated with this sequence are linked to the @dmabuf using the
1909462306a36Sopenharmony_ci * dbuf list. This function looks for two major things. 1) That the first frame
1909562306a36Sopenharmony_ci * has a sequence count of zero. 2) There is a frame with last frame of sequence
1909662306a36Sopenharmony_ci * set. 3) That there are no holes in the sequence count. The function will
1909762306a36Sopenharmony_ci * return 1 when the sequence is complete, otherwise it will return 0.
1909862306a36Sopenharmony_ci **/
1909962306a36Sopenharmony_cistatic int
1910062306a36Sopenharmony_cilpfc_seq_complete(struct hbq_dmabuf *dmabuf)
1910162306a36Sopenharmony_ci{
1910262306a36Sopenharmony_ci	struct fc_frame_header *hdr;
1910362306a36Sopenharmony_ci	struct lpfc_dmabuf *d_buf;
1910462306a36Sopenharmony_ci	struct hbq_dmabuf *seq_dmabuf;
1910562306a36Sopenharmony_ci	uint32_t fctl;
1910662306a36Sopenharmony_ci	int seq_count = 0;
1910762306a36Sopenharmony_ci
1910862306a36Sopenharmony_ci	hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
1910962306a36Sopenharmony_ci	/* make sure first fame of sequence has a sequence count of zero */
1911062306a36Sopenharmony_ci	if (hdr->fh_seq_cnt != seq_count)
1911162306a36Sopenharmony_ci		return 0;
1911262306a36Sopenharmony_ci	fctl = (hdr->fh_f_ctl[0] << 16 |
1911362306a36Sopenharmony_ci		hdr->fh_f_ctl[1] << 8 |
1911462306a36Sopenharmony_ci		hdr->fh_f_ctl[2]);
1911562306a36Sopenharmony_ci	/* If last frame of sequence we can return success. */
1911662306a36Sopenharmony_ci	if (fctl & FC_FC_END_SEQ)
1911762306a36Sopenharmony_ci		return 1;
1911862306a36Sopenharmony_ci	list_for_each_entry(d_buf, &dmabuf->dbuf.list, list) {
1911962306a36Sopenharmony_ci		seq_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
1912062306a36Sopenharmony_ci		hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
1912162306a36Sopenharmony_ci		/* If there is a hole in the sequence count then fail. */
1912262306a36Sopenharmony_ci		if (++seq_count != be16_to_cpu(hdr->fh_seq_cnt))
1912362306a36Sopenharmony_ci			return 0;
1912462306a36Sopenharmony_ci		fctl = (hdr->fh_f_ctl[0] << 16 |
1912562306a36Sopenharmony_ci			hdr->fh_f_ctl[1] << 8 |
1912662306a36Sopenharmony_ci			hdr->fh_f_ctl[2]);
1912762306a36Sopenharmony_ci		/* If last frame of sequence we can return success. */
1912862306a36Sopenharmony_ci		if (fctl & FC_FC_END_SEQ)
1912962306a36Sopenharmony_ci			return 1;
1913062306a36Sopenharmony_ci	}
1913162306a36Sopenharmony_ci	return 0;
1913262306a36Sopenharmony_ci}
1913362306a36Sopenharmony_ci
1913462306a36Sopenharmony_ci/**
1913562306a36Sopenharmony_ci * lpfc_prep_seq - Prep sequence for ULP processing
1913662306a36Sopenharmony_ci * @vport: Pointer to the vport on which this sequence was received
1913762306a36Sopenharmony_ci * @seq_dmabuf: pointer to a dmabuf that describes the FC sequence
1913862306a36Sopenharmony_ci *
1913962306a36Sopenharmony_ci * This function takes a sequence, described by a list of frames, and creates
1914062306a36Sopenharmony_ci * a list of iocbq structures to describe the sequence. This iocbq list will be
1914162306a36Sopenharmony_ci * used to issue to the generic unsolicited sequence handler. This routine
1914262306a36Sopenharmony_ci * returns a pointer to the first iocbq in the list. If the function is unable
1914362306a36Sopenharmony_ci * to allocate an iocbq then it throw out the received frames that were not
1914462306a36Sopenharmony_ci * able to be described and return a pointer to the first iocbq. If unable to
1914562306a36Sopenharmony_ci * allocate any iocbqs (including the first) this function will return NULL.
1914662306a36Sopenharmony_ci **/
1914762306a36Sopenharmony_cistatic struct lpfc_iocbq *
1914862306a36Sopenharmony_cilpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
1914962306a36Sopenharmony_ci{
1915062306a36Sopenharmony_ci	struct hbq_dmabuf *hbq_buf;
1915162306a36Sopenharmony_ci	struct lpfc_dmabuf *d_buf, *n_buf;
1915262306a36Sopenharmony_ci	struct lpfc_iocbq *first_iocbq, *iocbq;
1915362306a36Sopenharmony_ci	struct fc_frame_header *fc_hdr;
1915462306a36Sopenharmony_ci	uint32_t sid;
1915562306a36Sopenharmony_ci	uint32_t len, tot_len;
1915662306a36Sopenharmony_ci
1915762306a36Sopenharmony_ci	fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
1915862306a36Sopenharmony_ci	/* remove from receive buffer list */
1915962306a36Sopenharmony_ci	list_del_init(&seq_dmabuf->hbuf.list);
1916062306a36Sopenharmony_ci	lpfc_update_rcv_time_stamp(vport);
1916162306a36Sopenharmony_ci	/* get the Remote Port's SID */
1916262306a36Sopenharmony_ci	sid = sli4_sid_from_fc_hdr(fc_hdr);
1916362306a36Sopenharmony_ci	tot_len = 0;
1916462306a36Sopenharmony_ci	/* Get an iocbq struct to fill in. */
1916562306a36Sopenharmony_ci	first_iocbq = lpfc_sli_get_iocbq(vport->phba);
1916662306a36Sopenharmony_ci	if (first_iocbq) {
1916762306a36Sopenharmony_ci		/* Initialize the first IOCB. */
1916862306a36Sopenharmony_ci		first_iocbq->wcqe_cmpl.total_data_placed = 0;
1916962306a36Sopenharmony_ci		bf_set(lpfc_wcqe_c_status, &first_iocbq->wcqe_cmpl,
1917062306a36Sopenharmony_ci		       IOSTAT_SUCCESS);
1917162306a36Sopenharmony_ci		first_iocbq->vport = vport;
1917262306a36Sopenharmony_ci
1917362306a36Sopenharmony_ci		/* Check FC Header to see what TYPE of frame we are rcv'ing */
1917462306a36Sopenharmony_ci		if (sli4_type_from_fc_hdr(fc_hdr) == FC_TYPE_ELS) {
1917562306a36Sopenharmony_ci			bf_set(els_rsp64_sid, &first_iocbq->wqe.xmit_els_rsp,
1917662306a36Sopenharmony_ci			       sli4_did_from_fc_hdr(fc_hdr));
1917762306a36Sopenharmony_ci		}
1917862306a36Sopenharmony_ci
1917962306a36Sopenharmony_ci		bf_set(wqe_ctxt_tag, &first_iocbq->wqe.xmit_els_rsp.wqe_com,
1918062306a36Sopenharmony_ci		       NO_XRI);
1918162306a36Sopenharmony_ci		bf_set(wqe_rcvoxid, &first_iocbq->wqe.xmit_els_rsp.wqe_com,
1918262306a36Sopenharmony_ci		       be16_to_cpu(fc_hdr->fh_ox_id));
1918362306a36Sopenharmony_ci
1918462306a36Sopenharmony_ci		/* put the first buffer into the first iocb */
1918562306a36Sopenharmony_ci		tot_len = bf_get(lpfc_rcqe_length,
1918662306a36Sopenharmony_ci				 &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
1918762306a36Sopenharmony_ci
1918862306a36Sopenharmony_ci		first_iocbq->cmd_dmabuf = &seq_dmabuf->dbuf;
1918962306a36Sopenharmony_ci		first_iocbq->bpl_dmabuf = NULL;
1919062306a36Sopenharmony_ci		/* Keep track of the BDE count */
1919162306a36Sopenharmony_ci		first_iocbq->wcqe_cmpl.word3 = 1;
1919262306a36Sopenharmony_ci
1919362306a36Sopenharmony_ci		if (tot_len > LPFC_DATA_BUF_SIZE)
1919462306a36Sopenharmony_ci			first_iocbq->wqe.gen_req.bde.tus.f.bdeSize =
1919562306a36Sopenharmony_ci				LPFC_DATA_BUF_SIZE;
1919662306a36Sopenharmony_ci		else
1919762306a36Sopenharmony_ci			first_iocbq->wqe.gen_req.bde.tus.f.bdeSize = tot_len;
1919862306a36Sopenharmony_ci
1919962306a36Sopenharmony_ci		first_iocbq->wcqe_cmpl.total_data_placed = tot_len;
1920062306a36Sopenharmony_ci		bf_set(wqe_els_did, &first_iocbq->wqe.xmit_els_rsp.wqe_dest,
1920162306a36Sopenharmony_ci		       sid);
1920262306a36Sopenharmony_ci	}
1920362306a36Sopenharmony_ci	iocbq = first_iocbq;
1920462306a36Sopenharmony_ci	/*
1920562306a36Sopenharmony_ci	 * Each IOCBq can have two Buffers assigned, so go through the list
1920662306a36Sopenharmony_ci	 * of buffers for this sequence and save two buffers in each IOCBq
1920762306a36Sopenharmony_ci	 */
1920862306a36Sopenharmony_ci	list_for_each_entry_safe(d_buf, n_buf, &seq_dmabuf->dbuf.list, list) {
1920962306a36Sopenharmony_ci		if (!iocbq) {
1921062306a36Sopenharmony_ci			lpfc_in_buf_free(vport->phba, d_buf);
1921162306a36Sopenharmony_ci			continue;
1921262306a36Sopenharmony_ci		}
1921362306a36Sopenharmony_ci		if (!iocbq->bpl_dmabuf) {
1921462306a36Sopenharmony_ci			iocbq->bpl_dmabuf = d_buf;
1921562306a36Sopenharmony_ci			iocbq->wcqe_cmpl.word3++;
1921662306a36Sopenharmony_ci			/* We need to get the size out of the right CQE */
1921762306a36Sopenharmony_ci			hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
1921862306a36Sopenharmony_ci			len = bf_get(lpfc_rcqe_length,
1921962306a36Sopenharmony_ci				       &hbq_buf->cq_event.cqe.rcqe_cmpl);
1922062306a36Sopenharmony_ci			iocbq->unsol_rcv_len = len;
1922162306a36Sopenharmony_ci			iocbq->wcqe_cmpl.total_data_placed += len;
1922262306a36Sopenharmony_ci			tot_len += len;
1922362306a36Sopenharmony_ci		} else {
1922462306a36Sopenharmony_ci			iocbq = lpfc_sli_get_iocbq(vport->phba);
1922562306a36Sopenharmony_ci			if (!iocbq) {
1922662306a36Sopenharmony_ci				if (first_iocbq) {
1922762306a36Sopenharmony_ci					bf_set(lpfc_wcqe_c_status,
1922862306a36Sopenharmony_ci					       &first_iocbq->wcqe_cmpl,
1922962306a36Sopenharmony_ci					       IOSTAT_SUCCESS);
1923062306a36Sopenharmony_ci					first_iocbq->wcqe_cmpl.parameter =
1923162306a36Sopenharmony_ci						IOERR_NO_RESOURCES;
1923262306a36Sopenharmony_ci				}
1923362306a36Sopenharmony_ci				lpfc_in_buf_free(vport->phba, d_buf);
1923462306a36Sopenharmony_ci				continue;
1923562306a36Sopenharmony_ci			}
1923662306a36Sopenharmony_ci			/* We need to get the size out of the right CQE */
1923762306a36Sopenharmony_ci			hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
1923862306a36Sopenharmony_ci			len = bf_get(lpfc_rcqe_length,
1923962306a36Sopenharmony_ci				       &hbq_buf->cq_event.cqe.rcqe_cmpl);
1924062306a36Sopenharmony_ci			iocbq->cmd_dmabuf = d_buf;
1924162306a36Sopenharmony_ci			iocbq->bpl_dmabuf = NULL;
1924262306a36Sopenharmony_ci			iocbq->wcqe_cmpl.word3 = 1;
1924362306a36Sopenharmony_ci
1924462306a36Sopenharmony_ci			if (len > LPFC_DATA_BUF_SIZE)
1924562306a36Sopenharmony_ci				iocbq->wqe.xmit_els_rsp.bde.tus.f.bdeSize =
1924662306a36Sopenharmony_ci					LPFC_DATA_BUF_SIZE;
1924762306a36Sopenharmony_ci			else
1924862306a36Sopenharmony_ci				iocbq->wqe.xmit_els_rsp.bde.tus.f.bdeSize =
1924962306a36Sopenharmony_ci					len;
1925062306a36Sopenharmony_ci
1925162306a36Sopenharmony_ci			tot_len += len;
1925262306a36Sopenharmony_ci			iocbq->wcqe_cmpl.total_data_placed = tot_len;
1925362306a36Sopenharmony_ci			bf_set(wqe_els_did, &iocbq->wqe.xmit_els_rsp.wqe_dest,
1925462306a36Sopenharmony_ci			       sid);
1925562306a36Sopenharmony_ci			list_add_tail(&iocbq->list, &first_iocbq->list);
1925662306a36Sopenharmony_ci		}
1925762306a36Sopenharmony_ci	}
1925862306a36Sopenharmony_ci	/* Free the sequence's header buffer */
1925962306a36Sopenharmony_ci	if (!first_iocbq)
1926062306a36Sopenharmony_ci		lpfc_in_buf_free(vport->phba, &seq_dmabuf->dbuf);
1926162306a36Sopenharmony_ci
1926262306a36Sopenharmony_ci	return first_iocbq;
1926362306a36Sopenharmony_ci}
1926462306a36Sopenharmony_ci
1926562306a36Sopenharmony_cistatic void
1926662306a36Sopenharmony_cilpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport,
1926762306a36Sopenharmony_ci			  struct hbq_dmabuf *seq_dmabuf)
1926862306a36Sopenharmony_ci{
1926962306a36Sopenharmony_ci	struct fc_frame_header *fc_hdr;
1927062306a36Sopenharmony_ci	struct lpfc_iocbq *iocbq, *curr_iocb, *next_iocb;
1927162306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
1927262306a36Sopenharmony_ci
1927362306a36Sopenharmony_ci	fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
1927462306a36Sopenharmony_ci	iocbq = lpfc_prep_seq(vport, seq_dmabuf);
1927562306a36Sopenharmony_ci	if (!iocbq) {
1927662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1927762306a36Sopenharmony_ci				"2707 Ring %d handler: Failed to allocate "
1927862306a36Sopenharmony_ci				"iocb Rctl x%x Type x%x received\n",
1927962306a36Sopenharmony_ci				LPFC_ELS_RING,
1928062306a36Sopenharmony_ci				fc_hdr->fh_r_ctl, fc_hdr->fh_type);
1928162306a36Sopenharmony_ci		return;
1928262306a36Sopenharmony_ci	}
1928362306a36Sopenharmony_ci	if (!lpfc_complete_unsol_iocb(phba,
1928462306a36Sopenharmony_ci				      phba->sli4_hba.els_wq->pring,
1928562306a36Sopenharmony_ci				      iocbq, fc_hdr->fh_r_ctl,
1928662306a36Sopenharmony_ci				      fc_hdr->fh_type)) {
1928762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1928862306a36Sopenharmony_ci				"2540 Ring %d handler: unexpected Rctl "
1928962306a36Sopenharmony_ci				"x%x Type x%x received\n",
1929062306a36Sopenharmony_ci				LPFC_ELS_RING,
1929162306a36Sopenharmony_ci				fc_hdr->fh_r_ctl, fc_hdr->fh_type);
1929262306a36Sopenharmony_ci		lpfc_in_buf_free(phba, &seq_dmabuf->dbuf);
1929362306a36Sopenharmony_ci	}
1929462306a36Sopenharmony_ci
1929562306a36Sopenharmony_ci	/* Free iocb created in lpfc_prep_seq */
1929662306a36Sopenharmony_ci	list_for_each_entry_safe(curr_iocb, next_iocb,
1929762306a36Sopenharmony_ci				 &iocbq->list, list) {
1929862306a36Sopenharmony_ci		list_del_init(&curr_iocb->list);
1929962306a36Sopenharmony_ci		lpfc_sli_release_iocbq(phba, curr_iocb);
1930062306a36Sopenharmony_ci	}
1930162306a36Sopenharmony_ci	lpfc_sli_release_iocbq(phba, iocbq);
1930262306a36Sopenharmony_ci}
1930362306a36Sopenharmony_ci
1930462306a36Sopenharmony_cistatic void
1930562306a36Sopenharmony_cilpfc_sli4_mds_loopback_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1930662306a36Sopenharmony_ci			    struct lpfc_iocbq *rspiocb)
1930762306a36Sopenharmony_ci{
1930862306a36Sopenharmony_ci	struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf;
1930962306a36Sopenharmony_ci
1931062306a36Sopenharmony_ci	if (pcmd && pcmd->virt)
1931162306a36Sopenharmony_ci		dma_pool_free(phba->lpfc_drb_pool, pcmd->virt, pcmd->phys);
1931262306a36Sopenharmony_ci	kfree(pcmd);
1931362306a36Sopenharmony_ci	lpfc_sli_release_iocbq(phba, cmdiocb);
1931462306a36Sopenharmony_ci	lpfc_drain_txq(phba);
1931562306a36Sopenharmony_ci}
1931662306a36Sopenharmony_ci
1931762306a36Sopenharmony_cistatic void
1931862306a36Sopenharmony_cilpfc_sli4_handle_mds_loopback(struct lpfc_vport *vport,
1931962306a36Sopenharmony_ci			      struct hbq_dmabuf *dmabuf)
1932062306a36Sopenharmony_ci{
1932162306a36Sopenharmony_ci	struct fc_frame_header *fc_hdr;
1932262306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
1932362306a36Sopenharmony_ci	struct lpfc_iocbq *iocbq = NULL;
1932462306a36Sopenharmony_ci	union  lpfc_wqe128 *pwqe;
1932562306a36Sopenharmony_ci	struct lpfc_dmabuf *pcmd = NULL;
1932662306a36Sopenharmony_ci	uint32_t frame_len;
1932762306a36Sopenharmony_ci	int rc;
1932862306a36Sopenharmony_ci	unsigned long iflags;
1932962306a36Sopenharmony_ci
1933062306a36Sopenharmony_ci	fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
1933162306a36Sopenharmony_ci	frame_len = bf_get(lpfc_rcqe_length, &dmabuf->cq_event.cqe.rcqe_cmpl);
1933262306a36Sopenharmony_ci
1933362306a36Sopenharmony_ci	/* Send the received frame back */
1933462306a36Sopenharmony_ci	iocbq = lpfc_sli_get_iocbq(phba);
1933562306a36Sopenharmony_ci	if (!iocbq) {
1933662306a36Sopenharmony_ci		/* Queue cq event and wakeup worker thread to process it */
1933762306a36Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
1933862306a36Sopenharmony_ci		list_add_tail(&dmabuf->cq_event.list,
1933962306a36Sopenharmony_ci			      &phba->sli4_hba.sp_queue_event);
1934062306a36Sopenharmony_ci		phba->hba_flag |= HBA_SP_QUEUE_EVT;
1934162306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
1934262306a36Sopenharmony_ci		lpfc_worker_wake_up(phba);
1934362306a36Sopenharmony_ci		return;
1934462306a36Sopenharmony_ci	}
1934562306a36Sopenharmony_ci
1934662306a36Sopenharmony_ci	/* Allocate buffer for command payload */
1934762306a36Sopenharmony_ci	pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
1934862306a36Sopenharmony_ci	if (pcmd)
1934962306a36Sopenharmony_ci		pcmd->virt = dma_pool_alloc(phba->lpfc_drb_pool, GFP_KERNEL,
1935062306a36Sopenharmony_ci					    &pcmd->phys);
1935162306a36Sopenharmony_ci	if (!pcmd || !pcmd->virt)
1935262306a36Sopenharmony_ci		goto exit;
1935362306a36Sopenharmony_ci
1935462306a36Sopenharmony_ci	INIT_LIST_HEAD(&pcmd->list);
1935562306a36Sopenharmony_ci
1935662306a36Sopenharmony_ci	/* copyin the payload */
1935762306a36Sopenharmony_ci	memcpy(pcmd->virt, dmabuf->dbuf.virt, frame_len);
1935862306a36Sopenharmony_ci
1935962306a36Sopenharmony_ci	iocbq->cmd_dmabuf = pcmd;
1936062306a36Sopenharmony_ci	iocbq->vport = vport;
1936162306a36Sopenharmony_ci	iocbq->cmd_flag &= ~LPFC_FIP_ELS_ID_MASK;
1936262306a36Sopenharmony_ci	iocbq->cmd_flag |= LPFC_USE_FCPWQIDX;
1936362306a36Sopenharmony_ci	iocbq->num_bdes = 0;
1936462306a36Sopenharmony_ci
1936562306a36Sopenharmony_ci	pwqe = &iocbq->wqe;
1936662306a36Sopenharmony_ci	/* fill in BDE's for command */
1936762306a36Sopenharmony_ci	pwqe->gen_req.bde.addrHigh = putPaddrHigh(pcmd->phys);
1936862306a36Sopenharmony_ci	pwqe->gen_req.bde.addrLow = putPaddrLow(pcmd->phys);
1936962306a36Sopenharmony_ci	pwqe->gen_req.bde.tus.f.bdeSize = frame_len;
1937062306a36Sopenharmony_ci	pwqe->gen_req.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
1937162306a36Sopenharmony_ci
1937262306a36Sopenharmony_ci	pwqe->send_frame.frame_len = frame_len;
1937362306a36Sopenharmony_ci	pwqe->send_frame.fc_hdr_wd0 = be32_to_cpu(*((__be32 *)fc_hdr));
1937462306a36Sopenharmony_ci	pwqe->send_frame.fc_hdr_wd1 = be32_to_cpu(*((__be32 *)fc_hdr + 1));
1937562306a36Sopenharmony_ci	pwqe->send_frame.fc_hdr_wd2 = be32_to_cpu(*((__be32 *)fc_hdr + 2));
1937662306a36Sopenharmony_ci	pwqe->send_frame.fc_hdr_wd3 = be32_to_cpu(*((__be32 *)fc_hdr + 3));
1937762306a36Sopenharmony_ci	pwqe->send_frame.fc_hdr_wd4 = be32_to_cpu(*((__be32 *)fc_hdr + 4));
1937862306a36Sopenharmony_ci	pwqe->send_frame.fc_hdr_wd5 = be32_to_cpu(*((__be32 *)fc_hdr + 5));
1937962306a36Sopenharmony_ci
1938062306a36Sopenharmony_ci	pwqe->generic.wqe_com.word7 = 0;
1938162306a36Sopenharmony_ci	pwqe->generic.wqe_com.word10 = 0;
1938262306a36Sopenharmony_ci
1938362306a36Sopenharmony_ci	bf_set(wqe_cmnd, &pwqe->generic.wqe_com, CMD_SEND_FRAME);
1938462306a36Sopenharmony_ci	bf_set(wqe_sof, &pwqe->generic.wqe_com, 0x2E); /* SOF byte */
1938562306a36Sopenharmony_ci	bf_set(wqe_eof, &pwqe->generic.wqe_com, 0x41); /* EOF byte */
1938662306a36Sopenharmony_ci	bf_set(wqe_lenloc, &pwqe->generic.wqe_com, 1);
1938762306a36Sopenharmony_ci	bf_set(wqe_xbl, &pwqe->generic.wqe_com, 1);
1938862306a36Sopenharmony_ci	bf_set(wqe_dbde, &pwqe->generic.wqe_com, 1);
1938962306a36Sopenharmony_ci	bf_set(wqe_xc, &pwqe->generic.wqe_com, 1);
1939062306a36Sopenharmony_ci	bf_set(wqe_cmd_type, &pwqe->generic.wqe_com, 0xA);
1939162306a36Sopenharmony_ci	bf_set(wqe_cqid, &pwqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
1939262306a36Sopenharmony_ci	bf_set(wqe_xri_tag, &pwqe->generic.wqe_com, iocbq->sli4_xritag);
1939362306a36Sopenharmony_ci	bf_set(wqe_reqtag, &pwqe->generic.wqe_com, iocbq->iotag);
1939462306a36Sopenharmony_ci	bf_set(wqe_class, &pwqe->generic.wqe_com, CLASS3);
1939562306a36Sopenharmony_ci	pwqe->generic.wqe_com.abort_tag = iocbq->iotag;
1939662306a36Sopenharmony_ci
1939762306a36Sopenharmony_ci	iocbq->cmd_cmpl = lpfc_sli4_mds_loopback_cmpl;
1939862306a36Sopenharmony_ci
1939962306a36Sopenharmony_ci	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocbq, 0);
1940062306a36Sopenharmony_ci	if (rc == IOCB_ERROR)
1940162306a36Sopenharmony_ci		goto exit;
1940262306a36Sopenharmony_ci
1940362306a36Sopenharmony_ci	lpfc_in_buf_free(phba, &dmabuf->dbuf);
1940462306a36Sopenharmony_ci	return;
1940562306a36Sopenharmony_ci
1940662306a36Sopenharmony_ciexit:
1940762306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
1940862306a36Sopenharmony_ci			"2023 Unable to process MDS loopback frame\n");
1940962306a36Sopenharmony_ci	if (pcmd && pcmd->virt)
1941062306a36Sopenharmony_ci		dma_pool_free(phba->lpfc_drb_pool, pcmd->virt, pcmd->phys);
1941162306a36Sopenharmony_ci	kfree(pcmd);
1941262306a36Sopenharmony_ci	if (iocbq)
1941362306a36Sopenharmony_ci		lpfc_sli_release_iocbq(phba, iocbq);
1941462306a36Sopenharmony_ci	lpfc_in_buf_free(phba, &dmabuf->dbuf);
1941562306a36Sopenharmony_ci}
1941662306a36Sopenharmony_ci
1941762306a36Sopenharmony_ci/**
1941862306a36Sopenharmony_ci * lpfc_sli4_handle_received_buffer - Handle received buffers from firmware
1941962306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
1942062306a36Sopenharmony_ci * @dmabuf: Pointer to a dmabuf that describes the FC sequence.
1942162306a36Sopenharmony_ci *
1942262306a36Sopenharmony_ci * This function is called with no lock held. This function processes all
1942362306a36Sopenharmony_ci * the received buffers and gives it to upper layers when a received buffer
1942462306a36Sopenharmony_ci * indicates that it is the final frame in the sequence. The interrupt
1942562306a36Sopenharmony_ci * service routine processes received buffers at interrupt contexts.
1942662306a36Sopenharmony_ci * Worker thread calls lpfc_sli4_handle_received_buffer, which will call the
1942762306a36Sopenharmony_ci * appropriate receive function when the final frame in a sequence is received.
1942862306a36Sopenharmony_ci **/
1942962306a36Sopenharmony_civoid
1943062306a36Sopenharmony_cilpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
1943162306a36Sopenharmony_ci				 struct hbq_dmabuf *dmabuf)
1943262306a36Sopenharmony_ci{
1943362306a36Sopenharmony_ci	struct hbq_dmabuf *seq_dmabuf;
1943462306a36Sopenharmony_ci	struct fc_frame_header *fc_hdr;
1943562306a36Sopenharmony_ci	struct lpfc_vport *vport;
1943662306a36Sopenharmony_ci	uint32_t fcfi;
1943762306a36Sopenharmony_ci	uint32_t did;
1943862306a36Sopenharmony_ci
1943962306a36Sopenharmony_ci	/* Process each received buffer */
1944062306a36Sopenharmony_ci	fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
1944162306a36Sopenharmony_ci
1944262306a36Sopenharmony_ci	if (fc_hdr->fh_r_ctl == FC_RCTL_MDS_DIAGS ||
1944362306a36Sopenharmony_ci	    fc_hdr->fh_r_ctl == FC_RCTL_DD_UNSOL_DATA) {
1944462306a36Sopenharmony_ci		vport = phba->pport;
1944562306a36Sopenharmony_ci		/* Handle MDS Loopback frames */
1944662306a36Sopenharmony_ci		if  (!(phba->pport->load_flag & FC_UNLOADING))
1944762306a36Sopenharmony_ci			lpfc_sli4_handle_mds_loopback(vport, dmabuf);
1944862306a36Sopenharmony_ci		else
1944962306a36Sopenharmony_ci			lpfc_in_buf_free(phba, &dmabuf->dbuf);
1945062306a36Sopenharmony_ci		return;
1945162306a36Sopenharmony_ci	}
1945262306a36Sopenharmony_ci
1945362306a36Sopenharmony_ci	/* check to see if this a valid type of frame */
1945462306a36Sopenharmony_ci	if (lpfc_fc_frame_check(phba, fc_hdr)) {
1945562306a36Sopenharmony_ci		lpfc_in_buf_free(phba, &dmabuf->dbuf);
1945662306a36Sopenharmony_ci		return;
1945762306a36Sopenharmony_ci	}
1945862306a36Sopenharmony_ci
1945962306a36Sopenharmony_ci	if ((bf_get(lpfc_cqe_code,
1946062306a36Sopenharmony_ci		    &dmabuf->cq_event.cqe.rcqe_cmpl) == CQE_CODE_RECEIVE_V1))
1946162306a36Sopenharmony_ci		fcfi = bf_get(lpfc_rcqe_fcf_id_v1,
1946262306a36Sopenharmony_ci			      &dmabuf->cq_event.cqe.rcqe_cmpl);
1946362306a36Sopenharmony_ci	else
1946462306a36Sopenharmony_ci		fcfi = bf_get(lpfc_rcqe_fcf_id,
1946562306a36Sopenharmony_ci			      &dmabuf->cq_event.cqe.rcqe_cmpl);
1946662306a36Sopenharmony_ci
1946762306a36Sopenharmony_ci	if (fc_hdr->fh_r_ctl == 0xF4 && fc_hdr->fh_type == 0xFF) {
1946862306a36Sopenharmony_ci		vport = phba->pport;
1946962306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
1947062306a36Sopenharmony_ci				"2023 MDS Loopback %d bytes\n",
1947162306a36Sopenharmony_ci				bf_get(lpfc_rcqe_length,
1947262306a36Sopenharmony_ci				       &dmabuf->cq_event.cqe.rcqe_cmpl));
1947362306a36Sopenharmony_ci		/* Handle MDS Loopback frames */
1947462306a36Sopenharmony_ci		lpfc_sli4_handle_mds_loopback(vport, dmabuf);
1947562306a36Sopenharmony_ci		return;
1947662306a36Sopenharmony_ci	}
1947762306a36Sopenharmony_ci
1947862306a36Sopenharmony_ci	/* d_id this frame is directed to */
1947962306a36Sopenharmony_ci	did = sli4_did_from_fc_hdr(fc_hdr);
1948062306a36Sopenharmony_ci
1948162306a36Sopenharmony_ci	vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi, did);
1948262306a36Sopenharmony_ci	if (!vport) {
1948362306a36Sopenharmony_ci		/* throw out the frame */
1948462306a36Sopenharmony_ci		lpfc_in_buf_free(phba, &dmabuf->dbuf);
1948562306a36Sopenharmony_ci		return;
1948662306a36Sopenharmony_ci	}
1948762306a36Sopenharmony_ci
1948862306a36Sopenharmony_ci	/* vport is registered unless we rcv a FLOGI directed to Fabric_DID */
1948962306a36Sopenharmony_ci	if (!(vport->vpi_state & LPFC_VPI_REGISTERED) &&
1949062306a36Sopenharmony_ci		(did != Fabric_DID)) {
1949162306a36Sopenharmony_ci		/*
1949262306a36Sopenharmony_ci		 * Throw out the frame if we are not pt2pt.
1949362306a36Sopenharmony_ci		 * The pt2pt protocol allows for discovery frames
1949462306a36Sopenharmony_ci		 * to be received without a registered VPI.
1949562306a36Sopenharmony_ci		 */
1949662306a36Sopenharmony_ci		if (!(vport->fc_flag & FC_PT2PT) ||
1949762306a36Sopenharmony_ci			(phba->link_state == LPFC_HBA_READY)) {
1949862306a36Sopenharmony_ci			lpfc_in_buf_free(phba, &dmabuf->dbuf);
1949962306a36Sopenharmony_ci			return;
1950062306a36Sopenharmony_ci		}
1950162306a36Sopenharmony_ci	}
1950262306a36Sopenharmony_ci
1950362306a36Sopenharmony_ci	/* Handle the basic abort sequence (BA_ABTS) event */
1950462306a36Sopenharmony_ci	if (fc_hdr->fh_r_ctl == FC_RCTL_BA_ABTS) {
1950562306a36Sopenharmony_ci		lpfc_sli4_handle_unsol_abort(vport, dmabuf);
1950662306a36Sopenharmony_ci		return;
1950762306a36Sopenharmony_ci	}
1950862306a36Sopenharmony_ci
1950962306a36Sopenharmony_ci	/* Link this frame */
1951062306a36Sopenharmony_ci	seq_dmabuf = lpfc_fc_frame_add(vport, dmabuf);
1951162306a36Sopenharmony_ci	if (!seq_dmabuf) {
1951262306a36Sopenharmony_ci		/* unable to add frame to vport - throw it out */
1951362306a36Sopenharmony_ci		lpfc_in_buf_free(phba, &dmabuf->dbuf);
1951462306a36Sopenharmony_ci		return;
1951562306a36Sopenharmony_ci	}
1951662306a36Sopenharmony_ci	/* If not last frame in sequence continue processing frames. */
1951762306a36Sopenharmony_ci	if (!lpfc_seq_complete(seq_dmabuf))
1951862306a36Sopenharmony_ci		return;
1951962306a36Sopenharmony_ci
1952062306a36Sopenharmony_ci	/* Send the complete sequence to the upper layer protocol */
1952162306a36Sopenharmony_ci	lpfc_sli4_send_seq_to_ulp(vport, seq_dmabuf);
1952262306a36Sopenharmony_ci}
1952362306a36Sopenharmony_ci
1952462306a36Sopenharmony_ci/**
1952562306a36Sopenharmony_ci * lpfc_sli4_post_all_rpi_hdrs - Post the rpi header memory region to the port
1952662306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1952762306a36Sopenharmony_ci *
1952862306a36Sopenharmony_ci * This routine is invoked to post rpi header templates to the
1952962306a36Sopenharmony_ci * HBA consistent with the SLI-4 interface spec.  This routine
1953062306a36Sopenharmony_ci * posts a SLI4_PAGE_SIZE memory region to the port to hold up to
1953162306a36Sopenharmony_ci * SLI4_PAGE_SIZE modulo 64 rpi context headers.
1953262306a36Sopenharmony_ci *
1953362306a36Sopenharmony_ci * This routine does not require any locks.  It's usage is expected
1953462306a36Sopenharmony_ci * to be driver load or reset recovery when the driver is
1953562306a36Sopenharmony_ci * sequential.
1953662306a36Sopenharmony_ci *
1953762306a36Sopenharmony_ci * Return codes
1953862306a36Sopenharmony_ci * 	0 - successful
1953962306a36Sopenharmony_ci *      -EIO - The mailbox failed to complete successfully.
1954062306a36Sopenharmony_ci * 	When this error occurs, the driver is not guaranteed
1954162306a36Sopenharmony_ci *	to have any rpi regions posted to the device and
1954262306a36Sopenharmony_ci *	must either attempt to repost the regions or take a
1954362306a36Sopenharmony_ci *	fatal error.
1954462306a36Sopenharmony_ci **/
1954562306a36Sopenharmony_ciint
1954662306a36Sopenharmony_cilpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba)
1954762306a36Sopenharmony_ci{
1954862306a36Sopenharmony_ci	struct lpfc_rpi_hdr *rpi_page;
1954962306a36Sopenharmony_ci	uint32_t rc = 0;
1955062306a36Sopenharmony_ci	uint16_t lrpi = 0;
1955162306a36Sopenharmony_ci
1955262306a36Sopenharmony_ci	/* SLI4 ports that support extents do not require RPI headers. */
1955362306a36Sopenharmony_ci	if (!phba->sli4_hba.rpi_hdrs_in_use)
1955462306a36Sopenharmony_ci		goto exit;
1955562306a36Sopenharmony_ci	if (phba->sli4_hba.extents_in_use)
1955662306a36Sopenharmony_ci		return -EIO;
1955762306a36Sopenharmony_ci
1955862306a36Sopenharmony_ci	list_for_each_entry(rpi_page, &phba->sli4_hba.lpfc_rpi_hdr_list, list) {
1955962306a36Sopenharmony_ci		/*
1956062306a36Sopenharmony_ci		 * Assign the rpi headers a physical rpi only if the driver
1956162306a36Sopenharmony_ci		 * has not initialized those resources.  A port reset only
1956262306a36Sopenharmony_ci		 * needs the headers posted.
1956362306a36Sopenharmony_ci		 */
1956462306a36Sopenharmony_ci		if (bf_get(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags) !=
1956562306a36Sopenharmony_ci		    LPFC_RPI_RSRC_RDY)
1956662306a36Sopenharmony_ci			rpi_page->start_rpi = phba->sli4_hba.rpi_ids[lrpi];
1956762306a36Sopenharmony_ci
1956862306a36Sopenharmony_ci		rc = lpfc_sli4_post_rpi_hdr(phba, rpi_page);
1956962306a36Sopenharmony_ci		if (rc != MBX_SUCCESS) {
1957062306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1957162306a36Sopenharmony_ci					"2008 Error %d posting all rpi "
1957262306a36Sopenharmony_ci					"headers\n", rc);
1957362306a36Sopenharmony_ci			rc = -EIO;
1957462306a36Sopenharmony_ci			break;
1957562306a36Sopenharmony_ci		}
1957662306a36Sopenharmony_ci	}
1957762306a36Sopenharmony_ci
1957862306a36Sopenharmony_ci exit:
1957962306a36Sopenharmony_ci	bf_set(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags,
1958062306a36Sopenharmony_ci	       LPFC_RPI_RSRC_RDY);
1958162306a36Sopenharmony_ci	return rc;
1958262306a36Sopenharmony_ci}
1958362306a36Sopenharmony_ci
1958462306a36Sopenharmony_ci/**
1958562306a36Sopenharmony_ci * lpfc_sli4_post_rpi_hdr - Post an rpi header memory region to the port
1958662306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1958762306a36Sopenharmony_ci * @rpi_page:  pointer to the rpi memory region.
1958862306a36Sopenharmony_ci *
1958962306a36Sopenharmony_ci * This routine is invoked to post a single rpi header to the
1959062306a36Sopenharmony_ci * HBA consistent with the SLI-4 interface spec.  This memory region
1959162306a36Sopenharmony_ci * maps up to 64 rpi context regions.
1959262306a36Sopenharmony_ci *
1959362306a36Sopenharmony_ci * Return codes
1959462306a36Sopenharmony_ci * 	0 - successful
1959562306a36Sopenharmony_ci * 	-ENOMEM - No available memory
1959662306a36Sopenharmony_ci *      -EIO - The mailbox failed to complete successfully.
1959762306a36Sopenharmony_ci **/
1959862306a36Sopenharmony_ciint
1959962306a36Sopenharmony_cilpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
1960062306a36Sopenharmony_ci{
1960162306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
1960262306a36Sopenharmony_ci	struct lpfc_mbx_post_hdr_tmpl *hdr_tmpl;
1960362306a36Sopenharmony_ci	uint32_t rc = 0;
1960462306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1960562306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1960662306a36Sopenharmony_ci
1960762306a36Sopenharmony_ci	/* SLI4 ports that support extents do not require RPI headers. */
1960862306a36Sopenharmony_ci	if (!phba->sli4_hba.rpi_hdrs_in_use)
1960962306a36Sopenharmony_ci		return rc;
1961062306a36Sopenharmony_ci	if (phba->sli4_hba.extents_in_use)
1961162306a36Sopenharmony_ci		return -EIO;
1961262306a36Sopenharmony_ci
1961362306a36Sopenharmony_ci	/* The port is notified of the header region via a mailbox command. */
1961462306a36Sopenharmony_ci	mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1961562306a36Sopenharmony_ci	if (!mboxq) {
1961662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1961762306a36Sopenharmony_ci				"2001 Unable to allocate memory for issuing "
1961862306a36Sopenharmony_ci				"SLI_CONFIG_SPECIAL mailbox command\n");
1961962306a36Sopenharmony_ci		return -ENOMEM;
1962062306a36Sopenharmony_ci	}
1962162306a36Sopenharmony_ci
1962262306a36Sopenharmony_ci	/* Post all rpi memory regions to the port. */
1962362306a36Sopenharmony_ci	hdr_tmpl = &mboxq->u.mqe.un.hdr_tmpl;
1962462306a36Sopenharmony_ci	lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
1962562306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE,
1962662306a36Sopenharmony_ci			 sizeof(struct lpfc_mbx_post_hdr_tmpl) -
1962762306a36Sopenharmony_ci			 sizeof(struct lpfc_sli4_cfg_mhdr),
1962862306a36Sopenharmony_ci			 LPFC_SLI4_MBX_EMBED);
1962962306a36Sopenharmony_ci
1963062306a36Sopenharmony_ci
1963162306a36Sopenharmony_ci	/* Post the physical rpi to the port for this rpi header. */
1963262306a36Sopenharmony_ci	bf_set(lpfc_mbx_post_hdr_tmpl_rpi_offset, hdr_tmpl,
1963362306a36Sopenharmony_ci	       rpi_page->start_rpi);
1963462306a36Sopenharmony_ci	bf_set(lpfc_mbx_post_hdr_tmpl_page_cnt,
1963562306a36Sopenharmony_ci	       hdr_tmpl, rpi_page->page_count);
1963662306a36Sopenharmony_ci
1963762306a36Sopenharmony_ci	hdr_tmpl->rpi_paddr_lo = putPaddrLow(rpi_page->dmabuf->phys);
1963862306a36Sopenharmony_ci	hdr_tmpl->rpi_paddr_hi = putPaddrHigh(rpi_page->dmabuf->phys);
1963962306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
1964062306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *) &hdr_tmpl->header.cfg_shdr;
1964162306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1964262306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1964362306a36Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
1964462306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || rc) {
1964562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1964662306a36Sopenharmony_ci				"2514 POST_RPI_HDR mailbox failed with "
1964762306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
1964862306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
1964962306a36Sopenharmony_ci		rc = -ENXIO;
1965062306a36Sopenharmony_ci	} else {
1965162306a36Sopenharmony_ci		/*
1965262306a36Sopenharmony_ci		 * The next_rpi stores the next logical module-64 rpi value used
1965362306a36Sopenharmony_ci		 * to post physical rpis in subsequent rpi postings.
1965462306a36Sopenharmony_ci		 */
1965562306a36Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
1965662306a36Sopenharmony_ci		phba->sli4_hba.next_rpi = rpi_page->next_rpi;
1965762306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
1965862306a36Sopenharmony_ci	}
1965962306a36Sopenharmony_ci	return rc;
1966062306a36Sopenharmony_ci}
1966162306a36Sopenharmony_ci
1966262306a36Sopenharmony_ci/**
1966362306a36Sopenharmony_ci * lpfc_sli4_alloc_rpi - Get an available rpi in the device's range
1966462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1966562306a36Sopenharmony_ci *
1966662306a36Sopenharmony_ci * This routine is invoked to post rpi header templates to the
1966762306a36Sopenharmony_ci * HBA consistent with the SLI-4 interface spec.  This routine
1966862306a36Sopenharmony_ci * posts a SLI4_PAGE_SIZE memory region to the port to hold up to
1966962306a36Sopenharmony_ci * SLI4_PAGE_SIZE modulo 64 rpi context headers.
1967062306a36Sopenharmony_ci *
1967162306a36Sopenharmony_ci * Returns
1967262306a36Sopenharmony_ci * 	A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful
1967362306a36Sopenharmony_ci * 	LPFC_RPI_ALLOC_ERROR if no rpis are available.
1967462306a36Sopenharmony_ci **/
1967562306a36Sopenharmony_ciint
1967662306a36Sopenharmony_cilpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
1967762306a36Sopenharmony_ci{
1967862306a36Sopenharmony_ci	unsigned long rpi;
1967962306a36Sopenharmony_ci	uint16_t max_rpi, rpi_limit;
1968062306a36Sopenharmony_ci	uint16_t rpi_remaining, lrpi = 0;
1968162306a36Sopenharmony_ci	struct lpfc_rpi_hdr *rpi_hdr;
1968262306a36Sopenharmony_ci	unsigned long iflag;
1968362306a36Sopenharmony_ci
1968462306a36Sopenharmony_ci	/*
1968562306a36Sopenharmony_ci	 * Fetch the next logical rpi.  Because this index is logical,
1968662306a36Sopenharmony_ci	 * the  driver starts at 0 each time.
1968762306a36Sopenharmony_ci	 */
1968862306a36Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflag);
1968962306a36Sopenharmony_ci	max_rpi = phba->sli4_hba.max_cfg_param.max_rpi;
1969062306a36Sopenharmony_ci	rpi_limit = phba->sli4_hba.next_rpi;
1969162306a36Sopenharmony_ci
1969262306a36Sopenharmony_ci	rpi = find_first_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit);
1969362306a36Sopenharmony_ci	if (rpi >= rpi_limit)
1969462306a36Sopenharmony_ci		rpi = LPFC_RPI_ALLOC_ERROR;
1969562306a36Sopenharmony_ci	else {
1969662306a36Sopenharmony_ci		set_bit(rpi, phba->sli4_hba.rpi_bmask);
1969762306a36Sopenharmony_ci		phba->sli4_hba.max_cfg_param.rpi_used++;
1969862306a36Sopenharmony_ci		phba->sli4_hba.rpi_count++;
1969962306a36Sopenharmony_ci	}
1970062306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO,
1970162306a36Sopenharmony_ci			LOG_NODE | LOG_DISCOVERY,
1970262306a36Sopenharmony_ci			"0001 Allocated rpi:x%x max:x%x lim:x%x\n",
1970362306a36Sopenharmony_ci			(int) rpi, max_rpi, rpi_limit);
1970462306a36Sopenharmony_ci
1970562306a36Sopenharmony_ci	/*
1970662306a36Sopenharmony_ci	 * Don't try to allocate more rpi header regions if the device limit
1970762306a36Sopenharmony_ci	 * has been exhausted.
1970862306a36Sopenharmony_ci	 */
1970962306a36Sopenharmony_ci	if ((rpi == LPFC_RPI_ALLOC_ERROR) &&
1971062306a36Sopenharmony_ci	    (phba->sli4_hba.rpi_count >= max_rpi)) {
1971162306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
1971262306a36Sopenharmony_ci		return rpi;
1971362306a36Sopenharmony_ci	}
1971462306a36Sopenharmony_ci
1971562306a36Sopenharmony_ci	/*
1971662306a36Sopenharmony_ci	 * RPI header postings are not required for SLI4 ports capable of
1971762306a36Sopenharmony_ci	 * extents.
1971862306a36Sopenharmony_ci	 */
1971962306a36Sopenharmony_ci	if (!phba->sli4_hba.rpi_hdrs_in_use) {
1972062306a36Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflag);
1972162306a36Sopenharmony_ci		return rpi;
1972262306a36Sopenharmony_ci	}
1972362306a36Sopenharmony_ci
1972462306a36Sopenharmony_ci	/*
1972562306a36Sopenharmony_ci	 * If the driver is running low on rpi resources, allocate another
1972662306a36Sopenharmony_ci	 * page now.  Note that the next_rpi value is used because
1972762306a36Sopenharmony_ci	 * it represents how many are actually in use whereas max_rpi notes
1972862306a36Sopenharmony_ci	 * how many are supported max by the device.
1972962306a36Sopenharmony_ci	 */
1973062306a36Sopenharmony_ci	rpi_remaining = phba->sli4_hba.next_rpi - phba->sli4_hba.rpi_count;
1973162306a36Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflag);
1973262306a36Sopenharmony_ci	if (rpi_remaining < LPFC_RPI_LOW_WATER_MARK) {
1973362306a36Sopenharmony_ci		rpi_hdr = lpfc_sli4_create_rpi_hdr(phba);
1973462306a36Sopenharmony_ci		if (!rpi_hdr) {
1973562306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1973662306a36Sopenharmony_ci					"2002 Error Could not grow rpi "
1973762306a36Sopenharmony_ci					"count\n");
1973862306a36Sopenharmony_ci		} else {
1973962306a36Sopenharmony_ci			lrpi = rpi_hdr->start_rpi;
1974062306a36Sopenharmony_ci			rpi_hdr->start_rpi = phba->sli4_hba.rpi_ids[lrpi];
1974162306a36Sopenharmony_ci			lpfc_sli4_post_rpi_hdr(phba, rpi_hdr);
1974262306a36Sopenharmony_ci		}
1974362306a36Sopenharmony_ci	}
1974462306a36Sopenharmony_ci
1974562306a36Sopenharmony_ci	return rpi;
1974662306a36Sopenharmony_ci}
1974762306a36Sopenharmony_ci
1974862306a36Sopenharmony_ci/**
1974962306a36Sopenharmony_ci * __lpfc_sli4_free_rpi - Release an rpi for reuse.
1975062306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1975162306a36Sopenharmony_ci * @rpi: rpi to free
1975262306a36Sopenharmony_ci *
1975362306a36Sopenharmony_ci * This routine is invoked to release an rpi to the pool of
1975462306a36Sopenharmony_ci * available rpis maintained by the driver.
1975562306a36Sopenharmony_ci **/
1975662306a36Sopenharmony_cistatic void
1975762306a36Sopenharmony_ci__lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
1975862306a36Sopenharmony_ci{
1975962306a36Sopenharmony_ci	/*
1976062306a36Sopenharmony_ci	 * if the rpi value indicates a prior unreg has already
1976162306a36Sopenharmony_ci	 * been done, skip the unreg.
1976262306a36Sopenharmony_ci	 */
1976362306a36Sopenharmony_ci	if (rpi == LPFC_RPI_ALLOC_ERROR)
1976462306a36Sopenharmony_ci		return;
1976562306a36Sopenharmony_ci
1976662306a36Sopenharmony_ci	if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) {
1976762306a36Sopenharmony_ci		phba->sli4_hba.rpi_count--;
1976862306a36Sopenharmony_ci		phba->sli4_hba.max_cfg_param.rpi_used--;
1976962306a36Sopenharmony_ci	} else {
1977062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO,
1977162306a36Sopenharmony_ci				LOG_NODE | LOG_DISCOVERY,
1977262306a36Sopenharmony_ci				"2016 rpi %x not inuse\n",
1977362306a36Sopenharmony_ci				rpi);
1977462306a36Sopenharmony_ci	}
1977562306a36Sopenharmony_ci}
1977662306a36Sopenharmony_ci
1977762306a36Sopenharmony_ci/**
1977862306a36Sopenharmony_ci * lpfc_sli4_free_rpi - Release an rpi for reuse.
1977962306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1978062306a36Sopenharmony_ci * @rpi: rpi to free
1978162306a36Sopenharmony_ci *
1978262306a36Sopenharmony_ci * This routine is invoked to release an rpi to the pool of
1978362306a36Sopenharmony_ci * available rpis maintained by the driver.
1978462306a36Sopenharmony_ci **/
1978562306a36Sopenharmony_civoid
1978662306a36Sopenharmony_cilpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
1978762306a36Sopenharmony_ci{
1978862306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
1978962306a36Sopenharmony_ci	__lpfc_sli4_free_rpi(phba, rpi);
1979062306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
1979162306a36Sopenharmony_ci}
1979262306a36Sopenharmony_ci
1979362306a36Sopenharmony_ci/**
1979462306a36Sopenharmony_ci * lpfc_sli4_remove_rpis - Remove the rpi bitmask region
1979562306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1979662306a36Sopenharmony_ci *
1979762306a36Sopenharmony_ci * This routine is invoked to remove the memory region that
1979862306a36Sopenharmony_ci * provided rpi via a bitmask.
1979962306a36Sopenharmony_ci **/
1980062306a36Sopenharmony_civoid
1980162306a36Sopenharmony_cilpfc_sli4_remove_rpis(struct lpfc_hba *phba)
1980262306a36Sopenharmony_ci{
1980362306a36Sopenharmony_ci	kfree(phba->sli4_hba.rpi_bmask);
1980462306a36Sopenharmony_ci	kfree(phba->sli4_hba.rpi_ids);
1980562306a36Sopenharmony_ci	bf_set(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
1980662306a36Sopenharmony_ci}
1980762306a36Sopenharmony_ci
1980862306a36Sopenharmony_ci/**
1980962306a36Sopenharmony_ci * lpfc_sli4_resume_rpi - Remove the rpi bitmask region
1981062306a36Sopenharmony_ci * @ndlp: pointer to lpfc nodelist data structure.
1981162306a36Sopenharmony_ci * @cmpl: completion call-back.
1981262306a36Sopenharmony_ci * @arg: data to load as MBox 'caller buffer information'
1981362306a36Sopenharmony_ci *
1981462306a36Sopenharmony_ci * This routine is invoked to remove the memory region that
1981562306a36Sopenharmony_ci * provided rpi via a bitmask.
1981662306a36Sopenharmony_ci **/
1981762306a36Sopenharmony_ciint
1981862306a36Sopenharmony_cilpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp,
1981962306a36Sopenharmony_ci	void (*cmpl)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *arg)
1982062306a36Sopenharmony_ci{
1982162306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
1982262306a36Sopenharmony_ci	struct lpfc_hba *phba = ndlp->phba;
1982362306a36Sopenharmony_ci	int rc;
1982462306a36Sopenharmony_ci
1982562306a36Sopenharmony_ci	/* The port is notified of the header region via a mailbox command. */
1982662306a36Sopenharmony_ci	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1982762306a36Sopenharmony_ci	if (!mboxq)
1982862306a36Sopenharmony_ci		return -ENOMEM;
1982962306a36Sopenharmony_ci
1983062306a36Sopenharmony_ci	/* If cmpl assigned, then this nlp_get pairs with
1983162306a36Sopenharmony_ci	 * lpfc_mbx_cmpl_resume_rpi.
1983262306a36Sopenharmony_ci	 *
1983362306a36Sopenharmony_ci	 * Else cmpl is NULL, then this nlp_get pairs with
1983462306a36Sopenharmony_ci	 * lpfc_sli_def_mbox_cmpl.
1983562306a36Sopenharmony_ci	 */
1983662306a36Sopenharmony_ci	if (!lpfc_nlp_get(ndlp)) {
1983762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1983862306a36Sopenharmony_ci				"2122 %s: Failed to get nlp ref\n",
1983962306a36Sopenharmony_ci				__func__);
1984062306a36Sopenharmony_ci		mempool_free(mboxq, phba->mbox_mem_pool);
1984162306a36Sopenharmony_ci		return -EIO;
1984262306a36Sopenharmony_ci	}
1984362306a36Sopenharmony_ci
1984462306a36Sopenharmony_ci	/* Post all rpi memory regions to the port. */
1984562306a36Sopenharmony_ci	lpfc_resume_rpi(mboxq, ndlp);
1984662306a36Sopenharmony_ci	if (cmpl) {
1984762306a36Sopenharmony_ci		mboxq->mbox_cmpl = cmpl;
1984862306a36Sopenharmony_ci		mboxq->ctx_buf = arg;
1984962306a36Sopenharmony_ci	} else
1985062306a36Sopenharmony_ci		mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
1985162306a36Sopenharmony_ci	mboxq->ctx_ndlp = ndlp;
1985262306a36Sopenharmony_ci	mboxq->vport = ndlp->vport;
1985362306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
1985462306a36Sopenharmony_ci	if (rc == MBX_NOT_FINISHED) {
1985562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1985662306a36Sopenharmony_ci				"2010 Resume RPI Mailbox failed "
1985762306a36Sopenharmony_ci				"status %d, mbxStatus x%x\n", rc,
1985862306a36Sopenharmony_ci				bf_get(lpfc_mqe_status, &mboxq->u.mqe));
1985962306a36Sopenharmony_ci		lpfc_nlp_put(ndlp);
1986062306a36Sopenharmony_ci		mempool_free(mboxq, phba->mbox_mem_pool);
1986162306a36Sopenharmony_ci		return -EIO;
1986262306a36Sopenharmony_ci	}
1986362306a36Sopenharmony_ci	return 0;
1986462306a36Sopenharmony_ci}
1986562306a36Sopenharmony_ci
1986662306a36Sopenharmony_ci/**
1986762306a36Sopenharmony_ci * lpfc_sli4_init_vpi - Initialize a vpi with the port
1986862306a36Sopenharmony_ci * @vport: Pointer to the vport for which the vpi is being initialized
1986962306a36Sopenharmony_ci *
1987062306a36Sopenharmony_ci * This routine is invoked to activate a vpi with the port.
1987162306a36Sopenharmony_ci *
1987262306a36Sopenharmony_ci * Returns:
1987362306a36Sopenharmony_ci *    0 success
1987462306a36Sopenharmony_ci *    -Evalue otherwise
1987562306a36Sopenharmony_ci **/
1987662306a36Sopenharmony_ciint
1987762306a36Sopenharmony_cilpfc_sli4_init_vpi(struct lpfc_vport *vport)
1987862306a36Sopenharmony_ci{
1987962306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
1988062306a36Sopenharmony_ci	int rc = 0;
1988162306a36Sopenharmony_ci	int retval = MBX_SUCCESS;
1988262306a36Sopenharmony_ci	uint32_t mbox_tmo;
1988362306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
1988462306a36Sopenharmony_ci	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1988562306a36Sopenharmony_ci	if (!mboxq)
1988662306a36Sopenharmony_ci		return -ENOMEM;
1988762306a36Sopenharmony_ci	lpfc_init_vpi(phba, mboxq, vport->vpi);
1988862306a36Sopenharmony_ci	mbox_tmo = lpfc_mbox_tmo_val(phba, mboxq);
1988962306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
1989062306a36Sopenharmony_ci	if (rc != MBX_SUCCESS) {
1989162306a36Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
1989262306a36Sopenharmony_ci				"2022 INIT VPI Mailbox failed "
1989362306a36Sopenharmony_ci				"status %d, mbxStatus x%x\n", rc,
1989462306a36Sopenharmony_ci				bf_get(lpfc_mqe_status, &mboxq->u.mqe));
1989562306a36Sopenharmony_ci		retval = -EIO;
1989662306a36Sopenharmony_ci	}
1989762306a36Sopenharmony_ci	if (rc != MBX_TIMEOUT)
1989862306a36Sopenharmony_ci		mempool_free(mboxq, vport->phba->mbox_mem_pool);
1989962306a36Sopenharmony_ci
1990062306a36Sopenharmony_ci	return retval;
1990162306a36Sopenharmony_ci}
1990262306a36Sopenharmony_ci
1990362306a36Sopenharmony_ci/**
1990462306a36Sopenharmony_ci * lpfc_mbx_cmpl_add_fcf_record - add fcf mbox completion handler.
1990562306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1990662306a36Sopenharmony_ci * @mboxq: Pointer to mailbox object.
1990762306a36Sopenharmony_ci *
1990862306a36Sopenharmony_ci * This routine is invoked to manually add a single FCF record. The caller
1990962306a36Sopenharmony_ci * must pass a completely initialized FCF_Record.  This routine takes
1991062306a36Sopenharmony_ci * care of the nonembedded mailbox operations.
1991162306a36Sopenharmony_ci **/
1991262306a36Sopenharmony_cistatic void
1991362306a36Sopenharmony_cilpfc_mbx_cmpl_add_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
1991462306a36Sopenharmony_ci{
1991562306a36Sopenharmony_ci	void *virt_addr;
1991662306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
1991762306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
1991862306a36Sopenharmony_ci
1991962306a36Sopenharmony_ci	virt_addr = mboxq->sge_array->addr[0];
1992062306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
1992162306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *) virt_addr;
1992262306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1992362306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
1992462306a36Sopenharmony_ci
1992562306a36Sopenharmony_ci	if ((shdr_status || shdr_add_status) &&
1992662306a36Sopenharmony_ci		(shdr_status != STATUS_FCF_IN_USE))
1992762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1992862306a36Sopenharmony_ci			"2558 ADD_FCF_RECORD mailbox failed with "
1992962306a36Sopenharmony_ci			"status x%x add_status x%x\n",
1993062306a36Sopenharmony_ci			shdr_status, shdr_add_status);
1993162306a36Sopenharmony_ci
1993262306a36Sopenharmony_ci	lpfc_sli4_mbox_cmd_free(phba, mboxq);
1993362306a36Sopenharmony_ci}
1993462306a36Sopenharmony_ci
1993562306a36Sopenharmony_ci/**
1993662306a36Sopenharmony_ci * lpfc_sli4_add_fcf_record - Manually add an FCF Record.
1993762306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
1993862306a36Sopenharmony_ci * @fcf_record:  pointer to the initialized fcf record to add.
1993962306a36Sopenharmony_ci *
1994062306a36Sopenharmony_ci * This routine is invoked to manually add a single FCF record. The caller
1994162306a36Sopenharmony_ci * must pass a completely initialized FCF_Record.  This routine takes
1994262306a36Sopenharmony_ci * care of the nonembedded mailbox operations.
1994362306a36Sopenharmony_ci **/
1994462306a36Sopenharmony_ciint
1994562306a36Sopenharmony_cilpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record)
1994662306a36Sopenharmony_ci{
1994762306a36Sopenharmony_ci	int rc = 0;
1994862306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
1994962306a36Sopenharmony_ci	uint8_t *bytep;
1995062306a36Sopenharmony_ci	void *virt_addr;
1995162306a36Sopenharmony_ci	struct lpfc_mbx_sge sge;
1995262306a36Sopenharmony_ci	uint32_t alloc_len, req_len;
1995362306a36Sopenharmony_ci	uint32_t fcfindex;
1995462306a36Sopenharmony_ci
1995562306a36Sopenharmony_ci	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1995662306a36Sopenharmony_ci	if (!mboxq) {
1995762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1995862306a36Sopenharmony_ci			"2009 Failed to allocate mbox for ADD_FCF cmd\n");
1995962306a36Sopenharmony_ci		return -ENOMEM;
1996062306a36Sopenharmony_ci	}
1996162306a36Sopenharmony_ci
1996262306a36Sopenharmony_ci	req_len = sizeof(struct fcf_record) + sizeof(union lpfc_sli4_cfg_shdr) +
1996362306a36Sopenharmony_ci		  sizeof(uint32_t);
1996462306a36Sopenharmony_ci
1996562306a36Sopenharmony_ci	/* Allocate DMA memory and set up the non-embedded mailbox command */
1996662306a36Sopenharmony_ci	alloc_len = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
1996762306a36Sopenharmony_ci				     LPFC_MBOX_OPCODE_FCOE_ADD_FCF,
1996862306a36Sopenharmony_ci				     req_len, LPFC_SLI4_MBX_NEMBED);
1996962306a36Sopenharmony_ci	if (alloc_len < req_len) {
1997062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
1997162306a36Sopenharmony_ci			"2523 Allocated DMA memory size (x%x) is "
1997262306a36Sopenharmony_ci			"less than the requested DMA memory "
1997362306a36Sopenharmony_ci			"size (x%x)\n", alloc_len, req_len);
1997462306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mboxq);
1997562306a36Sopenharmony_ci		return -ENOMEM;
1997662306a36Sopenharmony_ci	}
1997762306a36Sopenharmony_ci
1997862306a36Sopenharmony_ci	/*
1997962306a36Sopenharmony_ci	 * Get the first SGE entry from the non-embedded DMA memory.  This
1998062306a36Sopenharmony_ci	 * routine only uses a single SGE.
1998162306a36Sopenharmony_ci	 */
1998262306a36Sopenharmony_ci	lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
1998362306a36Sopenharmony_ci	virt_addr = mboxq->sge_array->addr[0];
1998462306a36Sopenharmony_ci	/*
1998562306a36Sopenharmony_ci	 * Configure the FCF record for FCFI 0.  This is the driver's
1998662306a36Sopenharmony_ci	 * hardcoded default and gets used in nonFIP mode.
1998762306a36Sopenharmony_ci	 */
1998862306a36Sopenharmony_ci	fcfindex = bf_get(lpfc_fcf_record_fcf_index, fcf_record);
1998962306a36Sopenharmony_ci	bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr);
1999062306a36Sopenharmony_ci	lpfc_sli_pcimem_bcopy(&fcfindex, bytep, sizeof(uint32_t));
1999162306a36Sopenharmony_ci
1999262306a36Sopenharmony_ci	/*
1999362306a36Sopenharmony_ci	 * Copy the fcf_index and the FCF Record Data. The data starts after
1999462306a36Sopenharmony_ci	 * the FCoE header plus word10. The data copy needs to be endian
1999562306a36Sopenharmony_ci	 * correct.
1999662306a36Sopenharmony_ci	 */
1999762306a36Sopenharmony_ci	bytep += sizeof(uint32_t);
1999862306a36Sopenharmony_ci	lpfc_sli_pcimem_bcopy(fcf_record, bytep, sizeof(struct fcf_record));
1999962306a36Sopenharmony_ci	mboxq->vport = phba->pport;
2000062306a36Sopenharmony_ci	mboxq->mbox_cmpl = lpfc_mbx_cmpl_add_fcf_record;
2000162306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
2000262306a36Sopenharmony_ci	if (rc == MBX_NOT_FINISHED) {
2000362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
2000462306a36Sopenharmony_ci			"2515 ADD_FCF_RECORD mailbox failed with "
2000562306a36Sopenharmony_ci			"status 0x%x\n", rc);
2000662306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mboxq);
2000762306a36Sopenharmony_ci		rc = -EIO;
2000862306a36Sopenharmony_ci	} else
2000962306a36Sopenharmony_ci		rc = 0;
2001062306a36Sopenharmony_ci
2001162306a36Sopenharmony_ci	return rc;
2001262306a36Sopenharmony_ci}
2001362306a36Sopenharmony_ci
2001462306a36Sopenharmony_ci/**
2001562306a36Sopenharmony_ci * lpfc_sli4_build_dflt_fcf_record - Build the driver's default FCF Record.
2001662306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2001762306a36Sopenharmony_ci * @fcf_record:  pointer to the fcf record to write the default data.
2001862306a36Sopenharmony_ci * @fcf_index: FCF table entry index.
2001962306a36Sopenharmony_ci *
2002062306a36Sopenharmony_ci * This routine is invoked to build the driver's default FCF record.  The
2002162306a36Sopenharmony_ci * values used are hardcoded.  This routine handles memory initialization.
2002262306a36Sopenharmony_ci *
2002362306a36Sopenharmony_ci **/
2002462306a36Sopenharmony_civoid
2002562306a36Sopenharmony_cilpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *phba,
2002662306a36Sopenharmony_ci				struct fcf_record *fcf_record,
2002762306a36Sopenharmony_ci				uint16_t fcf_index)
2002862306a36Sopenharmony_ci{
2002962306a36Sopenharmony_ci	memset(fcf_record, 0, sizeof(struct fcf_record));
2003062306a36Sopenharmony_ci	fcf_record->max_rcv_size = LPFC_FCOE_MAX_RCV_SIZE;
2003162306a36Sopenharmony_ci	fcf_record->fka_adv_period = LPFC_FCOE_FKA_ADV_PER;
2003262306a36Sopenharmony_ci	fcf_record->fip_priority = LPFC_FCOE_FIP_PRIORITY;
2003362306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_mac_0, fcf_record, phba->fc_map[0]);
2003462306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_mac_1, fcf_record, phba->fc_map[1]);
2003562306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_mac_2, fcf_record, phba->fc_map[2]);
2003662306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_mac_3, fcf_record, LPFC_FCOE_FCF_MAC3);
2003762306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_mac_4, fcf_record, LPFC_FCOE_FCF_MAC4);
2003862306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_mac_5, fcf_record, LPFC_FCOE_FCF_MAC5);
2003962306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_fc_map_0, fcf_record, phba->fc_map[0]);
2004062306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_fc_map_1, fcf_record, phba->fc_map[1]);
2004162306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_fc_map_2, fcf_record, phba->fc_map[2]);
2004262306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_fcf_valid, fcf_record, 1);
2004362306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_fcf_avail, fcf_record, 1);
2004462306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_fcf_index, fcf_record, fcf_index);
2004562306a36Sopenharmony_ci	bf_set(lpfc_fcf_record_mac_addr_prov, fcf_record,
2004662306a36Sopenharmony_ci		LPFC_FCF_FPMA | LPFC_FCF_SPMA);
2004762306a36Sopenharmony_ci	/* Set the VLAN bit map */
2004862306a36Sopenharmony_ci	if (phba->valid_vlan) {
2004962306a36Sopenharmony_ci		fcf_record->vlan_bitmap[phba->vlan_id / 8]
2005062306a36Sopenharmony_ci			= 1 << (phba->vlan_id % 8);
2005162306a36Sopenharmony_ci	}
2005262306a36Sopenharmony_ci}
2005362306a36Sopenharmony_ci
2005462306a36Sopenharmony_ci/**
2005562306a36Sopenharmony_ci * lpfc_sli4_fcf_scan_read_fcf_rec - Read hba fcf record for fcf scan.
2005662306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2005762306a36Sopenharmony_ci * @fcf_index: FCF table entry offset.
2005862306a36Sopenharmony_ci *
2005962306a36Sopenharmony_ci * This routine is invoked to scan the entire FCF table by reading FCF
2006062306a36Sopenharmony_ci * record and processing it one at a time starting from the @fcf_index
2006162306a36Sopenharmony_ci * for initial FCF discovery or fast FCF failover rediscovery.
2006262306a36Sopenharmony_ci *
2006362306a36Sopenharmony_ci * Return 0 if the mailbox command is submitted successfully, none 0
2006462306a36Sopenharmony_ci * otherwise.
2006562306a36Sopenharmony_ci **/
2006662306a36Sopenharmony_ciint
2006762306a36Sopenharmony_cilpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
2006862306a36Sopenharmony_ci{
2006962306a36Sopenharmony_ci	int rc = 0, error;
2007062306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
2007162306a36Sopenharmony_ci
2007262306a36Sopenharmony_ci	phba->fcoe_eventtag_at_fcf_scan = phba->fcoe_eventtag;
2007362306a36Sopenharmony_ci	phba->fcoe_cvl_eventtag_attn = phba->fcoe_cvl_eventtag;
2007462306a36Sopenharmony_ci	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
2007562306a36Sopenharmony_ci	if (!mboxq) {
2007662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
2007762306a36Sopenharmony_ci				"2000 Failed to allocate mbox for "
2007862306a36Sopenharmony_ci				"READ_FCF cmd\n");
2007962306a36Sopenharmony_ci		error = -ENOMEM;
2008062306a36Sopenharmony_ci		goto fail_fcf_scan;
2008162306a36Sopenharmony_ci	}
2008262306a36Sopenharmony_ci	/* Construct the read FCF record mailbox command */
2008362306a36Sopenharmony_ci	rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index);
2008462306a36Sopenharmony_ci	if (rc) {
2008562306a36Sopenharmony_ci		error = -EINVAL;
2008662306a36Sopenharmony_ci		goto fail_fcf_scan;
2008762306a36Sopenharmony_ci	}
2008862306a36Sopenharmony_ci	/* Issue the mailbox command asynchronously */
2008962306a36Sopenharmony_ci	mboxq->vport = phba->pport;
2009062306a36Sopenharmony_ci	mboxq->mbox_cmpl = lpfc_mbx_cmpl_fcf_scan_read_fcf_rec;
2009162306a36Sopenharmony_ci
2009262306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
2009362306a36Sopenharmony_ci	phba->hba_flag |= FCF_TS_INPROG;
2009462306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
2009562306a36Sopenharmony_ci
2009662306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
2009762306a36Sopenharmony_ci	if (rc == MBX_NOT_FINISHED)
2009862306a36Sopenharmony_ci		error = -EIO;
2009962306a36Sopenharmony_ci	else {
2010062306a36Sopenharmony_ci		/* Reset eligible FCF count for new scan */
2010162306a36Sopenharmony_ci		if (fcf_index == LPFC_FCOE_FCF_GET_FIRST)
2010262306a36Sopenharmony_ci			phba->fcf.eligible_fcf_cnt = 0;
2010362306a36Sopenharmony_ci		error = 0;
2010462306a36Sopenharmony_ci	}
2010562306a36Sopenharmony_cifail_fcf_scan:
2010662306a36Sopenharmony_ci	if (error) {
2010762306a36Sopenharmony_ci		if (mboxq)
2010862306a36Sopenharmony_ci			lpfc_sli4_mbox_cmd_free(phba, mboxq);
2010962306a36Sopenharmony_ci		/* FCF scan failed, clear FCF_TS_INPROG flag */
2011062306a36Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
2011162306a36Sopenharmony_ci		phba->hba_flag &= ~FCF_TS_INPROG;
2011262306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
2011362306a36Sopenharmony_ci	}
2011462306a36Sopenharmony_ci	return error;
2011562306a36Sopenharmony_ci}
2011662306a36Sopenharmony_ci
2011762306a36Sopenharmony_ci/**
2011862306a36Sopenharmony_ci * lpfc_sli4_fcf_rr_read_fcf_rec - Read hba fcf record for roundrobin fcf.
2011962306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2012062306a36Sopenharmony_ci * @fcf_index: FCF table entry offset.
2012162306a36Sopenharmony_ci *
2012262306a36Sopenharmony_ci * This routine is invoked to read an FCF record indicated by @fcf_index
2012362306a36Sopenharmony_ci * and to use it for FLOGI roundrobin FCF failover.
2012462306a36Sopenharmony_ci *
2012562306a36Sopenharmony_ci * Return 0 if the mailbox command is submitted successfully, none 0
2012662306a36Sopenharmony_ci * otherwise.
2012762306a36Sopenharmony_ci **/
2012862306a36Sopenharmony_ciint
2012962306a36Sopenharmony_cilpfc_sli4_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
2013062306a36Sopenharmony_ci{
2013162306a36Sopenharmony_ci	int rc = 0, error;
2013262306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
2013362306a36Sopenharmony_ci
2013462306a36Sopenharmony_ci	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
2013562306a36Sopenharmony_ci	if (!mboxq) {
2013662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_INIT,
2013762306a36Sopenharmony_ci				"2763 Failed to allocate mbox for "
2013862306a36Sopenharmony_ci				"READ_FCF cmd\n");
2013962306a36Sopenharmony_ci		error = -ENOMEM;
2014062306a36Sopenharmony_ci		goto fail_fcf_read;
2014162306a36Sopenharmony_ci	}
2014262306a36Sopenharmony_ci	/* Construct the read FCF record mailbox command */
2014362306a36Sopenharmony_ci	rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index);
2014462306a36Sopenharmony_ci	if (rc) {
2014562306a36Sopenharmony_ci		error = -EINVAL;
2014662306a36Sopenharmony_ci		goto fail_fcf_read;
2014762306a36Sopenharmony_ci	}
2014862306a36Sopenharmony_ci	/* Issue the mailbox command asynchronously */
2014962306a36Sopenharmony_ci	mboxq->vport = phba->pport;
2015062306a36Sopenharmony_ci	mboxq->mbox_cmpl = lpfc_mbx_cmpl_fcf_rr_read_fcf_rec;
2015162306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
2015262306a36Sopenharmony_ci	if (rc == MBX_NOT_FINISHED)
2015362306a36Sopenharmony_ci		error = -EIO;
2015462306a36Sopenharmony_ci	else
2015562306a36Sopenharmony_ci		error = 0;
2015662306a36Sopenharmony_ci
2015762306a36Sopenharmony_cifail_fcf_read:
2015862306a36Sopenharmony_ci	if (error && mboxq)
2015962306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mboxq);
2016062306a36Sopenharmony_ci	return error;
2016162306a36Sopenharmony_ci}
2016262306a36Sopenharmony_ci
2016362306a36Sopenharmony_ci/**
2016462306a36Sopenharmony_ci * lpfc_sli4_read_fcf_rec - Read hba fcf record for update eligible fcf bmask.
2016562306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2016662306a36Sopenharmony_ci * @fcf_index: FCF table entry offset.
2016762306a36Sopenharmony_ci *
2016862306a36Sopenharmony_ci * This routine is invoked to read an FCF record indicated by @fcf_index to
2016962306a36Sopenharmony_ci * determine whether it's eligible for FLOGI roundrobin failover list.
2017062306a36Sopenharmony_ci *
2017162306a36Sopenharmony_ci * Return 0 if the mailbox command is submitted successfully, none 0
2017262306a36Sopenharmony_ci * otherwise.
2017362306a36Sopenharmony_ci **/
2017462306a36Sopenharmony_ciint
2017562306a36Sopenharmony_cilpfc_sli4_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
2017662306a36Sopenharmony_ci{
2017762306a36Sopenharmony_ci	int rc = 0, error;
2017862306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
2017962306a36Sopenharmony_ci
2018062306a36Sopenharmony_ci	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
2018162306a36Sopenharmony_ci	if (!mboxq) {
2018262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_INIT,
2018362306a36Sopenharmony_ci				"2758 Failed to allocate mbox for "
2018462306a36Sopenharmony_ci				"READ_FCF cmd\n");
2018562306a36Sopenharmony_ci				error = -ENOMEM;
2018662306a36Sopenharmony_ci				goto fail_fcf_read;
2018762306a36Sopenharmony_ci	}
2018862306a36Sopenharmony_ci	/* Construct the read FCF record mailbox command */
2018962306a36Sopenharmony_ci	rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index);
2019062306a36Sopenharmony_ci	if (rc) {
2019162306a36Sopenharmony_ci		error = -EINVAL;
2019262306a36Sopenharmony_ci		goto fail_fcf_read;
2019362306a36Sopenharmony_ci	}
2019462306a36Sopenharmony_ci	/* Issue the mailbox command asynchronously */
2019562306a36Sopenharmony_ci	mboxq->vport = phba->pport;
2019662306a36Sopenharmony_ci	mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_rec;
2019762306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
2019862306a36Sopenharmony_ci	if (rc == MBX_NOT_FINISHED)
2019962306a36Sopenharmony_ci		error = -EIO;
2020062306a36Sopenharmony_ci	else
2020162306a36Sopenharmony_ci		error = 0;
2020262306a36Sopenharmony_ci
2020362306a36Sopenharmony_cifail_fcf_read:
2020462306a36Sopenharmony_ci	if (error && mboxq)
2020562306a36Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mboxq);
2020662306a36Sopenharmony_ci	return error;
2020762306a36Sopenharmony_ci}
2020862306a36Sopenharmony_ci
2020962306a36Sopenharmony_ci/**
2021062306a36Sopenharmony_ci * lpfc_check_next_fcf_pri_level
2021162306a36Sopenharmony_ci * @phba: pointer to the lpfc_hba struct for this port.
2021262306a36Sopenharmony_ci * This routine is called from the lpfc_sli4_fcf_rr_next_index_get
2021362306a36Sopenharmony_ci * routine when the rr_bmask is empty. The FCF indecies are put into the
2021462306a36Sopenharmony_ci * rr_bmask based on their priority level. Starting from the highest priority
2021562306a36Sopenharmony_ci * to the lowest. The most likely FCF candidate will be in the highest
2021662306a36Sopenharmony_ci * priority group. When this routine is called it searches the fcf_pri list for
2021762306a36Sopenharmony_ci * next lowest priority group and repopulates the rr_bmask with only those
2021862306a36Sopenharmony_ci * fcf_indexes.
2021962306a36Sopenharmony_ci * returns:
2022062306a36Sopenharmony_ci * 1=success 0=failure
2022162306a36Sopenharmony_ci **/
2022262306a36Sopenharmony_cistatic int
2022362306a36Sopenharmony_cilpfc_check_next_fcf_pri_level(struct lpfc_hba *phba)
2022462306a36Sopenharmony_ci{
2022562306a36Sopenharmony_ci	uint16_t next_fcf_pri;
2022662306a36Sopenharmony_ci	uint16_t last_index;
2022762306a36Sopenharmony_ci	struct lpfc_fcf_pri *fcf_pri;
2022862306a36Sopenharmony_ci	int rc;
2022962306a36Sopenharmony_ci	int ret = 0;
2023062306a36Sopenharmony_ci
2023162306a36Sopenharmony_ci	last_index = find_first_bit(phba->fcf.fcf_rr_bmask,
2023262306a36Sopenharmony_ci			LPFC_SLI4_FCF_TBL_INDX_MAX);
2023362306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
2023462306a36Sopenharmony_ci			"3060 Last IDX %d\n", last_index);
2023562306a36Sopenharmony_ci
2023662306a36Sopenharmony_ci	/* Verify the priority list has 2 or more entries */
2023762306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
2023862306a36Sopenharmony_ci	if (list_empty(&phba->fcf.fcf_pri_list) ||
2023962306a36Sopenharmony_ci	    list_is_singular(&phba->fcf.fcf_pri_list)) {
2024062306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
2024162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
2024262306a36Sopenharmony_ci			"3061 Last IDX %d\n", last_index);
2024362306a36Sopenharmony_ci		return 0; /* Empty rr list */
2024462306a36Sopenharmony_ci	}
2024562306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
2024662306a36Sopenharmony_ci
2024762306a36Sopenharmony_ci	next_fcf_pri = 0;
2024862306a36Sopenharmony_ci	/*
2024962306a36Sopenharmony_ci	 * Clear the rr_bmask and set all of the bits that are at this
2025062306a36Sopenharmony_ci	 * priority.
2025162306a36Sopenharmony_ci	 */
2025262306a36Sopenharmony_ci	memset(phba->fcf.fcf_rr_bmask, 0,
2025362306a36Sopenharmony_ci			sizeof(*phba->fcf.fcf_rr_bmask));
2025462306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
2025562306a36Sopenharmony_ci	list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
2025662306a36Sopenharmony_ci		if (fcf_pri->fcf_rec.flag & LPFC_FCF_FLOGI_FAILED)
2025762306a36Sopenharmony_ci			continue;
2025862306a36Sopenharmony_ci		/*
2025962306a36Sopenharmony_ci		 * the 1st priority that has not FLOGI failed
2026062306a36Sopenharmony_ci		 * will be the highest.
2026162306a36Sopenharmony_ci		 */
2026262306a36Sopenharmony_ci		if (!next_fcf_pri)
2026362306a36Sopenharmony_ci			next_fcf_pri = fcf_pri->fcf_rec.priority;
2026462306a36Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
2026562306a36Sopenharmony_ci		if (fcf_pri->fcf_rec.priority == next_fcf_pri) {
2026662306a36Sopenharmony_ci			rc = lpfc_sli4_fcf_rr_index_set(phba,
2026762306a36Sopenharmony_ci						fcf_pri->fcf_rec.fcf_index);
2026862306a36Sopenharmony_ci			if (rc)
2026962306a36Sopenharmony_ci				return 0;
2027062306a36Sopenharmony_ci		}
2027162306a36Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
2027262306a36Sopenharmony_ci	}
2027362306a36Sopenharmony_ci	/*
2027462306a36Sopenharmony_ci	 * if next_fcf_pri was not set above and the list is not empty then
2027562306a36Sopenharmony_ci	 * we have failed flogis on all of them. So reset flogi failed
2027662306a36Sopenharmony_ci	 * and start at the beginning.
2027762306a36Sopenharmony_ci	 */
2027862306a36Sopenharmony_ci	if (!next_fcf_pri && !list_empty(&phba->fcf.fcf_pri_list)) {
2027962306a36Sopenharmony_ci		list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
2028062306a36Sopenharmony_ci			fcf_pri->fcf_rec.flag &= ~LPFC_FCF_FLOGI_FAILED;
2028162306a36Sopenharmony_ci			/*
2028262306a36Sopenharmony_ci			 * the 1st priority that has not FLOGI failed
2028362306a36Sopenharmony_ci			 * will be the highest.
2028462306a36Sopenharmony_ci			 */
2028562306a36Sopenharmony_ci			if (!next_fcf_pri)
2028662306a36Sopenharmony_ci				next_fcf_pri = fcf_pri->fcf_rec.priority;
2028762306a36Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
2028862306a36Sopenharmony_ci			if (fcf_pri->fcf_rec.priority == next_fcf_pri) {
2028962306a36Sopenharmony_ci				rc = lpfc_sli4_fcf_rr_index_set(phba,
2029062306a36Sopenharmony_ci						fcf_pri->fcf_rec.fcf_index);
2029162306a36Sopenharmony_ci				if (rc)
2029262306a36Sopenharmony_ci					return 0;
2029362306a36Sopenharmony_ci			}
2029462306a36Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
2029562306a36Sopenharmony_ci		}
2029662306a36Sopenharmony_ci	} else
2029762306a36Sopenharmony_ci		ret = 1;
2029862306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
2029962306a36Sopenharmony_ci
2030062306a36Sopenharmony_ci	return ret;
2030162306a36Sopenharmony_ci}
2030262306a36Sopenharmony_ci/**
2030362306a36Sopenharmony_ci * lpfc_sli4_fcf_rr_next_index_get - Get next eligible fcf record index
2030462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2030562306a36Sopenharmony_ci *
2030662306a36Sopenharmony_ci * This routine is to get the next eligible FCF record index in a round
2030762306a36Sopenharmony_ci * robin fashion. If the next eligible FCF record index equals to the
2030862306a36Sopenharmony_ci * initial roundrobin FCF record index, LPFC_FCOE_FCF_NEXT_NONE (0xFFFF)
2030962306a36Sopenharmony_ci * shall be returned, otherwise, the next eligible FCF record's index
2031062306a36Sopenharmony_ci * shall be returned.
2031162306a36Sopenharmony_ci **/
2031262306a36Sopenharmony_ciuint16_t
2031362306a36Sopenharmony_cilpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
2031462306a36Sopenharmony_ci{
2031562306a36Sopenharmony_ci	uint16_t next_fcf_index;
2031662306a36Sopenharmony_ci
2031762306a36Sopenharmony_ciinitial_priority:
2031862306a36Sopenharmony_ci	/* Search start from next bit of currently registered FCF index */
2031962306a36Sopenharmony_ci	next_fcf_index = phba->fcf.current_rec.fcf_indx;
2032062306a36Sopenharmony_ci
2032162306a36Sopenharmony_cinext_priority:
2032262306a36Sopenharmony_ci	/* Determine the next fcf index to check */
2032362306a36Sopenharmony_ci	next_fcf_index = (next_fcf_index + 1) % LPFC_SLI4_FCF_TBL_INDX_MAX;
2032462306a36Sopenharmony_ci	next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
2032562306a36Sopenharmony_ci				       LPFC_SLI4_FCF_TBL_INDX_MAX,
2032662306a36Sopenharmony_ci				       next_fcf_index);
2032762306a36Sopenharmony_ci
2032862306a36Sopenharmony_ci	/* Wrap around condition on phba->fcf.fcf_rr_bmask */
2032962306a36Sopenharmony_ci	if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
2033062306a36Sopenharmony_ci		/*
2033162306a36Sopenharmony_ci		 * If we have wrapped then we need to clear the bits that
2033262306a36Sopenharmony_ci		 * have been tested so that we can detect when we should
2033362306a36Sopenharmony_ci		 * change the priority level.
2033462306a36Sopenharmony_ci		 */
2033562306a36Sopenharmony_ci		next_fcf_index = find_first_bit(phba->fcf.fcf_rr_bmask,
2033662306a36Sopenharmony_ci					       LPFC_SLI4_FCF_TBL_INDX_MAX);
2033762306a36Sopenharmony_ci	}
2033862306a36Sopenharmony_ci
2033962306a36Sopenharmony_ci
2034062306a36Sopenharmony_ci	/* Check roundrobin failover list empty condition */
2034162306a36Sopenharmony_ci	if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX ||
2034262306a36Sopenharmony_ci		next_fcf_index == phba->fcf.current_rec.fcf_indx) {
2034362306a36Sopenharmony_ci		/*
2034462306a36Sopenharmony_ci		 * If next fcf index is not found check if there are lower
2034562306a36Sopenharmony_ci		 * Priority level fcf's in the fcf_priority list.
2034662306a36Sopenharmony_ci		 * Set up the rr_bmask with all of the avaiable fcf bits
2034762306a36Sopenharmony_ci		 * at that level and continue the selection process.
2034862306a36Sopenharmony_ci		 */
2034962306a36Sopenharmony_ci		if (lpfc_check_next_fcf_pri_level(phba))
2035062306a36Sopenharmony_ci			goto initial_priority;
2035162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
2035262306a36Sopenharmony_ci				"2844 No roundrobin failover FCF available\n");
2035362306a36Sopenharmony_ci
2035462306a36Sopenharmony_ci		return LPFC_FCOE_FCF_NEXT_NONE;
2035562306a36Sopenharmony_ci	}
2035662306a36Sopenharmony_ci
2035762306a36Sopenharmony_ci	if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX &&
2035862306a36Sopenharmony_ci		phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag &
2035962306a36Sopenharmony_ci		LPFC_FCF_FLOGI_FAILED) {
2036062306a36Sopenharmony_ci		if (list_is_singular(&phba->fcf.fcf_pri_list))
2036162306a36Sopenharmony_ci			return LPFC_FCOE_FCF_NEXT_NONE;
2036262306a36Sopenharmony_ci
2036362306a36Sopenharmony_ci		goto next_priority;
2036462306a36Sopenharmony_ci	}
2036562306a36Sopenharmony_ci
2036662306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
2036762306a36Sopenharmony_ci			"2845 Get next roundrobin failover FCF (x%x)\n",
2036862306a36Sopenharmony_ci			next_fcf_index);
2036962306a36Sopenharmony_ci
2037062306a36Sopenharmony_ci	return next_fcf_index;
2037162306a36Sopenharmony_ci}
2037262306a36Sopenharmony_ci
2037362306a36Sopenharmony_ci/**
2037462306a36Sopenharmony_ci * lpfc_sli4_fcf_rr_index_set - Set bmask with eligible fcf record index
2037562306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2037662306a36Sopenharmony_ci * @fcf_index: index into the FCF table to 'set'
2037762306a36Sopenharmony_ci *
2037862306a36Sopenharmony_ci * This routine sets the FCF record index in to the eligible bmask for
2037962306a36Sopenharmony_ci * roundrobin failover search. It checks to make sure that the index
2038062306a36Sopenharmony_ci * does not go beyond the range of the driver allocated bmask dimension
2038162306a36Sopenharmony_ci * before setting the bit.
2038262306a36Sopenharmony_ci *
2038362306a36Sopenharmony_ci * Returns 0 if the index bit successfully set, otherwise, it returns
2038462306a36Sopenharmony_ci * -EINVAL.
2038562306a36Sopenharmony_ci **/
2038662306a36Sopenharmony_ciint
2038762306a36Sopenharmony_cilpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
2038862306a36Sopenharmony_ci{
2038962306a36Sopenharmony_ci	if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
2039062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
2039162306a36Sopenharmony_ci				"2610 FCF (x%x) reached driver's book "
2039262306a36Sopenharmony_ci				"keeping dimension:x%x\n",
2039362306a36Sopenharmony_ci				fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX);
2039462306a36Sopenharmony_ci		return -EINVAL;
2039562306a36Sopenharmony_ci	}
2039662306a36Sopenharmony_ci	/* Set the eligible FCF record index bmask */
2039762306a36Sopenharmony_ci	set_bit(fcf_index, phba->fcf.fcf_rr_bmask);
2039862306a36Sopenharmony_ci
2039962306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
2040062306a36Sopenharmony_ci			"2790 Set FCF (x%x) to roundrobin FCF failover "
2040162306a36Sopenharmony_ci			"bmask\n", fcf_index);
2040262306a36Sopenharmony_ci
2040362306a36Sopenharmony_ci	return 0;
2040462306a36Sopenharmony_ci}
2040562306a36Sopenharmony_ci
2040662306a36Sopenharmony_ci/**
2040762306a36Sopenharmony_ci * lpfc_sli4_fcf_rr_index_clear - Clear bmask from eligible fcf record index
2040862306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2040962306a36Sopenharmony_ci * @fcf_index: index into the FCF table to 'clear'
2041062306a36Sopenharmony_ci *
2041162306a36Sopenharmony_ci * This routine clears the FCF record index from the eligible bmask for
2041262306a36Sopenharmony_ci * roundrobin failover search. It checks to make sure that the index
2041362306a36Sopenharmony_ci * does not go beyond the range of the driver allocated bmask dimension
2041462306a36Sopenharmony_ci * before clearing the bit.
2041562306a36Sopenharmony_ci **/
2041662306a36Sopenharmony_civoid
2041762306a36Sopenharmony_cilpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
2041862306a36Sopenharmony_ci{
2041962306a36Sopenharmony_ci	struct lpfc_fcf_pri *fcf_pri, *fcf_pri_next;
2042062306a36Sopenharmony_ci	if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
2042162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
2042262306a36Sopenharmony_ci				"2762 FCF (x%x) reached driver's book "
2042362306a36Sopenharmony_ci				"keeping dimension:x%x\n",
2042462306a36Sopenharmony_ci				fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX);
2042562306a36Sopenharmony_ci		return;
2042662306a36Sopenharmony_ci	}
2042762306a36Sopenharmony_ci	/* Clear the eligible FCF record index bmask */
2042862306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
2042962306a36Sopenharmony_ci	list_for_each_entry_safe(fcf_pri, fcf_pri_next, &phba->fcf.fcf_pri_list,
2043062306a36Sopenharmony_ci				 list) {
2043162306a36Sopenharmony_ci		if (fcf_pri->fcf_rec.fcf_index == fcf_index) {
2043262306a36Sopenharmony_ci			list_del_init(&fcf_pri->list);
2043362306a36Sopenharmony_ci			break;
2043462306a36Sopenharmony_ci		}
2043562306a36Sopenharmony_ci	}
2043662306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
2043762306a36Sopenharmony_ci	clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);
2043862306a36Sopenharmony_ci
2043962306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
2044062306a36Sopenharmony_ci			"2791 Clear FCF (x%x) from roundrobin failover "
2044162306a36Sopenharmony_ci			"bmask\n", fcf_index);
2044262306a36Sopenharmony_ci}
2044362306a36Sopenharmony_ci
2044462306a36Sopenharmony_ci/**
2044562306a36Sopenharmony_ci * lpfc_mbx_cmpl_redisc_fcf_table - completion routine for rediscover FCF table
2044662306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2044762306a36Sopenharmony_ci * @mbox: An allocated pointer to type LPFC_MBOXQ_t
2044862306a36Sopenharmony_ci *
2044962306a36Sopenharmony_ci * This routine is the completion routine for the rediscover FCF table mailbox
2045062306a36Sopenharmony_ci * command. If the mailbox command returned failure, it will try to stop the
2045162306a36Sopenharmony_ci * FCF rediscover wait timer.
2045262306a36Sopenharmony_ci **/
2045362306a36Sopenharmony_cistatic void
2045462306a36Sopenharmony_cilpfc_mbx_cmpl_redisc_fcf_table(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
2045562306a36Sopenharmony_ci{
2045662306a36Sopenharmony_ci	struct lpfc_mbx_redisc_fcf_tbl *redisc_fcf;
2045762306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
2045862306a36Sopenharmony_ci
2045962306a36Sopenharmony_ci	redisc_fcf = &mbox->u.mqe.un.redisc_fcf_tbl;
2046062306a36Sopenharmony_ci
2046162306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status,
2046262306a36Sopenharmony_ci			     &redisc_fcf->header.cfg_shdr.response);
2046362306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
2046462306a36Sopenharmony_ci			     &redisc_fcf->header.cfg_shdr.response);
2046562306a36Sopenharmony_ci	if (shdr_status || shdr_add_status) {
2046662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
2046762306a36Sopenharmony_ci				"2746 Requesting for FCF rediscovery failed "
2046862306a36Sopenharmony_ci				"status x%x add_status x%x\n",
2046962306a36Sopenharmony_ci				shdr_status, shdr_add_status);
2047062306a36Sopenharmony_ci		if (phba->fcf.fcf_flag & FCF_ACVL_DISC) {
2047162306a36Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
2047262306a36Sopenharmony_ci			phba->fcf.fcf_flag &= ~FCF_ACVL_DISC;
2047362306a36Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
2047462306a36Sopenharmony_ci			/*
2047562306a36Sopenharmony_ci			 * CVL event triggered FCF rediscover request failed,
2047662306a36Sopenharmony_ci			 * last resort to re-try current registered FCF entry.
2047762306a36Sopenharmony_ci			 */
2047862306a36Sopenharmony_ci			lpfc_retry_pport_discovery(phba);
2047962306a36Sopenharmony_ci		} else {
2048062306a36Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
2048162306a36Sopenharmony_ci			phba->fcf.fcf_flag &= ~FCF_DEAD_DISC;
2048262306a36Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
2048362306a36Sopenharmony_ci			/*
2048462306a36Sopenharmony_ci			 * DEAD FCF event triggered FCF rediscover request
2048562306a36Sopenharmony_ci			 * failed, last resort to fail over as a link down
2048662306a36Sopenharmony_ci			 * to FCF registration.
2048762306a36Sopenharmony_ci			 */
2048862306a36Sopenharmony_ci			lpfc_sli4_fcf_dead_failthrough(phba);
2048962306a36Sopenharmony_ci		}
2049062306a36Sopenharmony_ci	} else {
2049162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
2049262306a36Sopenharmony_ci				"2775 Start FCF rediscover quiescent timer\n");
2049362306a36Sopenharmony_ci		/*
2049462306a36Sopenharmony_ci		 * Start FCF rediscovery wait timer for pending FCF
2049562306a36Sopenharmony_ci		 * before rescan FCF record table.
2049662306a36Sopenharmony_ci		 */
2049762306a36Sopenharmony_ci		lpfc_fcf_redisc_wait_start_timer(phba);
2049862306a36Sopenharmony_ci	}
2049962306a36Sopenharmony_ci
2050062306a36Sopenharmony_ci	mempool_free(mbox, phba->mbox_mem_pool);
2050162306a36Sopenharmony_ci}
2050262306a36Sopenharmony_ci
2050362306a36Sopenharmony_ci/**
2050462306a36Sopenharmony_ci * lpfc_sli4_redisc_fcf_table - Request to rediscover entire FCF table by port.
2050562306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2050662306a36Sopenharmony_ci *
2050762306a36Sopenharmony_ci * This routine is invoked to request for rediscovery of the entire FCF table
2050862306a36Sopenharmony_ci * by the port.
2050962306a36Sopenharmony_ci **/
2051062306a36Sopenharmony_ciint
2051162306a36Sopenharmony_cilpfc_sli4_redisc_fcf_table(struct lpfc_hba *phba)
2051262306a36Sopenharmony_ci{
2051362306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
2051462306a36Sopenharmony_ci	struct lpfc_mbx_redisc_fcf_tbl *redisc_fcf;
2051562306a36Sopenharmony_ci	int rc, length;
2051662306a36Sopenharmony_ci
2051762306a36Sopenharmony_ci	/* Cancel retry delay timers to all vports before FCF rediscover */
2051862306a36Sopenharmony_ci	lpfc_cancel_all_vport_retry_delay_timer(phba);
2051962306a36Sopenharmony_ci
2052062306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
2052162306a36Sopenharmony_ci	if (!mbox) {
2052262306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
2052362306a36Sopenharmony_ci				"2745 Failed to allocate mbox for "
2052462306a36Sopenharmony_ci				"requesting FCF rediscover.\n");
2052562306a36Sopenharmony_ci		return -ENOMEM;
2052662306a36Sopenharmony_ci	}
2052762306a36Sopenharmony_ci
2052862306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_redisc_fcf_tbl) -
2052962306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
2053062306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
2053162306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_FCOE_REDISCOVER_FCF,
2053262306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
2053362306a36Sopenharmony_ci
2053462306a36Sopenharmony_ci	redisc_fcf = &mbox->u.mqe.un.redisc_fcf_tbl;
2053562306a36Sopenharmony_ci	/* Set count to 0 for invalidating the entire FCF database */
2053662306a36Sopenharmony_ci	bf_set(lpfc_mbx_redisc_fcf_count, redisc_fcf, 0);
2053762306a36Sopenharmony_ci
2053862306a36Sopenharmony_ci	/* Issue the mailbox command asynchronously */
2053962306a36Sopenharmony_ci	mbox->vport = phba->pport;
2054062306a36Sopenharmony_ci	mbox->mbox_cmpl = lpfc_mbx_cmpl_redisc_fcf_table;
2054162306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
2054262306a36Sopenharmony_ci
2054362306a36Sopenharmony_ci	if (rc == MBX_NOT_FINISHED) {
2054462306a36Sopenharmony_ci		mempool_free(mbox, phba->mbox_mem_pool);
2054562306a36Sopenharmony_ci		return -EIO;
2054662306a36Sopenharmony_ci	}
2054762306a36Sopenharmony_ci	return 0;
2054862306a36Sopenharmony_ci}
2054962306a36Sopenharmony_ci
2055062306a36Sopenharmony_ci/**
2055162306a36Sopenharmony_ci * lpfc_sli4_fcf_dead_failthrough - Failthrough routine to fcf dead event
2055262306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2055362306a36Sopenharmony_ci *
2055462306a36Sopenharmony_ci * This function is the failover routine as a last resort to the FCF DEAD
2055562306a36Sopenharmony_ci * event when driver failed to perform fast FCF failover.
2055662306a36Sopenharmony_ci **/
2055762306a36Sopenharmony_civoid
2055862306a36Sopenharmony_cilpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *phba)
2055962306a36Sopenharmony_ci{
2056062306a36Sopenharmony_ci	uint32_t link_state;
2056162306a36Sopenharmony_ci
2056262306a36Sopenharmony_ci	/*
2056362306a36Sopenharmony_ci	 * Last resort as FCF DEAD event failover will treat this as
2056462306a36Sopenharmony_ci	 * a link down, but save the link state because we don't want
2056562306a36Sopenharmony_ci	 * it to be changed to Link Down unless it is already down.
2056662306a36Sopenharmony_ci	 */
2056762306a36Sopenharmony_ci	link_state = phba->link_state;
2056862306a36Sopenharmony_ci	lpfc_linkdown(phba);
2056962306a36Sopenharmony_ci	phba->link_state = link_state;
2057062306a36Sopenharmony_ci
2057162306a36Sopenharmony_ci	/* Unregister FCF if no devices connected to it */
2057262306a36Sopenharmony_ci	lpfc_unregister_unused_fcf(phba);
2057362306a36Sopenharmony_ci}
2057462306a36Sopenharmony_ci
2057562306a36Sopenharmony_ci/**
2057662306a36Sopenharmony_ci * lpfc_sli_get_config_region23 - Get sli3 port region 23 data.
2057762306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2057862306a36Sopenharmony_ci * @rgn23_data: pointer to configure region 23 data.
2057962306a36Sopenharmony_ci *
2058062306a36Sopenharmony_ci * This function gets SLI3 port configure region 23 data through memory dump
2058162306a36Sopenharmony_ci * mailbox command. When it successfully retrieves data, the size of the data
2058262306a36Sopenharmony_ci * will be returned, otherwise, 0 will be returned.
2058362306a36Sopenharmony_ci **/
2058462306a36Sopenharmony_cistatic uint32_t
2058562306a36Sopenharmony_cilpfc_sli_get_config_region23(struct lpfc_hba *phba, char *rgn23_data)
2058662306a36Sopenharmony_ci{
2058762306a36Sopenharmony_ci	LPFC_MBOXQ_t *pmb = NULL;
2058862306a36Sopenharmony_ci	MAILBOX_t *mb;
2058962306a36Sopenharmony_ci	uint32_t offset = 0;
2059062306a36Sopenharmony_ci	int rc;
2059162306a36Sopenharmony_ci
2059262306a36Sopenharmony_ci	if (!rgn23_data)
2059362306a36Sopenharmony_ci		return 0;
2059462306a36Sopenharmony_ci
2059562306a36Sopenharmony_ci	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
2059662306a36Sopenharmony_ci	if (!pmb) {
2059762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
2059862306a36Sopenharmony_ci				"2600 failed to allocate mailbox memory\n");
2059962306a36Sopenharmony_ci		return 0;
2060062306a36Sopenharmony_ci	}
2060162306a36Sopenharmony_ci	mb = &pmb->u.mb;
2060262306a36Sopenharmony_ci
2060362306a36Sopenharmony_ci	do {
2060462306a36Sopenharmony_ci		lpfc_dump_mem(phba, pmb, offset, DMP_REGION_23);
2060562306a36Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
2060662306a36Sopenharmony_ci
2060762306a36Sopenharmony_ci		if (rc != MBX_SUCCESS) {
2060862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2060962306a36Sopenharmony_ci					"2601 failed to read config "
2061062306a36Sopenharmony_ci					"region 23, rc 0x%x Status 0x%x\n",
2061162306a36Sopenharmony_ci					rc, mb->mbxStatus);
2061262306a36Sopenharmony_ci			mb->un.varDmp.word_cnt = 0;
2061362306a36Sopenharmony_ci		}
2061462306a36Sopenharmony_ci		/*
2061562306a36Sopenharmony_ci		 * dump mem may return a zero when finished or we got a
2061662306a36Sopenharmony_ci		 * mailbox error, either way we are done.
2061762306a36Sopenharmony_ci		 */
2061862306a36Sopenharmony_ci		if (mb->un.varDmp.word_cnt == 0)
2061962306a36Sopenharmony_ci			break;
2062062306a36Sopenharmony_ci
2062162306a36Sopenharmony_ci		if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset)
2062262306a36Sopenharmony_ci			mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset;
2062362306a36Sopenharmony_ci
2062462306a36Sopenharmony_ci		lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
2062562306a36Sopenharmony_ci				       rgn23_data + offset,
2062662306a36Sopenharmony_ci				       mb->un.varDmp.word_cnt);
2062762306a36Sopenharmony_ci		offset += mb->un.varDmp.word_cnt;
2062862306a36Sopenharmony_ci	} while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE);
2062962306a36Sopenharmony_ci
2063062306a36Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
2063162306a36Sopenharmony_ci	return offset;
2063262306a36Sopenharmony_ci}
2063362306a36Sopenharmony_ci
2063462306a36Sopenharmony_ci/**
2063562306a36Sopenharmony_ci * lpfc_sli4_get_config_region23 - Get sli4 port region 23 data.
2063662306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2063762306a36Sopenharmony_ci * @rgn23_data: pointer to configure region 23 data.
2063862306a36Sopenharmony_ci *
2063962306a36Sopenharmony_ci * This function gets SLI4 port configure region 23 data through memory dump
2064062306a36Sopenharmony_ci * mailbox command. When it successfully retrieves data, the size of the data
2064162306a36Sopenharmony_ci * will be returned, otherwise, 0 will be returned.
2064262306a36Sopenharmony_ci **/
2064362306a36Sopenharmony_cistatic uint32_t
2064462306a36Sopenharmony_cilpfc_sli4_get_config_region23(struct lpfc_hba *phba, char *rgn23_data)
2064562306a36Sopenharmony_ci{
2064662306a36Sopenharmony_ci	LPFC_MBOXQ_t *mboxq = NULL;
2064762306a36Sopenharmony_ci	struct lpfc_dmabuf *mp = NULL;
2064862306a36Sopenharmony_ci	struct lpfc_mqe *mqe;
2064962306a36Sopenharmony_ci	uint32_t data_length = 0;
2065062306a36Sopenharmony_ci	int rc;
2065162306a36Sopenharmony_ci
2065262306a36Sopenharmony_ci	if (!rgn23_data)
2065362306a36Sopenharmony_ci		return 0;
2065462306a36Sopenharmony_ci
2065562306a36Sopenharmony_ci	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
2065662306a36Sopenharmony_ci	if (!mboxq) {
2065762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
2065862306a36Sopenharmony_ci				"3105 failed to allocate mailbox memory\n");
2065962306a36Sopenharmony_ci		return 0;
2066062306a36Sopenharmony_ci	}
2066162306a36Sopenharmony_ci
2066262306a36Sopenharmony_ci	if (lpfc_sli4_dump_cfg_rg23(phba, mboxq))
2066362306a36Sopenharmony_ci		goto out;
2066462306a36Sopenharmony_ci	mqe = &mboxq->u.mqe;
2066562306a36Sopenharmony_ci	mp = (struct lpfc_dmabuf *)mboxq->ctx_buf;
2066662306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
2066762306a36Sopenharmony_ci	if (rc)
2066862306a36Sopenharmony_ci		goto out;
2066962306a36Sopenharmony_ci	data_length = mqe->un.mb_words[5];
2067062306a36Sopenharmony_ci	if (data_length == 0)
2067162306a36Sopenharmony_ci		goto out;
2067262306a36Sopenharmony_ci	if (data_length > DMP_RGN23_SIZE) {
2067362306a36Sopenharmony_ci		data_length = 0;
2067462306a36Sopenharmony_ci		goto out;
2067562306a36Sopenharmony_ci	}
2067662306a36Sopenharmony_ci	lpfc_sli_pcimem_bcopy((char *)mp->virt, rgn23_data, data_length);
2067762306a36Sopenharmony_ciout:
2067862306a36Sopenharmony_ci	lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED);
2067962306a36Sopenharmony_ci	return data_length;
2068062306a36Sopenharmony_ci}
2068162306a36Sopenharmony_ci
2068262306a36Sopenharmony_ci/**
2068362306a36Sopenharmony_ci * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled.
2068462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2068562306a36Sopenharmony_ci *
2068662306a36Sopenharmony_ci * This function read region 23 and parse TLV for port status to
2068762306a36Sopenharmony_ci * decide if the user disaled the port. If the TLV indicates the
2068862306a36Sopenharmony_ci * port is disabled, the hba_flag is set accordingly.
2068962306a36Sopenharmony_ci **/
2069062306a36Sopenharmony_civoid
2069162306a36Sopenharmony_cilpfc_sli_read_link_ste(struct lpfc_hba *phba)
2069262306a36Sopenharmony_ci{
2069362306a36Sopenharmony_ci	uint8_t *rgn23_data = NULL;
2069462306a36Sopenharmony_ci	uint32_t if_type, data_size, sub_tlv_len, tlv_offset;
2069562306a36Sopenharmony_ci	uint32_t offset = 0;
2069662306a36Sopenharmony_ci
2069762306a36Sopenharmony_ci	/* Get adapter Region 23 data */
2069862306a36Sopenharmony_ci	rgn23_data = kzalloc(DMP_RGN23_SIZE, GFP_KERNEL);
2069962306a36Sopenharmony_ci	if (!rgn23_data)
2070062306a36Sopenharmony_ci		goto out;
2070162306a36Sopenharmony_ci
2070262306a36Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
2070362306a36Sopenharmony_ci		data_size = lpfc_sli_get_config_region23(phba, rgn23_data);
2070462306a36Sopenharmony_ci	else {
2070562306a36Sopenharmony_ci		if_type = bf_get(lpfc_sli_intf_if_type,
2070662306a36Sopenharmony_ci				 &phba->sli4_hba.sli_intf);
2070762306a36Sopenharmony_ci		if (if_type == LPFC_SLI_INTF_IF_TYPE_0)
2070862306a36Sopenharmony_ci			goto out;
2070962306a36Sopenharmony_ci		data_size = lpfc_sli4_get_config_region23(phba, rgn23_data);
2071062306a36Sopenharmony_ci	}
2071162306a36Sopenharmony_ci
2071262306a36Sopenharmony_ci	if (!data_size)
2071362306a36Sopenharmony_ci		goto out;
2071462306a36Sopenharmony_ci
2071562306a36Sopenharmony_ci	/* Check the region signature first */
2071662306a36Sopenharmony_ci	if (memcmp(&rgn23_data[offset], LPFC_REGION23_SIGNATURE, 4)) {
2071762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
2071862306a36Sopenharmony_ci			"2619 Config region 23 has bad signature\n");
2071962306a36Sopenharmony_ci			goto out;
2072062306a36Sopenharmony_ci	}
2072162306a36Sopenharmony_ci	offset += 4;
2072262306a36Sopenharmony_ci
2072362306a36Sopenharmony_ci	/* Check the data structure version */
2072462306a36Sopenharmony_ci	if (rgn23_data[offset] != LPFC_REGION23_VERSION) {
2072562306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
2072662306a36Sopenharmony_ci			"2620 Config region 23 has bad version\n");
2072762306a36Sopenharmony_ci		goto out;
2072862306a36Sopenharmony_ci	}
2072962306a36Sopenharmony_ci	offset += 4;
2073062306a36Sopenharmony_ci
2073162306a36Sopenharmony_ci	/* Parse TLV entries in the region */
2073262306a36Sopenharmony_ci	while (offset < data_size) {
2073362306a36Sopenharmony_ci		if (rgn23_data[offset] == LPFC_REGION23_LAST_REC)
2073462306a36Sopenharmony_ci			break;
2073562306a36Sopenharmony_ci		/*
2073662306a36Sopenharmony_ci		 * If the TLV is not driver specific TLV or driver id is
2073762306a36Sopenharmony_ci		 * not linux driver id, skip the record.
2073862306a36Sopenharmony_ci		 */
2073962306a36Sopenharmony_ci		if ((rgn23_data[offset] != DRIVER_SPECIFIC_TYPE) ||
2074062306a36Sopenharmony_ci		    (rgn23_data[offset + 2] != LINUX_DRIVER_ID) ||
2074162306a36Sopenharmony_ci		    (rgn23_data[offset + 3] != 0)) {
2074262306a36Sopenharmony_ci			offset += rgn23_data[offset + 1] * 4 + 4;
2074362306a36Sopenharmony_ci			continue;
2074462306a36Sopenharmony_ci		}
2074562306a36Sopenharmony_ci
2074662306a36Sopenharmony_ci		/* Driver found a driver specific TLV in the config region */
2074762306a36Sopenharmony_ci		sub_tlv_len = rgn23_data[offset + 1] * 4;
2074862306a36Sopenharmony_ci		offset += 4;
2074962306a36Sopenharmony_ci		tlv_offset = 0;
2075062306a36Sopenharmony_ci
2075162306a36Sopenharmony_ci		/*
2075262306a36Sopenharmony_ci		 * Search for configured port state sub-TLV.
2075362306a36Sopenharmony_ci		 */
2075462306a36Sopenharmony_ci		while ((offset < data_size) &&
2075562306a36Sopenharmony_ci			(tlv_offset < sub_tlv_len)) {
2075662306a36Sopenharmony_ci			if (rgn23_data[offset] == LPFC_REGION23_LAST_REC) {
2075762306a36Sopenharmony_ci				offset += 4;
2075862306a36Sopenharmony_ci				tlv_offset += 4;
2075962306a36Sopenharmony_ci				break;
2076062306a36Sopenharmony_ci			}
2076162306a36Sopenharmony_ci			if (rgn23_data[offset] != PORT_STE_TYPE) {
2076262306a36Sopenharmony_ci				offset += rgn23_data[offset + 1] * 4 + 4;
2076362306a36Sopenharmony_ci				tlv_offset += rgn23_data[offset + 1] * 4 + 4;
2076462306a36Sopenharmony_ci				continue;
2076562306a36Sopenharmony_ci			}
2076662306a36Sopenharmony_ci
2076762306a36Sopenharmony_ci			/* This HBA contains PORT_STE configured */
2076862306a36Sopenharmony_ci			if (!rgn23_data[offset + 2])
2076962306a36Sopenharmony_ci				phba->hba_flag |= LINK_DISABLED;
2077062306a36Sopenharmony_ci
2077162306a36Sopenharmony_ci			goto out;
2077262306a36Sopenharmony_ci		}
2077362306a36Sopenharmony_ci	}
2077462306a36Sopenharmony_ci
2077562306a36Sopenharmony_ciout:
2077662306a36Sopenharmony_ci	kfree(rgn23_data);
2077762306a36Sopenharmony_ci	return;
2077862306a36Sopenharmony_ci}
2077962306a36Sopenharmony_ci
2078062306a36Sopenharmony_ci/**
2078162306a36Sopenharmony_ci * lpfc_log_fw_write_cmpl - logs firmware write completion status
2078262306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure
2078362306a36Sopenharmony_ci * @shdr_status: wr_object rsp's status field
2078462306a36Sopenharmony_ci * @shdr_add_status: wr_object rsp's add_status field
2078562306a36Sopenharmony_ci * @shdr_add_status_2: wr_object rsp's add_status_2 field
2078662306a36Sopenharmony_ci * @shdr_change_status: wr_object rsp's change_status field
2078762306a36Sopenharmony_ci * @shdr_csf: wr_object rsp's csf bit
2078862306a36Sopenharmony_ci *
2078962306a36Sopenharmony_ci * This routine is intended to be called after a firmware write completes.
2079062306a36Sopenharmony_ci * It will log next action items to be performed by the user to instantiate
2079162306a36Sopenharmony_ci * the newly downloaded firmware or reason for incompatibility.
2079262306a36Sopenharmony_ci **/
2079362306a36Sopenharmony_cistatic void
2079462306a36Sopenharmony_cilpfc_log_fw_write_cmpl(struct lpfc_hba *phba, u32 shdr_status,
2079562306a36Sopenharmony_ci		       u32 shdr_add_status, u32 shdr_add_status_2,
2079662306a36Sopenharmony_ci		       u32 shdr_change_status, u32 shdr_csf)
2079762306a36Sopenharmony_ci{
2079862306a36Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
2079962306a36Sopenharmony_ci			"4198 %s: flash_id x%02x, asic_rev x%02x, "
2080062306a36Sopenharmony_ci			"status x%02x, add_status x%02x, add_status_2 x%02x, "
2080162306a36Sopenharmony_ci			"change_status x%02x, csf %01x\n", __func__,
2080262306a36Sopenharmony_ci			phba->sli4_hba.flash_id, phba->sli4_hba.asic_rev,
2080362306a36Sopenharmony_ci			shdr_status, shdr_add_status, shdr_add_status_2,
2080462306a36Sopenharmony_ci			shdr_change_status, shdr_csf);
2080562306a36Sopenharmony_ci
2080662306a36Sopenharmony_ci	if (shdr_add_status == LPFC_ADD_STATUS_INCOMPAT_OBJ) {
2080762306a36Sopenharmony_ci		switch (shdr_add_status_2) {
2080862306a36Sopenharmony_ci		case LPFC_ADD_STATUS_2_INCOMPAT_FLASH:
2080962306a36Sopenharmony_ci			lpfc_log_msg(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
2081062306a36Sopenharmony_ci				     "4199 Firmware write failed: "
2081162306a36Sopenharmony_ci				     "image incompatible with flash x%02x\n",
2081262306a36Sopenharmony_ci				     phba->sli4_hba.flash_id);
2081362306a36Sopenharmony_ci			break;
2081462306a36Sopenharmony_ci		case LPFC_ADD_STATUS_2_INCORRECT_ASIC:
2081562306a36Sopenharmony_ci			lpfc_log_msg(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
2081662306a36Sopenharmony_ci				     "4200 Firmware write failed: "
2081762306a36Sopenharmony_ci				     "image incompatible with ASIC "
2081862306a36Sopenharmony_ci				     "architecture x%02x\n",
2081962306a36Sopenharmony_ci				     phba->sli4_hba.asic_rev);
2082062306a36Sopenharmony_ci			break;
2082162306a36Sopenharmony_ci		default:
2082262306a36Sopenharmony_ci			lpfc_log_msg(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
2082362306a36Sopenharmony_ci				     "4210 Firmware write failed: "
2082462306a36Sopenharmony_ci				     "add_status_2 x%02x\n",
2082562306a36Sopenharmony_ci				     shdr_add_status_2);
2082662306a36Sopenharmony_ci			break;
2082762306a36Sopenharmony_ci		}
2082862306a36Sopenharmony_ci	} else if (!shdr_status && !shdr_add_status) {
2082962306a36Sopenharmony_ci		if (shdr_change_status == LPFC_CHANGE_STATUS_FW_RESET ||
2083062306a36Sopenharmony_ci		    shdr_change_status == LPFC_CHANGE_STATUS_PORT_MIGRATION) {
2083162306a36Sopenharmony_ci			if (shdr_csf)
2083262306a36Sopenharmony_ci				shdr_change_status =
2083362306a36Sopenharmony_ci						   LPFC_CHANGE_STATUS_PCI_RESET;
2083462306a36Sopenharmony_ci		}
2083562306a36Sopenharmony_ci
2083662306a36Sopenharmony_ci		switch (shdr_change_status) {
2083762306a36Sopenharmony_ci		case (LPFC_CHANGE_STATUS_PHYS_DEV_RESET):
2083862306a36Sopenharmony_ci			lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
2083962306a36Sopenharmony_ci				     "3198 Firmware write complete: System "
2084062306a36Sopenharmony_ci				     "reboot required to instantiate\n");
2084162306a36Sopenharmony_ci			break;
2084262306a36Sopenharmony_ci		case (LPFC_CHANGE_STATUS_FW_RESET):
2084362306a36Sopenharmony_ci			lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
2084462306a36Sopenharmony_ci				     "3199 Firmware write complete: "
2084562306a36Sopenharmony_ci				     "Firmware reset required to "
2084662306a36Sopenharmony_ci				     "instantiate\n");
2084762306a36Sopenharmony_ci			break;
2084862306a36Sopenharmony_ci		case (LPFC_CHANGE_STATUS_PORT_MIGRATION):
2084962306a36Sopenharmony_ci			lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
2085062306a36Sopenharmony_ci				     "3200 Firmware write complete: Port "
2085162306a36Sopenharmony_ci				     "Migration or PCI Reset required to "
2085262306a36Sopenharmony_ci				     "instantiate\n");
2085362306a36Sopenharmony_ci			break;
2085462306a36Sopenharmony_ci		case (LPFC_CHANGE_STATUS_PCI_RESET):
2085562306a36Sopenharmony_ci			lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
2085662306a36Sopenharmony_ci				     "3201 Firmware write complete: PCI "
2085762306a36Sopenharmony_ci				     "Reset required to instantiate\n");
2085862306a36Sopenharmony_ci			break;
2085962306a36Sopenharmony_ci		default:
2086062306a36Sopenharmony_ci			break;
2086162306a36Sopenharmony_ci		}
2086262306a36Sopenharmony_ci	}
2086362306a36Sopenharmony_ci}
2086462306a36Sopenharmony_ci
2086562306a36Sopenharmony_ci/**
2086662306a36Sopenharmony_ci * lpfc_wr_object - write an object to the firmware
2086762306a36Sopenharmony_ci * @phba: HBA structure that indicates port to create a queue on.
2086862306a36Sopenharmony_ci * @dmabuf_list: list of dmabufs to write to the port.
2086962306a36Sopenharmony_ci * @size: the total byte value of the objects to write to the port.
2087062306a36Sopenharmony_ci * @offset: the current offset to be used to start the transfer.
2087162306a36Sopenharmony_ci *
2087262306a36Sopenharmony_ci * This routine will create a wr_object mailbox command to send to the port.
2087362306a36Sopenharmony_ci * the mailbox command will be constructed using the dma buffers described in
2087462306a36Sopenharmony_ci * @dmabuf_list to create a list of BDEs. This routine will fill in as many
2087562306a36Sopenharmony_ci * BDEs that the imbedded mailbox can support. The @offset variable will be
2087662306a36Sopenharmony_ci * used to indicate the starting offset of the transfer and will also return
2087762306a36Sopenharmony_ci * the offset after the write object mailbox has completed. @size is used to
2087862306a36Sopenharmony_ci * determine the end of the object and whether the eof bit should be set.
2087962306a36Sopenharmony_ci *
2088062306a36Sopenharmony_ci * Return 0 is successful and offset will contain the new offset to use
2088162306a36Sopenharmony_ci * for the next write.
2088262306a36Sopenharmony_ci * Return negative value for error cases.
2088362306a36Sopenharmony_ci **/
2088462306a36Sopenharmony_ciint
2088562306a36Sopenharmony_cilpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
2088662306a36Sopenharmony_ci	       uint32_t size, uint32_t *offset)
2088762306a36Sopenharmony_ci{
2088862306a36Sopenharmony_ci	struct lpfc_mbx_wr_object *wr_object;
2088962306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
2089062306a36Sopenharmony_ci	int rc = 0, i = 0;
2089162306a36Sopenharmony_ci	int mbox_status = 0;
2089262306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status, shdr_add_status_2;
2089362306a36Sopenharmony_ci	uint32_t shdr_change_status = 0, shdr_csf = 0;
2089462306a36Sopenharmony_ci	uint32_t mbox_tmo;
2089562306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
2089662306a36Sopenharmony_ci	uint32_t written = 0;
2089762306a36Sopenharmony_ci	bool check_change_status = false;
2089862306a36Sopenharmony_ci
2089962306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
2090062306a36Sopenharmony_ci	if (!mbox)
2090162306a36Sopenharmony_ci		return -ENOMEM;
2090262306a36Sopenharmony_ci
2090362306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
2090462306a36Sopenharmony_ci			LPFC_MBOX_OPCODE_WRITE_OBJECT,
2090562306a36Sopenharmony_ci			sizeof(struct lpfc_mbx_wr_object) -
2090662306a36Sopenharmony_ci			sizeof(struct lpfc_sli4_cfg_mhdr), LPFC_SLI4_MBX_EMBED);
2090762306a36Sopenharmony_ci
2090862306a36Sopenharmony_ci	wr_object = (struct lpfc_mbx_wr_object *)&mbox->u.mqe.un.wr_object;
2090962306a36Sopenharmony_ci	wr_object->u.request.write_offset = *offset;
2091062306a36Sopenharmony_ci	sprintf((uint8_t *)wr_object->u.request.object_name, "/");
2091162306a36Sopenharmony_ci	wr_object->u.request.object_name[0] =
2091262306a36Sopenharmony_ci		cpu_to_le32(wr_object->u.request.object_name[0]);
2091362306a36Sopenharmony_ci	bf_set(lpfc_wr_object_eof, &wr_object->u.request, 0);
2091462306a36Sopenharmony_ci	list_for_each_entry(dmabuf, dmabuf_list, list) {
2091562306a36Sopenharmony_ci		if (i >= LPFC_MBX_WR_CONFIG_MAX_BDE || written >= size)
2091662306a36Sopenharmony_ci			break;
2091762306a36Sopenharmony_ci		wr_object->u.request.bde[i].addrLow = putPaddrLow(dmabuf->phys);
2091862306a36Sopenharmony_ci		wr_object->u.request.bde[i].addrHigh =
2091962306a36Sopenharmony_ci			putPaddrHigh(dmabuf->phys);
2092062306a36Sopenharmony_ci		if (written + SLI4_PAGE_SIZE >= size) {
2092162306a36Sopenharmony_ci			wr_object->u.request.bde[i].tus.f.bdeSize =
2092262306a36Sopenharmony_ci				(size - written);
2092362306a36Sopenharmony_ci			written += (size - written);
2092462306a36Sopenharmony_ci			bf_set(lpfc_wr_object_eof, &wr_object->u.request, 1);
2092562306a36Sopenharmony_ci			bf_set(lpfc_wr_object_eas, &wr_object->u.request, 1);
2092662306a36Sopenharmony_ci			check_change_status = true;
2092762306a36Sopenharmony_ci		} else {
2092862306a36Sopenharmony_ci			wr_object->u.request.bde[i].tus.f.bdeSize =
2092962306a36Sopenharmony_ci				SLI4_PAGE_SIZE;
2093062306a36Sopenharmony_ci			written += SLI4_PAGE_SIZE;
2093162306a36Sopenharmony_ci		}
2093262306a36Sopenharmony_ci		i++;
2093362306a36Sopenharmony_ci	}
2093462306a36Sopenharmony_ci	wr_object->u.request.bde_count = i;
2093562306a36Sopenharmony_ci	bf_set(lpfc_wr_object_write_length, &wr_object->u.request, written);
2093662306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable)
2093762306a36Sopenharmony_ci		mbox_status = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
2093862306a36Sopenharmony_ci	else {
2093962306a36Sopenharmony_ci		mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
2094062306a36Sopenharmony_ci		mbox_status = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
2094162306a36Sopenharmony_ci	}
2094262306a36Sopenharmony_ci
2094362306a36Sopenharmony_ci	/* The mbox status needs to be maintained to detect MBOX_TIMEOUT. */
2094462306a36Sopenharmony_ci	rc = mbox_status;
2094562306a36Sopenharmony_ci
2094662306a36Sopenharmony_ci	/* The IOCTL status is embedded in the mailbox subheader. */
2094762306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status,
2094862306a36Sopenharmony_ci			     &wr_object->header.cfg_shdr.response);
2094962306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
2095062306a36Sopenharmony_ci				 &wr_object->header.cfg_shdr.response);
2095162306a36Sopenharmony_ci	shdr_add_status_2 = bf_get(lpfc_mbox_hdr_add_status_2,
2095262306a36Sopenharmony_ci				   &wr_object->header.cfg_shdr.response);
2095362306a36Sopenharmony_ci	if (check_change_status) {
2095462306a36Sopenharmony_ci		shdr_change_status = bf_get(lpfc_wr_object_change_status,
2095562306a36Sopenharmony_ci					    &wr_object->u.response);
2095662306a36Sopenharmony_ci		shdr_csf = bf_get(lpfc_wr_object_csf,
2095762306a36Sopenharmony_ci				  &wr_object->u.response);
2095862306a36Sopenharmony_ci	}
2095962306a36Sopenharmony_ci
2096062306a36Sopenharmony_ci	if (shdr_status || shdr_add_status || shdr_add_status_2 || rc) {
2096162306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
2096262306a36Sopenharmony_ci				"3025 Write Object mailbox failed with "
2096362306a36Sopenharmony_ci				"status x%x add_status x%x, add_status_2 x%x, "
2096462306a36Sopenharmony_ci				"mbx status x%x\n",
2096562306a36Sopenharmony_ci				shdr_status, shdr_add_status, shdr_add_status_2,
2096662306a36Sopenharmony_ci				rc);
2096762306a36Sopenharmony_ci		rc = -ENXIO;
2096862306a36Sopenharmony_ci		*offset = shdr_add_status;
2096962306a36Sopenharmony_ci	} else {
2097062306a36Sopenharmony_ci		*offset += wr_object->u.response.actual_write_length;
2097162306a36Sopenharmony_ci	}
2097262306a36Sopenharmony_ci
2097362306a36Sopenharmony_ci	if (rc || check_change_status)
2097462306a36Sopenharmony_ci		lpfc_log_fw_write_cmpl(phba, shdr_status, shdr_add_status,
2097562306a36Sopenharmony_ci				       shdr_add_status_2, shdr_change_status,
2097662306a36Sopenharmony_ci				       shdr_csf);
2097762306a36Sopenharmony_ci
2097862306a36Sopenharmony_ci	if (!phba->sli4_hba.intr_enable)
2097962306a36Sopenharmony_ci		mempool_free(mbox, phba->mbox_mem_pool);
2098062306a36Sopenharmony_ci	else if (mbox_status != MBX_TIMEOUT)
2098162306a36Sopenharmony_ci		mempool_free(mbox, phba->mbox_mem_pool);
2098262306a36Sopenharmony_ci
2098362306a36Sopenharmony_ci	return rc;
2098462306a36Sopenharmony_ci}
2098562306a36Sopenharmony_ci
2098662306a36Sopenharmony_ci/**
2098762306a36Sopenharmony_ci * lpfc_cleanup_pending_mbox - Free up vport discovery mailbox commands.
2098862306a36Sopenharmony_ci * @vport: pointer to vport data structure.
2098962306a36Sopenharmony_ci *
2099062306a36Sopenharmony_ci * This function iterate through the mailboxq and clean up all REG_LOGIN
2099162306a36Sopenharmony_ci * and REG_VPI mailbox commands associated with the vport. This function
2099262306a36Sopenharmony_ci * is called when driver want to restart discovery of the vport due to
2099362306a36Sopenharmony_ci * a Clear Virtual Link event.
2099462306a36Sopenharmony_ci **/
2099562306a36Sopenharmony_civoid
2099662306a36Sopenharmony_cilpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
2099762306a36Sopenharmony_ci{
2099862306a36Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
2099962306a36Sopenharmony_ci	LPFC_MBOXQ_t *mb, *nextmb;
2100062306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp;
2100162306a36Sopenharmony_ci	struct lpfc_nodelist *act_mbx_ndlp = NULL;
2100262306a36Sopenharmony_ci	LIST_HEAD(mbox_cmd_list);
2100362306a36Sopenharmony_ci	uint8_t restart_loop;
2100462306a36Sopenharmony_ci
2100562306a36Sopenharmony_ci	/* Clean up internally queued mailbox commands with the vport */
2100662306a36Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
2100762306a36Sopenharmony_ci	list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
2100862306a36Sopenharmony_ci		if (mb->vport != vport)
2100962306a36Sopenharmony_ci			continue;
2101062306a36Sopenharmony_ci
2101162306a36Sopenharmony_ci		if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) &&
2101262306a36Sopenharmony_ci			(mb->u.mb.mbxCommand != MBX_REG_VPI))
2101362306a36Sopenharmony_ci			continue;
2101462306a36Sopenharmony_ci
2101562306a36Sopenharmony_ci		list_move_tail(&mb->list, &mbox_cmd_list);
2101662306a36Sopenharmony_ci	}
2101762306a36Sopenharmony_ci	/* Clean up active mailbox command with the vport */
2101862306a36Sopenharmony_ci	mb = phba->sli.mbox_active;
2101962306a36Sopenharmony_ci	if (mb && (mb->vport == vport)) {
2102062306a36Sopenharmony_ci		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) ||
2102162306a36Sopenharmony_ci			(mb->u.mb.mbxCommand == MBX_REG_VPI))
2102262306a36Sopenharmony_ci			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
2102362306a36Sopenharmony_ci		if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
2102462306a36Sopenharmony_ci			act_mbx_ndlp = (struct lpfc_nodelist *)mb->ctx_ndlp;
2102562306a36Sopenharmony_ci
2102662306a36Sopenharmony_ci			/* This reference is local to this routine.  The
2102762306a36Sopenharmony_ci			 * reference is removed at routine exit.
2102862306a36Sopenharmony_ci			 */
2102962306a36Sopenharmony_ci			act_mbx_ndlp = lpfc_nlp_get(act_mbx_ndlp);
2103062306a36Sopenharmony_ci
2103162306a36Sopenharmony_ci			/* Unregister the RPI when mailbox complete */
2103262306a36Sopenharmony_ci			mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
2103362306a36Sopenharmony_ci		}
2103462306a36Sopenharmony_ci	}
2103562306a36Sopenharmony_ci	/* Cleanup any mailbox completions which are not yet processed */
2103662306a36Sopenharmony_ci	do {
2103762306a36Sopenharmony_ci		restart_loop = 0;
2103862306a36Sopenharmony_ci		list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) {
2103962306a36Sopenharmony_ci			/*
2104062306a36Sopenharmony_ci			 * If this mailox is already processed or it is
2104162306a36Sopenharmony_ci			 * for another vport ignore it.
2104262306a36Sopenharmony_ci			 */
2104362306a36Sopenharmony_ci			if ((mb->vport != vport) ||
2104462306a36Sopenharmony_ci				(mb->mbox_flag & LPFC_MBX_IMED_UNREG))
2104562306a36Sopenharmony_ci				continue;
2104662306a36Sopenharmony_ci
2104762306a36Sopenharmony_ci			if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) &&
2104862306a36Sopenharmony_ci				(mb->u.mb.mbxCommand != MBX_REG_VPI))
2104962306a36Sopenharmony_ci				continue;
2105062306a36Sopenharmony_ci
2105162306a36Sopenharmony_ci			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
2105262306a36Sopenharmony_ci			if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
2105362306a36Sopenharmony_ci				ndlp = (struct lpfc_nodelist *)mb->ctx_ndlp;
2105462306a36Sopenharmony_ci				/* Unregister the RPI when mailbox complete */
2105562306a36Sopenharmony_ci				mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
2105662306a36Sopenharmony_ci				restart_loop = 1;
2105762306a36Sopenharmony_ci				spin_unlock_irq(&phba->hbalock);
2105862306a36Sopenharmony_ci				spin_lock(&ndlp->lock);
2105962306a36Sopenharmony_ci				ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
2106062306a36Sopenharmony_ci				spin_unlock(&ndlp->lock);
2106162306a36Sopenharmony_ci				spin_lock_irq(&phba->hbalock);
2106262306a36Sopenharmony_ci				break;
2106362306a36Sopenharmony_ci			}
2106462306a36Sopenharmony_ci		}
2106562306a36Sopenharmony_ci	} while (restart_loop);
2106662306a36Sopenharmony_ci
2106762306a36Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
2106862306a36Sopenharmony_ci
2106962306a36Sopenharmony_ci	/* Release the cleaned-up mailbox commands */
2107062306a36Sopenharmony_ci	while (!list_empty(&mbox_cmd_list)) {
2107162306a36Sopenharmony_ci		list_remove_head(&mbox_cmd_list, mb, LPFC_MBOXQ_t, list);
2107262306a36Sopenharmony_ci		if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
2107362306a36Sopenharmony_ci			ndlp = (struct lpfc_nodelist *)mb->ctx_ndlp;
2107462306a36Sopenharmony_ci			mb->ctx_ndlp = NULL;
2107562306a36Sopenharmony_ci			if (ndlp) {
2107662306a36Sopenharmony_ci				spin_lock(&ndlp->lock);
2107762306a36Sopenharmony_ci				ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
2107862306a36Sopenharmony_ci				spin_unlock(&ndlp->lock);
2107962306a36Sopenharmony_ci				lpfc_nlp_put(ndlp);
2108062306a36Sopenharmony_ci			}
2108162306a36Sopenharmony_ci		}
2108262306a36Sopenharmony_ci		lpfc_mbox_rsrc_cleanup(phba, mb, MBOX_THD_UNLOCKED);
2108362306a36Sopenharmony_ci	}
2108462306a36Sopenharmony_ci
2108562306a36Sopenharmony_ci	/* Release the ndlp with the cleaned-up active mailbox command */
2108662306a36Sopenharmony_ci	if (act_mbx_ndlp) {
2108762306a36Sopenharmony_ci		spin_lock(&act_mbx_ndlp->lock);
2108862306a36Sopenharmony_ci		act_mbx_ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
2108962306a36Sopenharmony_ci		spin_unlock(&act_mbx_ndlp->lock);
2109062306a36Sopenharmony_ci		lpfc_nlp_put(act_mbx_ndlp);
2109162306a36Sopenharmony_ci	}
2109262306a36Sopenharmony_ci}
2109362306a36Sopenharmony_ci
2109462306a36Sopenharmony_ci/**
2109562306a36Sopenharmony_ci * lpfc_drain_txq - Drain the txq
2109662306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
2109762306a36Sopenharmony_ci *
2109862306a36Sopenharmony_ci * This function attempt to submit IOCBs on the txq
2109962306a36Sopenharmony_ci * to the adapter.  For SLI4 adapters, the txq contains
2110062306a36Sopenharmony_ci * ELS IOCBs that have been deferred because the there
2110162306a36Sopenharmony_ci * are no SGLs.  This congestion can occur with large
2110262306a36Sopenharmony_ci * vport counts during node discovery.
2110362306a36Sopenharmony_ci **/
2110462306a36Sopenharmony_ci
2110562306a36Sopenharmony_ciuint32_t
2110662306a36Sopenharmony_cilpfc_drain_txq(struct lpfc_hba *phba)
2110762306a36Sopenharmony_ci{
2110862306a36Sopenharmony_ci	LIST_HEAD(completions);
2110962306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
2111062306a36Sopenharmony_ci	struct lpfc_iocbq *piocbq = NULL;
2111162306a36Sopenharmony_ci	unsigned long iflags = 0;
2111262306a36Sopenharmony_ci	char *fail_msg = NULL;
2111362306a36Sopenharmony_ci	uint32_t txq_cnt = 0;
2111462306a36Sopenharmony_ci	struct lpfc_queue *wq;
2111562306a36Sopenharmony_ci	int ret = 0;
2111662306a36Sopenharmony_ci
2111762306a36Sopenharmony_ci	if (phba->link_flag & LS_MDS_LOOPBACK) {
2111862306a36Sopenharmony_ci		/* MDS WQE are posted only to first WQ*/
2111962306a36Sopenharmony_ci		wq = phba->sli4_hba.hdwq[0].io_wq;
2112062306a36Sopenharmony_ci		if (unlikely(!wq))
2112162306a36Sopenharmony_ci			return 0;
2112262306a36Sopenharmony_ci		pring = wq->pring;
2112362306a36Sopenharmony_ci	} else {
2112462306a36Sopenharmony_ci		wq = phba->sli4_hba.els_wq;
2112562306a36Sopenharmony_ci		if (unlikely(!wq))
2112662306a36Sopenharmony_ci			return 0;
2112762306a36Sopenharmony_ci		pring = lpfc_phba_elsring(phba);
2112862306a36Sopenharmony_ci	}
2112962306a36Sopenharmony_ci
2113062306a36Sopenharmony_ci	if (unlikely(!pring) || list_empty(&pring->txq))
2113162306a36Sopenharmony_ci		return 0;
2113262306a36Sopenharmony_ci
2113362306a36Sopenharmony_ci	spin_lock_irqsave(&pring->ring_lock, iflags);
2113462306a36Sopenharmony_ci	list_for_each_entry(piocbq, &pring->txq, list) {
2113562306a36Sopenharmony_ci		txq_cnt++;
2113662306a36Sopenharmony_ci	}
2113762306a36Sopenharmony_ci
2113862306a36Sopenharmony_ci	if (txq_cnt > pring->txq_max)
2113962306a36Sopenharmony_ci		pring->txq_max = txq_cnt;
2114062306a36Sopenharmony_ci
2114162306a36Sopenharmony_ci	spin_unlock_irqrestore(&pring->ring_lock, iflags);
2114262306a36Sopenharmony_ci
2114362306a36Sopenharmony_ci	while (!list_empty(&pring->txq)) {
2114462306a36Sopenharmony_ci		spin_lock_irqsave(&pring->ring_lock, iflags);
2114562306a36Sopenharmony_ci
2114662306a36Sopenharmony_ci		piocbq = lpfc_sli_ringtx_get(phba, pring);
2114762306a36Sopenharmony_ci		if (!piocbq) {
2114862306a36Sopenharmony_ci			spin_unlock_irqrestore(&pring->ring_lock, iflags);
2114962306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
2115062306a36Sopenharmony_ci				"2823 txq empty and txq_cnt is %d\n ",
2115162306a36Sopenharmony_ci				txq_cnt);
2115262306a36Sopenharmony_ci			break;
2115362306a36Sopenharmony_ci		}
2115462306a36Sopenharmony_ci		txq_cnt--;
2115562306a36Sopenharmony_ci
2115662306a36Sopenharmony_ci		ret = __lpfc_sli_issue_iocb(phba, pring->ringno, piocbq, 0);
2115762306a36Sopenharmony_ci
2115862306a36Sopenharmony_ci		if (ret && ret != IOCB_BUSY) {
2115962306a36Sopenharmony_ci			fail_msg = " - Cannot send IO ";
2116062306a36Sopenharmony_ci			piocbq->cmd_flag &= ~LPFC_DRIVER_ABORTED;
2116162306a36Sopenharmony_ci		}
2116262306a36Sopenharmony_ci		if (fail_msg) {
2116362306a36Sopenharmony_ci			piocbq->cmd_flag |= LPFC_DRIVER_ABORTED;
2116462306a36Sopenharmony_ci			/* Failed means we can't issue and need to cancel */
2116562306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
2116662306a36Sopenharmony_ci					"2822 IOCB failed %s iotag 0x%x "
2116762306a36Sopenharmony_ci					"xri 0x%x %d flg x%x\n",
2116862306a36Sopenharmony_ci					fail_msg, piocbq->iotag,
2116962306a36Sopenharmony_ci					piocbq->sli4_xritag, ret,
2117062306a36Sopenharmony_ci					piocbq->cmd_flag);
2117162306a36Sopenharmony_ci			list_add_tail(&piocbq->list, &completions);
2117262306a36Sopenharmony_ci			fail_msg = NULL;
2117362306a36Sopenharmony_ci		}
2117462306a36Sopenharmony_ci		spin_unlock_irqrestore(&pring->ring_lock, iflags);
2117562306a36Sopenharmony_ci		if (txq_cnt == 0 || ret == IOCB_BUSY)
2117662306a36Sopenharmony_ci			break;
2117762306a36Sopenharmony_ci	}
2117862306a36Sopenharmony_ci	/* Cancel all the IOCBs that cannot be issued */
2117962306a36Sopenharmony_ci	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
2118062306a36Sopenharmony_ci			      IOERR_SLI_ABORTED);
2118162306a36Sopenharmony_ci
2118262306a36Sopenharmony_ci	return txq_cnt;
2118362306a36Sopenharmony_ci}
2118462306a36Sopenharmony_ci
2118562306a36Sopenharmony_ci/**
2118662306a36Sopenharmony_ci * lpfc_wqe_bpl2sgl - Convert the bpl/bde to a sgl.
2118762306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
2118862306a36Sopenharmony_ci * @pwqeq: Pointer to command WQE.
2118962306a36Sopenharmony_ci * @sglq: Pointer to the scatter gather queue object.
2119062306a36Sopenharmony_ci *
2119162306a36Sopenharmony_ci * This routine converts the bpl or bde that is in the WQE
2119262306a36Sopenharmony_ci * to a sgl list for the sli4 hardware. The physical address
2119362306a36Sopenharmony_ci * of the bpl/bde is converted back to a virtual address.
2119462306a36Sopenharmony_ci * If the WQE contains a BPL then the list of BDE's is
2119562306a36Sopenharmony_ci * converted to sli4_sge's. If the WQE contains a single
2119662306a36Sopenharmony_ci * BDE then it is converted to a single sli_sge.
2119762306a36Sopenharmony_ci * The WQE is still in cpu endianness so the contents of
2119862306a36Sopenharmony_ci * the bpl can be used without byte swapping.
2119962306a36Sopenharmony_ci *
2120062306a36Sopenharmony_ci * Returns valid XRI = Success, NO_XRI = Failure.
2120162306a36Sopenharmony_ci */
2120262306a36Sopenharmony_cistatic uint16_t
2120362306a36Sopenharmony_cilpfc_wqe_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeq,
2120462306a36Sopenharmony_ci		 struct lpfc_sglq *sglq)
2120562306a36Sopenharmony_ci{
2120662306a36Sopenharmony_ci	uint16_t xritag = NO_XRI;
2120762306a36Sopenharmony_ci	struct ulp_bde64 *bpl = NULL;
2120862306a36Sopenharmony_ci	struct ulp_bde64 bde;
2120962306a36Sopenharmony_ci	struct sli4_sge *sgl  = NULL;
2121062306a36Sopenharmony_ci	struct lpfc_dmabuf *dmabuf;
2121162306a36Sopenharmony_ci	union lpfc_wqe128 *wqe;
2121262306a36Sopenharmony_ci	int numBdes = 0;
2121362306a36Sopenharmony_ci	int i = 0;
2121462306a36Sopenharmony_ci	uint32_t offset = 0; /* accumulated offset in the sg request list */
2121562306a36Sopenharmony_ci	int inbound = 0; /* number of sg reply entries inbound from firmware */
2121662306a36Sopenharmony_ci	uint32_t cmd;
2121762306a36Sopenharmony_ci
2121862306a36Sopenharmony_ci	if (!pwqeq || !sglq)
2121962306a36Sopenharmony_ci		return xritag;
2122062306a36Sopenharmony_ci
2122162306a36Sopenharmony_ci	sgl  = (struct sli4_sge *)sglq->sgl;
2122262306a36Sopenharmony_ci	wqe = &pwqeq->wqe;
2122362306a36Sopenharmony_ci	pwqeq->iocb.ulpIoTag = pwqeq->iotag;
2122462306a36Sopenharmony_ci
2122562306a36Sopenharmony_ci	cmd = bf_get(wqe_cmnd, &wqe->generic.wqe_com);
2122662306a36Sopenharmony_ci	if (cmd == CMD_XMIT_BLS_RSP64_WQE)
2122762306a36Sopenharmony_ci		return sglq->sli4_xritag;
2122862306a36Sopenharmony_ci	numBdes = pwqeq->num_bdes;
2122962306a36Sopenharmony_ci	if (numBdes) {
2123062306a36Sopenharmony_ci		/* The addrHigh and addrLow fields within the WQE
2123162306a36Sopenharmony_ci		 * have not been byteswapped yet so there is no
2123262306a36Sopenharmony_ci		 * need to swap them back.
2123362306a36Sopenharmony_ci		 */
2123462306a36Sopenharmony_ci		if (pwqeq->bpl_dmabuf)
2123562306a36Sopenharmony_ci			dmabuf = pwqeq->bpl_dmabuf;
2123662306a36Sopenharmony_ci		else
2123762306a36Sopenharmony_ci			return xritag;
2123862306a36Sopenharmony_ci
2123962306a36Sopenharmony_ci		bpl  = (struct ulp_bde64 *)dmabuf->virt;
2124062306a36Sopenharmony_ci		if (!bpl)
2124162306a36Sopenharmony_ci			return xritag;
2124262306a36Sopenharmony_ci
2124362306a36Sopenharmony_ci		for (i = 0; i < numBdes; i++) {
2124462306a36Sopenharmony_ci			/* Should already be byte swapped. */
2124562306a36Sopenharmony_ci			sgl->addr_hi = bpl->addrHigh;
2124662306a36Sopenharmony_ci			sgl->addr_lo = bpl->addrLow;
2124762306a36Sopenharmony_ci
2124862306a36Sopenharmony_ci			sgl->word2 = le32_to_cpu(sgl->word2);
2124962306a36Sopenharmony_ci			if ((i+1) == numBdes)
2125062306a36Sopenharmony_ci				bf_set(lpfc_sli4_sge_last, sgl, 1);
2125162306a36Sopenharmony_ci			else
2125262306a36Sopenharmony_ci				bf_set(lpfc_sli4_sge_last, sgl, 0);
2125362306a36Sopenharmony_ci			/* swap the size field back to the cpu so we
2125462306a36Sopenharmony_ci			 * can assign it to the sgl.
2125562306a36Sopenharmony_ci			 */
2125662306a36Sopenharmony_ci			bde.tus.w = le32_to_cpu(bpl->tus.w);
2125762306a36Sopenharmony_ci			sgl->sge_len = cpu_to_le32(bde.tus.f.bdeSize);
2125862306a36Sopenharmony_ci			/* The offsets in the sgl need to be accumulated
2125962306a36Sopenharmony_ci			 * separately for the request and reply lists.
2126062306a36Sopenharmony_ci			 * The request is always first, the reply follows.
2126162306a36Sopenharmony_ci			 */
2126262306a36Sopenharmony_ci			switch (cmd) {
2126362306a36Sopenharmony_ci			case CMD_GEN_REQUEST64_WQE:
2126462306a36Sopenharmony_ci				/* add up the reply sg entries */
2126562306a36Sopenharmony_ci				if (bpl->tus.f.bdeFlags == BUFF_TYPE_BDE_64I)
2126662306a36Sopenharmony_ci					inbound++;
2126762306a36Sopenharmony_ci				/* first inbound? reset the offset */
2126862306a36Sopenharmony_ci				if (inbound == 1)
2126962306a36Sopenharmony_ci					offset = 0;
2127062306a36Sopenharmony_ci				bf_set(lpfc_sli4_sge_offset, sgl, offset);
2127162306a36Sopenharmony_ci				bf_set(lpfc_sli4_sge_type, sgl,
2127262306a36Sopenharmony_ci					LPFC_SGE_TYPE_DATA);
2127362306a36Sopenharmony_ci				offset += bde.tus.f.bdeSize;
2127462306a36Sopenharmony_ci				break;
2127562306a36Sopenharmony_ci			case CMD_FCP_TRSP64_WQE:
2127662306a36Sopenharmony_ci				bf_set(lpfc_sli4_sge_offset, sgl, 0);
2127762306a36Sopenharmony_ci				bf_set(lpfc_sli4_sge_type, sgl,
2127862306a36Sopenharmony_ci					LPFC_SGE_TYPE_DATA);
2127962306a36Sopenharmony_ci				break;
2128062306a36Sopenharmony_ci			case CMD_FCP_TSEND64_WQE:
2128162306a36Sopenharmony_ci			case CMD_FCP_TRECEIVE64_WQE:
2128262306a36Sopenharmony_ci				bf_set(lpfc_sli4_sge_type, sgl,
2128362306a36Sopenharmony_ci					bpl->tus.f.bdeFlags);
2128462306a36Sopenharmony_ci				if (i < 3)
2128562306a36Sopenharmony_ci					offset = 0;
2128662306a36Sopenharmony_ci				else
2128762306a36Sopenharmony_ci					offset += bde.tus.f.bdeSize;
2128862306a36Sopenharmony_ci				bf_set(lpfc_sli4_sge_offset, sgl, offset);
2128962306a36Sopenharmony_ci				break;
2129062306a36Sopenharmony_ci			}
2129162306a36Sopenharmony_ci			sgl->word2 = cpu_to_le32(sgl->word2);
2129262306a36Sopenharmony_ci			bpl++;
2129362306a36Sopenharmony_ci			sgl++;
2129462306a36Sopenharmony_ci		}
2129562306a36Sopenharmony_ci	} else if (wqe->gen_req.bde.tus.f.bdeFlags == BUFF_TYPE_BDE_64) {
2129662306a36Sopenharmony_ci		/* The addrHigh and addrLow fields of the BDE have not
2129762306a36Sopenharmony_ci		 * been byteswapped yet so they need to be swapped
2129862306a36Sopenharmony_ci		 * before putting them in the sgl.
2129962306a36Sopenharmony_ci		 */
2130062306a36Sopenharmony_ci		sgl->addr_hi = cpu_to_le32(wqe->gen_req.bde.addrHigh);
2130162306a36Sopenharmony_ci		sgl->addr_lo = cpu_to_le32(wqe->gen_req.bde.addrLow);
2130262306a36Sopenharmony_ci		sgl->word2 = le32_to_cpu(sgl->word2);
2130362306a36Sopenharmony_ci		bf_set(lpfc_sli4_sge_last, sgl, 1);
2130462306a36Sopenharmony_ci		sgl->word2 = cpu_to_le32(sgl->word2);
2130562306a36Sopenharmony_ci		sgl->sge_len = cpu_to_le32(wqe->gen_req.bde.tus.f.bdeSize);
2130662306a36Sopenharmony_ci	}
2130762306a36Sopenharmony_ci	return sglq->sli4_xritag;
2130862306a36Sopenharmony_ci}
2130962306a36Sopenharmony_ci
2131062306a36Sopenharmony_ci/**
2131162306a36Sopenharmony_ci * lpfc_sli4_issue_wqe - Issue an SLI4 Work Queue Entry (WQE)
2131262306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
2131362306a36Sopenharmony_ci * @qp: Pointer to HDW queue.
2131462306a36Sopenharmony_ci * @pwqe: Pointer to command WQE.
2131562306a36Sopenharmony_ci **/
2131662306a36Sopenharmony_ciint
2131762306a36Sopenharmony_cilpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp,
2131862306a36Sopenharmony_ci		    struct lpfc_iocbq *pwqe)
2131962306a36Sopenharmony_ci{
2132062306a36Sopenharmony_ci	union lpfc_wqe128 *wqe = &pwqe->wqe;
2132162306a36Sopenharmony_ci	struct lpfc_async_xchg_ctx *ctxp;
2132262306a36Sopenharmony_ci	struct lpfc_queue *wq;
2132362306a36Sopenharmony_ci	struct lpfc_sglq *sglq;
2132462306a36Sopenharmony_ci	struct lpfc_sli_ring *pring;
2132562306a36Sopenharmony_ci	unsigned long iflags;
2132662306a36Sopenharmony_ci	uint32_t ret = 0;
2132762306a36Sopenharmony_ci
2132862306a36Sopenharmony_ci	/* NVME_LS and NVME_LS ABTS requests. */
2132962306a36Sopenharmony_ci	if (pwqe->cmd_flag & LPFC_IO_NVME_LS) {
2133062306a36Sopenharmony_ci		pring =  phba->sli4_hba.nvmels_wq->pring;
2133162306a36Sopenharmony_ci		lpfc_qp_spin_lock_irqsave(&pring->ring_lock, iflags,
2133262306a36Sopenharmony_ci					  qp, wq_access);
2133362306a36Sopenharmony_ci		sglq = __lpfc_sli_get_els_sglq(phba, pwqe);
2133462306a36Sopenharmony_ci		if (!sglq) {
2133562306a36Sopenharmony_ci			spin_unlock_irqrestore(&pring->ring_lock, iflags);
2133662306a36Sopenharmony_ci			return WQE_BUSY;
2133762306a36Sopenharmony_ci		}
2133862306a36Sopenharmony_ci		pwqe->sli4_lxritag = sglq->sli4_lxritag;
2133962306a36Sopenharmony_ci		pwqe->sli4_xritag = sglq->sli4_xritag;
2134062306a36Sopenharmony_ci		if (lpfc_wqe_bpl2sgl(phba, pwqe, sglq) == NO_XRI) {
2134162306a36Sopenharmony_ci			spin_unlock_irqrestore(&pring->ring_lock, iflags);
2134262306a36Sopenharmony_ci			return WQE_ERROR;
2134362306a36Sopenharmony_ci		}
2134462306a36Sopenharmony_ci		bf_set(wqe_xri_tag, &pwqe->wqe.xmit_bls_rsp.wqe_com,
2134562306a36Sopenharmony_ci		       pwqe->sli4_xritag);
2134662306a36Sopenharmony_ci		ret = lpfc_sli4_wq_put(phba->sli4_hba.nvmels_wq, wqe);
2134762306a36Sopenharmony_ci		if (ret) {
2134862306a36Sopenharmony_ci			spin_unlock_irqrestore(&pring->ring_lock, iflags);
2134962306a36Sopenharmony_ci			return ret;
2135062306a36Sopenharmony_ci		}
2135162306a36Sopenharmony_ci
2135262306a36Sopenharmony_ci		lpfc_sli_ringtxcmpl_put(phba, pring, pwqe);
2135362306a36Sopenharmony_ci		spin_unlock_irqrestore(&pring->ring_lock, iflags);
2135462306a36Sopenharmony_ci
2135562306a36Sopenharmony_ci		lpfc_sli4_poll_eq(qp->hba_eq);
2135662306a36Sopenharmony_ci		return 0;
2135762306a36Sopenharmony_ci	}
2135862306a36Sopenharmony_ci
2135962306a36Sopenharmony_ci	/* NVME_FCREQ and NVME_ABTS requests */
2136062306a36Sopenharmony_ci	if (pwqe->cmd_flag & (LPFC_IO_NVME | LPFC_IO_FCP | LPFC_IO_CMF)) {
2136162306a36Sopenharmony_ci		/* Get the IO distribution (hba_wqidx) for WQ assignment. */
2136262306a36Sopenharmony_ci		wq = qp->io_wq;
2136362306a36Sopenharmony_ci		pring = wq->pring;
2136462306a36Sopenharmony_ci
2136562306a36Sopenharmony_ci		bf_set(wqe_cqid, &wqe->generic.wqe_com, qp->io_cq_map);
2136662306a36Sopenharmony_ci
2136762306a36Sopenharmony_ci		lpfc_qp_spin_lock_irqsave(&pring->ring_lock, iflags,
2136862306a36Sopenharmony_ci					  qp, wq_access);
2136962306a36Sopenharmony_ci		ret = lpfc_sli4_wq_put(wq, wqe);
2137062306a36Sopenharmony_ci		if (ret) {
2137162306a36Sopenharmony_ci			spin_unlock_irqrestore(&pring->ring_lock, iflags);
2137262306a36Sopenharmony_ci			return ret;
2137362306a36Sopenharmony_ci		}
2137462306a36Sopenharmony_ci		lpfc_sli_ringtxcmpl_put(phba, pring, pwqe);
2137562306a36Sopenharmony_ci		spin_unlock_irqrestore(&pring->ring_lock, iflags);
2137662306a36Sopenharmony_ci
2137762306a36Sopenharmony_ci		lpfc_sli4_poll_eq(qp->hba_eq);
2137862306a36Sopenharmony_ci		return 0;
2137962306a36Sopenharmony_ci	}
2138062306a36Sopenharmony_ci
2138162306a36Sopenharmony_ci	/* NVMET requests */
2138262306a36Sopenharmony_ci	if (pwqe->cmd_flag & LPFC_IO_NVMET) {
2138362306a36Sopenharmony_ci		/* Get the IO distribution (hba_wqidx) for WQ assignment. */
2138462306a36Sopenharmony_ci		wq = qp->io_wq;
2138562306a36Sopenharmony_ci		pring = wq->pring;
2138662306a36Sopenharmony_ci
2138762306a36Sopenharmony_ci		ctxp = pwqe->context_un.axchg;
2138862306a36Sopenharmony_ci		sglq = ctxp->ctxbuf->sglq;
2138962306a36Sopenharmony_ci		if (pwqe->sli4_xritag ==  NO_XRI) {
2139062306a36Sopenharmony_ci			pwqe->sli4_lxritag = sglq->sli4_lxritag;
2139162306a36Sopenharmony_ci			pwqe->sli4_xritag = sglq->sli4_xritag;
2139262306a36Sopenharmony_ci		}
2139362306a36Sopenharmony_ci		bf_set(wqe_xri_tag, &pwqe->wqe.xmit_bls_rsp.wqe_com,
2139462306a36Sopenharmony_ci		       pwqe->sli4_xritag);
2139562306a36Sopenharmony_ci		bf_set(wqe_cqid, &wqe->generic.wqe_com, qp->io_cq_map);
2139662306a36Sopenharmony_ci
2139762306a36Sopenharmony_ci		lpfc_qp_spin_lock_irqsave(&pring->ring_lock, iflags,
2139862306a36Sopenharmony_ci					  qp, wq_access);
2139962306a36Sopenharmony_ci		ret = lpfc_sli4_wq_put(wq, wqe);
2140062306a36Sopenharmony_ci		if (ret) {
2140162306a36Sopenharmony_ci			spin_unlock_irqrestore(&pring->ring_lock, iflags);
2140262306a36Sopenharmony_ci			return ret;
2140362306a36Sopenharmony_ci		}
2140462306a36Sopenharmony_ci		lpfc_sli_ringtxcmpl_put(phba, pring, pwqe);
2140562306a36Sopenharmony_ci		spin_unlock_irqrestore(&pring->ring_lock, iflags);
2140662306a36Sopenharmony_ci
2140762306a36Sopenharmony_ci		lpfc_sli4_poll_eq(qp->hba_eq);
2140862306a36Sopenharmony_ci		return 0;
2140962306a36Sopenharmony_ci	}
2141062306a36Sopenharmony_ci	return WQE_ERROR;
2141162306a36Sopenharmony_ci}
2141262306a36Sopenharmony_ci
2141362306a36Sopenharmony_ci/**
2141462306a36Sopenharmony_ci * lpfc_sli4_issue_abort_iotag - SLI-4 WQE init & issue for the Abort
2141562306a36Sopenharmony_ci * @phba: Pointer to HBA context object.
2141662306a36Sopenharmony_ci * @cmdiocb: Pointer to driver command iocb object.
2141762306a36Sopenharmony_ci * @cmpl: completion function.
2141862306a36Sopenharmony_ci *
2141962306a36Sopenharmony_ci * Fill the appropriate fields for the abort WQE and call
2142062306a36Sopenharmony_ci * internal routine lpfc_sli4_issue_wqe to send the WQE
2142162306a36Sopenharmony_ci * This function is called with hbalock held and no ring_lock held.
2142262306a36Sopenharmony_ci *
2142362306a36Sopenharmony_ci * RETURNS 0 - SUCCESS
2142462306a36Sopenharmony_ci **/
2142562306a36Sopenharmony_ci
2142662306a36Sopenharmony_ciint
2142762306a36Sopenharmony_cilpfc_sli4_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
2142862306a36Sopenharmony_ci			    void *cmpl)
2142962306a36Sopenharmony_ci{
2143062306a36Sopenharmony_ci	struct lpfc_vport *vport = cmdiocb->vport;
2143162306a36Sopenharmony_ci	struct lpfc_iocbq *abtsiocb = NULL;
2143262306a36Sopenharmony_ci	union lpfc_wqe128 *abtswqe;
2143362306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_cmd;
2143462306a36Sopenharmony_ci	int retval = IOCB_ERROR;
2143562306a36Sopenharmony_ci	u16 xritag = cmdiocb->sli4_xritag;
2143662306a36Sopenharmony_ci
2143762306a36Sopenharmony_ci	/*
2143862306a36Sopenharmony_ci	 * The scsi command can not be in txq and it is in flight because the
2143962306a36Sopenharmony_ci	 * pCmd is still pointing at the SCSI command we have to abort. There
2144062306a36Sopenharmony_ci	 * is no need to search the txcmplq. Just send an abort to the FW.
2144162306a36Sopenharmony_ci	 */
2144262306a36Sopenharmony_ci
2144362306a36Sopenharmony_ci	abtsiocb = __lpfc_sli_get_iocbq(phba);
2144462306a36Sopenharmony_ci	if (!abtsiocb)
2144562306a36Sopenharmony_ci		return WQE_NORESOURCE;
2144662306a36Sopenharmony_ci
2144762306a36Sopenharmony_ci	/* Indicate the IO is being aborted by the driver. */
2144862306a36Sopenharmony_ci	cmdiocb->cmd_flag |= LPFC_DRIVER_ABORTED;
2144962306a36Sopenharmony_ci
2145062306a36Sopenharmony_ci	abtswqe = &abtsiocb->wqe;
2145162306a36Sopenharmony_ci	memset(abtswqe, 0, sizeof(*abtswqe));
2145262306a36Sopenharmony_ci
2145362306a36Sopenharmony_ci	if (!lpfc_is_link_up(phba) || (phba->link_flag & LS_EXTERNAL_LOOPBACK))
2145462306a36Sopenharmony_ci		bf_set(abort_cmd_ia, &abtswqe->abort_cmd, 1);
2145562306a36Sopenharmony_ci	bf_set(abort_cmd_criteria, &abtswqe->abort_cmd, T_XRI_TAG);
2145662306a36Sopenharmony_ci	abtswqe->abort_cmd.rsrvd5 = 0;
2145762306a36Sopenharmony_ci	abtswqe->abort_cmd.wqe_com.abort_tag = xritag;
2145862306a36Sopenharmony_ci	bf_set(wqe_reqtag, &abtswqe->abort_cmd.wqe_com, abtsiocb->iotag);
2145962306a36Sopenharmony_ci	bf_set(wqe_cmnd, &abtswqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX);
2146062306a36Sopenharmony_ci	bf_set(wqe_xri_tag, &abtswqe->generic.wqe_com, 0);
2146162306a36Sopenharmony_ci	bf_set(wqe_qosd, &abtswqe->abort_cmd.wqe_com, 1);
2146262306a36Sopenharmony_ci	bf_set(wqe_lenloc, &abtswqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE);
2146362306a36Sopenharmony_ci	bf_set(wqe_cmd_type, &abtswqe->abort_cmd.wqe_com, OTHER_COMMAND);
2146462306a36Sopenharmony_ci
2146562306a36Sopenharmony_ci	/* ABTS WQE must go to the same WQ as the WQE to be aborted */
2146662306a36Sopenharmony_ci	abtsiocb->hba_wqidx = cmdiocb->hba_wqidx;
2146762306a36Sopenharmony_ci	abtsiocb->cmd_flag |= LPFC_USE_FCPWQIDX;
2146862306a36Sopenharmony_ci	if (cmdiocb->cmd_flag & LPFC_IO_FCP)
2146962306a36Sopenharmony_ci		abtsiocb->cmd_flag |= LPFC_IO_FCP;
2147062306a36Sopenharmony_ci	if (cmdiocb->cmd_flag & LPFC_IO_NVME)
2147162306a36Sopenharmony_ci		abtsiocb->cmd_flag |= LPFC_IO_NVME;
2147262306a36Sopenharmony_ci	if (cmdiocb->cmd_flag & LPFC_IO_FOF)
2147362306a36Sopenharmony_ci		abtsiocb->cmd_flag |= LPFC_IO_FOF;
2147462306a36Sopenharmony_ci	abtsiocb->vport = vport;
2147562306a36Sopenharmony_ci	abtsiocb->cmd_cmpl = cmpl;
2147662306a36Sopenharmony_ci
2147762306a36Sopenharmony_ci	lpfc_cmd = container_of(cmdiocb, struct lpfc_io_buf, cur_iocbq);
2147862306a36Sopenharmony_ci	retval = lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, abtsiocb);
2147962306a36Sopenharmony_ci
2148062306a36Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI | LOG_NVME_ABTS | LOG_FCP,
2148162306a36Sopenharmony_ci			 "0359 Abort xri x%x, original iotag x%x, "
2148262306a36Sopenharmony_ci			 "abort cmd iotag x%x retval x%x\n",
2148362306a36Sopenharmony_ci			 xritag, cmdiocb->iotag, abtsiocb->iotag, retval);
2148462306a36Sopenharmony_ci
2148562306a36Sopenharmony_ci	if (retval) {
2148662306a36Sopenharmony_ci		cmdiocb->cmd_flag &= ~LPFC_DRIVER_ABORTED;
2148762306a36Sopenharmony_ci		__lpfc_sli_release_iocbq(phba, abtsiocb);
2148862306a36Sopenharmony_ci	}
2148962306a36Sopenharmony_ci
2149062306a36Sopenharmony_ci	return retval;
2149162306a36Sopenharmony_ci}
2149262306a36Sopenharmony_ci
2149362306a36Sopenharmony_ci#ifdef LPFC_MXP_STAT
2149462306a36Sopenharmony_ci/**
2149562306a36Sopenharmony_ci * lpfc_snapshot_mxp - Snapshot pbl, pvt and busy count
2149662306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2149762306a36Sopenharmony_ci * @hwqid: belong to which HWQ.
2149862306a36Sopenharmony_ci *
2149962306a36Sopenharmony_ci * The purpose of this routine is to take a snapshot of pbl, pvt and busy count
2150062306a36Sopenharmony_ci * 15 seconds after a test case is running.
2150162306a36Sopenharmony_ci *
2150262306a36Sopenharmony_ci * The user should call lpfc_debugfs_multixripools_write before running a test
2150362306a36Sopenharmony_ci * case to clear stat_snapshot_taken. Then the user starts a test case. During
2150462306a36Sopenharmony_ci * test case is running, stat_snapshot_taken is incremented by 1 every time when
2150562306a36Sopenharmony_ci * this routine is called from heartbeat timer. When stat_snapshot_taken is
2150662306a36Sopenharmony_ci * equal to LPFC_MXP_SNAPSHOT_TAKEN, a snapshot is taken.
2150762306a36Sopenharmony_ci **/
2150862306a36Sopenharmony_civoid lpfc_snapshot_mxp(struct lpfc_hba *phba, u32 hwqid)
2150962306a36Sopenharmony_ci{
2151062306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *qp;
2151162306a36Sopenharmony_ci	struct lpfc_multixri_pool *multixri_pool;
2151262306a36Sopenharmony_ci	struct lpfc_pvt_pool *pvt_pool;
2151362306a36Sopenharmony_ci	struct lpfc_pbl_pool *pbl_pool;
2151462306a36Sopenharmony_ci	u32 txcmplq_cnt;
2151562306a36Sopenharmony_ci
2151662306a36Sopenharmony_ci	qp = &phba->sli4_hba.hdwq[hwqid];
2151762306a36Sopenharmony_ci	multixri_pool = qp->p_multixri_pool;
2151862306a36Sopenharmony_ci	if (!multixri_pool)
2151962306a36Sopenharmony_ci		return;
2152062306a36Sopenharmony_ci
2152162306a36Sopenharmony_ci	if (multixri_pool->stat_snapshot_taken == LPFC_MXP_SNAPSHOT_TAKEN) {
2152262306a36Sopenharmony_ci		pvt_pool = &qp->p_multixri_pool->pvt_pool;
2152362306a36Sopenharmony_ci		pbl_pool = &qp->p_multixri_pool->pbl_pool;
2152462306a36Sopenharmony_ci		txcmplq_cnt = qp->io_wq->pring->txcmplq_cnt;
2152562306a36Sopenharmony_ci
2152662306a36Sopenharmony_ci		multixri_pool->stat_pbl_count = pbl_pool->count;
2152762306a36Sopenharmony_ci		multixri_pool->stat_pvt_count = pvt_pool->count;
2152862306a36Sopenharmony_ci		multixri_pool->stat_busy_count = txcmplq_cnt;
2152962306a36Sopenharmony_ci	}
2153062306a36Sopenharmony_ci
2153162306a36Sopenharmony_ci	multixri_pool->stat_snapshot_taken++;
2153262306a36Sopenharmony_ci}
2153362306a36Sopenharmony_ci#endif
2153462306a36Sopenharmony_ci
2153562306a36Sopenharmony_ci/**
2153662306a36Sopenharmony_ci * lpfc_adjust_pvt_pool_count - Adjust private pool count
2153762306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2153862306a36Sopenharmony_ci * @hwqid: belong to which HWQ.
2153962306a36Sopenharmony_ci *
2154062306a36Sopenharmony_ci * This routine moves some XRIs from private to public pool when private pool
2154162306a36Sopenharmony_ci * is not busy.
2154262306a36Sopenharmony_ci **/
2154362306a36Sopenharmony_civoid lpfc_adjust_pvt_pool_count(struct lpfc_hba *phba, u32 hwqid)
2154462306a36Sopenharmony_ci{
2154562306a36Sopenharmony_ci	struct lpfc_multixri_pool *multixri_pool;
2154662306a36Sopenharmony_ci	u32 io_req_count;
2154762306a36Sopenharmony_ci	u32 prev_io_req_count;
2154862306a36Sopenharmony_ci
2154962306a36Sopenharmony_ci	multixri_pool = phba->sli4_hba.hdwq[hwqid].p_multixri_pool;
2155062306a36Sopenharmony_ci	if (!multixri_pool)
2155162306a36Sopenharmony_ci		return;
2155262306a36Sopenharmony_ci	io_req_count = multixri_pool->io_req_count;
2155362306a36Sopenharmony_ci	prev_io_req_count = multixri_pool->prev_io_req_count;
2155462306a36Sopenharmony_ci
2155562306a36Sopenharmony_ci	if (prev_io_req_count != io_req_count) {
2155662306a36Sopenharmony_ci		/* Private pool is busy */
2155762306a36Sopenharmony_ci		multixri_pool->prev_io_req_count = io_req_count;
2155862306a36Sopenharmony_ci	} else {
2155962306a36Sopenharmony_ci		/* Private pool is not busy.
2156062306a36Sopenharmony_ci		 * Move XRIs from private to public pool.
2156162306a36Sopenharmony_ci		 */
2156262306a36Sopenharmony_ci		lpfc_move_xri_pvt_to_pbl(phba, hwqid);
2156362306a36Sopenharmony_ci	}
2156462306a36Sopenharmony_ci}
2156562306a36Sopenharmony_ci
2156662306a36Sopenharmony_ci/**
2156762306a36Sopenharmony_ci * lpfc_adjust_high_watermark - Adjust high watermark
2156862306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2156962306a36Sopenharmony_ci * @hwqid: belong to which HWQ.
2157062306a36Sopenharmony_ci *
2157162306a36Sopenharmony_ci * This routine sets high watermark as number of outstanding XRIs,
2157262306a36Sopenharmony_ci * but make sure the new value is between xri_limit/2 and xri_limit.
2157362306a36Sopenharmony_ci **/
2157462306a36Sopenharmony_civoid lpfc_adjust_high_watermark(struct lpfc_hba *phba, u32 hwqid)
2157562306a36Sopenharmony_ci{
2157662306a36Sopenharmony_ci	u32 new_watermark;
2157762306a36Sopenharmony_ci	u32 watermark_max;
2157862306a36Sopenharmony_ci	u32 watermark_min;
2157962306a36Sopenharmony_ci	u32 xri_limit;
2158062306a36Sopenharmony_ci	u32 txcmplq_cnt;
2158162306a36Sopenharmony_ci	u32 abts_io_bufs;
2158262306a36Sopenharmony_ci	struct lpfc_multixri_pool *multixri_pool;
2158362306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *qp;
2158462306a36Sopenharmony_ci
2158562306a36Sopenharmony_ci	qp = &phba->sli4_hba.hdwq[hwqid];
2158662306a36Sopenharmony_ci	multixri_pool = qp->p_multixri_pool;
2158762306a36Sopenharmony_ci	if (!multixri_pool)
2158862306a36Sopenharmony_ci		return;
2158962306a36Sopenharmony_ci	xri_limit = multixri_pool->xri_limit;
2159062306a36Sopenharmony_ci
2159162306a36Sopenharmony_ci	watermark_max = xri_limit;
2159262306a36Sopenharmony_ci	watermark_min = xri_limit / 2;
2159362306a36Sopenharmony_ci
2159462306a36Sopenharmony_ci	txcmplq_cnt = qp->io_wq->pring->txcmplq_cnt;
2159562306a36Sopenharmony_ci	abts_io_bufs = qp->abts_scsi_io_bufs;
2159662306a36Sopenharmony_ci	abts_io_bufs += qp->abts_nvme_io_bufs;
2159762306a36Sopenharmony_ci
2159862306a36Sopenharmony_ci	new_watermark = txcmplq_cnt + abts_io_bufs;
2159962306a36Sopenharmony_ci	new_watermark = min(watermark_max, new_watermark);
2160062306a36Sopenharmony_ci	new_watermark = max(watermark_min, new_watermark);
2160162306a36Sopenharmony_ci	multixri_pool->pvt_pool.high_watermark = new_watermark;
2160262306a36Sopenharmony_ci
2160362306a36Sopenharmony_ci#ifdef LPFC_MXP_STAT
2160462306a36Sopenharmony_ci	multixri_pool->stat_max_hwm = max(multixri_pool->stat_max_hwm,
2160562306a36Sopenharmony_ci					  new_watermark);
2160662306a36Sopenharmony_ci#endif
2160762306a36Sopenharmony_ci}
2160862306a36Sopenharmony_ci
2160962306a36Sopenharmony_ci/**
2161062306a36Sopenharmony_ci * lpfc_move_xri_pvt_to_pbl - Move some XRIs from private to public pool
2161162306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2161262306a36Sopenharmony_ci * @hwqid: belong to which HWQ.
2161362306a36Sopenharmony_ci *
2161462306a36Sopenharmony_ci * This routine is called from hearbeat timer when pvt_pool is idle.
2161562306a36Sopenharmony_ci * All free XRIs are moved from private to public pool on hwqid with 2 steps.
2161662306a36Sopenharmony_ci * The first step moves (all - low_watermark) amount of XRIs.
2161762306a36Sopenharmony_ci * The second step moves the rest of XRIs.
2161862306a36Sopenharmony_ci **/
2161962306a36Sopenharmony_civoid lpfc_move_xri_pvt_to_pbl(struct lpfc_hba *phba, u32 hwqid)
2162062306a36Sopenharmony_ci{
2162162306a36Sopenharmony_ci	struct lpfc_pbl_pool *pbl_pool;
2162262306a36Sopenharmony_ci	struct lpfc_pvt_pool *pvt_pool;
2162362306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *qp;
2162462306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_ncmd;
2162562306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_ncmd_next;
2162662306a36Sopenharmony_ci	unsigned long iflag;
2162762306a36Sopenharmony_ci	struct list_head tmp_list;
2162862306a36Sopenharmony_ci	u32 tmp_count;
2162962306a36Sopenharmony_ci
2163062306a36Sopenharmony_ci	qp = &phba->sli4_hba.hdwq[hwqid];
2163162306a36Sopenharmony_ci	pbl_pool = &qp->p_multixri_pool->pbl_pool;
2163262306a36Sopenharmony_ci	pvt_pool = &qp->p_multixri_pool->pvt_pool;
2163362306a36Sopenharmony_ci	tmp_count = 0;
2163462306a36Sopenharmony_ci
2163562306a36Sopenharmony_ci	lpfc_qp_spin_lock_irqsave(&pbl_pool->lock, iflag, qp, mv_to_pub_pool);
2163662306a36Sopenharmony_ci	lpfc_qp_spin_lock(&pvt_pool->lock, qp, mv_from_pvt_pool);
2163762306a36Sopenharmony_ci
2163862306a36Sopenharmony_ci	if (pvt_pool->count > pvt_pool->low_watermark) {
2163962306a36Sopenharmony_ci		/* Step 1: move (all - low_watermark) from pvt_pool
2164062306a36Sopenharmony_ci		 * to pbl_pool
2164162306a36Sopenharmony_ci		 */
2164262306a36Sopenharmony_ci
2164362306a36Sopenharmony_ci		/* Move low watermark of bufs from pvt_pool to tmp_list */
2164462306a36Sopenharmony_ci		INIT_LIST_HEAD(&tmp_list);
2164562306a36Sopenharmony_ci		list_for_each_entry_safe(lpfc_ncmd, lpfc_ncmd_next,
2164662306a36Sopenharmony_ci					 &pvt_pool->list, list) {
2164762306a36Sopenharmony_ci			list_move_tail(&lpfc_ncmd->list, &tmp_list);
2164862306a36Sopenharmony_ci			tmp_count++;
2164962306a36Sopenharmony_ci			if (tmp_count >= pvt_pool->low_watermark)
2165062306a36Sopenharmony_ci				break;
2165162306a36Sopenharmony_ci		}
2165262306a36Sopenharmony_ci
2165362306a36Sopenharmony_ci		/* Move all bufs from pvt_pool to pbl_pool */
2165462306a36Sopenharmony_ci		list_splice_init(&pvt_pool->list, &pbl_pool->list);
2165562306a36Sopenharmony_ci
2165662306a36Sopenharmony_ci		/* Move all bufs from tmp_list to pvt_pool */
2165762306a36Sopenharmony_ci		list_splice(&tmp_list, &pvt_pool->list);
2165862306a36Sopenharmony_ci
2165962306a36Sopenharmony_ci		pbl_pool->count += (pvt_pool->count - tmp_count);
2166062306a36Sopenharmony_ci		pvt_pool->count = tmp_count;
2166162306a36Sopenharmony_ci	} else {
2166262306a36Sopenharmony_ci		/* Step 2: move the rest from pvt_pool to pbl_pool */
2166362306a36Sopenharmony_ci		list_splice_init(&pvt_pool->list, &pbl_pool->list);
2166462306a36Sopenharmony_ci		pbl_pool->count += pvt_pool->count;
2166562306a36Sopenharmony_ci		pvt_pool->count = 0;
2166662306a36Sopenharmony_ci	}
2166762306a36Sopenharmony_ci
2166862306a36Sopenharmony_ci	spin_unlock(&pvt_pool->lock);
2166962306a36Sopenharmony_ci	spin_unlock_irqrestore(&pbl_pool->lock, iflag);
2167062306a36Sopenharmony_ci}
2167162306a36Sopenharmony_ci
2167262306a36Sopenharmony_ci/**
2167362306a36Sopenharmony_ci * _lpfc_move_xri_pbl_to_pvt - Move some XRIs from public to private pool
2167462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure
2167562306a36Sopenharmony_ci * @qp: pointer to HDW queue
2167662306a36Sopenharmony_ci * @pbl_pool: specified public free XRI pool
2167762306a36Sopenharmony_ci * @pvt_pool: specified private free XRI pool
2167862306a36Sopenharmony_ci * @count: number of XRIs to move
2167962306a36Sopenharmony_ci *
2168062306a36Sopenharmony_ci * This routine tries to move some free common bufs from the specified pbl_pool
2168162306a36Sopenharmony_ci * to the specified pvt_pool. It might move less than count XRIs if there's not
2168262306a36Sopenharmony_ci * enough in public pool.
2168362306a36Sopenharmony_ci *
2168462306a36Sopenharmony_ci * Return:
2168562306a36Sopenharmony_ci *   true - if XRIs are successfully moved from the specified pbl_pool to the
2168662306a36Sopenharmony_ci *          specified pvt_pool
2168762306a36Sopenharmony_ci *   false - if the specified pbl_pool is empty or locked by someone else
2168862306a36Sopenharmony_ci **/
2168962306a36Sopenharmony_cistatic bool
2169062306a36Sopenharmony_ci_lpfc_move_xri_pbl_to_pvt(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp,
2169162306a36Sopenharmony_ci			  struct lpfc_pbl_pool *pbl_pool,
2169262306a36Sopenharmony_ci			  struct lpfc_pvt_pool *pvt_pool, u32 count)
2169362306a36Sopenharmony_ci{
2169462306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_ncmd;
2169562306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_ncmd_next;
2169662306a36Sopenharmony_ci	unsigned long iflag;
2169762306a36Sopenharmony_ci	int ret;
2169862306a36Sopenharmony_ci
2169962306a36Sopenharmony_ci	ret = spin_trylock_irqsave(&pbl_pool->lock, iflag);
2170062306a36Sopenharmony_ci	if (ret) {
2170162306a36Sopenharmony_ci		if (pbl_pool->count) {
2170262306a36Sopenharmony_ci			/* Move a batch of XRIs from public to private pool */
2170362306a36Sopenharmony_ci			lpfc_qp_spin_lock(&pvt_pool->lock, qp, mv_to_pvt_pool);
2170462306a36Sopenharmony_ci			list_for_each_entry_safe(lpfc_ncmd,
2170562306a36Sopenharmony_ci						 lpfc_ncmd_next,
2170662306a36Sopenharmony_ci						 &pbl_pool->list,
2170762306a36Sopenharmony_ci						 list) {
2170862306a36Sopenharmony_ci				list_move_tail(&lpfc_ncmd->list,
2170962306a36Sopenharmony_ci					       &pvt_pool->list);
2171062306a36Sopenharmony_ci				pvt_pool->count++;
2171162306a36Sopenharmony_ci				pbl_pool->count--;
2171262306a36Sopenharmony_ci				count--;
2171362306a36Sopenharmony_ci				if (count == 0)
2171462306a36Sopenharmony_ci					break;
2171562306a36Sopenharmony_ci			}
2171662306a36Sopenharmony_ci
2171762306a36Sopenharmony_ci			spin_unlock(&pvt_pool->lock);
2171862306a36Sopenharmony_ci			spin_unlock_irqrestore(&pbl_pool->lock, iflag);
2171962306a36Sopenharmony_ci			return true;
2172062306a36Sopenharmony_ci		}
2172162306a36Sopenharmony_ci		spin_unlock_irqrestore(&pbl_pool->lock, iflag);
2172262306a36Sopenharmony_ci	}
2172362306a36Sopenharmony_ci
2172462306a36Sopenharmony_ci	return false;
2172562306a36Sopenharmony_ci}
2172662306a36Sopenharmony_ci
2172762306a36Sopenharmony_ci/**
2172862306a36Sopenharmony_ci * lpfc_move_xri_pbl_to_pvt - Move some XRIs from public to private pool
2172962306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2173062306a36Sopenharmony_ci * @hwqid: belong to which HWQ.
2173162306a36Sopenharmony_ci * @count: number of XRIs to move
2173262306a36Sopenharmony_ci *
2173362306a36Sopenharmony_ci * This routine tries to find some free common bufs in one of public pools with
2173462306a36Sopenharmony_ci * Round Robin method. The search always starts from local hwqid, then the next
2173562306a36Sopenharmony_ci * HWQ which was found last time (rrb_next_hwqid). Once a public pool is found,
2173662306a36Sopenharmony_ci * a batch of free common bufs are moved to private pool on hwqid.
2173762306a36Sopenharmony_ci * It might move less than count XRIs if there's not enough in public pool.
2173862306a36Sopenharmony_ci **/
2173962306a36Sopenharmony_civoid lpfc_move_xri_pbl_to_pvt(struct lpfc_hba *phba, u32 hwqid, u32 count)
2174062306a36Sopenharmony_ci{
2174162306a36Sopenharmony_ci	struct lpfc_multixri_pool *multixri_pool;
2174262306a36Sopenharmony_ci	struct lpfc_multixri_pool *next_multixri_pool;
2174362306a36Sopenharmony_ci	struct lpfc_pvt_pool *pvt_pool;
2174462306a36Sopenharmony_ci	struct lpfc_pbl_pool *pbl_pool;
2174562306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *qp;
2174662306a36Sopenharmony_ci	u32 next_hwqid;
2174762306a36Sopenharmony_ci	u32 hwq_count;
2174862306a36Sopenharmony_ci	int ret;
2174962306a36Sopenharmony_ci
2175062306a36Sopenharmony_ci	qp = &phba->sli4_hba.hdwq[hwqid];
2175162306a36Sopenharmony_ci	multixri_pool = qp->p_multixri_pool;
2175262306a36Sopenharmony_ci	pvt_pool = &multixri_pool->pvt_pool;
2175362306a36Sopenharmony_ci	pbl_pool = &multixri_pool->pbl_pool;
2175462306a36Sopenharmony_ci
2175562306a36Sopenharmony_ci	/* Check if local pbl_pool is available */
2175662306a36Sopenharmony_ci	ret = _lpfc_move_xri_pbl_to_pvt(phba, qp, pbl_pool, pvt_pool, count);
2175762306a36Sopenharmony_ci	if (ret) {
2175862306a36Sopenharmony_ci#ifdef LPFC_MXP_STAT
2175962306a36Sopenharmony_ci		multixri_pool->local_pbl_hit_count++;
2176062306a36Sopenharmony_ci#endif
2176162306a36Sopenharmony_ci		return;
2176262306a36Sopenharmony_ci	}
2176362306a36Sopenharmony_ci
2176462306a36Sopenharmony_ci	hwq_count = phba->cfg_hdw_queue;
2176562306a36Sopenharmony_ci
2176662306a36Sopenharmony_ci	/* Get the next hwqid which was found last time */
2176762306a36Sopenharmony_ci	next_hwqid = multixri_pool->rrb_next_hwqid;
2176862306a36Sopenharmony_ci
2176962306a36Sopenharmony_ci	do {
2177062306a36Sopenharmony_ci		/* Go to next hwq */
2177162306a36Sopenharmony_ci		next_hwqid = (next_hwqid + 1) % hwq_count;
2177262306a36Sopenharmony_ci
2177362306a36Sopenharmony_ci		next_multixri_pool =
2177462306a36Sopenharmony_ci			phba->sli4_hba.hdwq[next_hwqid].p_multixri_pool;
2177562306a36Sopenharmony_ci		pbl_pool = &next_multixri_pool->pbl_pool;
2177662306a36Sopenharmony_ci
2177762306a36Sopenharmony_ci		/* Check if the public free xri pool is available */
2177862306a36Sopenharmony_ci		ret = _lpfc_move_xri_pbl_to_pvt(
2177962306a36Sopenharmony_ci			phba, qp, pbl_pool, pvt_pool, count);
2178062306a36Sopenharmony_ci
2178162306a36Sopenharmony_ci		/* Exit while-loop if success or all hwqid are checked */
2178262306a36Sopenharmony_ci	} while (!ret && next_hwqid != multixri_pool->rrb_next_hwqid);
2178362306a36Sopenharmony_ci
2178462306a36Sopenharmony_ci	/* Starting point for the next time */
2178562306a36Sopenharmony_ci	multixri_pool->rrb_next_hwqid = next_hwqid;
2178662306a36Sopenharmony_ci
2178762306a36Sopenharmony_ci	if (!ret) {
2178862306a36Sopenharmony_ci		/* stats: all public pools are empty*/
2178962306a36Sopenharmony_ci		multixri_pool->pbl_empty_count++;
2179062306a36Sopenharmony_ci	}
2179162306a36Sopenharmony_ci
2179262306a36Sopenharmony_ci#ifdef LPFC_MXP_STAT
2179362306a36Sopenharmony_ci	if (ret) {
2179462306a36Sopenharmony_ci		if (next_hwqid == hwqid)
2179562306a36Sopenharmony_ci			multixri_pool->local_pbl_hit_count++;
2179662306a36Sopenharmony_ci		else
2179762306a36Sopenharmony_ci			multixri_pool->other_pbl_hit_count++;
2179862306a36Sopenharmony_ci	}
2179962306a36Sopenharmony_ci#endif
2180062306a36Sopenharmony_ci}
2180162306a36Sopenharmony_ci
2180262306a36Sopenharmony_ci/**
2180362306a36Sopenharmony_ci * lpfc_keep_pvt_pool_above_lowwm - Keep pvt_pool above low watermark
2180462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2180562306a36Sopenharmony_ci * @hwqid: belong to which HWQ.
2180662306a36Sopenharmony_ci *
2180762306a36Sopenharmony_ci * This routine get a batch of XRIs from pbl_pool if pvt_pool is less than
2180862306a36Sopenharmony_ci * low watermark.
2180962306a36Sopenharmony_ci **/
2181062306a36Sopenharmony_civoid lpfc_keep_pvt_pool_above_lowwm(struct lpfc_hba *phba, u32 hwqid)
2181162306a36Sopenharmony_ci{
2181262306a36Sopenharmony_ci	struct lpfc_multixri_pool *multixri_pool;
2181362306a36Sopenharmony_ci	struct lpfc_pvt_pool *pvt_pool;
2181462306a36Sopenharmony_ci
2181562306a36Sopenharmony_ci	multixri_pool = phba->sli4_hba.hdwq[hwqid].p_multixri_pool;
2181662306a36Sopenharmony_ci	pvt_pool = &multixri_pool->pvt_pool;
2181762306a36Sopenharmony_ci
2181862306a36Sopenharmony_ci	if (pvt_pool->count < pvt_pool->low_watermark)
2181962306a36Sopenharmony_ci		lpfc_move_xri_pbl_to_pvt(phba, hwqid, XRI_BATCH);
2182062306a36Sopenharmony_ci}
2182162306a36Sopenharmony_ci
2182262306a36Sopenharmony_ci/**
2182362306a36Sopenharmony_ci * lpfc_release_io_buf - Return one IO buf back to free pool
2182462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2182562306a36Sopenharmony_ci * @lpfc_ncmd: IO buf to be returned.
2182662306a36Sopenharmony_ci * @qp: belong to which HWQ.
2182762306a36Sopenharmony_ci *
2182862306a36Sopenharmony_ci * This routine returns one IO buf back to free pool. If this is an urgent IO,
2182962306a36Sopenharmony_ci * the IO buf is returned to expedite pool. If cfg_xri_rebalancing==1,
2183062306a36Sopenharmony_ci * the IO buf is returned to pbl_pool or pvt_pool based on watermark and
2183162306a36Sopenharmony_ci * xri_limit.  If cfg_xri_rebalancing==0, the IO buf is returned to
2183262306a36Sopenharmony_ci * lpfc_io_buf_list_put.
2183362306a36Sopenharmony_ci **/
2183462306a36Sopenharmony_civoid lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd,
2183562306a36Sopenharmony_ci			 struct lpfc_sli4_hdw_queue *qp)
2183662306a36Sopenharmony_ci{
2183762306a36Sopenharmony_ci	unsigned long iflag;
2183862306a36Sopenharmony_ci	struct lpfc_pbl_pool *pbl_pool;
2183962306a36Sopenharmony_ci	struct lpfc_pvt_pool *pvt_pool;
2184062306a36Sopenharmony_ci	struct lpfc_epd_pool *epd_pool;
2184162306a36Sopenharmony_ci	u32 txcmplq_cnt;
2184262306a36Sopenharmony_ci	u32 xri_owned;
2184362306a36Sopenharmony_ci	u32 xri_limit;
2184462306a36Sopenharmony_ci	u32 abts_io_bufs;
2184562306a36Sopenharmony_ci
2184662306a36Sopenharmony_ci	/* MUST zero fields if buffer is reused by another protocol */
2184762306a36Sopenharmony_ci	lpfc_ncmd->nvmeCmd = NULL;
2184862306a36Sopenharmony_ci	lpfc_ncmd->cur_iocbq.cmd_cmpl = NULL;
2184962306a36Sopenharmony_ci
2185062306a36Sopenharmony_ci	if (phba->cfg_xpsgl && !phba->nvmet_support &&
2185162306a36Sopenharmony_ci	    !list_empty(&lpfc_ncmd->dma_sgl_xtra_list))
2185262306a36Sopenharmony_ci		lpfc_put_sgl_per_hdwq(phba, lpfc_ncmd);
2185362306a36Sopenharmony_ci
2185462306a36Sopenharmony_ci	if (!list_empty(&lpfc_ncmd->dma_cmd_rsp_list))
2185562306a36Sopenharmony_ci		lpfc_put_cmd_rsp_buf_per_hdwq(phba, lpfc_ncmd);
2185662306a36Sopenharmony_ci
2185762306a36Sopenharmony_ci	if (phba->cfg_xri_rebalancing) {
2185862306a36Sopenharmony_ci		if (lpfc_ncmd->expedite) {
2185962306a36Sopenharmony_ci			/* Return to expedite pool */
2186062306a36Sopenharmony_ci			epd_pool = &phba->epd_pool;
2186162306a36Sopenharmony_ci			spin_lock_irqsave(&epd_pool->lock, iflag);
2186262306a36Sopenharmony_ci			list_add_tail(&lpfc_ncmd->list, &epd_pool->list);
2186362306a36Sopenharmony_ci			epd_pool->count++;
2186462306a36Sopenharmony_ci			spin_unlock_irqrestore(&epd_pool->lock, iflag);
2186562306a36Sopenharmony_ci			return;
2186662306a36Sopenharmony_ci		}
2186762306a36Sopenharmony_ci
2186862306a36Sopenharmony_ci		/* Avoid invalid access if an IO sneaks in and is being rejected
2186962306a36Sopenharmony_ci		 * just _after_ xri pools are destroyed in lpfc_offline.
2187062306a36Sopenharmony_ci		 * Nothing much can be done at this point.
2187162306a36Sopenharmony_ci		 */
2187262306a36Sopenharmony_ci		if (!qp->p_multixri_pool)
2187362306a36Sopenharmony_ci			return;
2187462306a36Sopenharmony_ci
2187562306a36Sopenharmony_ci		pbl_pool = &qp->p_multixri_pool->pbl_pool;
2187662306a36Sopenharmony_ci		pvt_pool = &qp->p_multixri_pool->pvt_pool;
2187762306a36Sopenharmony_ci
2187862306a36Sopenharmony_ci		txcmplq_cnt = qp->io_wq->pring->txcmplq_cnt;
2187962306a36Sopenharmony_ci		abts_io_bufs = qp->abts_scsi_io_bufs;
2188062306a36Sopenharmony_ci		abts_io_bufs += qp->abts_nvme_io_bufs;
2188162306a36Sopenharmony_ci
2188262306a36Sopenharmony_ci		xri_owned = pvt_pool->count + txcmplq_cnt + abts_io_bufs;
2188362306a36Sopenharmony_ci		xri_limit = qp->p_multixri_pool->xri_limit;
2188462306a36Sopenharmony_ci
2188562306a36Sopenharmony_ci#ifdef LPFC_MXP_STAT
2188662306a36Sopenharmony_ci		if (xri_owned <= xri_limit)
2188762306a36Sopenharmony_ci			qp->p_multixri_pool->below_limit_count++;
2188862306a36Sopenharmony_ci		else
2188962306a36Sopenharmony_ci			qp->p_multixri_pool->above_limit_count++;
2189062306a36Sopenharmony_ci#endif
2189162306a36Sopenharmony_ci
2189262306a36Sopenharmony_ci		/* XRI goes to either public or private free xri pool
2189362306a36Sopenharmony_ci		 *     based on watermark and xri_limit
2189462306a36Sopenharmony_ci		 */
2189562306a36Sopenharmony_ci		if ((pvt_pool->count < pvt_pool->low_watermark) ||
2189662306a36Sopenharmony_ci		    (xri_owned < xri_limit &&
2189762306a36Sopenharmony_ci		     pvt_pool->count < pvt_pool->high_watermark)) {
2189862306a36Sopenharmony_ci			lpfc_qp_spin_lock_irqsave(&pvt_pool->lock, iflag,
2189962306a36Sopenharmony_ci						  qp, free_pvt_pool);
2190062306a36Sopenharmony_ci			list_add_tail(&lpfc_ncmd->list,
2190162306a36Sopenharmony_ci				      &pvt_pool->list);
2190262306a36Sopenharmony_ci			pvt_pool->count++;
2190362306a36Sopenharmony_ci			spin_unlock_irqrestore(&pvt_pool->lock, iflag);
2190462306a36Sopenharmony_ci		} else {
2190562306a36Sopenharmony_ci			lpfc_qp_spin_lock_irqsave(&pbl_pool->lock, iflag,
2190662306a36Sopenharmony_ci						  qp, free_pub_pool);
2190762306a36Sopenharmony_ci			list_add_tail(&lpfc_ncmd->list,
2190862306a36Sopenharmony_ci				      &pbl_pool->list);
2190962306a36Sopenharmony_ci			pbl_pool->count++;
2191062306a36Sopenharmony_ci			spin_unlock_irqrestore(&pbl_pool->lock, iflag);
2191162306a36Sopenharmony_ci		}
2191262306a36Sopenharmony_ci	} else {
2191362306a36Sopenharmony_ci		lpfc_qp_spin_lock_irqsave(&qp->io_buf_list_put_lock, iflag,
2191462306a36Sopenharmony_ci					  qp, free_xri);
2191562306a36Sopenharmony_ci		list_add_tail(&lpfc_ncmd->list,
2191662306a36Sopenharmony_ci			      &qp->lpfc_io_buf_list_put);
2191762306a36Sopenharmony_ci		qp->put_io_bufs++;
2191862306a36Sopenharmony_ci		spin_unlock_irqrestore(&qp->io_buf_list_put_lock,
2191962306a36Sopenharmony_ci				       iflag);
2192062306a36Sopenharmony_ci	}
2192162306a36Sopenharmony_ci}
2192262306a36Sopenharmony_ci
2192362306a36Sopenharmony_ci/**
2192462306a36Sopenharmony_ci * lpfc_get_io_buf_from_private_pool - Get one free IO buf from private pool
2192562306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2192662306a36Sopenharmony_ci * @qp: pointer to HDW queue
2192762306a36Sopenharmony_ci * @pvt_pool: pointer to private pool data structure.
2192862306a36Sopenharmony_ci * @ndlp: pointer to lpfc nodelist data structure.
2192962306a36Sopenharmony_ci *
2193062306a36Sopenharmony_ci * This routine tries to get one free IO buf from private pool.
2193162306a36Sopenharmony_ci *
2193262306a36Sopenharmony_ci * Return:
2193362306a36Sopenharmony_ci *   pointer to one free IO buf - if private pool is not empty
2193462306a36Sopenharmony_ci *   NULL - if private pool is empty
2193562306a36Sopenharmony_ci **/
2193662306a36Sopenharmony_cistatic struct lpfc_io_buf *
2193762306a36Sopenharmony_cilpfc_get_io_buf_from_private_pool(struct lpfc_hba *phba,
2193862306a36Sopenharmony_ci				  struct lpfc_sli4_hdw_queue *qp,
2193962306a36Sopenharmony_ci				  struct lpfc_pvt_pool *pvt_pool,
2194062306a36Sopenharmony_ci				  struct lpfc_nodelist *ndlp)
2194162306a36Sopenharmony_ci{
2194262306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_ncmd;
2194362306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_ncmd_next;
2194462306a36Sopenharmony_ci	unsigned long iflag;
2194562306a36Sopenharmony_ci
2194662306a36Sopenharmony_ci	lpfc_qp_spin_lock_irqsave(&pvt_pool->lock, iflag, qp, alloc_pvt_pool);
2194762306a36Sopenharmony_ci	list_for_each_entry_safe(lpfc_ncmd, lpfc_ncmd_next,
2194862306a36Sopenharmony_ci				 &pvt_pool->list, list) {
2194962306a36Sopenharmony_ci		if (lpfc_test_rrq_active(
2195062306a36Sopenharmony_ci			phba, ndlp, lpfc_ncmd->cur_iocbq.sli4_lxritag))
2195162306a36Sopenharmony_ci			continue;
2195262306a36Sopenharmony_ci		list_del(&lpfc_ncmd->list);
2195362306a36Sopenharmony_ci		pvt_pool->count--;
2195462306a36Sopenharmony_ci		spin_unlock_irqrestore(&pvt_pool->lock, iflag);
2195562306a36Sopenharmony_ci		return lpfc_ncmd;
2195662306a36Sopenharmony_ci	}
2195762306a36Sopenharmony_ci	spin_unlock_irqrestore(&pvt_pool->lock, iflag);
2195862306a36Sopenharmony_ci
2195962306a36Sopenharmony_ci	return NULL;
2196062306a36Sopenharmony_ci}
2196162306a36Sopenharmony_ci
2196262306a36Sopenharmony_ci/**
2196362306a36Sopenharmony_ci * lpfc_get_io_buf_from_expedite_pool - Get one free IO buf from expedite pool
2196462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2196562306a36Sopenharmony_ci *
2196662306a36Sopenharmony_ci * This routine tries to get one free IO buf from expedite pool.
2196762306a36Sopenharmony_ci *
2196862306a36Sopenharmony_ci * Return:
2196962306a36Sopenharmony_ci *   pointer to one free IO buf - if expedite pool is not empty
2197062306a36Sopenharmony_ci *   NULL - if expedite pool is empty
2197162306a36Sopenharmony_ci **/
2197262306a36Sopenharmony_cistatic struct lpfc_io_buf *
2197362306a36Sopenharmony_cilpfc_get_io_buf_from_expedite_pool(struct lpfc_hba *phba)
2197462306a36Sopenharmony_ci{
2197562306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_ncmd = NULL, *iter;
2197662306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_ncmd_next;
2197762306a36Sopenharmony_ci	unsigned long iflag;
2197862306a36Sopenharmony_ci	struct lpfc_epd_pool *epd_pool;
2197962306a36Sopenharmony_ci
2198062306a36Sopenharmony_ci	epd_pool = &phba->epd_pool;
2198162306a36Sopenharmony_ci
2198262306a36Sopenharmony_ci	spin_lock_irqsave(&epd_pool->lock, iflag);
2198362306a36Sopenharmony_ci	if (epd_pool->count > 0) {
2198462306a36Sopenharmony_ci		list_for_each_entry_safe(iter, lpfc_ncmd_next,
2198562306a36Sopenharmony_ci					 &epd_pool->list, list) {
2198662306a36Sopenharmony_ci			list_del(&iter->list);
2198762306a36Sopenharmony_ci			epd_pool->count--;
2198862306a36Sopenharmony_ci			lpfc_ncmd = iter;
2198962306a36Sopenharmony_ci			break;
2199062306a36Sopenharmony_ci		}
2199162306a36Sopenharmony_ci	}
2199262306a36Sopenharmony_ci	spin_unlock_irqrestore(&epd_pool->lock, iflag);
2199362306a36Sopenharmony_ci
2199462306a36Sopenharmony_ci	return lpfc_ncmd;
2199562306a36Sopenharmony_ci}
2199662306a36Sopenharmony_ci
2199762306a36Sopenharmony_ci/**
2199862306a36Sopenharmony_ci * lpfc_get_io_buf_from_multixri_pools - Get one free IO bufs
2199962306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
2200062306a36Sopenharmony_ci * @ndlp: pointer to lpfc nodelist data structure.
2200162306a36Sopenharmony_ci * @hwqid: belong to which HWQ
2200262306a36Sopenharmony_ci * @expedite: 1 means this request is urgent.
2200362306a36Sopenharmony_ci *
2200462306a36Sopenharmony_ci * This routine will do the following actions and then return a pointer to
2200562306a36Sopenharmony_ci * one free IO buf.
2200662306a36Sopenharmony_ci *
2200762306a36Sopenharmony_ci * 1. If private free xri count is empty, move some XRIs from public to
2200862306a36Sopenharmony_ci *    private pool.
2200962306a36Sopenharmony_ci * 2. Get one XRI from private free xri pool.
2201062306a36Sopenharmony_ci * 3. If we fail to get one from pvt_pool and this is an expedite request,
2201162306a36Sopenharmony_ci *    get one free xri from expedite pool.
2201262306a36Sopenharmony_ci *
2201362306a36Sopenharmony_ci * Note: ndlp is only used on SCSI side for RRQ testing.
2201462306a36Sopenharmony_ci *       The caller should pass NULL for ndlp on NVME side.
2201562306a36Sopenharmony_ci *
2201662306a36Sopenharmony_ci * Return:
2201762306a36Sopenharmony_ci *   pointer to one free IO buf - if private pool is not empty
2201862306a36Sopenharmony_ci *   NULL - if private pool is empty
2201962306a36Sopenharmony_ci **/
2202062306a36Sopenharmony_cistatic struct lpfc_io_buf *
2202162306a36Sopenharmony_cilpfc_get_io_buf_from_multixri_pools(struct lpfc_hba *phba,
2202262306a36Sopenharmony_ci				    struct lpfc_nodelist *ndlp,
2202362306a36Sopenharmony_ci				    int hwqid, int expedite)
2202462306a36Sopenharmony_ci{
2202562306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *qp;
2202662306a36Sopenharmony_ci	struct lpfc_multixri_pool *multixri_pool;
2202762306a36Sopenharmony_ci	struct lpfc_pvt_pool *pvt_pool;
2202862306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_ncmd;
2202962306a36Sopenharmony_ci
2203062306a36Sopenharmony_ci	qp = &phba->sli4_hba.hdwq[hwqid];
2203162306a36Sopenharmony_ci	lpfc_ncmd = NULL;
2203262306a36Sopenharmony_ci	if (!qp) {
2203362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO,
2203462306a36Sopenharmony_ci				LOG_SLI | LOG_NVME_ABTS | LOG_FCP,
2203562306a36Sopenharmony_ci				"5556 NULL qp for hwqid  x%x\n", hwqid);
2203662306a36Sopenharmony_ci		return lpfc_ncmd;
2203762306a36Sopenharmony_ci	}
2203862306a36Sopenharmony_ci	multixri_pool = qp->p_multixri_pool;
2203962306a36Sopenharmony_ci	if (!multixri_pool) {
2204062306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO,
2204162306a36Sopenharmony_ci				LOG_SLI | LOG_NVME_ABTS | LOG_FCP,
2204262306a36Sopenharmony_ci				"5557 NULL multixri for hwqid  x%x\n", hwqid);
2204362306a36Sopenharmony_ci		return lpfc_ncmd;
2204462306a36Sopenharmony_ci	}
2204562306a36Sopenharmony_ci	pvt_pool = &multixri_pool->pvt_pool;
2204662306a36Sopenharmony_ci	if (!pvt_pool) {
2204762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO,
2204862306a36Sopenharmony_ci				LOG_SLI | LOG_NVME_ABTS | LOG_FCP,
2204962306a36Sopenharmony_ci				"5558 NULL pvt_pool for hwqid  x%x\n", hwqid);
2205062306a36Sopenharmony_ci		return lpfc_ncmd;
2205162306a36Sopenharmony_ci	}
2205262306a36Sopenharmony_ci	multixri_pool->io_req_count++;
2205362306a36Sopenharmony_ci
2205462306a36Sopenharmony_ci	/* If pvt_pool is empty, move some XRIs from public to private pool */
2205562306a36Sopenharmony_ci	if (pvt_pool->count == 0)
2205662306a36Sopenharmony_ci		lpfc_move_xri_pbl_to_pvt(phba, hwqid, XRI_BATCH);
2205762306a36Sopenharmony_ci
2205862306a36Sopenharmony_ci	/* Get one XRI from private free xri pool */
2205962306a36Sopenharmony_ci	lpfc_ncmd = lpfc_get_io_buf_from_private_pool(phba, qp, pvt_pool, ndlp);
2206062306a36Sopenharmony_ci
2206162306a36Sopenharmony_ci	if (lpfc_ncmd) {
2206262306a36Sopenharmony_ci		lpfc_ncmd->hdwq = qp;
2206362306a36Sopenharmony_ci		lpfc_ncmd->hdwq_no = hwqid;
2206462306a36Sopenharmony_ci	} else if (expedite) {
2206562306a36Sopenharmony_ci		/* If we fail to get one from pvt_pool and this is an expedite
2206662306a36Sopenharmony_ci		 * request, get one free xri from expedite pool.
2206762306a36Sopenharmony_ci		 */
2206862306a36Sopenharmony_ci		lpfc_ncmd = lpfc_get_io_buf_from_expedite_pool(phba);
2206962306a36Sopenharmony_ci	}
2207062306a36Sopenharmony_ci
2207162306a36Sopenharmony_ci	return lpfc_ncmd;
2207262306a36Sopenharmony_ci}
2207362306a36Sopenharmony_ci
2207462306a36Sopenharmony_cistatic inline struct lpfc_io_buf *
2207562306a36Sopenharmony_cilpfc_io_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int idx)
2207662306a36Sopenharmony_ci{
2207762306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *qp;
2207862306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_cmd, *lpfc_cmd_next;
2207962306a36Sopenharmony_ci
2208062306a36Sopenharmony_ci	qp = &phba->sli4_hba.hdwq[idx];
2208162306a36Sopenharmony_ci	list_for_each_entry_safe(lpfc_cmd, lpfc_cmd_next,
2208262306a36Sopenharmony_ci				 &qp->lpfc_io_buf_list_get, list) {
2208362306a36Sopenharmony_ci		if (lpfc_test_rrq_active(phba, ndlp,
2208462306a36Sopenharmony_ci					 lpfc_cmd->cur_iocbq.sli4_lxritag))
2208562306a36Sopenharmony_ci			continue;
2208662306a36Sopenharmony_ci
2208762306a36Sopenharmony_ci		if (lpfc_cmd->flags & LPFC_SBUF_NOT_POSTED)
2208862306a36Sopenharmony_ci			continue;
2208962306a36Sopenharmony_ci
2209062306a36Sopenharmony_ci		list_del_init(&lpfc_cmd->list);
2209162306a36Sopenharmony_ci		qp->get_io_bufs--;
2209262306a36Sopenharmony_ci		lpfc_cmd->hdwq = qp;
2209362306a36Sopenharmony_ci		lpfc_cmd->hdwq_no = idx;
2209462306a36Sopenharmony_ci		return lpfc_cmd;
2209562306a36Sopenharmony_ci	}
2209662306a36Sopenharmony_ci	return NULL;
2209762306a36Sopenharmony_ci}
2209862306a36Sopenharmony_ci
2209962306a36Sopenharmony_ci/**
2210062306a36Sopenharmony_ci * lpfc_get_io_buf - Get one IO buffer from free pool
2210162306a36Sopenharmony_ci * @phba: The HBA for which this call is being executed.
2210262306a36Sopenharmony_ci * @ndlp: pointer to lpfc nodelist data structure.
2210362306a36Sopenharmony_ci * @hwqid: belong to which HWQ
2210462306a36Sopenharmony_ci * @expedite: 1 means this request is urgent.
2210562306a36Sopenharmony_ci *
2210662306a36Sopenharmony_ci * This routine gets one IO buffer from free pool. If cfg_xri_rebalancing==1,
2210762306a36Sopenharmony_ci * removes a IO buffer from multiXRI pools. If cfg_xri_rebalancing==0, removes
2210862306a36Sopenharmony_ci * a IO buffer from head of @hdwq io_buf_list and returns to caller.
2210962306a36Sopenharmony_ci *
2211062306a36Sopenharmony_ci * Note: ndlp is only used on SCSI side for RRQ testing.
2211162306a36Sopenharmony_ci *       The caller should pass NULL for ndlp on NVME side.
2211262306a36Sopenharmony_ci *
2211362306a36Sopenharmony_ci * Return codes:
2211462306a36Sopenharmony_ci *   NULL - Error
2211562306a36Sopenharmony_ci *   Pointer to lpfc_io_buf - Success
2211662306a36Sopenharmony_ci **/
2211762306a36Sopenharmony_cistruct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba,
2211862306a36Sopenharmony_ci				    struct lpfc_nodelist *ndlp,
2211962306a36Sopenharmony_ci				    u32 hwqid, int expedite)
2212062306a36Sopenharmony_ci{
2212162306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *qp;
2212262306a36Sopenharmony_ci	unsigned long iflag;
2212362306a36Sopenharmony_ci	struct lpfc_io_buf *lpfc_cmd;
2212462306a36Sopenharmony_ci
2212562306a36Sopenharmony_ci	qp = &phba->sli4_hba.hdwq[hwqid];
2212662306a36Sopenharmony_ci	lpfc_cmd = NULL;
2212762306a36Sopenharmony_ci	if (!qp) {
2212862306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING,
2212962306a36Sopenharmony_ci				LOG_SLI | LOG_NVME_ABTS | LOG_FCP,
2213062306a36Sopenharmony_ci				"5555 NULL qp for hwqid  x%x\n", hwqid);
2213162306a36Sopenharmony_ci		return lpfc_cmd;
2213262306a36Sopenharmony_ci	}
2213362306a36Sopenharmony_ci
2213462306a36Sopenharmony_ci	if (phba->cfg_xri_rebalancing)
2213562306a36Sopenharmony_ci		lpfc_cmd = lpfc_get_io_buf_from_multixri_pools(
2213662306a36Sopenharmony_ci			phba, ndlp, hwqid, expedite);
2213762306a36Sopenharmony_ci	else {
2213862306a36Sopenharmony_ci		lpfc_qp_spin_lock_irqsave(&qp->io_buf_list_get_lock, iflag,
2213962306a36Sopenharmony_ci					  qp, alloc_xri_get);
2214062306a36Sopenharmony_ci		if (qp->get_io_bufs > LPFC_NVME_EXPEDITE_XRICNT || expedite)
2214162306a36Sopenharmony_ci			lpfc_cmd = lpfc_io_buf(phba, ndlp, hwqid);
2214262306a36Sopenharmony_ci		if (!lpfc_cmd) {
2214362306a36Sopenharmony_ci			lpfc_qp_spin_lock(&qp->io_buf_list_put_lock,
2214462306a36Sopenharmony_ci					  qp, alloc_xri_put);
2214562306a36Sopenharmony_ci			list_splice(&qp->lpfc_io_buf_list_put,
2214662306a36Sopenharmony_ci				    &qp->lpfc_io_buf_list_get);
2214762306a36Sopenharmony_ci			qp->get_io_bufs += qp->put_io_bufs;
2214862306a36Sopenharmony_ci			INIT_LIST_HEAD(&qp->lpfc_io_buf_list_put);
2214962306a36Sopenharmony_ci			qp->put_io_bufs = 0;
2215062306a36Sopenharmony_ci			spin_unlock(&qp->io_buf_list_put_lock);
2215162306a36Sopenharmony_ci			if (qp->get_io_bufs > LPFC_NVME_EXPEDITE_XRICNT ||
2215262306a36Sopenharmony_ci			    expedite)
2215362306a36Sopenharmony_ci				lpfc_cmd = lpfc_io_buf(phba, ndlp, hwqid);
2215462306a36Sopenharmony_ci		}
2215562306a36Sopenharmony_ci		spin_unlock_irqrestore(&qp->io_buf_list_get_lock, iflag);
2215662306a36Sopenharmony_ci	}
2215762306a36Sopenharmony_ci
2215862306a36Sopenharmony_ci	return lpfc_cmd;
2215962306a36Sopenharmony_ci}
2216062306a36Sopenharmony_ci
2216162306a36Sopenharmony_ci/**
2216262306a36Sopenharmony_ci * lpfc_read_object - Retrieve object data from HBA
2216362306a36Sopenharmony_ci * @phba: The HBA for which this call is being executed.
2216462306a36Sopenharmony_ci * @rdobject: Pathname of object data we want to read.
2216562306a36Sopenharmony_ci * @datap: Pointer to where data will be copied to.
2216662306a36Sopenharmony_ci * @datasz: size of data area
2216762306a36Sopenharmony_ci *
2216862306a36Sopenharmony_ci * This routine is limited to object sizes of LPFC_BPL_SIZE (1024) or less.
2216962306a36Sopenharmony_ci * The data will be truncated if datasz is not large enough.
2217062306a36Sopenharmony_ci * Version 1 is not supported with Embedded mbox cmd, so we must use version 0.
2217162306a36Sopenharmony_ci * Returns the actual bytes read from the object.
2217262306a36Sopenharmony_ci */
2217362306a36Sopenharmony_ciint
2217462306a36Sopenharmony_cilpfc_read_object(struct lpfc_hba *phba, char *rdobject, uint32_t *datap,
2217562306a36Sopenharmony_ci		 uint32_t datasz)
2217662306a36Sopenharmony_ci{
2217762306a36Sopenharmony_ci	struct lpfc_mbx_read_object *read_object;
2217862306a36Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
2217962306a36Sopenharmony_ci	int rc, length, eof, j, byte_cnt = 0;
2218062306a36Sopenharmony_ci	uint32_t shdr_status, shdr_add_status;
2218162306a36Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
2218262306a36Sopenharmony_ci	struct lpfc_dmabuf *pcmd;
2218362306a36Sopenharmony_ci	u32 rd_object_name[LPFC_MBX_OBJECT_NAME_LEN_DW] = {0};
2218462306a36Sopenharmony_ci
2218562306a36Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
2218662306a36Sopenharmony_ci	if (!mbox)
2218762306a36Sopenharmony_ci		return -ENOMEM;
2218862306a36Sopenharmony_ci	length = (sizeof(struct lpfc_mbx_read_object) -
2218962306a36Sopenharmony_ci		  sizeof(struct lpfc_sli4_cfg_mhdr));
2219062306a36Sopenharmony_ci	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
2219162306a36Sopenharmony_ci			 LPFC_MBOX_OPCODE_READ_OBJECT,
2219262306a36Sopenharmony_ci			 length, LPFC_SLI4_MBX_EMBED);
2219362306a36Sopenharmony_ci	read_object = &mbox->u.mqe.un.read_object;
2219462306a36Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)&read_object->header.cfg_shdr;
2219562306a36Sopenharmony_ci
2219662306a36Sopenharmony_ci	bf_set(lpfc_mbox_hdr_version, &shdr->request, LPFC_Q_CREATE_VERSION_0);
2219762306a36Sopenharmony_ci	bf_set(lpfc_mbx_rd_object_rlen, &read_object->u.request, datasz);
2219862306a36Sopenharmony_ci	read_object->u.request.rd_object_offset = 0;
2219962306a36Sopenharmony_ci	read_object->u.request.rd_object_cnt = 1;
2220062306a36Sopenharmony_ci
2220162306a36Sopenharmony_ci	memset((void *)read_object->u.request.rd_object_name, 0,
2220262306a36Sopenharmony_ci	       LPFC_OBJ_NAME_SZ);
2220362306a36Sopenharmony_ci	scnprintf((char *)rd_object_name, sizeof(rd_object_name), rdobject);
2220462306a36Sopenharmony_ci	for (j = 0; j < strlen(rdobject); j++)
2220562306a36Sopenharmony_ci		read_object->u.request.rd_object_name[j] =
2220662306a36Sopenharmony_ci			cpu_to_le32(rd_object_name[j]);
2220762306a36Sopenharmony_ci
2220862306a36Sopenharmony_ci	pcmd = kmalloc(sizeof(*pcmd), GFP_KERNEL);
2220962306a36Sopenharmony_ci	if (pcmd)
2221062306a36Sopenharmony_ci		pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys);
2221162306a36Sopenharmony_ci	if (!pcmd || !pcmd->virt) {
2221262306a36Sopenharmony_ci		kfree(pcmd);
2221362306a36Sopenharmony_ci		mempool_free(mbox, phba->mbox_mem_pool);
2221462306a36Sopenharmony_ci		return -ENOMEM;
2221562306a36Sopenharmony_ci	}
2221662306a36Sopenharmony_ci	memset((void *)pcmd->virt, 0, LPFC_BPL_SIZE);
2221762306a36Sopenharmony_ci	read_object->u.request.rd_object_hbuf[0].pa_lo =
2221862306a36Sopenharmony_ci		putPaddrLow(pcmd->phys);
2221962306a36Sopenharmony_ci	read_object->u.request.rd_object_hbuf[0].pa_hi =
2222062306a36Sopenharmony_ci		putPaddrHigh(pcmd->phys);
2222162306a36Sopenharmony_ci	read_object->u.request.rd_object_hbuf[0].length = LPFC_BPL_SIZE;
2222262306a36Sopenharmony_ci
2222362306a36Sopenharmony_ci	mbox->vport = phba->pport;
2222462306a36Sopenharmony_ci	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
2222562306a36Sopenharmony_ci	mbox->ctx_ndlp = NULL;
2222662306a36Sopenharmony_ci
2222762306a36Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
2222862306a36Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
2222962306a36Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
2223062306a36Sopenharmony_ci
2223162306a36Sopenharmony_ci	if (shdr_status == STATUS_FAILED &&
2223262306a36Sopenharmony_ci	    shdr_add_status == ADD_STATUS_INVALID_OBJECT_NAME) {
2223362306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_CGN_MGMT,
2223462306a36Sopenharmony_ci				"4674 No port cfg file in FW.\n");
2223562306a36Sopenharmony_ci		byte_cnt = -ENOENT;
2223662306a36Sopenharmony_ci	} else if (shdr_status || shdr_add_status || rc) {
2223762306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_CGN_MGMT,
2223862306a36Sopenharmony_ci				"2625 READ_OBJECT mailbox failed with "
2223962306a36Sopenharmony_ci				"status x%x add_status x%x, mbx status x%x\n",
2224062306a36Sopenharmony_ci				shdr_status, shdr_add_status, rc);
2224162306a36Sopenharmony_ci		byte_cnt = -ENXIO;
2224262306a36Sopenharmony_ci	} else {
2224362306a36Sopenharmony_ci		/* Success */
2224462306a36Sopenharmony_ci		length = read_object->u.response.rd_object_actual_rlen;
2224562306a36Sopenharmony_ci		eof = bf_get(lpfc_mbx_rd_object_eof, &read_object->u.response);
2224662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_CGN_MGMT,
2224762306a36Sopenharmony_ci				"2626 READ_OBJECT Success len %d:%d, EOF %d\n",
2224862306a36Sopenharmony_ci				length, datasz, eof);
2224962306a36Sopenharmony_ci
2225062306a36Sopenharmony_ci		/* Detect the port config file exists but is empty */
2225162306a36Sopenharmony_ci		if (!length && eof) {
2225262306a36Sopenharmony_ci			byte_cnt = 0;
2225362306a36Sopenharmony_ci			goto exit;
2225462306a36Sopenharmony_ci		}
2225562306a36Sopenharmony_ci
2225662306a36Sopenharmony_ci		byte_cnt = length;
2225762306a36Sopenharmony_ci		lpfc_sli_pcimem_bcopy(pcmd->virt, datap, byte_cnt);
2225862306a36Sopenharmony_ci	}
2225962306a36Sopenharmony_ci
2226062306a36Sopenharmony_ci exit:
2226162306a36Sopenharmony_ci	/* This is an embedded SLI4 mailbox with an external buffer allocated.
2226262306a36Sopenharmony_ci	 * Free the pcmd and then cleanup with the correct routine.
2226362306a36Sopenharmony_ci	 */
2226462306a36Sopenharmony_ci	lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
2226562306a36Sopenharmony_ci	kfree(pcmd);
2226662306a36Sopenharmony_ci	lpfc_sli4_mbox_cmd_free(phba, mbox);
2226762306a36Sopenharmony_ci	return byte_cnt;
2226862306a36Sopenharmony_ci}
2226962306a36Sopenharmony_ci
2227062306a36Sopenharmony_ci/**
2227162306a36Sopenharmony_ci * lpfc_get_sgl_per_hdwq - Get one SGL chunk from hdwq's pool
2227262306a36Sopenharmony_ci * @phba: The HBA for which this call is being executed.
2227362306a36Sopenharmony_ci * @lpfc_buf: IO buf structure to append the SGL chunk
2227462306a36Sopenharmony_ci *
2227562306a36Sopenharmony_ci * This routine gets one SGL chunk buffer from hdwq's SGL chunk pool,
2227662306a36Sopenharmony_ci * and will allocate an SGL chunk if the pool is empty.
2227762306a36Sopenharmony_ci *
2227862306a36Sopenharmony_ci * Return codes:
2227962306a36Sopenharmony_ci *   NULL - Error
2228062306a36Sopenharmony_ci *   Pointer to sli4_hybrid_sgl - Success
2228162306a36Sopenharmony_ci **/
2228262306a36Sopenharmony_cistruct sli4_hybrid_sgl *
2228362306a36Sopenharmony_cilpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf)
2228462306a36Sopenharmony_ci{
2228562306a36Sopenharmony_ci	struct sli4_hybrid_sgl *list_entry = NULL;
2228662306a36Sopenharmony_ci	struct sli4_hybrid_sgl *tmp = NULL;
2228762306a36Sopenharmony_ci	struct sli4_hybrid_sgl *allocated_sgl = NULL;
2228862306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq;
2228962306a36Sopenharmony_ci	struct list_head *buf_list = &hdwq->sgl_list;
2229062306a36Sopenharmony_ci	unsigned long iflags;
2229162306a36Sopenharmony_ci
2229262306a36Sopenharmony_ci	spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
2229362306a36Sopenharmony_ci
2229462306a36Sopenharmony_ci	if (likely(!list_empty(buf_list))) {
2229562306a36Sopenharmony_ci		/* break off 1 chunk from the sgl_list */
2229662306a36Sopenharmony_ci		list_for_each_entry_safe(list_entry, tmp,
2229762306a36Sopenharmony_ci					 buf_list, list_node) {
2229862306a36Sopenharmony_ci			list_move_tail(&list_entry->list_node,
2229962306a36Sopenharmony_ci				       &lpfc_buf->dma_sgl_xtra_list);
2230062306a36Sopenharmony_ci			break;
2230162306a36Sopenharmony_ci		}
2230262306a36Sopenharmony_ci	} else {
2230362306a36Sopenharmony_ci		/* allocate more */
2230462306a36Sopenharmony_ci		spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
2230562306a36Sopenharmony_ci		tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC,
2230662306a36Sopenharmony_ci				   cpu_to_node(hdwq->io_wq->chann));
2230762306a36Sopenharmony_ci		if (!tmp) {
2230862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
2230962306a36Sopenharmony_ci					"8353 error kmalloc memory for HDWQ "
2231062306a36Sopenharmony_ci					"%d %s\n",
2231162306a36Sopenharmony_ci					lpfc_buf->hdwq_no, __func__);
2231262306a36Sopenharmony_ci			return NULL;
2231362306a36Sopenharmony_ci		}
2231462306a36Sopenharmony_ci
2231562306a36Sopenharmony_ci		tmp->dma_sgl = dma_pool_alloc(phba->lpfc_sg_dma_buf_pool,
2231662306a36Sopenharmony_ci					      GFP_ATOMIC, &tmp->dma_phys_sgl);
2231762306a36Sopenharmony_ci		if (!tmp->dma_sgl) {
2231862306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
2231962306a36Sopenharmony_ci					"8354 error pool_alloc memory for HDWQ "
2232062306a36Sopenharmony_ci					"%d %s\n",
2232162306a36Sopenharmony_ci					lpfc_buf->hdwq_no, __func__);
2232262306a36Sopenharmony_ci			kfree(tmp);
2232362306a36Sopenharmony_ci			return NULL;
2232462306a36Sopenharmony_ci		}
2232562306a36Sopenharmony_ci
2232662306a36Sopenharmony_ci		spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
2232762306a36Sopenharmony_ci		list_add_tail(&tmp->list_node, &lpfc_buf->dma_sgl_xtra_list);
2232862306a36Sopenharmony_ci	}
2232962306a36Sopenharmony_ci
2233062306a36Sopenharmony_ci	allocated_sgl = list_last_entry(&lpfc_buf->dma_sgl_xtra_list,
2233162306a36Sopenharmony_ci					struct sli4_hybrid_sgl,
2233262306a36Sopenharmony_ci					list_node);
2233362306a36Sopenharmony_ci
2233462306a36Sopenharmony_ci	spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
2233562306a36Sopenharmony_ci
2233662306a36Sopenharmony_ci	return allocated_sgl;
2233762306a36Sopenharmony_ci}
2233862306a36Sopenharmony_ci
2233962306a36Sopenharmony_ci/**
2234062306a36Sopenharmony_ci * lpfc_put_sgl_per_hdwq - Put one SGL chunk into hdwq pool
2234162306a36Sopenharmony_ci * @phba: The HBA for which this call is being executed.
2234262306a36Sopenharmony_ci * @lpfc_buf: IO buf structure with the SGL chunk
2234362306a36Sopenharmony_ci *
2234462306a36Sopenharmony_ci * This routine puts one SGL chunk buffer into hdwq's SGL chunk pool.
2234562306a36Sopenharmony_ci *
2234662306a36Sopenharmony_ci * Return codes:
2234762306a36Sopenharmony_ci *   0 - Success
2234862306a36Sopenharmony_ci *   -EINVAL - Error
2234962306a36Sopenharmony_ci **/
2235062306a36Sopenharmony_ciint
2235162306a36Sopenharmony_cilpfc_put_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf)
2235262306a36Sopenharmony_ci{
2235362306a36Sopenharmony_ci	int rc = 0;
2235462306a36Sopenharmony_ci	struct sli4_hybrid_sgl *list_entry = NULL;
2235562306a36Sopenharmony_ci	struct sli4_hybrid_sgl *tmp = NULL;
2235662306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq;
2235762306a36Sopenharmony_ci	struct list_head *buf_list = &hdwq->sgl_list;
2235862306a36Sopenharmony_ci	unsigned long iflags;
2235962306a36Sopenharmony_ci
2236062306a36Sopenharmony_ci	spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
2236162306a36Sopenharmony_ci
2236262306a36Sopenharmony_ci	if (likely(!list_empty(&lpfc_buf->dma_sgl_xtra_list))) {
2236362306a36Sopenharmony_ci		list_for_each_entry_safe(list_entry, tmp,
2236462306a36Sopenharmony_ci					 &lpfc_buf->dma_sgl_xtra_list,
2236562306a36Sopenharmony_ci					 list_node) {
2236662306a36Sopenharmony_ci			list_move_tail(&list_entry->list_node,
2236762306a36Sopenharmony_ci				       buf_list);
2236862306a36Sopenharmony_ci		}
2236962306a36Sopenharmony_ci	} else {
2237062306a36Sopenharmony_ci		rc = -EINVAL;
2237162306a36Sopenharmony_ci	}
2237262306a36Sopenharmony_ci
2237362306a36Sopenharmony_ci	spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
2237462306a36Sopenharmony_ci	return rc;
2237562306a36Sopenharmony_ci}
2237662306a36Sopenharmony_ci
2237762306a36Sopenharmony_ci/**
2237862306a36Sopenharmony_ci * lpfc_free_sgl_per_hdwq - Free all SGL chunks of hdwq pool
2237962306a36Sopenharmony_ci * @phba: phba object
2238062306a36Sopenharmony_ci * @hdwq: hdwq to cleanup sgl buff resources on
2238162306a36Sopenharmony_ci *
2238262306a36Sopenharmony_ci * This routine frees all SGL chunks of hdwq SGL chunk pool.
2238362306a36Sopenharmony_ci *
2238462306a36Sopenharmony_ci * Return codes:
2238562306a36Sopenharmony_ci *   None
2238662306a36Sopenharmony_ci **/
2238762306a36Sopenharmony_civoid
2238862306a36Sopenharmony_cilpfc_free_sgl_per_hdwq(struct lpfc_hba *phba,
2238962306a36Sopenharmony_ci		       struct lpfc_sli4_hdw_queue *hdwq)
2239062306a36Sopenharmony_ci{
2239162306a36Sopenharmony_ci	struct list_head *buf_list = &hdwq->sgl_list;
2239262306a36Sopenharmony_ci	struct sli4_hybrid_sgl *list_entry = NULL;
2239362306a36Sopenharmony_ci	struct sli4_hybrid_sgl *tmp = NULL;
2239462306a36Sopenharmony_ci	unsigned long iflags;
2239562306a36Sopenharmony_ci
2239662306a36Sopenharmony_ci	spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
2239762306a36Sopenharmony_ci
2239862306a36Sopenharmony_ci	/* Free sgl pool */
2239962306a36Sopenharmony_ci	list_for_each_entry_safe(list_entry, tmp,
2240062306a36Sopenharmony_ci				 buf_list, list_node) {
2240162306a36Sopenharmony_ci		list_del(&list_entry->list_node);
2240262306a36Sopenharmony_ci		dma_pool_free(phba->lpfc_sg_dma_buf_pool,
2240362306a36Sopenharmony_ci			      list_entry->dma_sgl,
2240462306a36Sopenharmony_ci			      list_entry->dma_phys_sgl);
2240562306a36Sopenharmony_ci		kfree(list_entry);
2240662306a36Sopenharmony_ci	}
2240762306a36Sopenharmony_ci
2240862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
2240962306a36Sopenharmony_ci}
2241062306a36Sopenharmony_ci
2241162306a36Sopenharmony_ci/**
2241262306a36Sopenharmony_ci * lpfc_get_cmd_rsp_buf_per_hdwq - Get one CMD/RSP buffer from hdwq
2241362306a36Sopenharmony_ci * @phba: The HBA for which this call is being executed.
2241462306a36Sopenharmony_ci * @lpfc_buf: IO buf structure to attach the CMD/RSP buffer
2241562306a36Sopenharmony_ci *
2241662306a36Sopenharmony_ci * This routine gets one CMD/RSP buffer from hdwq's CMD/RSP pool,
2241762306a36Sopenharmony_ci * and will allocate an CMD/RSP buffer if the pool is empty.
2241862306a36Sopenharmony_ci *
2241962306a36Sopenharmony_ci * Return codes:
2242062306a36Sopenharmony_ci *   NULL - Error
2242162306a36Sopenharmony_ci *   Pointer to fcp_cmd_rsp_buf - Success
2242262306a36Sopenharmony_ci **/
2242362306a36Sopenharmony_cistruct fcp_cmd_rsp_buf *
2242462306a36Sopenharmony_cilpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
2242562306a36Sopenharmony_ci			      struct lpfc_io_buf *lpfc_buf)
2242662306a36Sopenharmony_ci{
2242762306a36Sopenharmony_ci	struct fcp_cmd_rsp_buf *list_entry = NULL;
2242862306a36Sopenharmony_ci	struct fcp_cmd_rsp_buf *tmp = NULL;
2242962306a36Sopenharmony_ci	struct fcp_cmd_rsp_buf *allocated_buf = NULL;
2243062306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq;
2243162306a36Sopenharmony_ci	struct list_head *buf_list = &hdwq->cmd_rsp_buf_list;
2243262306a36Sopenharmony_ci	unsigned long iflags;
2243362306a36Sopenharmony_ci
2243462306a36Sopenharmony_ci	spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
2243562306a36Sopenharmony_ci
2243662306a36Sopenharmony_ci	if (likely(!list_empty(buf_list))) {
2243762306a36Sopenharmony_ci		/* break off 1 chunk from the list */
2243862306a36Sopenharmony_ci		list_for_each_entry_safe(list_entry, tmp,
2243962306a36Sopenharmony_ci					 buf_list,
2244062306a36Sopenharmony_ci					 list_node) {
2244162306a36Sopenharmony_ci			list_move_tail(&list_entry->list_node,
2244262306a36Sopenharmony_ci				       &lpfc_buf->dma_cmd_rsp_list);
2244362306a36Sopenharmony_ci			break;
2244462306a36Sopenharmony_ci		}
2244562306a36Sopenharmony_ci	} else {
2244662306a36Sopenharmony_ci		/* allocate more */
2244762306a36Sopenharmony_ci		spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
2244862306a36Sopenharmony_ci		tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC,
2244962306a36Sopenharmony_ci				   cpu_to_node(hdwq->io_wq->chann));
2245062306a36Sopenharmony_ci		if (!tmp) {
2245162306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
2245262306a36Sopenharmony_ci					"8355 error kmalloc memory for HDWQ "
2245362306a36Sopenharmony_ci					"%d %s\n",
2245462306a36Sopenharmony_ci					lpfc_buf->hdwq_no, __func__);
2245562306a36Sopenharmony_ci			return NULL;
2245662306a36Sopenharmony_ci		}
2245762306a36Sopenharmony_ci
2245862306a36Sopenharmony_ci		tmp->fcp_cmnd = dma_pool_zalloc(phba->lpfc_cmd_rsp_buf_pool,
2245962306a36Sopenharmony_ci						GFP_ATOMIC,
2246062306a36Sopenharmony_ci						&tmp->fcp_cmd_rsp_dma_handle);
2246162306a36Sopenharmony_ci
2246262306a36Sopenharmony_ci		if (!tmp->fcp_cmnd) {
2246362306a36Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
2246462306a36Sopenharmony_ci					"8356 error pool_alloc memory for HDWQ "
2246562306a36Sopenharmony_ci					"%d %s\n",
2246662306a36Sopenharmony_ci					lpfc_buf->hdwq_no, __func__);
2246762306a36Sopenharmony_ci			kfree(tmp);
2246862306a36Sopenharmony_ci			return NULL;
2246962306a36Sopenharmony_ci		}
2247062306a36Sopenharmony_ci
2247162306a36Sopenharmony_ci		tmp->fcp_rsp = (struct fcp_rsp *)((uint8_t *)tmp->fcp_cmnd +
2247262306a36Sopenharmony_ci				sizeof(struct fcp_cmnd));
2247362306a36Sopenharmony_ci
2247462306a36Sopenharmony_ci		spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
2247562306a36Sopenharmony_ci		list_add_tail(&tmp->list_node, &lpfc_buf->dma_cmd_rsp_list);
2247662306a36Sopenharmony_ci	}
2247762306a36Sopenharmony_ci
2247862306a36Sopenharmony_ci	allocated_buf = list_last_entry(&lpfc_buf->dma_cmd_rsp_list,
2247962306a36Sopenharmony_ci					struct fcp_cmd_rsp_buf,
2248062306a36Sopenharmony_ci					list_node);
2248162306a36Sopenharmony_ci
2248262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
2248362306a36Sopenharmony_ci
2248462306a36Sopenharmony_ci	return allocated_buf;
2248562306a36Sopenharmony_ci}
2248662306a36Sopenharmony_ci
2248762306a36Sopenharmony_ci/**
2248862306a36Sopenharmony_ci * lpfc_put_cmd_rsp_buf_per_hdwq - Put one CMD/RSP buffer into hdwq pool
2248962306a36Sopenharmony_ci * @phba: The HBA for which this call is being executed.
2249062306a36Sopenharmony_ci * @lpfc_buf: IO buf structure with the CMD/RSP buf
2249162306a36Sopenharmony_ci *
2249262306a36Sopenharmony_ci * This routine puts one CMD/RSP buffer into executing CPU's CMD/RSP pool.
2249362306a36Sopenharmony_ci *
2249462306a36Sopenharmony_ci * Return codes:
2249562306a36Sopenharmony_ci *   0 - Success
2249662306a36Sopenharmony_ci *   -EINVAL - Error
2249762306a36Sopenharmony_ci **/
2249862306a36Sopenharmony_ciint
2249962306a36Sopenharmony_cilpfc_put_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
2250062306a36Sopenharmony_ci			      struct lpfc_io_buf *lpfc_buf)
2250162306a36Sopenharmony_ci{
2250262306a36Sopenharmony_ci	int rc = 0;
2250362306a36Sopenharmony_ci	struct fcp_cmd_rsp_buf *list_entry = NULL;
2250462306a36Sopenharmony_ci	struct fcp_cmd_rsp_buf *tmp = NULL;
2250562306a36Sopenharmony_ci	struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq;
2250662306a36Sopenharmony_ci	struct list_head *buf_list = &hdwq->cmd_rsp_buf_list;
2250762306a36Sopenharmony_ci	unsigned long iflags;
2250862306a36Sopenharmony_ci
2250962306a36Sopenharmony_ci	spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
2251062306a36Sopenharmony_ci
2251162306a36Sopenharmony_ci	if (likely(!list_empty(&lpfc_buf->dma_cmd_rsp_list))) {
2251262306a36Sopenharmony_ci		list_for_each_entry_safe(list_entry, tmp,
2251362306a36Sopenharmony_ci					 &lpfc_buf->dma_cmd_rsp_list,
2251462306a36Sopenharmony_ci					 list_node) {
2251562306a36Sopenharmony_ci			list_move_tail(&list_entry->list_node,
2251662306a36Sopenharmony_ci				       buf_list);
2251762306a36Sopenharmony_ci		}
2251862306a36Sopenharmony_ci	} else {
2251962306a36Sopenharmony_ci		rc = -EINVAL;
2252062306a36Sopenharmony_ci	}
2252162306a36Sopenharmony_ci
2252262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
2252362306a36Sopenharmony_ci	return rc;
2252462306a36Sopenharmony_ci}
2252562306a36Sopenharmony_ci
2252662306a36Sopenharmony_ci/**
2252762306a36Sopenharmony_ci * lpfc_free_cmd_rsp_buf_per_hdwq - Free all CMD/RSP chunks of hdwq pool
2252862306a36Sopenharmony_ci * @phba: phba object
2252962306a36Sopenharmony_ci * @hdwq: hdwq to cleanup cmd rsp buff resources on
2253062306a36Sopenharmony_ci *
2253162306a36Sopenharmony_ci * This routine frees all CMD/RSP buffers of hdwq's CMD/RSP buf pool.
2253262306a36Sopenharmony_ci *
2253362306a36Sopenharmony_ci * Return codes:
2253462306a36Sopenharmony_ci *   None
2253562306a36Sopenharmony_ci **/
2253662306a36Sopenharmony_civoid
2253762306a36Sopenharmony_cilpfc_free_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
2253862306a36Sopenharmony_ci			       struct lpfc_sli4_hdw_queue *hdwq)
2253962306a36Sopenharmony_ci{
2254062306a36Sopenharmony_ci	struct list_head *buf_list = &hdwq->cmd_rsp_buf_list;
2254162306a36Sopenharmony_ci	struct fcp_cmd_rsp_buf *list_entry = NULL;
2254262306a36Sopenharmony_ci	struct fcp_cmd_rsp_buf *tmp = NULL;
2254362306a36Sopenharmony_ci	unsigned long iflags;
2254462306a36Sopenharmony_ci
2254562306a36Sopenharmony_ci	spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
2254662306a36Sopenharmony_ci
2254762306a36Sopenharmony_ci	/* Free cmd_rsp buf pool */
2254862306a36Sopenharmony_ci	list_for_each_entry_safe(list_entry, tmp,
2254962306a36Sopenharmony_ci				 buf_list,
2255062306a36Sopenharmony_ci				 list_node) {
2255162306a36Sopenharmony_ci		list_del(&list_entry->list_node);
2255262306a36Sopenharmony_ci		dma_pool_free(phba->lpfc_cmd_rsp_buf_pool,
2255362306a36Sopenharmony_ci			      list_entry->fcp_cmnd,
2255462306a36Sopenharmony_ci			      list_entry->fcp_cmd_rsp_dma_handle);
2255562306a36Sopenharmony_ci		kfree(list_entry);
2255662306a36Sopenharmony_ci	}
2255762306a36Sopenharmony_ci
2255862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
2255962306a36Sopenharmony_ci}
2256062306a36Sopenharmony_ci
2256162306a36Sopenharmony_ci/**
2256262306a36Sopenharmony_ci * lpfc_sli_prep_wqe - Prepare WQE for the command to be posted
2256362306a36Sopenharmony_ci * @phba: phba object
2256462306a36Sopenharmony_ci * @job: job entry of the command to be posted.
2256562306a36Sopenharmony_ci *
2256662306a36Sopenharmony_ci * Fill the common fields of the wqe for each of the command.
2256762306a36Sopenharmony_ci *
2256862306a36Sopenharmony_ci * Return codes:
2256962306a36Sopenharmony_ci *	None
2257062306a36Sopenharmony_ci **/
2257162306a36Sopenharmony_civoid
2257262306a36Sopenharmony_cilpfc_sli_prep_wqe(struct lpfc_hba *phba, struct lpfc_iocbq *job)
2257362306a36Sopenharmony_ci{
2257462306a36Sopenharmony_ci	u8 cmnd;
2257562306a36Sopenharmony_ci	u32 *pcmd;
2257662306a36Sopenharmony_ci	u32 if_type = 0;
2257762306a36Sopenharmony_ci	u32 fip, abort_tag;
2257862306a36Sopenharmony_ci	struct lpfc_nodelist *ndlp = NULL;
2257962306a36Sopenharmony_ci	union lpfc_wqe128 *wqe = &job->wqe;
2258062306a36Sopenharmony_ci	u8 command_type = ELS_COMMAND_NON_FIP;
2258162306a36Sopenharmony_ci
2258262306a36Sopenharmony_ci	fip = phba->hba_flag & HBA_FIP_SUPPORT;
2258362306a36Sopenharmony_ci	/* The fcp commands will set command type */
2258462306a36Sopenharmony_ci	if (job->cmd_flag &  LPFC_IO_FCP)
2258562306a36Sopenharmony_ci		command_type = FCP_COMMAND;
2258662306a36Sopenharmony_ci	else if (fip && (job->cmd_flag & LPFC_FIP_ELS_ID_MASK))
2258762306a36Sopenharmony_ci		command_type = ELS_COMMAND_FIP;
2258862306a36Sopenharmony_ci	else
2258962306a36Sopenharmony_ci		command_type = ELS_COMMAND_NON_FIP;
2259062306a36Sopenharmony_ci
2259162306a36Sopenharmony_ci	abort_tag = job->iotag;
2259262306a36Sopenharmony_ci	cmnd = bf_get(wqe_cmnd, &wqe->els_req.wqe_com);
2259362306a36Sopenharmony_ci
2259462306a36Sopenharmony_ci	switch (cmnd) {
2259562306a36Sopenharmony_ci	case CMD_ELS_REQUEST64_WQE:
2259662306a36Sopenharmony_ci		ndlp = job->ndlp;
2259762306a36Sopenharmony_ci
2259862306a36Sopenharmony_ci		if_type = bf_get(lpfc_sli_intf_if_type,
2259962306a36Sopenharmony_ci				 &phba->sli4_hba.sli_intf);
2260062306a36Sopenharmony_ci		if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
2260162306a36Sopenharmony_ci			pcmd = (u32 *)job->cmd_dmabuf->virt;
2260262306a36Sopenharmony_ci			if (pcmd && (*pcmd == ELS_CMD_FLOGI ||
2260362306a36Sopenharmony_ci				     *pcmd == ELS_CMD_SCR ||
2260462306a36Sopenharmony_ci				     *pcmd == ELS_CMD_RDF ||
2260562306a36Sopenharmony_ci				     *pcmd == ELS_CMD_EDC ||
2260662306a36Sopenharmony_ci				     *pcmd == ELS_CMD_RSCN_XMT ||
2260762306a36Sopenharmony_ci				     *pcmd == ELS_CMD_FDISC ||
2260862306a36Sopenharmony_ci				     *pcmd == ELS_CMD_LOGO ||
2260962306a36Sopenharmony_ci				     *pcmd == ELS_CMD_QFPA ||
2261062306a36Sopenharmony_ci				     *pcmd == ELS_CMD_UVEM ||
2261162306a36Sopenharmony_ci				     *pcmd == ELS_CMD_PLOGI)) {
2261262306a36Sopenharmony_ci				bf_set(els_req64_sp, &wqe->els_req, 1);
2261362306a36Sopenharmony_ci				bf_set(els_req64_sid, &wqe->els_req,
2261462306a36Sopenharmony_ci				       job->vport->fc_myDID);
2261562306a36Sopenharmony_ci
2261662306a36Sopenharmony_ci				if ((*pcmd == ELS_CMD_FLOGI) &&
2261762306a36Sopenharmony_ci				    !(phba->fc_topology ==
2261862306a36Sopenharmony_ci				      LPFC_TOPOLOGY_LOOP))
2261962306a36Sopenharmony_ci					bf_set(els_req64_sid, &wqe->els_req, 0);
2262062306a36Sopenharmony_ci
2262162306a36Sopenharmony_ci				bf_set(wqe_ct, &wqe->els_req.wqe_com, 1);
2262262306a36Sopenharmony_ci				bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
2262362306a36Sopenharmony_ci				       phba->vpi_ids[job->vport->vpi]);
2262462306a36Sopenharmony_ci			} else if (pcmd) {
2262562306a36Sopenharmony_ci				bf_set(wqe_ct, &wqe->els_req.wqe_com, 0);
2262662306a36Sopenharmony_ci				bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
2262762306a36Sopenharmony_ci				       phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
2262862306a36Sopenharmony_ci			}
2262962306a36Sopenharmony_ci		}
2263062306a36Sopenharmony_ci
2263162306a36Sopenharmony_ci		bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com,
2263262306a36Sopenharmony_ci		       phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
2263362306a36Sopenharmony_ci
2263462306a36Sopenharmony_ci		bf_set(wqe_dbde, &wqe->els_req.wqe_com, 1);
2263562306a36Sopenharmony_ci		bf_set(wqe_iod, &wqe->els_req.wqe_com, LPFC_WQE_IOD_READ);
2263662306a36Sopenharmony_ci		bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1);
2263762306a36Sopenharmony_ci		bf_set(wqe_lenloc, &wqe->els_req.wqe_com, LPFC_WQE_LENLOC_NONE);
2263862306a36Sopenharmony_ci		bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0);
2263962306a36Sopenharmony_ci		break;
2264062306a36Sopenharmony_ci	case CMD_XMIT_ELS_RSP64_WQE:
2264162306a36Sopenharmony_ci		ndlp = job->ndlp;
2264262306a36Sopenharmony_ci
2264362306a36Sopenharmony_ci		/* word4 */
2264462306a36Sopenharmony_ci		wqe->xmit_els_rsp.word4 = 0;
2264562306a36Sopenharmony_ci
2264662306a36Sopenharmony_ci		if_type = bf_get(lpfc_sli_intf_if_type,
2264762306a36Sopenharmony_ci				 &phba->sli4_hba.sli_intf);
2264862306a36Sopenharmony_ci		if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
2264962306a36Sopenharmony_ci			if (job->vport->fc_flag & FC_PT2PT) {
2265062306a36Sopenharmony_ci				bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1);
2265162306a36Sopenharmony_ci				bf_set(els_rsp64_sid, &wqe->xmit_els_rsp,
2265262306a36Sopenharmony_ci				       job->vport->fc_myDID);
2265362306a36Sopenharmony_ci				if (job->vport->fc_myDID == Fabric_DID) {
2265462306a36Sopenharmony_ci					bf_set(wqe_els_did,
2265562306a36Sopenharmony_ci					       &wqe->xmit_els_rsp.wqe_dest, 0);
2265662306a36Sopenharmony_ci				}
2265762306a36Sopenharmony_ci			}
2265862306a36Sopenharmony_ci		}
2265962306a36Sopenharmony_ci
2266062306a36Sopenharmony_ci		bf_set(wqe_dbde, &wqe->xmit_els_rsp.wqe_com, 1);
2266162306a36Sopenharmony_ci		bf_set(wqe_iod, &wqe->xmit_els_rsp.wqe_com, LPFC_WQE_IOD_WRITE);
2266262306a36Sopenharmony_ci		bf_set(wqe_qosd, &wqe->xmit_els_rsp.wqe_com, 1);
2266362306a36Sopenharmony_ci		bf_set(wqe_lenloc, &wqe->xmit_els_rsp.wqe_com,
2266462306a36Sopenharmony_ci		       LPFC_WQE_LENLOC_WORD3);
2266562306a36Sopenharmony_ci		bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0);
2266662306a36Sopenharmony_ci
2266762306a36Sopenharmony_ci		if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
2266862306a36Sopenharmony_ci			bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1);
2266962306a36Sopenharmony_ci			bf_set(els_rsp64_sid, &wqe->xmit_els_rsp,
2267062306a36Sopenharmony_ci			       job->vport->fc_myDID);
2267162306a36Sopenharmony_ci			bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, 1);
2267262306a36Sopenharmony_ci		}
2267362306a36Sopenharmony_ci
2267462306a36Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4) {
2267562306a36Sopenharmony_ci			bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp,
2267662306a36Sopenharmony_ci			       phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
2267762306a36Sopenharmony_ci
2267862306a36Sopenharmony_ci			if (bf_get(wqe_ct, &wqe->xmit_els_rsp.wqe_com))
2267962306a36Sopenharmony_ci				bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com,
2268062306a36Sopenharmony_ci				       phba->vpi_ids[job->vport->vpi]);
2268162306a36Sopenharmony_ci		}
2268262306a36Sopenharmony_ci		command_type = OTHER_COMMAND;
2268362306a36Sopenharmony_ci		break;
2268462306a36Sopenharmony_ci	case CMD_GEN_REQUEST64_WQE:
2268562306a36Sopenharmony_ci		/* Word 10 */
2268662306a36Sopenharmony_ci		bf_set(wqe_dbde, &wqe->gen_req.wqe_com, 1);
2268762306a36Sopenharmony_ci		bf_set(wqe_iod, &wqe->gen_req.wqe_com, LPFC_WQE_IOD_READ);
2268862306a36Sopenharmony_ci		bf_set(wqe_qosd, &wqe->gen_req.wqe_com, 1);
2268962306a36Sopenharmony_ci		bf_set(wqe_lenloc, &wqe->gen_req.wqe_com, LPFC_WQE_LENLOC_NONE);
2269062306a36Sopenharmony_ci		bf_set(wqe_ebde_cnt, &wqe->gen_req.wqe_com, 0);
2269162306a36Sopenharmony_ci		command_type = OTHER_COMMAND;
2269262306a36Sopenharmony_ci		break;
2269362306a36Sopenharmony_ci	case CMD_XMIT_SEQUENCE64_WQE:
2269462306a36Sopenharmony_ci		if (phba->link_flag & LS_LOOPBACK_MODE)
2269562306a36Sopenharmony_ci			bf_set(wqe_xo, &wqe->xmit_sequence.wge_ctl, 1);
2269662306a36Sopenharmony_ci
2269762306a36Sopenharmony_ci		wqe->xmit_sequence.rsvd3 = 0;
2269862306a36Sopenharmony_ci		bf_set(wqe_pu, &wqe->xmit_sequence.wqe_com, 0);
2269962306a36Sopenharmony_ci		bf_set(wqe_dbde, &wqe->xmit_sequence.wqe_com, 1);
2270062306a36Sopenharmony_ci		bf_set(wqe_iod, &wqe->xmit_sequence.wqe_com,
2270162306a36Sopenharmony_ci		       LPFC_WQE_IOD_WRITE);
2270262306a36Sopenharmony_ci		bf_set(wqe_lenloc, &wqe->xmit_sequence.wqe_com,
2270362306a36Sopenharmony_ci		       LPFC_WQE_LENLOC_WORD12);
2270462306a36Sopenharmony_ci		bf_set(wqe_ebde_cnt, &wqe->xmit_sequence.wqe_com, 0);
2270562306a36Sopenharmony_ci		command_type = OTHER_COMMAND;
2270662306a36Sopenharmony_ci		break;
2270762306a36Sopenharmony_ci	case CMD_XMIT_BLS_RSP64_WQE:
2270862306a36Sopenharmony_ci		bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff);
2270962306a36Sopenharmony_ci		bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1);
2271062306a36Sopenharmony_ci		bf_set(wqe_ct, &wqe->xmit_bls_rsp.wqe_com, 1);
2271162306a36Sopenharmony_ci		bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com,
2271262306a36Sopenharmony_ci		       phba->vpi_ids[phba->pport->vpi]);
2271362306a36Sopenharmony_ci		bf_set(wqe_qosd, &wqe->xmit_bls_rsp.wqe_com, 1);
2271462306a36Sopenharmony_ci		bf_set(wqe_lenloc, &wqe->xmit_bls_rsp.wqe_com,
2271562306a36Sopenharmony_ci		       LPFC_WQE_LENLOC_NONE);
2271662306a36Sopenharmony_ci		/* Overwrite the pre-set comnd type with OTHER_COMMAND */
2271762306a36Sopenharmony_ci		command_type = OTHER_COMMAND;
2271862306a36Sopenharmony_ci		break;
2271962306a36Sopenharmony_ci	case CMD_FCP_ICMND64_WQE:	/* task mgmt commands */
2272062306a36Sopenharmony_ci	case CMD_ABORT_XRI_WQE:		/* abort iotag */
2272162306a36Sopenharmony_ci	case CMD_SEND_FRAME:		/* mds loopback */
2272262306a36Sopenharmony_ci		/* cases already formatted for sli4 wqe - no chgs necessary */
2272362306a36Sopenharmony_ci		return;
2272462306a36Sopenharmony_ci	default:
2272562306a36Sopenharmony_ci		dump_stack();
2272662306a36Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
2272762306a36Sopenharmony_ci				"6207 Invalid command 0x%x\n",
2272862306a36Sopenharmony_ci				cmnd);
2272962306a36Sopenharmony_ci		break;
2273062306a36Sopenharmony_ci	}
2273162306a36Sopenharmony_ci
2273262306a36Sopenharmony_ci	wqe->generic.wqe_com.abort_tag = abort_tag;
2273362306a36Sopenharmony_ci	bf_set(wqe_reqtag, &wqe->generic.wqe_com, job->iotag);
2273462306a36Sopenharmony_ci	bf_set(wqe_cmd_type, &wqe->generic.wqe_com, command_type);
2273562306a36Sopenharmony_ci	bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
2273662306a36Sopenharmony_ci}
22737