162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Marvell Fibre Channel HBA Driver
462306a36Sopenharmony_ci * Copyright (c)  2021     Marvell
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "qla_def.h"
762306a36Sopenharmony_ci#include "qla_edif.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/kthread.h>
1062306a36Sopenharmony_ci#include <linux/vmalloc.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic struct edif_sa_index_entry *qla_edif_sadb_find_sa_index_entry(uint16_t nport_handle,
1562306a36Sopenharmony_ci		struct list_head *sa_list);
1662306a36Sopenharmony_cistatic uint16_t qla_edif_sadb_get_sa_index(fc_port_t *fcport,
1762306a36Sopenharmony_ci		struct qla_sa_update_frame *sa_frame);
1862306a36Sopenharmony_cistatic int qla_edif_sadb_delete_sa_index(fc_port_t *fcport, uint16_t nport_handle,
1962306a36Sopenharmony_ci		uint16_t sa_index);
2062306a36Sopenharmony_cistatic int qla_pur_get_pending(scsi_qla_host_t *, fc_port_t *, struct bsg_job *);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct edb_node {
2362306a36Sopenharmony_ci	struct  list_head	list;
2462306a36Sopenharmony_ci	uint32_t		ntype;
2562306a36Sopenharmony_ci	union {
2662306a36Sopenharmony_ci		port_id_t	plogi_did;
2762306a36Sopenharmony_ci		uint32_t	async;
2862306a36Sopenharmony_ci		port_id_t	els_sid;
2962306a36Sopenharmony_ci		struct edif_sa_update_aen	sa_aen;
3062306a36Sopenharmony_ci	} u;
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic struct els_sub_cmd {
3462306a36Sopenharmony_ci	uint16_t cmd;
3562306a36Sopenharmony_ci	const char *str;
3662306a36Sopenharmony_ci} sc_str[] = {
3762306a36Sopenharmony_ci	{SEND_ELS, "send ELS"},
3862306a36Sopenharmony_ci	{SEND_ELS_REPLY, "send ELS Reply"},
3962306a36Sopenharmony_ci	{PULL_ELS, "retrieve ELS"},
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ciconst char *sc_to_str(uint16_t cmd)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	int i;
4562306a36Sopenharmony_ci	struct els_sub_cmd *e;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sc_str); i++) {
4862306a36Sopenharmony_ci		e = sc_str + i;
4962306a36Sopenharmony_ci		if (cmd == e->cmd)
5062306a36Sopenharmony_ci			return e->str;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci	return "unknown";
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic struct edb_node *qla_edb_getnext(scsi_qla_host_t *vha)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	unsigned long   flags;
5862306a36Sopenharmony_ci	struct edb_node *edbnode = NULL;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	spin_lock_irqsave(&vha->e_dbell.db_lock, flags);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/* db nodes are fifo - no qualifications done */
6362306a36Sopenharmony_ci	if (!list_empty(&vha->e_dbell.head)) {
6462306a36Sopenharmony_ci		edbnode = list_first_entry(&vha->e_dbell.head,
6562306a36Sopenharmony_ci					   struct edb_node, list);
6662306a36Sopenharmony_ci		list_del_init(&edbnode->list);
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	spin_unlock_irqrestore(&vha->e_dbell.db_lock, flags);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return edbnode;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic void qla_edb_node_free(scsi_qla_host_t *vha, struct edb_node *node)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	list_del_init(&node->list);
7762306a36Sopenharmony_ci	kfree(node);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic struct edif_list_entry *qla_edif_list_find_sa_index(fc_port_t *fcport,
8162306a36Sopenharmony_ci		uint16_t handle)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct edif_list_entry *entry;
8462306a36Sopenharmony_ci	struct edif_list_entry *tentry;
8562306a36Sopenharmony_ci	struct list_head *indx_list = &fcport->edif.edif_indx_list;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	list_for_each_entry_safe(entry, tentry, indx_list, next) {
8862306a36Sopenharmony_ci		if (entry->handle == handle)
8962306a36Sopenharmony_ci			return entry;
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci	return NULL;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/* timeout called when no traffic and delayed rx sa_index delete */
9562306a36Sopenharmony_cistatic void qla2x00_sa_replace_iocb_timeout(struct timer_list *t)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct edif_list_entry *edif_entry = from_timer(edif_entry, t, timer);
9862306a36Sopenharmony_ci	fc_port_t *fcport = edif_entry->fcport;
9962306a36Sopenharmony_ci	struct scsi_qla_host *vha = fcport->vha;
10062306a36Sopenharmony_ci	struct  edif_sa_ctl *sa_ctl;
10162306a36Sopenharmony_ci	uint16_t nport_handle;
10262306a36Sopenharmony_ci	unsigned long flags = 0;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x3069,
10562306a36Sopenharmony_ci	    "%s:  nport_handle 0x%x,  SA REPL Delay Timeout, %8phC portid=%06x\n",
10662306a36Sopenharmony_ci	    __func__, edif_entry->handle, fcport->port_name, fcport->d_id.b24);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/*
10962306a36Sopenharmony_ci	 * if delete_sa_index is valid then no one has serviced this
11062306a36Sopenharmony_ci	 * delayed delete
11162306a36Sopenharmony_ci	 */
11262306a36Sopenharmony_ci	spin_lock_irqsave(&fcport->edif.indx_list_lock, flags);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/*
11562306a36Sopenharmony_ci	 * delete_sa_index is invalidated when we find the new sa_index in
11662306a36Sopenharmony_ci	 * the incoming data stream.  If it is not invalidated then we are
11762306a36Sopenharmony_ci	 * still looking for the new sa_index because there is no I/O and we
11862306a36Sopenharmony_ci	 * need to just force the rx delete and move on.  Otherwise
11962306a36Sopenharmony_ci	 * we could get another rekey which will result in an error 66.
12062306a36Sopenharmony_ci	 */
12162306a36Sopenharmony_ci	if (edif_entry->delete_sa_index != INVALID_EDIF_SA_INDEX) {
12262306a36Sopenharmony_ci		uint16_t delete_sa_index = edif_entry->delete_sa_index;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		edif_entry->delete_sa_index = INVALID_EDIF_SA_INDEX;
12562306a36Sopenharmony_ci		nport_handle = edif_entry->handle;
12662306a36Sopenharmony_ci		spin_unlock_irqrestore(&fcport->edif.indx_list_lock, flags);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		sa_ctl = qla_edif_find_sa_ctl_by_index(fcport,
12962306a36Sopenharmony_ci		    delete_sa_index, 0);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		if (sa_ctl) {
13262306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x3063,
13362306a36Sopenharmony_ci			    "%s: sa_ctl: %p, delete index %d, update index: %d, lid: 0x%x\n",
13462306a36Sopenharmony_ci			    __func__, sa_ctl, delete_sa_index, edif_entry->update_sa_index,
13562306a36Sopenharmony_ci			    nport_handle);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci			sa_ctl->flags = EDIF_SA_CTL_FLG_DEL;
13862306a36Sopenharmony_ci			set_bit(EDIF_SA_CTL_REPL, &sa_ctl->state);
13962306a36Sopenharmony_ci			qla_post_sa_replace_work(fcport->vha, fcport,
14062306a36Sopenharmony_ci			    nport_handle, sa_ctl);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		} else {
14362306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x3063,
14462306a36Sopenharmony_ci			    "%s: sa_ctl not found for delete_sa_index: %d\n",
14562306a36Sopenharmony_ci			    __func__, edif_entry->delete_sa_index);
14662306a36Sopenharmony_ci		}
14762306a36Sopenharmony_ci	} else {
14862306a36Sopenharmony_ci		spin_unlock_irqrestore(&fcport->edif.indx_list_lock, flags);
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/*
15362306a36Sopenharmony_ci * create a new list entry for this nport handle and
15462306a36Sopenharmony_ci * add an sa_update index to the list - called for sa_update
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_cistatic int qla_edif_list_add_sa_update_index(fc_port_t *fcport,
15762306a36Sopenharmony_ci		uint16_t sa_index, uint16_t handle)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct edif_list_entry *entry;
16062306a36Sopenharmony_ci	unsigned long flags = 0;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* if the entry exists, then just update the sa_index */
16362306a36Sopenharmony_ci	entry = qla_edif_list_find_sa_index(fcport, handle);
16462306a36Sopenharmony_ci	if (entry) {
16562306a36Sopenharmony_ci		entry->update_sa_index = sa_index;
16662306a36Sopenharmony_ci		entry->count = 0;
16762306a36Sopenharmony_ci		return 0;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/*
17162306a36Sopenharmony_ci	 * This is the normal path - there should be no existing entry
17262306a36Sopenharmony_ci	 * when update is called.  The exception is at startup
17362306a36Sopenharmony_ci	 * when update is called for the first two sa_indexes
17462306a36Sopenharmony_ci	 * followed by a delete of the first sa_index
17562306a36Sopenharmony_ci	 */
17662306a36Sopenharmony_ci	entry = kzalloc((sizeof(struct edif_list_entry)), GFP_ATOMIC);
17762306a36Sopenharmony_ci	if (!entry)
17862306a36Sopenharmony_ci		return -ENOMEM;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	INIT_LIST_HEAD(&entry->next);
18162306a36Sopenharmony_ci	entry->handle = handle;
18262306a36Sopenharmony_ci	entry->update_sa_index = sa_index;
18362306a36Sopenharmony_ci	entry->delete_sa_index = INVALID_EDIF_SA_INDEX;
18462306a36Sopenharmony_ci	entry->count = 0;
18562306a36Sopenharmony_ci	entry->flags = 0;
18662306a36Sopenharmony_ci	timer_setup(&entry->timer, qla2x00_sa_replace_iocb_timeout, 0);
18762306a36Sopenharmony_ci	spin_lock_irqsave(&fcport->edif.indx_list_lock, flags);
18862306a36Sopenharmony_ci	list_add_tail(&entry->next, &fcport->edif.edif_indx_list);
18962306a36Sopenharmony_ci	spin_unlock_irqrestore(&fcport->edif.indx_list_lock, flags);
19062306a36Sopenharmony_ci	return 0;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/* remove an entry from the list */
19462306a36Sopenharmony_cistatic void qla_edif_list_delete_sa_index(fc_port_t *fcport, struct edif_list_entry *entry)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	unsigned long flags = 0;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	spin_lock_irqsave(&fcport->edif.indx_list_lock, flags);
19962306a36Sopenharmony_ci	list_del(&entry->next);
20062306a36Sopenharmony_ci	spin_unlock_irqrestore(&fcport->edif.indx_list_lock, flags);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ciint qla_post_sa_replace_work(struct scsi_qla_host *vha,
20462306a36Sopenharmony_ci	 fc_port_t *fcport, uint16_t nport_handle, struct edif_sa_ctl *sa_ctl)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct qla_work_evt *e;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	e = qla2x00_alloc_work(vha, QLA_EVT_SA_REPLACE);
20962306a36Sopenharmony_ci	if (!e)
21062306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	e->u.sa_update.fcport = fcport;
21362306a36Sopenharmony_ci	e->u.sa_update.sa_ctl = sa_ctl;
21462306a36Sopenharmony_ci	e->u.sa_update.nport_handle = nport_handle;
21562306a36Sopenharmony_ci	fcport->flags |= FCF_ASYNC_ACTIVE;
21662306a36Sopenharmony_ci	return qla2x00_post_work(vha, e);
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic void
22062306a36Sopenharmony_ciqla_edif_sa_ctl_init(scsi_qla_host_t *vha, struct fc_port  *fcport)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x2058,
22362306a36Sopenharmony_ci	    "Init SA_CTL List for fcport - nn %8phN pn %8phN portid=%06x.\n",
22462306a36Sopenharmony_ci	    fcport->node_name, fcport->port_name, fcport->d_id.b24);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	fcport->edif.tx_rekey_cnt = 0;
22762306a36Sopenharmony_ci	fcport->edif.rx_rekey_cnt = 0;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	fcport->edif.tx_bytes = 0;
23062306a36Sopenharmony_ci	fcport->edif.rx_bytes = 0;
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic int qla_bsg_check(scsi_qla_host_t *vha, struct bsg_job *bsg_job,
23462306a36Sopenharmony_cifc_port_t *fcport)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	struct extra_auth_els *p;
23762306a36Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
23862306a36Sopenharmony_ci	struct qla_bsg_auth_els_request *req =
23962306a36Sopenharmony_ci	    (struct qla_bsg_auth_els_request *)bsg_job->request;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (!vha->hw->flags.edif_enabled) {
24262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x9105,
24362306a36Sopenharmony_ci		    "%s edif not enabled\n", __func__);
24462306a36Sopenharmony_ci		goto done;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci	if (DBELL_INACTIVE(vha)) {
24762306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102,
24862306a36Sopenharmony_ci		    "%s doorbell not enabled\n", __func__);
24962306a36Sopenharmony_ci		goto done;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	p = &req->e;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/* Get response */
25562306a36Sopenharmony_ci	if (p->sub_cmd == PULL_ELS) {
25662306a36Sopenharmony_ci		struct qla_bsg_auth_els_reply *rpl =
25762306a36Sopenharmony_ci			(struct qla_bsg_auth_els_reply *)bsg_job->reply;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		qla_pur_get_pending(vha, fcport, bsg_job);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d,
26262306a36Sopenharmony_ci			"%s %s %8phN sid=%x. xchg %x, nb=%xh bsg ptr %p\n",
26362306a36Sopenharmony_ci			__func__, sc_to_str(p->sub_cmd), fcport->port_name,
26462306a36Sopenharmony_ci			fcport->d_id.b24, rpl->rx_xchg_address,
26562306a36Sopenharmony_ci			rpl->r.reply_payload_rcv_len, bsg_job);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci		goto done;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci	return 0;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cidone:
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
27462306a36Sopenharmony_ci			bsg_reply->reply_payload_rcv_len);
27562306a36Sopenharmony_ci	return -EIO;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cifc_port_t *
27962306a36Sopenharmony_ciqla2x00_find_fcport_by_pid(scsi_qla_host_t *vha, port_id_t *id)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	fc_port_t *f, *tf;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	f = NULL;
28462306a36Sopenharmony_ci	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
28562306a36Sopenharmony_ci		if (f->d_id.b24 == id->b24)
28662306a36Sopenharmony_ci			return f;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci	return NULL;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/**
29262306a36Sopenharmony_ci * qla_edif_app_check(): check for valid application id.
29362306a36Sopenharmony_ci * @vha: host adapter pointer
29462306a36Sopenharmony_ci * @appid: application id
29562306a36Sopenharmony_ci * Return: false = fail, true = pass
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistatic bool
29862306a36Sopenharmony_ciqla_edif_app_check(scsi_qla_host_t *vha, struct app_id appid)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	/* check that the app is allow/known to the driver */
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (appid.app_vid != EDIF_APP_ID) {
30362306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d, "%s app id not ok (%x)",
30462306a36Sopenharmony_ci		    __func__, appid.app_vid);
30562306a36Sopenharmony_ci		return false;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (appid.version != EDIF_VERSION1) {
30962306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d, "%s app version is not ok (%x)",
31062306a36Sopenharmony_ci		    __func__, appid.version);
31162306a36Sopenharmony_ci		return false;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return true;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic void
31862306a36Sopenharmony_ciqla_edif_free_sa_ctl(fc_port_t *fcport, struct edif_sa_ctl *sa_ctl,
31962306a36Sopenharmony_ci	int index)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	unsigned long flags = 0;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	spin_lock_irqsave(&fcport->edif.sa_list_lock, flags);
32462306a36Sopenharmony_ci	list_del(&sa_ctl->next);
32562306a36Sopenharmony_ci	spin_unlock_irqrestore(&fcport->edif.sa_list_lock, flags);
32662306a36Sopenharmony_ci	if (index >= 512)
32762306a36Sopenharmony_ci		fcport->edif.tx_rekey_cnt--;
32862306a36Sopenharmony_ci	else
32962306a36Sopenharmony_ci		fcport->edif.rx_rekey_cnt--;
33062306a36Sopenharmony_ci	kfree(sa_ctl);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci/* return an index to the freepool */
33462306a36Sopenharmony_cistatic void qla_edif_add_sa_index_to_freepool(fc_port_t *fcport, int dir,
33562306a36Sopenharmony_ci		uint16_t sa_index)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	void *sa_id_map;
33862306a36Sopenharmony_ci	struct scsi_qla_host *vha = fcport->vha;
33962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
34062306a36Sopenharmony_ci	unsigned long flags = 0;
34162306a36Sopenharmony_ci	u16 lsa_index = sa_index;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif + ql_dbg_verbose, vha, 0x3063,
34462306a36Sopenharmony_ci	    "%s: entry\n", __func__);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (dir) {
34762306a36Sopenharmony_ci		sa_id_map = ha->edif_tx_sa_id_map;
34862306a36Sopenharmony_ci		lsa_index -= EDIF_TX_SA_INDEX_BASE;
34962306a36Sopenharmony_ci	} else {
35062306a36Sopenharmony_ci		sa_id_map = ha->edif_rx_sa_id_map;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	spin_lock_irqsave(&ha->sadb_fp_lock, flags);
35462306a36Sopenharmony_ci	clear_bit(lsa_index, sa_id_map);
35562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->sadb_fp_lock, flags);
35662306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x3063,
35762306a36Sopenharmony_ci	    "%s: index %d added to free pool\n", __func__, sa_index);
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic void __qla2x00_release_all_sadb(struct scsi_qla_host *vha,
36162306a36Sopenharmony_ci	struct fc_port *fcport, struct edif_sa_index_entry *entry,
36262306a36Sopenharmony_ci	int pdir)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	struct edif_list_entry *edif_entry;
36562306a36Sopenharmony_ci	struct  edif_sa_ctl *sa_ctl;
36662306a36Sopenharmony_ci	int i, dir;
36762306a36Sopenharmony_ci	int key_cnt = 0;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
37062306a36Sopenharmony_ci		if (entry->sa_pair[i].sa_index == INVALID_EDIF_SA_INDEX)
37162306a36Sopenharmony_ci			continue;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		if (fcport->loop_id != entry->handle) {
37462306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x3063,
37562306a36Sopenharmony_ci			    "%s: ** WARNING %d** entry handle: 0x%x, lid: 0x%x, sa_index: %d\n",
37662306a36Sopenharmony_ci			    __func__, i, entry->handle, fcport->loop_id,
37762306a36Sopenharmony_ci			    entry->sa_pair[i].sa_index);
37862306a36Sopenharmony_ci		}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		/* release the sa_ctl */
38162306a36Sopenharmony_ci		sa_ctl = qla_edif_find_sa_ctl_by_index(fcport,
38262306a36Sopenharmony_ci				entry->sa_pair[i].sa_index, pdir);
38362306a36Sopenharmony_ci		if (sa_ctl &&
38462306a36Sopenharmony_ci		    qla_edif_find_sa_ctl_by_index(fcport, sa_ctl->index, pdir)) {
38562306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x3063,
38662306a36Sopenharmony_ci			    "%s: freeing sa_ctl for index %d\n", __func__, sa_ctl->index);
38762306a36Sopenharmony_ci			qla_edif_free_sa_ctl(fcport, sa_ctl, sa_ctl->index);
38862306a36Sopenharmony_ci		} else {
38962306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x3063,
39062306a36Sopenharmony_ci			    "%s: sa_ctl NOT freed, sa_ctl: %p\n", __func__, sa_ctl);
39162306a36Sopenharmony_ci		}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		/* Release the index */
39462306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
39562306a36Sopenharmony_ci			"%s: freeing sa_index %d, nph: 0x%x\n",
39662306a36Sopenharmony_ci			__func__, entry->sa_pair[i].sa_index, entry->handle);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		dir = (entry->sa_pair[i].sa_index <
39962306a36Sopenharmony_ci			EDIF_TX_SA_INDEX_BASE) ? 0 : 1;
40062306a36Sopenharmony_ci		qla_edif_add_sa_index_to_freepool(fcport, dir,
40162306a36Sopenharmony_ci			entry->sa_pair[i].sa_index);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci		/* Delete timer on RX */
40462306a36Sopenharmony_ci		if (pdir != SAU_FLG_TX) {
40562306a36Sopenharmony_ci			edif_entry =
40662306a36Sopenharmony_ci				qla_edif_list_find_sa_index(fcport, entry->handle);
40762306a36Sopenharmony_ci			if (edif_entry) {
40862306a36Sopenharmony_ci				ql_dbg(ql_dbg_edif, vha, 0x5033,
40962306a36Sopenharmony_ci				    "%s: remove edif_entry %p, update_sa_index: 0x%x, delete_sa_index: 0x%x\n",
41062306a36Sopenharmony_ci				    __func__, edif_entry, edif_entry->update_sa_index,
41162306a36Sopenharmony_ci				    edif_entry->delete_sa_index);
41262306a36Sopenharmony_ci				qla_edif_list_delete_sa_index(fcport, edif_entry);
41362306a36Sopenharmony_ci				/*
41462306a36Sopenharmony_ci				 * valid delete_sa_index indicates there is a rx
41562306a36Sopenharmony_ci				 * delayed delete queued
41662306a36Sopenharmony_ci				 */
41762306a36Sopenharmony_ci				if (edif_entry->delete_sa_index !=
41862306a36Sopenharmony_ci						INVALID_EDIF_SA_INDEX) {
41962306a36Sopenharmony_ci					timer_shutdown(&edif_entry->timer);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci					/* build and send the aen */
42262306a36Sopenharmony_ci					fcport->edif.rx_sa_set = 1;
42362306a36Sopenharmony_ci					fcport->edif.rx_sa_pending = 0;
42462306a36Sopenharmony_ci					qla_edb_eventcreate(vha,
42562306a36Sopenharmony_ci							VND_CMD_AUTH_STATE_SAUPDATE_COMPL,
42662306a36Sopenharmony_ci							QL_VND_SA_STAT_SUCCESS,
42762306a36Sopenharmony_ci							QL_VND_RX_SA_KEY, fcport);
42862306a36Sopenharmony_ci				}
42962306a36Sopenharmony_ci				ql_dbg(ql_dbg_edif, vha, 0x5033,
43062306a36Sopenharmony_ci				    "%s: release edif_entry %p, update_sa_index: 0x%x, delete_sa_index: 0x%x\n",
43162306a36Sopenharmony_ci				    __func__, edif_entry, edif_entry->update_sa_index,
43262306a36Sopenharmony_ci				    edif_entry->delete_sa_index);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci				kfree(edif_entry);
43562306a36Sopenharmony_ci			}
43662306a36Sopenharmony_ci		}
43762306a36Sopenharmony_ci		key_cnt++;
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x3063,
44062306a36Sopenharmony_ci	    "%s: %d %s keys released\n",
44162306a36Sopenharmony_ci	    __func__, key_cnt, pdir ? "tx" : "rx");
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/* find an release all outstanding sadb sa_indicies */
44562306a36Sopenharmony_civoid qla2x00_release_all_sadb(struct scsi_qla_host *vha, struct fc_port *fcport)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct edif_sa_index_entry *entry, *tmp;
44862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
44962306a36Sopenharmony_ci	unsigned long flags;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif + ql_dbg_verbose, vha, 0x3063,
45262306a36Sopenharmony_ci	    "%s: Starting...\n", __func__);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	spin_lock_irqsave(&ha->sadb_lock, flags);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	list_for_each_entry_safe(entry, tmp, &ha->sadb_rx_index_list, next) {
45762306a36Sopenharmony_ci		if (entry->fcport == fcport) {
45862306a36Sopenharmony_ci			list_del(&entry->next);
45962306a36Sopenharmony_ci			spin_unlock_irqrestore(&ha->sadb_lock, flags);
46062306a36Sopenharmony_ci			__qla2x00_release_all_sadb(vha, fcport, entry, 0);
46162306a36Sopenharmony_ci			kfree(entry);
46262306a36Sopenharmony_ci			spin_lock_irqsave(&ha->sadb_lock, flags);
46362306a36Sopenharmony_ci			break;
46462306a36Sopenharmony_ci		}
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	list_for_each_entry_safe(entry, tmp, &ha->sadb_tx_index_list, next) {
46862306a36Sopenharmony_ci		if (entry->fcport == fcport) {
46962306a36Sopenharmony_ci			list_del(&entry->next);
47062306a36Sopenharmony_ci			spin_unlock_irqrestore(&ha->sadb_lock, flags);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci			__qla2x00_release_all_sadb(vha, fcport, entry, SAU_FLG_TX);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci			kfree(entry);
47562306a36Sopenharmony_ci			spin_lock_irqsave(&ha->sadb_lock, flags);
47662306a36Sopenharmony_ci			break;
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->sadb_lock, flags);
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci/**
48362306a36Sopenharmony_ci * qla_delete_n2n_sess_and_wait: search for N2N session, tear it down and
48462306a36Sopenharmony_ci *    wait for tear down to complete.  In N2N topology, there is only one
48562306a36Sopenharmony_ci *    session being active in tracking the remote device.
48662306a36Sopenharmony_ci * @vha: host adapter pointer
48762306a36Sopenharmony_ci * return code:  0 - found the session and completed the tear down.
48862306a36Sopenharmony_ci *	1 - timeout occurred.  Caller to use link bounce to reset.
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_cistatic int qla_delete_n2n_sess_and_wait(scsi_qla_host_t *vha)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	struct fc_port *fcport;
49362306a36Sopenharmony_ci	int rc = -EIO;
49462306a36Sopenharmony_ci	ulong expire = jiffies + 23 * HZ;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (!N2N_TOPO(vha->hw))
49762306a36Sopenharmony_ci		return 0;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	fcport = NULL;
50062306a36Sopenharmony_ci	list_for_each_entry(fcport, &vha->vp_fcports, list) {
50162306a36Sopenharmony_ci		if (!fcport->n2n_flag)
50262306a36Sopenharmony_ci			continue;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		ql_dbg(ql_dbg_disc, fcport->vha, 0x2016,
50562306a36Sopenharmony_ci		       "%s reset sess at app start \n", __func__);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		qla_edif_sa_ctl_init(vha, fcport);
50862306a36Sopenharmony_ci		qlt_schedule_sess_for_deletion(fcport);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		while (time_before_eq(jiffies, expire)) {
51162306a36Sopenharmony_ci			if (fcport->disc_state != DSC_DELETE_PEND) {
51262306a36Sopenharmony_ci				rc = 0;
51362306a36Sopenharmony_ci				break;
51462306a36Sopenharmony_ci			}
51562306a36Sopenharmony_ci			msleep(1);
51662306a36Sopenharmony_ci		}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
51962306a36Sopenharmony_ci		break;
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	return rc;
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci/**
52662306a36Sopenharmony_ci * qla_edif_app_start:  application has announce its present
52762306a36Sopenharmony_ci * @vha: host adapter pointer
52862306a36Sopenharmony_ci * @bsg_job: user request
52962306a36Sopenharmony_ci *
53062306a36Sopenharmony_ci * Set/activate doorbell.  Reset current sessions and re-login with
53162306a36Sopenharmony_ci * secure flag.
53262306a36Sopenharmony_ci */
53362306a36Sopenharmony_cistatic int
53462306a36Sopenharmony_ciqla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	int32_t			rval = 0;
53762306a36Sopenharmony_ci	struct fc_bsg_reply	*bsg_reply = bsg_job->reply;
53862306a36Sopenharmony_ci	struct app_start	appstart;
53962306a36Sopenharmony_ci	struct app_start_reply	appreply;
54062306a36Sopenharmony_ci	struct fc_port  *fcport, *tf;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x1313,
54362306a36Sopenharmony_ci	       "EDIF application registration with driver, FC device connections will be re-established.\n");
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
54662306a36Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, &appstart,
54762306a36Sopenharmony_ci	    sizeof(struct app_start));
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x911d, "%s app_vid=%x app_start_flags %x\n",
55062306a36Sopenharmony_ci	     __func__, appstart.app_info.app_vid, appstart.app_start_flags);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (DBELL_INACTIVE(vha)) {
55362306a36Sopenharmony_ci		/* mark doorbell as active since an app is now present */
55462306a36Sopenharmony_ci		vha->e_dbell.db_flags |= EDB_ACTIVE;
55562306a36Sopenharmony_ci	} else {
55662306a36Sopenharmony_ci		goto out;
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (N2N_TOPO(vha->hw)) {
56062306a36Sopenharmony_ci		list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list)
56162306a36Sopenharmony_ci			fcport->n2n_link_reset_cnt = 0;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		if (vha->hw->flags.n2n_fw_acc_sec) {
56462306a36Sopenharmony_ci			bool link_bounce = false;
56562306a36Sopenharmony_ci			/*
56662306a36Sopenharmony_ci			 * While authentication app was not running, remote device
56762306a36Sopenharmony_ci			 * could still try to login with this local port.  Let's
56862306a36Sopenharmony_ci			 * reset the session, reconnect and re-authenticate.
56962306a36Sopenharmony_ci			 */
57062306a36Sopenharmony_ci			if (qla_delete_n2n_sess_and_wait(vha))
57162306a36Sopenharmony_ci				link_bounce = true;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci			/* bounce the link to start login */
57462306a36Sopenharmony_ci			if (!vha->hw->flags.n2n_bigger || link_bounce) {
57562306a36Sopenharmony_ci				set_bit(N2N_LINK_RESET, &vha->dpc_flags);
57662306a36Sopenharmony_ci				qla2xxx_wake_dpc(vha);
57762306a36Sopenharmony_ci			}
57862306a36Sopenharmony_ci		} else {
57962306a36Sopenharmony_ci			qla2x00_wait_for_hba_online(vha);
58062306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
58162306a36Sopenharmony_ci			qla2xxx_wake_dpc(vha);
58262306a36Sopenharmony_ci			qla2x00_wait_for_hba_online(vha);
58362306a36Sopenharmony_ci		}
58462306a36Sopenharmony_ci	} else {
58562306a36Sopenharmony_ci		list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
58662306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x2058,
58762306a36Sopenharmony_ci			       "FCSP - nn %8phN pn %8phN portid=%06x.\n",
58862306a36Sopenharmony_ci			       fcport->node_name, fcport->port_name,
58962306a36Sopenharmony_ci			       fcport->d_id.b24);
59062306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0xf084,
59162306a36Sopenharmony_ci			       "%s: se_sess %p / sess %p from port %8phC "
59262306a36Sopenharmony_ci			       "loop_id %#04x s_id %06x logout %d "
59362306a36Sopenharmony_ci			       "keep %d els_logo %d disc state %d auth state %d"
59462306a36Sopenharmony_ci			       "stop state %d\n",
59562306a36Sopenharmony_ci			       __func__, fcport->se_sess, fcport,
59662306a36Sopenharmony_ci			       fcport->port_name, fcport->loop_id,
59762306a36Sopenharmony_ci			       fcport->d_id.b24, fcport->logout_on_delete,
59862306a36Sopenharmony_ci			       fcport->keep_nport_handle, fcport->send_els_logo,
59962306a36Sopenharmony_ci			       fcport->disc_state, fcport->edif.auth_state,
60062306a36Sopenharmony_ci			       fcport->edif.app_stop);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci			if (atomic_read(&vha->loop_state) == LOOP_DOWN)
60362306a36Sopenharmony_ci				break;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci			fcport->login_retry = vha->hw->login_retry_count;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci			fcport->edif.app_stop = 0;
60862306a36Sopenharmony_ci			fcport->edif.app_sess_online = 0;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci			if (fcport->scan_state != QLA_FCPORT_FOUND)
61162306a36Sopenharmony_ci				continue;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci			if (fcport->port_type == FCT_UNKNOWN &&
61462306a36Sopenharmony_ci			    !fcport->fc4_features)
61562306a36Sopenharmony_ci				rval = qla24xx_async_gffid(vha, fcport, true);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci			if (!rval && !(fcport->fc4_features & FC4_FF_TARGET ||
61862306a36Sopenharmony_ci			    fcport->port_type & (FCT_TARGET|FCT_NVME_TARGET)))
61962306a36Sopenharmony_ci				continue;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci			rval = 0;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x911e,
62462306a36Sopenharmony_ci			       "%s wwpn %8phC calling qla_edif_reset_auth_wait\n",
62562306a36Sopenharmony_ci			       __func__, fcport->port_name);
62662306a36Sopenharmony_ci			qlt_schedule_sess_for_deletion(fcport);
62762306a36Sopenharmony_ci			qla_edif_sa_ctl_init(vha, fcport);
62862306a36Sopenharmony_ci		}
62962306a36Sopenharmony_ci		set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (vha->pur_cinfo.enode_flags != ENODE_ACTIVE) {
63362306a36Sopenharmony_ci		/* mark as active since an app is now present */
63462306a36Sopenharmony_ci		vha->pur_cinfo.enode_flags = ENODE_ACTIVE;
63562306a36Sopenharmony_ci	} else {
63662306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911f, "%s enode already active\n",
63762306a36Sopenharmony_ci		     __func__);
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ciout:
64162306a36Sopenharmony_ci	appreply.host_support_edif = vha->hw->flags.edif_enabled;
64262306a36Sopenharmony_ci	appreply.edif_enode_active = vha->pur_cinfo.enode_flags;
64362306a36Sopenharmony_ci	appreply.edif_edb_active = vha->e_dbell.db_flags;
64462306a36Sopenharmony_ci	appreply.version = EDIF_VERSION1;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	SET_DID_STATUS(bsg_reply->result, DID_OK);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
65162306a36Sopenharmony_ci							       bsg_job->reply_payload.sg_cnt,
65262306a36Sopenharmony_ci							       &appreply,
65362306a36Sopenharmony_ci							       sizeof(struct app_start_reply));
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x911d,
65662306a36Sopenharmony_ci	    "%s app start completed with 0x%x\n",
65762306a36Sopenharmony_ci	    __func__, rval);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	return rval;
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci/**
66362306a36Sopenharmony_ci * qla_edif_app_stop - app has announced it's exiting.
66462306a36Sopenharmony_ci * @vha: host adapter pointer
66562306a36Sopenharmony_ci * @bsg_job: user space command pointer
66662306a36Sopenharmony_ci *
66762306a36Sopenharmony_ci * Free any in flight messages, clear all doorbell events
66862306a36Sopenharmony_ci * to application. Reject any message relate to security.
66962306a36Sopenharmony_ci */
67062306a36Sopenharmony_cistatic int
67162306a36Sopenharmony_ciqla_edif_app_stop(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	struct app_stop         appstop;
67462306a36Sopenharmony_ci	struct fc_bsg_reply     *bsg_reply = bsg_job->reply;
67562306a36Sopenharmony_ci	struct fc_port  *fcport, *tf;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
67862306a36Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, &appstop,
67962306a36Sopenharmony_ci	    sizeof(struct app_stop));
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x911d, "%s Stopping APP: app_vid=%x\n",
68262306a36Sopenharmony_ci	    __func__, appstop.app_info.app_vid);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* Call db stop and enode stop functions */
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	/* if we leave this running short waits are operational < 16 secs */
68762306a36Sopenharmony_ci	qla_enode_stop(vha);        /* stop enode */
68862306a36Sopenharmony_ci	qla_edb_stop(vha);          /* stop db */
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
69162306a36Sopenharmony_ci		if (!(fcport->flags & FCF_FCSP_DEVICE))
69262306a36Sopenharmony_ci			continue;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci		if (fcport->flags & FCF_FCSP_DEVICE) {
69562306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0xf084,
69662306a36Sopenharmony_ci			    "%s: sess %p from port %8phC lid %#04x s_id %06x logout %d keep %d els_logo %d\n",
69762306a36Sopenharmony_ci			    __func__, fcport,
69862306a36Sopenharmony_ci			    fcport->port_name, fcport->loop_id, fcport->d_id.b24,
69962306a36Sopenharmony_ci			    fcport->logout_on_delete, fcport->keep_nport_handle,
70062306a36Sopenharmony_ci			    fcport->send_els_logo);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci			if (atomic_read(&vha->loop_state) == LOOP_DOWN)
70362306a36Sopenharmony_ci				break;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci			fcport->edif.app_stop = 1;
70662306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x911e,
70762306a36Sopenharmony_ci				"%s wwpn %8phC calling qla_edif_reset_auth_wait\n",
70862306a36Sopenharmony_ci				__func__, fcport->port_name);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci			fcport->send_els_logo = 1;
71162306a36Sopenharmony_ci			qlt_schedule_sess_for_deletion(fcport);
71262306a36Sopenharmony_ci		}
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
71662306a36Sopenharmony_ci	SET_DID_STATUS(bsg_reply->result, DID_OK);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	/* no return interface to app - it assumes we cleaned up ok */
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	return 0;
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic int
72462306a36Sopenharmony_ciqla_edif_app_chk_sa_update(scsi_qla_host_t *vha, fc_port_t *fcport,
72562306a36Sopenharmony_ci		struct app_plogi_reply *appplogireply)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	int	ret = 0;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	if (!(fcport->edif.rx_sa_set && fcport->edif.tx_sa_set)) {
73062306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911e,
73162306a36Sopenharmony_ci		    "%s: wwpn %8phC Both SA indexes has not been SET TX %d, RX %d.\n",
73262306a36Sopenharmony_ci		    __func__, fcport->port_name, fcport->edif.tx_sa_set,
73362306a36Sopenharmony_ci		    fcport->edif.rx_sa_set);
73462306a36Sopenharmony_ci		appplogireply->prli_status = 0;
73562306a36Sopenharmony_ci		ret = 1;
73662306a36Sopenharmony_ci	} else  {
73762306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911e,
73862306a36Sopenharmony_ci		    "%s wwpn %8phC Both SA(s) updated.\n", __func__,
73962306a36Sopenharmony_ci		    fcport->port_name);
74062306a36Sopenharmony_ci		fcport->edif.rx_sa_set = fcport->edif.tx_sa_set = 0;
74162306a36Sopenharmony_ci		fcport->edif.rx_sa_pending = fcport->edif.tx_sa_pending = 0;
74262306a36Sopenharmony_ci		appplogireply->prli_status = 1;
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci	return ret;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci/**
74862306a36Sopenharmony_ci * qla_edif_app_authok - authentication by app succeeded.  Driver can proceed
74962306a36Sopenharmony_ci *   with prli
75062306a36Sopenharmony_ci * @vha: host adapter pointer
75162306a36Sopenharmony_ci * @bsg_job: user request
75262306a36Sopenharmony_ci */
75362306a36Sopenharmony_cistatic int
75462306a36Sopenharmony_ciqla_edif_app_authok(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	struct auth_complete_cmd appplogiok;
75762306a36Sopenharmony_ci	struct app_plogi_reply	appplogireply = {0};
75862306a36Sopenharmony_ci	struct fc_bsg_reply	*bsg_reply = bsg_job->reply;
75962306a36Sopenharmony_ci	fc_port_t		*fcport = NULL;
76062306a36Sopenharmony_ci	port_id_t		portid = {0};
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
76362306a36Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, &appplogiok,
76462306a36Sopenharmony_ci	    sizeof(struct auth_complete_cmd));
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	/* silent unaligned access warning */
76762306a36Sopenharmony_ci	portid.b.domain = appplogiok.u.d_id.b.domain;
76862306a36Sopenharmony_ci	portid.b.area   = appplogiok.u.d_id.b.area;
76962306a36Sopenharmony_ci	portid.b.al_pa  = appplogiok.u.d_id.b.al_pa;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	appplogireply.version = EDIF_VERSION1;
77262306a36Sopenharmony_ci	switch (appplogiok.type) {
77362306a36Sopenharmony_ci	case PL_TYPE_WWPN:
77462306a36Sopenharmony_ci		fcport = qla2x00_find_fcport_by_wwpn(vha,
77562306a36Sopenharmony_ci		    appplogiok.u.wwpn, 0);
77662306a36Sopenharmony_ci		if (!fcport)
77762306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x911d,
77862306a36Sopenharmony_ci			    "%s wwpn lookup failed: %8phC\n",
77962306a36Sopenharmony_ci			    __func__, appplogiok.u.wwpn);
78062306a36Sopenharmony_ci		break;
78162306a36Sopenharmony_ci	case PL_TYPE_DID:
78262306a36Sopenharmony_ci		fcport = qla2x00_find_fcport_by_pid(vha, &portid);
78362306a36Sopenharmony_ci		if (!fcport)
78462306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x911d,
78562306a36Sopenharmony_ci			    "%s d_id lookup failed: %x\n", __func__,
78662306a36Sopenharmony_ci			    portid.b24);
78762306a36Sopenharmony_ci		break;
78862306a36Sopenharmony_ci	default:
78962306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d,
79062306a36Sopenharmony_ci		    "%s undefined type: %x\n", __func__,
79162306a36Sopenharmony_ci		    appplogiok.type);
79262306a36Sopenharmony_ci		break;
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	if (!fcport) {
79662306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
79762306a36Sopenharmony_ci		goto errstate_exit;
79862306a36Sopenharmony_ci	}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	/*
80162306a36Sopenharmony_ci	 * if port is online then this is a REKEY operation
80262306a36Sopenharmony_ci	 * Only do sa update checking
80362306a36Sopenharmony_ci	 */
80462306a36Sopenharmony_ci	if (atomic_read(&fcport->state) == FCS_ONLINE) {
80562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d,
80662306a36Sopenharmony_ci		    "%s Skipping PRLI complete based on rekey\n", __func__);
80762306a36Sopenharmony_ci		appplogireply.prli_status = 1;
80862306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_OK);
80962306a36Sopenharmony_ci		qla_edif_app_chk_sa_update(vha, fcport, &appplogireply);
81062306a36Sopenharmony_ci		goto errstate_exit;
81162306a36Sopenharmony_ci	}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	/* make sure in AUTH_PENDING or else reject */
81462306a36Sopenharmony_ci	if (fcport->disc_state != DSC_LOGIN_AUTH_PEND) {
81562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911e,
81662306a36Sopenharmony_ci		    "%s wwpn %8phC is not in auth pending state (%x)\n",
81762306a36Sopenharmony_ci		    __func__, fcport->port_name, fcport->disc_state);
81862306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_OK);
81962306a36Sopenharmony_ci		appplogireply.prli_status = 0;
82062306a36Sopenharmony_ci		goto errstate_exit;
82162306a36Sopenharmony_ci	}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	SET_DID_STATUS(bsg_reply->result, DID_OK);
82462306a36Sopenharmony_ci	appplogireply.prli_status = 1;
82562306a36Sopenharmony_ci	fcport->edif.authok = 1;
82662306a36Sopenharmony_ci	if (!(fcport->edif.rx_sa_set && fcport->edif.tx_sa_set)) {
82762306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911e,
82862306a36Sopenharmony_ci		    "%s: wwpn %8phC Both SA indexes has not been SET TX %d, RX %d.\n",
82962306a36Sopenharmony_ci		    __func__, fcport->port_name, fcport->edif.tx_sa_set,
83062306a36Sopenharmony_ci		    fcport->edif.rx_sa_set);
83162306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_OK);
83262306a36Sopenharmony_ci		appplogireply.prli_status = 0;
83362306a36Sopenharmony_ci		goto errstate_exit;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	} else {
83662306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911e,
83762306a36Sopenharmony_ci		    "%s wwpn %8phC Both SA(s) updated.\n", __func__,
83862306a36Sopenharmony_ci		    fcport->port_name);
83962306a36Sopenharmony_ci		fcport->edif.rx_sa_set = fcport->edif.tx_sa_set = 0;
84062306a36Sopenharmony_ci		fcport->edif.rx_sa_pending = fcport->edif.tx_sa_pending = 0;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (qla_ini_mode_enabled(vha)) {
84462306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911e,
84562306a36Sopenharmony_ci		    "%s AUTH complete - RESUME with prli for wwpn %8phC\n",
84662306a36Sopenharmony_ci		    __func__, fcport->port_name);
84762306a36Sopenharmony_ci		qla24xx_post_prli_work(vha, fcport);
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_cierrstate_exit:
85162306a36Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
85262306a36Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
85362306a36Sopenharmony_ci							       bsg_job->reply_payload.sg_cnt,
85462306a36Sopenharmony_ci							       &appplogireply,
85562306a36Sopenharmony_ci							       sizeof(struct app_plogi_reply));
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	return 0;
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci/**
86162306a36Sopenharmony_ci * qla_edif_app_authfail - authentication by app has failed.  Driver is given
86262306a36Sopenharmony_ci *   notice to tear down current session.
86362306a36Sopenharmony_ci * @vha: host adapter pointer
86462306a36Sopenharmony_ci * @bsg_job: user request
86562306a36Sopenharmony_ci */
86662306a36Sopenharmony_cistatic int
86762306a36Sopenharmony_ciqla_edif_app_authfail(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	int32_t			rval = 0;
87062306a36Sopenharmony_ci	struct auth_complete_cmd appplogifail;
87162306a36Sopenharmony_ci	struct fc_bsg_reply	*bsg_reply = bsg_job->reply;
87262306a36Sopenharmony_ci	fc_port_t		*fcport = NULL;
87362306a36Sopenharmony_ci	port_id_t		portid = {0};
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x911d, "%s app auth fail\n", __func__);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
87862306a36Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, &appplogifail,
87962306a36Sopenharmony_ci	    sizeof(struct auth_complete_cmd));
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	/* silent unaligned access warning */
88262306a36Sopenharmony_ci	portid.b.domain = appplogifail.u.d_id.b.domain;
88362306a36Sopenharmony_ci	portid.b.area   = appplogifail.u.d_id.b.area;
88462306a36Sopenharmony_ci	portid.b.al_pa  = appplogifail.u.d_id.b.al_pa;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/*
88762306a36Sopenharmony_ci	 * TODO: edif: app has failed this plogi. Inform driver to
88862306a36Sopenharmony_ci	 * take any action (if any).
88962306a36Sopenharmony_ci	 */
89062306a36Sopenharmony_ci	switch (appplogifail.type) {
89162306a36Sopenharmony_ci	case PL_TYPE_WWPN:
89262306a36Sopenharmony_ci		fcport = qla2x00_find_fcport_by_wwpn(vha,
89362306a36Sopenharmony_ci		    appplogifail.u.wwpn, 0);
89462306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_OK);
89562306a36Sopenharmony_ci		break;
89662306a36Sopenharmony_ci	case PL_TYPE_DID:
89762306a36Sopenharmony_ci		fcport = qla2x00_find_fcport_by_pid(vha, &portid);
89862306a36Sopenharmony_ci		if (!fcport)
89962306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x911d,
90062306a36Sopenharmony_ci			    "%s d_id lookup failed: %x\n", __func__,
90162306a36Sopenharmony_ci			    portid.b24);
90262306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_OK);
90362306a36Sopenharmony_ci		break;
90462306a36Sopenharmony_ci	default:
90562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911e,
90662306a36Sopenharmony_ci		    "%s undefined type: %x\n", __func__,
90762306a36Sopenharmony_ci		    appplogifail.type);
90862306a36Sopenharmony_ci		bsg_job->reply_len = sizeof(struct fc_bsg_reply);
90962306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
91062306a36Sopenharmony_ci		rval = -1;
91162306a36Sopenharmony_ci		break;
91262306a36Sopenharmony_ci	}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x911d,
91562306a36Sopenharmony_ci	    "%s fcport is 0x%p\n", __func__, fcport);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	if (fcport) {
91862306a36Sopenharmony_ci		/* set/reset edif values and flags */
91962306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911e,
92062306a36Sopenharmony_ci		    "%s reset the auth process - %8phC, loopid=%x portid=%06x.\n",
92162306a36Sopenharmony_ci		    __func__, fcport->port_name, fcport->loop_id, fcport->d_id.b24);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci		if (qla_ini_mode_enabled(fcport->vha)) {
92462306a36Sopenharmony_ci			fcport->send_els_logo = 1;
92562306a36Sopenharmony_ci			qlt_schedule_sess_for_deletion(fcport);
92662306a36Sopenharmony_ci		}
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	return rval;
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci/**
93362306a36Sopenharmony_ci * qla_edif_app_getfcinfo - app would like to read session info (wwpn, nportid,
93462306a36Sopenharmony_ci *   [initiator|target] mode.  It can specific session with specific nport id or
93562306a36Sopenharmony_ci *   all sessions.
93662306a36Sopenharmony_ci * @vha: host adapter pointer
93762306a36Sopenharmony_ci * @bsg_job: user request pointer
93862306a36Sopenharmony_ci */
93962306a36Sopenharmony_cistatic int
94062306a36Sopenharmony_ciqla_edif_app_getfcinfo(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
94162306a36Sopenharmony_ci{
94262306a36Sopenharmony_ci	int32_t			rval = 0;
94362306a36Sopenharmony_ci	int32_t			pcnt = 0;
94462306a36Sopenharmony_ci	struct fc_bsg_reply	*bsg_reply = bsg_job->reply;
94562306a36Sopenharmony_ci	struct app_pinfo_req	app_req;
94662306a36Sopenharmony_ci	struct app_pinfo_reply	*app_reply;
94762306a36Sopenharmony_ci	port_id_t		tdid;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x911d, "%s app get fcinfo\n", __func__);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
95262306a36Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, &app_req,
95362306a36Sopenharmony_ci	    sizeof(struct app_pinfo_req));
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	app_reply = kzalloc((sizeof(struct app_pinfo_reply) +
95662306a36Sopenharmony_ci	    sizeof(struct app_pinfo) * app_req.num_ports), GFP_KERNEL);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	if (!app_reply) {
95962306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
96062306a36Sopenharmony_ci		rval = -1;
96162306a36Sopenharmony_ci	} else {
96262306a36Sopenharmony_ci		struct fc_port	*fcport = NULL, *tf;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci		app_reply->version = EDIF_VERSION1;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci		list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
96762306a36Sopenharmony_ci			if (!(fcport->flags & FCF_FCSP_DEVICE))
96862306a36Sopenharmony_ci				continue;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci			tdid.b.domain = app_req.remote_pid.domain;
97162306a36Sopenharmony_ci			tdid.b.area = app_req.remote_pid.area;
97262306a36Sopenharmony_ci			tdid.b.al_pa = app_req.remote_pid.al_pa;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x2058,
97562306a36Sopenharmony_ci			    "APP request entry - portid=%06x.\n", tdid.b24);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci			/* Ran out of space */
97862306a36Sopenharmony_ci			if (pcnt >= app_req.num_ports)
97962306a36Sopenharmony_ci				break;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci			if (tdid.b24 != 0 && tdid.b24 != fcport->d_id.b24)
98262306a36Sopenharmony_ci				continue;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci			if (!N2N_TOPO(vha->hw)) {
98562306a36Sopenharmony_ci				if (fcport->scan_state != QLA_FCPORT_FOUND)
98662306a36Sopenharmony_ci					continue;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci				if (fcport->port_type == FCT_UNKNOWN &&
98962306a36Sopenharmony_ci				    !fcport->fc4_features)
99062306a36Sopenharmony_ci					rval = qla24xx_async_gffid(vha, fcport,
99162306a36Sopenharmony_ci								   true);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci				if (!rval &&
99462306a36Sopenharmony_ci				    !(fcport->fc4_features & FC4_FF_TARGET ||
99562306a36Sopenharmony_ci				      fcport->port_type &
99662306a36Sopenharmony_ci				      (FCT_TARGET | FCT_NVME_TARGET)))
99762306a36Sopenharmony_ci					continue;
99862306a36Sopenharmony_ci			}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci			rval = 0;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci			app_reply->ports[pcnt].version = EDIF_VERSION1;
100362306a36Sopenharmony_ci			app_reply->ports[pcnt].remote_type =
100462306a36Sopenharmony_ci				VND_CMD_RTYPE_UNKNOWN;
100562306a36Sopenharmony_ci			if (fcport->port_type & (FCT_NVME_TARGET | FCT_TARGET))
100662306a36Sopenharmony_ci				app_reply->ports[pcnt].remote_type |=
100762306a36Sopenharmony_ci					VND_CMD_RTYPE_TARGET;
100862306a36Sopenharmony_ci			if (fcport->port_type & (FCT_NVME_INITIATOR | FCT_INITIATOR))
100962306a36Sopenharmony_ci				app_reply->ports[pcnt].remote_type |=
101062306a36Sopenharmony_ci					VND_CMD_RTYPE_INITIATOR;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci			app_reply->ports[pcnt].remote_pid = fcport->d_id;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x2058,
101562306a36Sopenharmony_ci			    "Found FC_SP fcport - nn %8phN pn %8phN pcnt %d portid=%06x secure %d.\n",
101662306a36Sopenharmony_ci			    fcport->node_name, fcport->port_name, pcnt,
101762306a36Sopenharmony_ci			    fcport->d_id.b24, fcport->flags & FCF_FCSP_DEVICE);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci			switch (fcport->edif.auth_state) {
102062306a36Sopenharmony_ci			case VND_CMD_AUTH_STATE_ELS_RCVD:
102162306a36Sopenharmony_ci				if (fcport->disc_state == DSC_LOGIN_AUTH_PEND) {
102262306a36Sopenharmony_ci					fcport->edif.auth_state = VND_CMD_AUTH_STATE_NEEDED;
102362306a36Sopenharmony_ci					app_reply->ports[pcnt].auth_state =
102462306a36Sopenharmony_ci						VND_CMD_AUTH_STATE_NEEDED;
102562306a36Sopenharmony_ci				} else {
102662306a36Sopenharmony_ci					app_reply->ports[pcnt].auth_state =
102762306a36Sopenharmony_ci						VND_CMD_AUTH_STATE_ELS_RCVD;
102862306a36Sopenharmony_ci				}
102962306a36Sopenharmony_ci				break;
103062306a36Sopenharmony_ci			default:
103162306a36Sopenharmony_ci				app_reply->ports[pcnt].auth_state = fcport->edif.auth_state;
103262306a36Sopenharmony_ci				break;
103362306a36Sopenharmony_ci			}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci			memcpy(app_reply->ports[pcnt].remote_wwpn,
103662306a36Sopenharmony_ci			    fcport->port_name, 8);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci			app_reply->ports[pcnt].remote_state =
103962306a36Sopenharmony_ci				(atomic_read(&fcport->state) ==
104062306a36Sopenharmony_ci				    FCS_ONLINE ? 1 : 0);
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci			pcnt++;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci			if (tdid.b24 != 0)
104562306a36Sopenharmony_ci				break;
104662306a36Sopenharmony_ci		}
104762306a36Sopenharmony_ci		app_reply->port_count = pcnt;
104862306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_OK);
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
105262306a36Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
105362306a36Sopenharmony_ci							       bsg_job->reply_payload.sg_cnt,
105462306a36Sopenharmony_ci							       app_reply,
105562306a36Sopenharmony_ci							       sizeof(struct app_pinfo_reply) + sizeof(struct app_pinfo) * pcnt);
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	kfree(app_reply);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	return rval;
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci/**
106362306a36Sopenharmony_ci * qla_edif_app_getstats - app would like to read various statistics info
106462306a36Sopenharmony_ci * @vha: host adapter pointer
106562306a36Sopenharmony_ci * @bsg_job: user request
106662306a36Sopenharmony_ci */
106762306a36Sopenharmony_cistatic int32_t
106862306a36Sopenharmony_ciqla_edif_app_getstats(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	int32_t			rval = 0;
107162306a36Sopenharmony_ci	struct fc_bsg_reply	*bsg_reply = bsg_job->reply;
107262306a36Sopenharmony_ci	uint32_t size;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	struct app_sinfo_req	app_req;
107562306a36Sopenharmony_ci	struct app_stats_reply	*app_reply;
107662306a36Sopenharmony_ci	uint32_t pcnt = 0;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
107962306a36Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, &app_req,
108062306a36Sopenharmony_ci	    sizeof(struct app_sinfo_req));
108162306a36Sopenharmony_ci	if (app_req.num_ports == 0) {
108262306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x911d,
108362306a36Sopenharmony_ci		   "%s app did not indicate number of ports to return\n",
108462306a36Sopenharmony_ci		    __func__);
108562306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
108662306a36Sopenharmony_ci		rval = -1;
108762306a36Sopenharmony_ci	}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	size = sizeof(struct app_stats_reply) +
109062306a36Sopenharmony_ci	    (sizeof(struct app_sinfo) * app_req.num_ports);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	app_reply = kzalloc(size, GFP_KERNEL);
109362306a36Sopenharmony_ci	if (!app_reply) {
109462306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
109562306a36Sopenharmony_ci		rval = -1;
109662306a36Sopenharmony_ci	} else {
109762306a36Sopenharmony_ci		struct fc_port	*fcport = NULL, *tf;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci		app_reply->version = EDIF_VERSION1;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci		list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
110262306a36Sopenharmony_ci			if (fcport->edif.enable) {
110362306a36Sopenharmony_ci				if (pcnt > app_req.num_ports)
110462306a36Sopenharmony_ci					break;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci				app_reply->elem[pcnt].rekey_count =
110762306a36Sopenharmony_ci				    fcport->edif.rekey_cnt;
110862306a36Sopenharmony_ci				app_reply->elem[pcnt].tx_bytes =
110962306a36Sopenharmony_ci				    fcport->edif.tx_bytes;
111062306a36Sopenharmony_ci				app_reply->elem[pcnt].rx_bytes =
111162306a36Sopenharmony_ci				    fcport->edif.rx_bytes;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci				memcpy(app_reply->elem[pcnt].remote_wwpn,
111462306a36Sopenharmony_ci				    fcport->port_name, 8);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci				pcnt++;
111762306a36Sopenharmony_ci			}
111862306a36Sopenharmony_ci		}
111962306a36Sopenharmony_ci		app_reply->elem_count = pcnt;
112062306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_OK);
112162306a36Sopenharmony_ci	}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
112462306a36Sopenharmony_ci	bsg_reply->reply_payload_rcv_len =
112562306a36Sopenharmony_ci	    sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
112662306a36Sopenharmony_ci	       bsg_job->reply_payload.sg_cnt, app_reply,
112762306a36Sopenharmony_ci	       sizeof(struct app_stats_reply) + (sizeof(struct app_sinfo) * pcnt));
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	kfree(app_reply);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	return rval;
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic int32_t
113562306a36Sopenharmony_ciqla_edif_ack(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
113662306a36Sopenharmony_ci{
113762306a36Sopenharmony_ci	struct fc_port *fcport;
113862306a36Sopenharmony_ci	struct aen_complete_cmd ack;
113962306a36Sopenharmony_ci	struct fc_bsg_reply     *bsg_reply = bsg_job->reply;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
114262306a36Sopenharmony_ci			  bsg_job->request_payload.sg_cnt, &ack, sizeof(ack));
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x70cf,
114562306a36Sopenharmony_ci	       "%s: %06x event_code %x\n",
114662306a36Sopenharmony_ci	       __func__, ack.port_id.b24, ack.event_code);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	fcport = qla2x00_find_fcport_by_pid(vha, &ack.port_id);
114962306a36Sopenharmony_ci	SET_DID_STATUS(bsg_reply->result, DID_OK);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	if (!fcport) {
115262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x70cf,
115362306a36Sopenharmony_ci		       "%s: unable to find fcport %06x \n",
115462306a36Sopenharmony_ci		       __func__, ack.port_id.b24);
115562306a36Sopenharmony_ci		return 0;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	switch (ack.event_code) {
115962306a36Sopenharmony_ci	case VND_CMD_AUTH_STATE_SESSION_SHUTDOWN:
116062306a36Sopenharmony_ci		fcport->edif.sess_down_acked = 1;
116162306a36Sopenharmony_ci		break;
116262306a36Sopenharmony_ci	default:
116362306a36Sopenharmony_ci		break;
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci	return 0;
116662306a36Sopenharmony_ci}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_cistatic int qla_edif_consume_dbell(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
116962306a36Sopenharmony_ci{
117062306a36Sopenharmony_ci	struct fc_bsg_reply	*bsg_reply = bsg_job->reply;
117162306a36Sopenharmony_ci	u32 sg_skip, reply_payload_len;
117262306a36Sopenharmony_ci	bool keep;
117362306a36Sopenharmony_ci	struct edb_node *dbnode = NULL;
117462306a36Sopenharmony_ci	struct edif_app_dbell ap;
117562306a36Sopenharmony_ci	int dat_size = 0;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	sg_skip = 0;
117862306a36Sopenharmony_ci	reply_payload_len = bsg_job->reply_payload.payload_len;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	while ((reply_payload_len - sg_skip) >= sizeof(struct edb_node)) {
118162306a36Sopenharmony_ci		dbnode = qla_edb_getnext(vha);
118262306a36Sopenharmony_ci		if (dbnode) {
118362306a36Sopenharmony_ci			keep = true;
118462306a36Sopenharmony_ci			dat_size = 0;
118562306a36Sopenharmony_ci			ap.event_code = dbnode->ntype;
118662306a36Sopenharmony_ci			switch (dbnode->ntype) {
118762306a36Sopenharmony_ci			case VND_CMD_AUTH_STATE_SESSION_SHUTDOWN:
118862306a36Sopenharmony_ci			case VND_CMD_AUTH_STATE_NEEDED:
118962306a36Sopenharmony_ci				ap.port_id = dbnode->u.plogi_did;
119062306a36Sopenharmony_ci				dat_size += sizeof(ap.port_id);
119162306a36Sopenharmony_ci				break;
119262306a36Sopenharmony_ci			case VND_CMD_AUTH_STATE_ELS_RCVD:
119362306a36Sopenharmony_ci				ap.port_id = dbnode->u.els_sid;
119462306a36Sopenharmony_ci				dat_size += sizeof(ap.port_id);
119562306a36Sopenharmony_ci				break;
119662306a36Sopenharmony_ci			case VND_CMD_AUTH_STATE_SAUPDATE_COMPL:
119762306a36Sopenharmony_ci				ap.port_id = dbnode->u.sa_aen.port_id;
119862306a36Sopenharmony_ci				memcpy(&ap.event_data, &dbnode->u,
119962306a36Sopenharmony_ci				    sizeof(struct edif_sa_update_aen));
120062306a36Sopenharmony_ci				dat_size += sizeof(struct edif_sa_update_aen);
120162306a36Sopenharmony_ci				break;
120262306a36Sopenharmony_ci			default:
120362306a36Sopenharmony_ci				keep = false;
120462306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x09102,
120562306a36Sopenharmony_ci					"%s unknown DB type=%d %p\n",
120662306a36Sopenharmony_ci					__func__, dbnode->ntype, dbnode);
120762306a36Sopenharmony_ci				break;
120862306a36Sopenharmony_ci			}
120962306a36Sopenharmony_ci			ap.event_data_size = dat_size;
121062306a36Sopenharmony_ci			/* 8 = sizeof(ap.event_code + ap.event_data_size) */
121162306a36Sopenharmony_ci			dat_size += 8;
121262306a36Sopenharmony_ci			if (keep)
121362306a36Sopenharmony_ci				sg_skip += sg_copy_buffer(bsg_job->reply_payload.sg_list,
121462306a36Sopenharmony_ci						bsg_job->reply_payload.sg_cnt,
121562306a36Sopenharmony_ci						&ap, dat_size, sg_skip, false);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x09102,
121862306a36Sopenharmony_ci				"%s Doorbell consumed : type=%d %p\n",
121962306a36Sopenharmony_ci				__func__, dbnode->ntype, dbnode);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci			kfree(dbnode);
122262306a36Sopenharmony_ci		} else {
122362306a36Sopenharmony_ci			break;
122462306a36Sopenharmony_ci		}
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	SET_DID_STATUS(bsg_reply->result, DID_OK);
122862306a36Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = sg_skip;
122962306a36Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	return 0;
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_cistatic void __qla_edif_dbell_bsg_done(scsi_qla_host_t *vha, struct bsg_job *bsg_job,
123562306a36Sopenharmony_ci	u32 delay)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	/* small sleep for doorbell events to accumulate */
124062306a36Sopenharmony_ci	if (delay)
124162306a36Sopenharmony_ci		msleep(delay);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	qla_edif_consume_dbell(vha, bsg_job);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len);
124662306a36Sopenharmony_ci}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_cistatic void qla_edif_dbell_bsg_done(scsi_qla_host_t *vha)
124962306a36Sopenharmony_ci{
125062306a36Sopenharmony_ci	unsigned long flags;
125162306a36Sopenharmony_ci	struct bsg_job *prev_bsg_job = NULL;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	spin_lock_irqsave(&vha->e_dbell.db_lock, flags);
125462306a36Sopenharmony_ci	if (vha->e_dbell.dbell_bsg_job) {
125562306a36Sopenharmony_ci		prev_bsg_job = vha->e_dbell.dbell_bsg_job;
125662306a36Sopenharmony_ci		vha->e_dbell.dbell_bsg_job = NULL;
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci	spin_unlock_irqrestore(&vha->e_dbell.db_lock, flags);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	if (prev_bsg_job)
126162306a36Sopenharmony_ci		__qla_edif_dbell_bsg_done(vha, prev_bsg_job, 0);
126262306a36Sopenharmony_ci}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_cistatic int
126562306a36Sopenharmony_ciqla_edif_dbell_bsg(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
126662306a36Sopenharmony_ci{
126762306a36Sopenharmony_ci	unsigned long flags;
126862306a36Sopenharmony_ci	bool return_bsg = false;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	/* flush previous dbell bsg */
127162306a36Sopenharmony_ci	qla_edif_dbell_bsg_done(vha);
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	spin_lock_irqsave(&vha->e_dbell.db_lock, flags);
127462306a36Sopenharmony_ci	if (list_empty(&vha->e_dbell.head) && DBELL_ACTIVE(vha)) {
127562306a36Sopenharmony_ci		/*
127662306a36Sopenharmony_ci		 * when the next db event happens, bsg_job will return.
127762306a36Sopenharmony_ci		 * Otherwise, timer will return it.
127862306a36Sopenharmony_ci		 */
127962306a36Sopenharmony_ci		vha->e_dbell.dbell_bsg_job = bsg_job;
128062306a36Sopenharmony_ci		vha->e_dbell.bsg_expire = jiffies + 10 * HZ;
128162306a36Sopenharmony_ci	} else {
128262306a36Sopenharmony_ci		return_bsg = true;
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci	spin_unlock_irqrestore(&vha->e_dbell.db_lock, flags);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	if (return_bsg)
128762306a36Sopenharmony_ci		__qla_edif_dbell_bsg_done(vha, bsg_job, 1);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	return 0;
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ciint32_t
129362306a36Sopenharmony_ciqla_edif_app_mgmt(struct bsg_job *bsg_job)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	struct fc_bsg_request	*bsg_request = bsg_job->request;
129662306a36Sopenharmony_ci	struct fc_bsg_reply	*bsg_reply = bsg_job->reply;
129762306a36Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
129862306a36Sopenharmony_ci	scsi_qla_host_t		*vha = shost_priv(host);
129962306a36Sopenharmony_ci	struct app_id		appcheck;
130062306a36Sopenharmony_ci	bool done = true;
130162306a36Sopenharmony_ci	int32_t         rval = 0;
130262306a36Sopenharmony_ci	uint32_t	vnd_sc = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
130362306a36Sopenharmony_ci	u32 level = ql_dbg_edif;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	/* doorbell is high traffic */
130662306a36Sopenharmony_ci	if (vnd_sc == QL_VND_SC_READ_DBELL)
130762306a36Sopenharmony_ci		level = 0;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	ql_dbg(level, vha, 0x911d, "%s vnd subcmd=%x\n",
131062306a36Sopenharmony_ci	    __func__, vnd_sc);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
131362306a36Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, &appcheck,
131462306a36Sopenharmony_ci	    sizeof(struct app_id));
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	if (!vha->hw->flags.edif_enabled ||
131762306a36Sopenharmony_ci		test_bit(VPORT_DELETE, &vha->dpc_flags)) {
131862306a36Sopenharmony_ci		ql_dbg(level, vha, 0x911d,
131962306a36Sopenharmony_ci		    "%s edif not enabled or vp delete. bsg ptr done %p. dpc_flags %lx\n",
132062306a36Sopenharmony_ci		    __func__, bsg_job, vha->dpc_flags);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
132362306a36Sopenharmony_ci		goto done;
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	if (!qla_edif_app_check(vha, appcheck)) {
132762306a36Sopenharmony_ci		ql_dbg(level, vha, 0x911d,
132862306a36Sopenharmony_ci		    "%s app checked failed.\n",
132962306a36Sopenharmony_ci		    __func__);
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci		bsg_job->reply_len = sizeof(struct fc_bsg_reply);
133262306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
133362306a36Sopenharmony_ci		goto done;
133462306a36Sopenharmony_ci	}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	switch (vnd_sc) {
133762306a36Sopenharmony_ci	case QL_VND_SC_SA_UPDATE:
133862306a36Sopenharmony_ci		done = false;
133962306a36Sopenharmony_ci		rval = qla24xx_sadb_update(bsg_job);
134062306a36Sopenharmony_ci		break;
134162306a36Sopenharmony_ci	case QL_VND_SC_APP_START:
134262306a36Sopenharmony_ci		rval = qla_edif_app_start(vha, bsg_job);
134362306a36Sopenharmony_ci		break;
134462306a36Sopenharmony_ci	case QL_VND_SC_APP_STOP:
134562306a36Sopenharmony_ci		rval = qla_edif_app_stop(vha, bsg_job);
134662306a36Sopenharmony_ci		break;
134762306a36Sopenharmony_ci	case QL_VND_SC_AUTH_OK:
134862306a36Sopenharmony_ci		rval = qla_edif_app_authok(vha, bsg_job);
134962306a36Sopenharmony_ci		break;
135062306a36Sopenharmony_ci	case QL_VND_SC_AUTH_FAIL:
135162306a36Sopenharmony_ci		rval = qla_edif_app_authfail(vha, bsg_job);
135262306a36Sopenharmony_ci		break;
135362306a36Sopenharmony_ci	case QL_VND_SC_GET_FCINFO:
135462306a36Sopenharmony_ci		rval = qla_edif_app_getfcinfo(vha, bsg_job);
135562306a36Sopenharmony_ci		break;
135662306a36Sopenharmony_ci	case QL_VND_SC_GET_STATS:
135762306a36Sopenharmony_ci		rval = qla_edif_app_getstats(vha, bsg_job);
135862306a36Sopenharmony_ci		break;
135962306a36Sopenharmony_ci	case QL_VND_SC_AEN_COMPLETE:
136062306a36Sopenharmony_ci		rval = qla_edif_ack(vha, bsg_job);
136162306a36Sopenharmony_ci		break;
136262306a36Sopenharmony_ci	case QL_VND_SC_READ_DBELL:
136362306a36Sopenharmony_ci		rval = qla_edif_dbell_bsg(vha, bsg_job);
136462306a36Sopenharmony_ci		done = false;
136562306a36Sopenharmony_ci		break;
136662306a36Sopenharmony_ci	default:
136762306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d, "%s unknown cmd=%x\n",
136862306a36Sopenharmony_ci		    __func__,
136962306a36Sopenharmony_ci		    bsg_request->rqst_data.h_vendor.vendor_cmd[1]);
137062306a36Sopenharmony_ci		rval = EXT_STATUS_INVALID_PARAM;
137162306a36Sopenharmony_ci		done = false;
137262306a36Sopenharmony_ci		break;
137362306a36Sopenharmony_ci	}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_cidone:
137662306a36Sopenharmony_ci	if (done) {
137762306a36Sopenharmony_ci		ql_dbg(level, vha, 0x7009,
137862306a36Sopenharmony_ci		    "%s: %d  bsg ptr done %p\n", __func__, __LINE__, bsg_job);
137962306a36Sopenharmony_ci		bsg_job_done(bsg_job, bsg_reply->result,
138062306a36Sopenharmony_ci		    bsg_reply->reply_payload_rcv_len);
138162306a36Sopenharmony_ci	}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	return rval;
138462306a36Sopenharmony_ci}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_cistatic struct edif_sa_ctl *
138762306a36Sopenharmony_ciqla_edif_add_sa_ctl(fc_port_t *fcport, struct qla_sa_update_frame *sa_frame,
138862306a36Sopenharmony_ci	int dir)
138962306a36Sopenharmony_ci{
139062306a36Sopenharmony_ci	struct	edif_sa_ctl *sa_ctl;
139162306a36Sopenharmony_ci	struct qla_sa_update_frame *sap;
139262306a36Sopenharmony_ci	int	index = sa_frame->fast_sa_index;
139362306a36Sopenharmony_ci	unsigned long flags = 0;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	sa_ctl = kzalloc(sizeof(*sa_ctl), GFP_KERNEL);
139662306a36Sopenharmony_ci	if (!sa_ctl) {
139762306a36Sopenharmony_ci		/* couldn't get space */
139862306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, fcport->vha, 0x9100,
139962306a36Sopenharmony_ci		    "unable to allocate SA CTL\n");
140062306a36Sopenharmony_ci		return NULL;
140162306a36Sopenharmony_ci	}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	/*
140462306a36Sopenharmony_ci	 * need to allocate sa_index here and save it
140562306a36Sopenharmony_ci	 * in both sa_ctl->index and sa_frame->fast_sa_index;
140662306a36Sopenharmony_ci	 * If alloc fails then delete sa_ctl and return NULL
140762306a36Sopenharmony_ci	 */
140862306a36Sopenharmony_ci	INIT_LIST_HEAD(&sa_ctl->next);
140962306a36Sopenharmony_ci	sap = &sa_ctl->sa_frame;
141062306a36Sopenharmony_ci	*sap = *sa_frame;
141162306a36Sopenharmony_ci	sa_ctl->index = index;
141262306a36Sopenharmony_ci	sa_ctl->fcport = fcport;
141362306a36Sopenharmony_ci	sa_ctl->flags = 0;
141462306a36Sopenharmony_ci	sa_ctl->state = 0L;
141562306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, fcport->vha, 0x9100,
141662306a36Sopenharmony_ci	    "%s: Added sa_ctl %p, index %d, state 0x%lx\n",
141762306a36Sopenharmony_ci	    __func__, sa_ctl, sa_ctl->index, sa_ctl->state);
141862306a36Sopenharmony_ci	spin_lock_irqsave(&fcport->edif.sa_list_lock, flags);
141962306a36Sopenharmony_ci	if (dir == SAU_FLG_TX)
142062306a36Sopenharmony_ci		list_add_tail(&sa_ctl->next, &fcport->edif.tx_sa_list);
142162306a36Sopenharmony_ci	else
142262306a36Sopenharmony_ci		list_add_tail(&sa_ctl->next, &fcport->edif.rx_sa_list);
142362306a36Sopenharmony_ci	spin_unlock_irqrestore(&fcport->edif.sa_list_lock, flags);
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	return sa_ctl;
142662306a36Sopenharmony_ci}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_civoid
142962306a36Sopenharmony_ciqla_edif_flush_sa_ctl_lists(fc_port_t *fcport)
143062306a36Sopenharmony_ci{
143162306a36Sopenharmony_ci	struct edif_sa_ctl *sa_ctl, *tsa_ctl;
143262306a36Sopenharmony_ci	unsigned long flags = 0;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	spin_lock_irqsave(&fcport->edif.sa_list_lock, flags);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	list_for_each_entry_safe(sa_ctl, tsa_ctl, &fcport->edif.tx_sa_list,
143762306a36Sopenharmony_ci	    next) {
143862306a36Sopenharmony_ci		list_del(&sa_ctl->next);
143962306a36Sopenharmony_ci		kfree(sa_ctl);
144062306a36Sopenharmony_ci	}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	list_for_each_entry_safe(sa_ctl, tsa_ctl, &fcport->edif.rx_sa_list,
144362306a36Sopenharmony_ci	    next) {
144462306a36Sopenharmony_ci		list_del(&sa_ctl->next);
144562306a36Sopenharmony_ci		kfree(sa_ctl);
144662306a36Sopenharmony_ci	}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	spin_unlock_irqrestore(&fcport->edif.sa_list_lock, flags);
144962306a36Sopenharmony_ci}
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_cistruct edif_sa_ctl *
145262306a36Sopenharmony_ciqla_edif_find_sa_ctl_by_index(fc_port_t *fcport, int index, int dir)
145362306a36Sopenharmony_ci{
145462306a36Sopenharmony_ci	struct edif_sa_ctl *sa_ctl, *tsa_ctl;
145562306a36Sopenharmony_ci	struct list_head *sa_list;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	if (dir == SAU_FLG_TX)
145862306a36Sopenharmony_ci		sa_list = &fcport->edif.tx_sa_list;
145962306a36Sopenharmony_ci	else
146062306a36Sopenharmony_ci		sa_list = &fcport->edif.rx_sa_list;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	list_for_each_entry_safe(sa_ctl, tsa_ctl, sa_list, next) {
146362306a36Sopenharmony_ci		if (test_bit(EDIF_SA_CTL_USED, &sa_ctl->state) &&
146462306a36Sopenharmony_ci		    sa_ctl->index == index)
146562306a36Sopenharmony_ci			return sa_ctl;
146662306a36Sopenharmony_ci	}
146762306a36Sopenharmony_ci	return NULL;
146862306a36Sopenharmony_ci}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci/* add the sa to the correct list */
147162306a36Sopenharmony_cistatic int
147262306a36Sopenharmony_ciqla24xx_check_sadb_avail_slot(struct bsg_job *bsg_job, fc_port_t *fcport,
147362306a36Sopenharmony_ci	struct qla_sa_update_frame *sa_frame)
147462306a36Sopenharmony_ci{
147562306a36Sopenharmony_ci	struct edif_sa_ctl *sa_ctl = NULL;
147662306a36Sopenharmony_ci	int dir;
147762306a36Sopenharmony_ci	uint16_t sa_index;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	dir = (sa_frame->flags & SAU_FLG_TX);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	/* map the spi to an sa_index */
148262306a36Sopenharmony_ci	sa_index = qla_edif_sadb_get_sa_index(fcport, sa_frame);
148362306a36Sopenharmony_ci	if (sa_index == RX_DELETE_NO_EDIF_SA_INDEX) {
148462306a36Sopenharmony_ci		/* process rx delete */
148562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, fcport->vha, 0x3063,
148662306a36Sopenharmony_ci		    "%s: rx delete for lid 0x%x, spi 0x%x, no entry found\n",
148762306a36Sopenharmony_ci		    __func__, fcport->loop_id, sa_frame->spi);
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		/* build and send the aen */
149062306a36Sopenharmony_ci		fcport->edif.rx_sa_set = 1;
149162306a36Sopenharmony_ci		fcport->edif.rx_sa_pending = 0;
149262306a36Sopenharmony_ci		qla_edb_eventcreate(fcport->vha,
149362306a36Sopenharmony_ci		    VND_CMD_AUTH_STATE_SAUPDATE_COMPL,
149462306a36Sopenharmony_ci		    QL_VND_SA_STAT_SUCCESS,
149562306a36Sopenharmony_ci		    QL_VND_RX_SA_KEY, fcport);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci		/* force a return of good bsg status; */
149862306a36Sopenharmony_ci		return RX_DELETE_NO_EDIF_SA_INDEX;
149962306a36Sopenharmony_ci	} else if (sa_index == INVALID_EDIF_SA_INDEX) {
150062306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, fcport->vha, 0x9100,
150162306a36Sopenharmony_ci		    "%s: Failed to get sa_index for spi 0x%x, dir: %d\n",
150262306a36Sopenharmony_ci		    __func__, sa_frame->spi, dir);
150362306a36Sopenharmony_ci		return INVALID_EDIF_SA_INDEX;
150462306a36Sopenharmony_ci	}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, fcport->vha, 0x9100,
150762306a36Sopenharmony_ci	    "%s: index %d allocated to spi 0x%x, dir: %d, nport_handle: 0x%x\n",
150862306a36Sopenharmony_ci	    __func__, sa_index, sa_frame->spi, dir, fcport->loop_id);
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	/* This is a local copy of sa_frame. */
151162306a36Sopenharmony_ci	sa_frame->fast_sa_index = sa_index;
151262306a36Sopenharmony_ci	/* create the sa_ctl */
151362306a36Sopenharmony_ci	sa_ctl = qla_edif_add_sa_ctl(fcport, sa_frame, dir);
151462306a36Sopenharmony_ci	if (!sa_ctl) {
151562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, fcport->vha, 0x9100,
151662306a36Sopenharmony_ci		    "%s: Failed to add sa_ctl for spi 0x%x, dir: %d, sa_index: %d\n",
151762306a36Sopenharmony_ci		    __func__, sa_frame->spi, dir, sa_index);
151862306a36Sopenharmony_ci		return -1;
151962306a36Sopenharmony_ci	}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	set_bit(EDIF_SA_CTL_USED, &sa_ctl->state);
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	if (dir == SAU_FLG_TX)
152462306a36Sopenharmony_ci		fcport->edif.tx_rekey_cnt++;
152562306a36Sopenharmony_ci	else
152662306a36Sopenharmony_ci		fcport->edif.rx_rekey_cnt++;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, fcport->vha, 0x9100,
152962306a36Sopenharmony_ci	    "%s: Found sa_ctl %p, index %d, state 0x%lx, tx_cnt %d, rx_cnt %d, nport_handle: 0x%x\n",
153062306a36Sopenharmony_ci	    __func__, sa_ctl, sa_ctl->index, sa_ctl->state,
153162306a36Sopenharmony_ci	    fcport->edif.tx_rekey_cnt,
153262306a36Sopenharmony_ci	    fcport->edif.rx_rekey_cnt, fcport->loop_id);
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	return 0;
153562306a36Sopenharmony_ci}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci#define QLA_SA_UPDATE_FLAGS_RX_KEY      0x0
153862306a36Sopenharmony_ci#define QLA_SA_UPDATE_FLAGS_TX_KEY      0x2
153962306a36Sopenharmony_ci#define EDIF_MSLEEP_INTERVAL 100
154062306a36Sopenharmony_ci#define EDIF_RETRY_COUNT  50
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ciint
154362306a36Sopenharmony_ciqla24xx_sadb_update(struct bsg_job *bsg_job)
154462306a36Sopenharmony_ci{
154562306a36Sopenharmony_ci	struct	fc_bsg_reply	*bsg_reply = bsg_job->reply;
154662306a36Sopenharmony_ci	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
154762306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
154862306a36Sopenharmony_ci	fc_port_t		*fcport = NULL;
154962306a36Sopenharmony_ci	srb_t			*sp = NULL;
155062306a36Sopenharmony_ci	struct edif_list_entry *edif_entry = NULL;
155162306a36Sopenharmony_ci	int			found = 0;
155262306a36Sopenharmony_ci	int			rval = 0;
155362306a36Sopenharmony_ci	int result = 0, cnt;
155462306a36Sopenharmony_ci	struct qla_sa_update_frame sa_frame;
155562306a36Sopenharmony_ci	struct srb_iocb *iocb_cmd;
155662306a36Sopenharmony_ci	port_id_t portid;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif + ql_dbg_verbose, vha, 0x911d,
155962306a36Sopenharmony_ci	    "%s entered, vha: 0x%p\n", __func__, vha);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
156262306a36Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, &sa_frame,
156362306a36Sopenharmony_ci	    sizeof(struct qla_sa_update_frame));
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	/* Check if host is online */
156662306a36Sopenharmony_ci	if (!vha->flags.online) {
156762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70a1, "Host is not online\n");
156862306a36Sopenharmony_ci		rval = -EIO;
156962306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
157062306a36Sopenharmony_ci		goto done;
157162306a36Sopenharmony_ci	}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	if (DBELL_INACTIVE(vha)) {
157462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70a1, "App not started\n");
157562306a36Sopenharmony_ci		rval = -EIO;
157662306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
157762306a36Sopenharmony_ci		goto done;
157862306a36Sopenharmony_ci	}
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	/* silent unaligned access warning */
158162306a36Sopenharmony_ci	portid.b.domain = sa_frame.port_id.b.domain;
158262306a36Sopenharmony_ci	portid.b.area   = sa_frame.port_id.b.area;
158362306a36Sopenharmony_ci	portid.b.al_pa  = sa_frame.port_id.b.al_pa;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	fcport = qla2x00_find_fcport_by_pid(vha, &portid);
158662306a36Sopenharmony_ci	if (fcport) {
158762306a36Sopenharmony_ci		found = 1;
158862306a36Sopenharmony_ci		if (sa_frame.flags == QLA_SA_UPDATE_FLAGS_TX_KEY)
158962306a36Sopenharmony_ci			fcport->edif.tx_bytes = 0;
159062306a36Sopenharmony_ci		if (sa_frame.flags == QLA_SA_UPDATE_FLAGS_RX_KEY)
159162306a36Sopenharmony_ci			fcport->edif.rx_bytes = 0;
159262306a36Sopenharmony_ci	}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	if (!found) {
159562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x70a3, "Failed to find port= %06x\n",
159662306a36Sopenharmony_ci		    sa_frame.port_id.b24);
159762306a36Sopenharmony_ci		rval = -EINVAL;
159862306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_NO_CONNECT);
159962306a36Sopenharmony_ci		goto done;
160062306a36Sopenharmony_ci	}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	/* make sure the nport_handle is valid */
160362306a36Sopenharmony_ci	if (fcport->loop_id == FC_NO_LOOP_ID) {
160462306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x70e1,
160562306a36Sopenharmony_ci		    "%s: %8phN lid=FC_NO_LOOP_ID, spi: 0x%x, DS %d, returning NO_CONNECT\n",
160662306a36Sopenharmony_ci		    __func__, fcport->port_name, sa_frame.spi,
160762306a36Sopenharmony_ci		    fcport->disc_state);
160862306a36Sopenharmony_ci		rval = -EINVAL;
160962306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_NO_CONNECT);
161062306a36Sopenharmony_ci		goto done;
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	/* allocate and queue an sa_ctl */
161462306a36Sopenharmony_ci	result = qla24xx_check_sadb_avail_slot(bsg_job, fcport, &sa_frame);
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	/* failure of bsg */
161762306a36Sopenharmony_ci	if (result == INVALID_EDIF_SA_INDEX) {
161862306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x70e1,
161962306a36Sopenharmony_ci		    "%s: %8phN, skipping update.\n",
162062306a36Sopenharmony_ci		    __func__, fcport->port_name);
162162306a36Sopenharmony_ci		rval = -EINVAL;
162262306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
162362306a36Sopenharmony_ci		goto done;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	/* rx delete failure */
162662306a36Sopenharmony_ci	} else if (result == RX_DELETE_NO_EDIF_SA_INDEX) {
162762306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x70e1,
162862306a36Sopenharmony_ci		    "%s: %8phN, skipping rx delete.\n",
162962306a36Sopenharmony_ci		    __func__, fcport->port_name);
163062306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_OK);
163162306a36Sopenharmony_ci		goto done;
163262306a36Sopenharmony_ci	}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x70e1,
163562306a36Sopenharmony_ci	    "%s: %8phN, sa_index in sa_frame: %d flags %xh\n",
163662306a36Sopenharmony_ci	    __func__, fcport->port_name, sa_frame.fast_sa_index,
163762306a36Sopenharmony_ci	    sa_frame.flags);
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	/* looking for rx index and delete */
164062306a36Sopenharmony_ci	if (((sa_frame.flags & SAU_FLG_TX) == 0) &&
164162306a36Sopenharmony_ci	    (sa_frame.flags & SAU_FLG_INV)) {
164262306a36Sopenharmony_ci		uint16_t nport_handle = fcport->loop_id;
164362306a36Sopenharmony_ci		uint16_t sa_index = sa_frame.fast_sa_index;
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci		/*
164662306a36Sopenharmony_ci		 * make sure we have an existing rx key, otherwise just process
164762306a36Sopenharmony_ci		 * this as a straight delete just like TX
164862306a36Sopenharmony_ci		 * This is NOT a normal case, it indicates an error recovery or key cleanup
164962306a36Sopenharmony_ci		 * by the ipsec code above us.
165062306a36Sopenharmony_ci		 */
165162306a36Sopenharmony_ci		edif_entry = qla_edif_list_find_sa_index(fcport, fcport->loop_id);
165262306a36Sopenharmony_ci		if (!edif_entry) {
165362306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x911d,
165462306a36Sopenharmony_ci			    "%s: WARNING: no active sa_index for nport_handle 0x%x, forcing delete for sa_index 0x%x\n",
165562306a36Sopenharmony_ci			    __func__, fcport->loop_id, sa_index);
165662306a36Sopenharmony_ci			goto force_rx_delete;
165762306a36Sopenharmony_ci		}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci		/*
166062306a36Sopenharmony_ci		 * if we have a forced delete for rx, remove the sa_index from the edif list
166162306a36Sopenharmony_ci		 * and proceed with normal delete.  The rx delay timer should not be running
166262306a36Sopenharmony_ci		 */
166362306a36Sopenharmony_ci		if ((sa_frame.flags & SAU_FLG_FORCE_DELETE) == SAU_FLG_FORCE_DELETE) {
166462306a36Sopenharmony_ci			qla_edif_list_delete_sa_index(fcport, edif_entry);
166562306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x911d,
166662306a36Sopenharmony_ci			    "%s: FORCE DELETE flag found for nport_handle 0x%x, sa_index 0x%x, forcing DELETE\n",
166762306a36Sopenharmony_ci			    __func__, fcport->loop_id, sa_index);
166862306a36Sopenharmony_ci			kfree(edif_entry);
166962306a36Sopenharmony_ci			goto force_rx_delete;
167062306a36Sopenharmony_ci		}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci		/*
167362306a36Sopenharmony_ci		 * delayed rx delete
167462306a36Sopenharmony_ci		 *
167562306a36Sopenharmony_ci		 * if delete_sa_index is not invalid then there is already
167662306a36Sopenharmony_ci		 * a delayed index in progress, return bsg bad status
167762306a36Sopenharmony_ci		 */
167862306a36Sopenharmony_ci		if (edif_entry->delete_sa_index != INVALID_EDIF_SA_INDEX) {
167962306a36Sopenharmony_ci			struct edif_sa_ctl *sa_ctl;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x911d,
168262306a36Sopenharmony_ci			    "%s: delete for lid 0x%x, delete_sa_index %d is pending\n",
168362306a36Sopenharmony_ci			    __func__, edif_entry->handle, edif_entry->delete_sa_index);
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci			/* free up the sa_ctl that was allocated with the sa_index */
168662306a36Sopenharmony_ci			sa_ctl = qla_edif_find_sa_ctl_by_index(fcport, sa_index,
168762306a36Sopenharmony_ci			    (sa_frame.flags & SAU_FLG_TX));
168862306a36Sopenharmony_ci			if (sa_ctl) {
168962306a36Sopenharmony_ci				ql_dbg(ql_dbg_edif, vha, 0x3063,
169062306a36Sopenharmony_ci				    "%s: freeing sa_ctl for index %d\n",
169162306a36Sopenharmony_ci				    __func__, sa_ctl->index);
169262306a36Sopenharmony_ci				qla_edif_free_sa_ctl(fcport, sa_ctl, sa_ctl->index);
169362306a36Sopenharmony_ci			}
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci			/* release the sa_index */
169662306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x3063,
169762306a36Sopenharmony_ci			    "%s: freeing sa_index %d, nph: 0x%x\n",
169862306a36Sopenharmony_ci			    __func__, sa_index, nport_handle);
169962306a36Sopenharmony_ci			qla_edif_sadb_delete_sa_index(fcport, nport_handle, sa_index);
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci			rval = -EINVAL;
170262306a36Sopenharmony_ci			SET_DID_STATUS(bsg_reply->result, DID_ERROR);
170362306a36Sopenharmony_ci			goto done;
170462306a36Sopenharmony_ci		}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci		fcport->edif.rekey_cnt++;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci		/* configure and start the rx delay timer */
170962306a36Sopenharmony_ci		edif_entry->fcport = fcport;
171062306a36Sopenharmony_ci		edif_entry->timer.expires = jiffies + RX_DELAY_DELETE_TIMEOUT * HZ;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d,
171362306a36Sopenharmony_ci		    "%s: adding timer, entry: %p, delete sa_index %d, lid 0x%x to edif_list\n",
171462306a36Sopenharmony_ci		    __func__, edif_entry, sa_index, nport_handle);
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci		/*
171762306a36Sopenharmony_ci		 * Start the timer when we queue the delayed rx delete.
171862306a36Sopenharmony_ci		 * This is an activity timer that goes off if we have not
171962306a36Sopenharmony_ci		 * received packets with the new sa_index
172062306a36Sopenharmony_ci		 */
172162306a36Sopenharmony_ci		add_timer(&edif_entry->timer);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci		/*
172462306a36Sopenharmony_ci		 * sa_delete for rx key with an active rx key including this one
172562306a36Sopenharmony_ci		 * add the delete rx sa index to the hash so we can look for it
172662306a36Sopenharmony_ci		 * in the rsp queue.  Do this after making any changes to the
172762306a36Sopenharmony_ci		 * edif_entry as part of the rx delete.
172862306a36Sopenharmony_ci		 */
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d,
173162306a36Sopenharmony_ci		    "%s: delete sa_index %d, lid 0x%x to edif_list. bsg done ptr %p\n",
173262306a36Sopenharmony_ci		    __func__, sa_index, nport_handle, bsg_job);
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci		edif_entry->delete_sa_index = sa_index;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci		bsg_job->reply_len = sizeof(struct fc_bsg_reply);
173762306a36Sopenharmony_ci		bsg_reply->result = DID_OK << 16;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci		goto done;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	/*
174262306a36Sopenharmony_ci	 * rx index and update
174362306a36Sopenharmony_ci	 * add the index to the list and continue with normal update
174462306a36Sopenharmony_ci	 */
174562306a36Sopenharmony_ci	} else if (((sa_frame.flags & SAU_FLG_TX) == 0) &&
174662306a36Sopenharmony_ci	    ((sa_frame.flags & SAU_FLG_INV) == 0)) {
174762306a36Sopenharmony_ci		/* sa_update for rx key */
174862306a36Sopenharmony_ci		uint32_t nport_handle = fcport->loop_id;
174962306a36Sopenharmony_ci		uint16_t sa_index = sa_frame.fast_sa_index;
175062306a36Sopenharmony_ci		int result;
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci		/*
175362306a36Sopenharmony_ci		 * add the update rx sa index to the hash so we can look for it
175462306a36Sopenharmony_ci		 * in the rsp queue and continue normally
175562306a36Sopenharmony_ci		 */
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d,
175862306a36Sopenharmony_ci		    "%s:  adding update sa_index %d, lid 0x%x to edif_list\n",
175962306a36Sopenharmony_ci		    __func__, sa_index, nport_handle);
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci		result = qla_edif_list_add_sa_update_index(fcport, sa_index,
176262306a36Sopenharmony_ci		    nport_handle);
176362306a36Sopenharmony_ci		if (result) {
176462306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x911d,
176562306a36Sopenharmony_ci			    "%s: SA_UPDATE failed to add new sa index %d to list for lid 0x%x\n",
176662306a36Sopenharmony_ci			    __func__, sa_index, nport_handle);
176762306a36Sopenharmony_ci		}
176862306a36Sopenharmony_ci	}
176962306a36Sopenharmony_ci	if (sa_frame.flags & SAU_FLG_GMAC_MODE)
177062306a36Sopenharmony_ci		fcport->edif.aes_gmac = 1;
177162306a36Sopenharmony_ci	else
177262306a36Sopenharmony_ci		fcport->edif.aes_gmac = 0;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ciforce_rx_delete:
177562306a36Sopenharmony_ci	/*
177662306a36Sopenharmony_ci	 * sa_update for both rx and tx keys, sa_delete for tx key
177762306a36Sopenharmony_ci	 * immediately process the request
177862306a36Sopenharmony_ci	 */
177962306a36Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
178062306a36Sopenharmony_ci	if (!sp) {
178162306a36Sopenharmony_ci		rval = -ENOMEM;
178262306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_IMM_RETRY);
178362306a36Sopenharmony_ci		goto done;
178462306a36Sopenharmony_ci	}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	sp->type = SRB_SA_UPDATE;
178762306a36Sopenharmony_ci	sp->name = "bsg_sa_update";
178862306a36Sopenharmony_ci	sp->u.bsg_job = bsg_job;
178962306a36Sopenharmony_ci	/* sp->free = qla2x00_bsg_sp_free; */
179062306a36Sopenharmony_ci	sp->free = qla2x00_rel_sp;
179162306a36Sopenharmony_ci	sp->done = qla2x00_bsg_job_done;
179262306a36Sopenharmony_ci	iocb_cmd = &sp->u.iocb_cmd;
179362306a36Sopenharmony_ci	iocb_cmd->u.sa_update.sa_frame  = sa_frame;
179462306a36Sopenharmony_ci	cnt = 0;
179562306a36Sopenharmony_ciretry:
179662306a36Sopenharmony_ci	rval = qla2x00_start_sp(sp);
179762306a36Sopenharmony_ci	switch (rval) {
179862306a36Sopenharmony_ci	case QLA_SUCCESS:
179962306a36Sopenharmony_ci		break;
180062306a36Sopenharmony_ci	case EAGAIN:
180162306a36Sopenharmony_ci		msleep(EDIF_MSLEEP_INTERVAL);
180262306a36Sopenharmony_ci		cnt++;
180362306a36Sopenharmony_ci		if (cnt < EDIF_RETRY_COUNT)
180462306a36Sopenharmony_ci			goto retry;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci		fallthrough;
180762306a36Sopenharmony_ci	default:
180862306a36Sopenharmony_ci		ql_log(ql_dbg_edif, vha, 0x70e3,
180962306a36Sopenharmony_ci		       "%s qla2x00_start_sp failed=%d.\n",
181062306a36Sopenharmony_ci		       __func__, rval);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci		qla2x00_rel_sp(sp);
181362306a36Sopenharmony_ci		rval = -EIO;
181462306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_IMM_RETRY);
181562306a36Sopenharmony_ci		goto done;
181662306a36Sopenharmony_ci	}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x911d,
181962306a36Sopenharmony_ci	    "%s:  %s sent, hdl=%x, portid=%06x.\n",
182062306a36Sopenharmony_ci	    __func__, sp->name, sp->handle, fcport->d_id.b24);
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	fcport->edif.rekey_cnt++;
182362306a36Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
182462306a36Sopenharmony_ci	SET_DID_STATUS(bsg_reply->result, DID_OK);
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	return 0;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci/*
182962306a36Sopenharmony_ci * send back error status
183062306a36Sopenharmony_ci */
183162306a36Sopenharmony_cidone:
183262306a36Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
183362306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x911d,
183462306a36Sopenharmony_ci	    "%s:status: FAIL, result: 0x%x, bsg ptr done %p\n",
183562306a36Sopenharmony_ci	    __func__, bsg_reply->result, bsg_job);
183662306a36Sopenharmony_ci	bsg_job_done(bsg_job, bsg_reply->result,
183762306a36Sopenharmony_ci	    bsg_reply->reply_payload_rcv_len);
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	return 0;
184062306a36Sopenharmony_ci}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_cistatic void
184362306a36Sopenharmony_ciqla_enode_free(scsi_qla_host_t *vha, struct enode *node)
184462306a36Sopenharmony_ci{
184562306a36Sopenharmony_ci	node->ntype = N_UNDEF;
184662306a36Sopenharmony_ci	kfree(node);
184762306a36Sopenharmony_ci}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci/**
185062306a36Sopenharmony_ci * qla_enode_init - initialize enode structs & lock
185162306a36Sopenharmony_ci * @vha: host adapter pointer
185262306a36Sopenharmony_ci *
185362306a36Sopenharmony_ci * should only be called when driver attaching
185462306a36Sopenharmony_ci */
185562306a36Sopenharmony_civoid
185662306a36Sopenharmony_ciqla_enode_init(scsi_qla_host_t *vha)
185762306a36Sopenharmony_ci{
185862306a36Sopenharmony_ci	struct	qla_hw_data *ha = vha->hw;
185962306a36Sopenharmony_ci	char	name[32];
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	if (vha->pur_cinfo.enode_flags == ENODE_ACTIVE) {
186262306a36Sopenharmony_ci		/* list still active - error */
186362306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102, "%s enode still active\n",
186462306a36Sopenharmony_ci		    __func__);
186562306a36Sopenharmony_ci		return;
186662306a36Sopenharmony_ci	}
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	/* initialize lock which protects pur_core & init list */
186962306a36Sopenharmony_ci	spin_lock_init(&vha->pur_cinfo.pur_lock);
187062306a36Sopenharmony_ci	INIT_LIST_HEAD(&vha->pur_cinfo.head);
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	snprintf(name, sizeof(name), "%s_%d_purex", QLA2XXX_DRIVER_NAME,
187362306a36Sopenharmony_ci	    ha->pdev->device);
187462306a36Sopenharmony_ci}
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci/**
187762306a36Sopenharmony_ci * qla_enode_stop - stop and clear and enode data
187862306a36Sopenharmony_ci * @vha: host adapter pointer
187962306a36Sopenharmony_ci *
188062306a36Sopenharmony_ci * called when app notified it is exiting
188162306a36Sopenharmony_ci */
188262306a36Sopenharmony_civoid
188362306a36Sopenharmony_ciqla_enode_stop(scsi_qla_host_t *vha)
188462306a36Sopenharmony_ci{
188562306a36Sopenharmony_ci	unsigned long flags;
188662306a36Sopenharmony_ci	struct enode *node, *q;
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	if (vha->pur_cinfo.enode_flags != ENODE_ACTIVE) {
188962306a36Sopenharmony_ci		/* doorbell list not enabled */
189062306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102,
189162306a36Sopenharmony_ci		    "%s enode not active\n", __func__);
189262306a36Sopenharmony_ci		return;
189362306a36Sopenharmony_ci	}
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	/* grab lock so list doesn't move */
189662306a36Sopenharmony_ci	spin_lock_irqsave(&vha->pur_cinfo.pur_lock, flags);
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	vha->pur_cinfo.enode_flags &= ~ENODE_ACTIVE; /* mark it not active */
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	/* hopefully this is a null list at this point */
190162306a36Sopenharmony_ci	list_for_each_entry_safe(node, q, &vha->pur_cinfo.head, list) {
190262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x910f,
190362306a36Sopenharmony_ci		    "%s freeing enode type=%x, cnt=%x\n", __func__, node->ntype,
190462306a36Sopenharmony_ci		    node->dinfo.nodecnt);
190562306a36Sopenharmony_ci		list_del_init(&node->list);
190662306a36Sopenharmony_ci		qla_enode_free(vha, node);
190762306a36Sopenharmony_ci	}
190862306a36Sopenharmony_ci	spin_unlock_irqrestore(&vha->pur_cinfo.pur_lock, flags);
190962306a36Sopenharmony_ci}
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_cistatic void qla_enode_clear(scsi_qla_host_t *vha, port_id_t portid)
191262306a36Sopenharmony_ci{
191362306a36Sopenharmony_ci	unsigned    long flags;
191462306a36Sopenharmony_ci	struct enode    *e, *tmp;
191562306a36Sopenharmony_ci	struct purexevent   *purex;
191662306a36Sopenharmony_ci	LIST_HEAD(enode_list);
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	if (vha->pur_cinfo.enode_flags != ENODE_ACTIVE) {
191962306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102,
192062306a36Sopenharmony_ci		       "%s enode not active\n", __func__);
192162306a36Sopenharmony_ci		return;
192262306a36Sopenharmony_ci	}
192362306a36Sopenharmony_ci	spin_lock_irqsave(&vha->pur_cinfo.pur_lock, flags);
192462306a36Sopenharmony_ci	list_for_each_entry_safe(e, tmp, &vha->pur_cinfo.head, list) {
192562306a36Sopenharmony_ci		purex = &e->u.purexinfo;
192662306a36Sopenharmony_ci		if (purex->pur_info.pur_sid.b24 == portid.b24) {
192762306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x911d,
192862306a36Sopenharmony_ci			    "%s free ELS sid=%06x. xchg %x, nb=%xh\n",
192962306a36Sopenharmony_ci			    __func__, portid.b24,
193062306a36Sopenharmony_ci			    purex->pur_info.pur_rx_xchg_address,
193162306a36Sopenharmony_ci			    purex->pur_info.pur_bytes_rcvd);
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci			list_del_init(&e->list);
193462306a36Sopenharmony_ci			list_add_tail(&e->list, &enode_list);
193562306a36Sopenharmony_ci		}
193662306a36Sopenharmony_ci	}
193762306a36Sopenharmony_ci	spin_unlock_irqrestore(&vha->pur_cinfo.pur_lock, flags);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	list_for_each_entry_safe(e, tmp, &enode_list, list) {
194062306a36Sopenharmony_ci		list_del_init(&e->list);
194162306a36Sopenharmony_ci		qla_enode_free(vha, e);
194262306a36Sopenharmony_ci	}
194362306a36Sopenharmony_ci}
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci/*
194662306a36Sopenharmony_ci *  allocate enode struct and populate buffer
194762306a36Sopenharmony_ci *  returns: enode pointer with buffers
194862306a36Sopenharmony_ci *           NULL on error
194962306a36Sopenharmony_ci */
195062306a36Sopenharmony_cistatic struct enode *
195162306a36Sopenharmony_ciqla_enode_alloc(scsi_qla_host_t *vha, uint32_t ntype)
195262306a36Sopenharmony_ci{
195362306a36Sopenharmony_ci	struct enode		*node;
195462306a36Sopenharmony_ci	struct purexevent	*purex;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	node = kzalloc(RX_ELS_SIZE, GFP_ATOMIC);
195762306a36Sopenharmony_ci	if (!node)
195862306a36Sopenharmony_ci		return NULL;
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	purex = &node->u.purexinfo;
196162306a36Sopenharmony_ci	purex->msgp = (u8 *)(node + 1);
196262306a36Sopenharmony_ci	purex->msgp_len = ELS_MAX_PAYLOAD;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	node->ntype = ntype;
196562306a36Sopenharmony_ci	INIT_LIST_HEAD(&node->list);
196662306a36Sopenharmony_ci	return node;
196762306a36Sopenharmony_ci}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_cistatic void
197062306a36Sopenharmony_ciqla_enode_add(scsi_qla_host_t *vha, struct enode *ptr)
197162306a36Sopenharmony_ci{
197262306a36Sopenharmony_ci	unsigned long flags;
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif + ql_dbg_verbose, vha, 0x9109,
197562306a36Sopenharmony_ci	    "%s add enode for type=%x, cnt=%x\n",
197662306a36Sopenharmony_ci	    __func__, ptr->ntype, ptr->dinfo.nodecnt);
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	spin_lock_irqsave(&vha->pur_cinfo.pur_lock, flags);
197962306a36Sopenharmony_ci	list_add_tail(&ptr->list, &vha->pur_cinfo.head);
198062306a36Sopenharmony_ci	spin_unlock_irqrestore(&vha->pur_cinfo.pur_lock, flags);
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	return;
198362306a36Sopenharmony_ci}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_cistatic struct enode *
198662306a36Sopenharmony_ciqla_enode_find(scsi_qla_host_t *vha, uint32_t ntype, uint32_t p1, uint32_t p2)
198762306a36Sopenharmony_ci{
198862306a36Sopenharmony_ci	struct enode		*node_rtn = NULL;
198962306a36Sopenharmony_ci	struct enode		*list_node, *q;
199062306a36Sopenharmony_ci	unsigned long		flags;
199162306a36Sopenharmony_ci	uint32_t		sid;
199262306a36Sopenharmony_ci	struct purexevent	*purex;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	/* secure the list from moving under us */
199562306a36Sopenharmony_ci	spin_lock_irqsave(&vha->pur_cinfo.pur_lock, flags);
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	list_for_each_entry_safe(list_node, q, &vha->pur_cinfo.head, list) {
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci		/* node type determines what p1 and p2 are */
200062306a36Sopenharmony_ci		purex = &list_node->u.purexinfo;
200162306a36Sopenharmony_ci		sid = p1;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci		if (purex->pur_info.pur_sid.b24 == sid) {
200462306a36Sopenharmony_ci			/* found it and its complete */
200562306a36Sopenharmony_ci			node_rtn = list_node;
200662306a36Sopenharmony_ci			list_del(&list_node->list);
200762306a36Sopenharmony_ci			break;
200862306a36Sopenharmony_ci		}
200962306a36Sopenharmony_ci	}
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	spin_unlock_irqrestore(&vha->pur_cinfo.pur_lock, flags);
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	return node_rtn;
201462306a36Sopenharmony_ci}
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci/**
201762306a36Sopenharmony_ci * qla_pur_get_pending - read/return authentication message sent
201862306a36Sopenharmony_ci *  from remote port
201962306a36Sopenharmony_ci * @vha: host adapter pointer
202062306a36Sopenharmony_ci * @fcport: session pointer
202162306a36Sopenharmony_ci * @bsg_job: user request where the message is copy to.
202262306a36Sopenharmony_ci */
202362306a36Sopenharmony_cistatic int
202462306a36Sopenharmony_ciqla_pur_get_pending(scsi_qla_host_t *vha, fc_port_t *fcport,
202562306a36Sopenharmony_ci	struct bsg_job *bsg_job)
202662306a36Sopenharmony_ci{
202762306a36Sopenharmony_ci	struct enode		*ptr;
202862306a36Sopenharmony_ci	struct purexevent	*purex;
202962306a36Sopenharmony_ci	struct qla_bsg_auth_els_reply *rpl =
203062306a36Sopenharmony_ci	    (struct qla_bsg_auth_els_reply *)bsg_job->reply;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	bsg_job->reply_len = sizeof(*rpl);
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	ptr = qla_enode_find(vha, N_PUREX, fcport->d_id.b24, PUR_GET);
203562306a36Sopenharmony_ci	if (!ptr) {
203662306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x9111,
203762306a36Sopenharmony_ci		    "%s no enode data found for %8phN sid=%06x\n",
203862306a36Sopenharmony_ci		    __func__, fcport->port_name, fcport->d_id.b24);
203962306a36Sopenharmony_ci		SET_DID_STATUS(rpl->r.result, DID_IMM_RETRY);
204062306a36Sopenharmony_ci		return -EIO;
204162306a36Sopenharmony_ci	}
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	/*
204462306a36Sopenharmony_ci	 * enode is now off the linked list and is ours to deal with
204562306a36Sopenharmony_ci	 */
204662306a36Sopenharmony_ci	purex = &ptr->u.purexinfo;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	/* Copy info back to caller */
204962306a36Sopenharmony_ci	rpl->rx_xchg_address = purex->pur_info.pur_rx_xchg_address;
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	SET_DID_STATUS(rpl->r.result, DID_OK);
205262306a36Sopenharmony_ci	rpl->r.reply_payload_rcv_len =
205362306a36Sopenharmony_ci	    sg_pcopy_from_buffer(bsg_job->reply_payload.sg_list,
205462306a36Sopenharmony_ci		bsg_job->reply_payload.sg_cnt, purex->msgp,
205562306a36Sopenharmony_ci		purex->pur_info.pur_bytes_rcvd, 0);
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	/* data copy / passback completed - destroy enode */
205862306a36Sopenharmony_ci	qla_enode_free(vha, ptr);
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	return 0;
206162306a36Sopenharmony_ci}
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci/* it is assume qpair lock is held */
206462306a36Sopenharmony_cistatic int
206562306a36Sopenharmony_ciqla_els_reject_iocb(scsi_qla_host_t *vha, struct qla_qpair *qp,
206662306a36Sopenharmony_ci	struct qla_els_pt_arg *a)
206762306a36Sopenharmony_ci{
206862306a36Sopenharmony_ci	struct els_entry_24xx *els_iocb;
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	els_iocb = __qla2x00_alloc_iocbs(qp, NULL);
207162306a36Sopenharmony_ci	if (!els_iocb) {
207262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x700c,
207362306a36Sopenharmony_ci		    "qla2x00_alloc_iocbs failed.\n");
207462306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
207562306a36Sopenharmony_ci	}
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	qla_els_pt_iocb(vha, els_iocb, a);
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x0183,
208062306a36Sopenharmony_ci	    "Sending ELS reject ox_id %04x s:%06x -> d:%06x\n",
208162306a36Sopenharmony_ci	    a->ox_id, a->sid.b24, a->did.b24);
208262306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_edif + ql_dbg_verbose, vha, 0x0185,
208362306a36Sopenharmony_ci	    vha->hw->elsrej.c, sizeof(*vha->hw->elsrej.c));
208462306a36Sopenharmony_ci	/* flush iocb to mem before notifying hw doorbell */
208562306a36Sopenharmony_ci	wmb();
208662306a36Sopenharmony_ci	qla2x00_start_iocbs(vha, qp->req);
208762306a36Sopenharmony_ci	return 0;
208862306a36Sopenharmony_ci}
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_civoid
209162306a36Sopenharmony_ciqla_edb_init(scsi_qla_host_t *vha)
209262306a36Sopenharmony_ci{
209362306a36Sopenharmony_ci	if (DBELL_ACTIVE(vha)) {
209462306a36Sopenharmony_ci		/* list already init'd - error */
209562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102,
209662306a36Sopenharmony_ci		    "edif db already initialized, cannot reinit\n");
209762306a36Sopenharmony_ci		return;
209862306a36Sopenharmony_ci	}
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	/* initialize lock which protects doorbell & init list */
210162306a36Sopenharmony_ci	spin_lock_init(&vha->e_dbell.db_lock);
210262306a36Sopenharmony_ci	INIT_LIST_HEAD(&vha->e_dbell.head);
210362306a36Sopenharmony_ci}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_cistatic void qla_edb_clear(scsi_qla_host_t *vha, port_id_t portid)
210662306a36Sopenharmony_ci{
210762306a36Sopenharmony_ci	unsigned long flags;
210862306a36Sopenharmony_ci	struct edb_node *e, *tmp;
210962306a36Sopenharmony_ci	port_id_t sid;
211062306a36Sopenharmony_ci	LIST_HEAD(edb_list);
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	if (DBELL_INACTIVE(vha)) {
211362306a36Sopenharmony_ci		/* doorbell list not enabled */
211462306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102,
211562306a36Sopenharmony_ci		       "%s doorbell not enabled\n", __func__);
211662306a36Sopenharmony_ci		return;
211762306a36Sopenharmony_ci	}
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	/* grab lock so list doesn't move */
212062306a36Sopenharmony_ci	spin_lock_irqsave(&vha->e_dbell.db_lock, flags);
212162306a36Sopenharmony_ci	list_for_each_entry_safe(e, tmp, &vha->e_dbell.head, list) {
212262306a36Sopenharmony_ci		switch (e->ntype) {
212362306a36Sopenharmony_ci		case VND_CMD_AUTH_STATE_NEEDED:
212462306a36Sopenharmony_ci		case VND_CMD_AUTH_STATE_SESSION_SHUTDOWN:
212562306a36Sopenharmony_ci			sid = e->u.plogi_did;
212662306a36Sopenharmony_ci			break;
212762306a36Sopenharmony_ci		case VND_CMD_AUTH_STATE_ELS_RCVD:
212862306a36Sopenharmony_ci			sid = e->u.els_sid;
212962306a36Sopenharmony_ci			break;
213062306a36Sopenharmony_ci		case VND_CMD_AUTH_STATE_SAUPDATE_COMPL:
213162306a36Sopenharmony_ci			/* app wants to see this  */
213262306a36Sopenharmony_ci			continue;
213362306a36Sopenharmony_ci		default:
213462306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x09102,
213562306a36Sopenharmony_ci			       "%s unknown node type: %x\n", __func__, e->ntype);
213662306a36Sopenharmony_ci			sid.b24 = 0;
213762306a36Sopenharmony_ci			break;
213862306a36Sopenharmony_ci		}
213962306a36Sopenharmony_ci		if (sid.b24 == portid.b24) {
214062306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x910f,
214162306a36Sopenharmony_ci			       "%s free doorbell event : node type = %x %p\n",
214262306a36Sopenharmony_ci			       __func__, e->ntype, e);
214362306a36Sopenharmony_ci			list_del_init(&e->list);
214462306a36Sopenharmony_ci			list_add_tail(&e->list, &edb_list);
214562306a36Sopenharmony_ci		}
214662306a36Sopenharmony_ci	}
214762306a36Sopenharmony_ci	spin_unlock_irqrestore(&vha->e_dbell.db_lock, flags);
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	list_for_each_entry_safe(e, tmp, &edb_list, list)
215062306a36Sopenharmony_ci		qla_edb_node_free(vha, e);
215162306a36Sopenharmony_ci}
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci/* function called when app is stopping */
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_civoid
215662306a36Sopenharmony_ciqla_edb_stop(scsi_qla_host_t *vha)
215762306a36Sopenharmony_ci{
215862306a36Sopenharmony_ci	unsigned long flags;
215962306a36Sopenharmony_ci	struct edb_node *node, *q;
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	if (DBELL_INACTIVE(vha)) {
216262306a36Sopenharmony_ci		/* doorbell list not enabled */
216362306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102,
216462306a36Sopenharmony_ci		    "%s doorbell not enabled\n", __func__);
216562306a36Sopenharmony_ci		return;
216662306a36Sopenharmony_ci	}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	/* grab lock so list doesn't move */
216962306a36Sopenharmony_ci	spin_lock_irqsave(&vha->e_dbell.db_lock, flags);
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	vha->e_dbell.db_flags &= ~EDB_ACTIVE; /* mark it not active */
217262306a36Sopenharmony_ci	/* hopefully this is a null list at this point */
217362306a36Sopenharmony_ci	list_for_each_entry_safe(node, q, &vha->e_dbell.head, list) {
217462306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x910f,
217562306a36Sopenharmony_ci		    "%s freeing edb_node type=%x\n",
217662306a36Sopenharmony_ci		    __func__, node->ntype);
217762306a36Sopenharmony_ci		qla_edb_node_free(vha, node);
217862306a36Sopenharmony_ci	}
217962306a36Sopenharmony_ci	spin_unlock_irqrestore(&vha->e_dbell.db_lock, flags);
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	qla_edif_dbell_bsg_done(vha);
218262306a36Sopenharmony_ci}
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_cistatic struct edb_node *
218562306a36Sopenharmony_ciqla_edb_node_alloc(scsi_qla_host_t *vha, uint32_t ntype)
218662306a36Sopenharmony_ci{
218762306a36Sopenharmony_ci	struct edb_node	*node;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	node = kzalloc(sizeof(*node), GFP_ATOMIC);
219062306a36Sopenharmony_ci	if (!node) {
219162306a36Sopenharmony_ci		/* couldn't get space */
219262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x9100,
219362306a36Sopenharmony_ci		    "edb node unable to be allocated\n");
219462306a36Sopenharmony_ci		return NULL;
219562306a36Sopenharmony_ci	}
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	node->ntype = ntype;
219862306a36Sopenharmony_ci	INIT_LIST_HEAD(&node->list);
219962306a36Sopenharmony_ci	return node;
220062306a36Sopenharmony_ci}
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci/* adds a already allocated enode to the linked list */
220362306a36Sopenharmony_cistatic bool
220462306a36Sopenharmony_ciqla_edb_node_add(scsi_qla_host_t *vha, struct edb_node *ptr)
220562306a36Sopenharmony_ci{
220662306a36Sopenharmony_ci	unsigned long		flags;
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	if (DBELL_INACTIVE(vha)) {
220962306a36Sopenharmony_ci		/* doorbell list not enabled */
221062306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102,
221162306a36Sopenharmony_ci		    "%s doorbell not enabled\n", __func__);
221262306a36Sopenharmony_ci		return false;
221362306a36Sopenharmony_ci	}
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	spin_lock_irqsave(&vha->e_dbell.db_lock, flags);
221662306a36Sopenharmony_ci	list_add_tail(&ptr->list, &vha->e_dbell.head);
221762306a36Sopenharmony_ci	spin_unlock_irqrestore(&vha->e_dbell.db_lock, flags);
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	return true;
222062306a36Sopenharmony_ci}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci/* adds event to doorbell list */
222362306a36Sopenharmony_civoid
222462306a36Sopenharmony_ciqla_edb_eventcreate(scsi_qla_host_t *vha, uint32_t dbtype,
222562306a36Sopenharmony_ci	uint32_t data, uint32_t data2, fc_port_t	*sfcport)
222662306a36Sopenharmony_ci{
222762306a36Sopenharmony_ci	struct edb_node	*edbnode;
222862306a36Sopenharmony_ci	fc_port_t *fcport = sfcport;
222962306a36Sopenharmony_ci	port_id_t id;
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	if (!vha->hw->flags.edif_enabled) {
223262306a36Sopenharmony_ci		/* edif not enabled */
223362306a36Sopenharmony_ci		return;
223462306a36Sopenharmony_ci	}
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci	if (DBELL_INACTIVE(vha)) {
223762306a36Sopenharmony_ci		if (fcport)
223862306a36Sopenharmony_ci			fcport->edif.auth_state = dbtype;
223962306a36Sopenharmony_ci		/* doorbell list not enabled */
224062306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102,
224162306a36Sopenharmony_ci		    "%s doorbell not enabled (type=%d\n", __func__, dbtype);
224262306a36Sopenharmony_ci		return;
224362306a36Sopenharmony_ci	}
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	edbnode = qla_edb_node_alloc(vha, dbtype);
224662306a36Sopenharmony_ci	if (!edbnode) {
224762306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102,
224862306a36Sopenharmony_ci		    "%s unable to alloc db node\n", __func__);
224962306a36Sopenharmony_ci		return;
225062306a36Sopenharmony_ci	}
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	if (!fcport) {
225362306a36Sopenharmony_ci		id.b.domain = (data >> 16) & 0xff;
225462306a36Sopenharmony_ci		id.b.area = (data >> 8) & 0xff;
225562306a36Sopenharmony_ci		id.b.al_pa = data & 0xff;
225662306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09222,
225762306a36Sopenharmony_ci		    "%s: Arrived s_id: %06x\n", __func__,
225862306a36Sopenharmony_ci		    id.b24);
225962306a36Sopenharmony_ci		fcport = qla2x00_find_fcport_by_pid(vha, &id);
226062306a36Sopenharmony_ci		if (!fcport) {
226162306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x09102,
226262306a36Sopenharmony_ci			    "%s can't find fcport for sid= 0x%x - ignoring\n",
226362306a36Sopenharmony_ci			__func__, id.b24);
226462306a36Sopenharmony_ci			kfree(edbnode);
226562306a36Sopenharmony_ci			return;
226662306a36Sopenharmony_ci		}
226762306a36Sopenharmony_ci	}
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	/* populate the edb node */
227062306a36Sopenharmony_ci	switch (dbtype) {
227162306a36Sopenharmony_ci	case VND_CMD_AUTH_STATE_NEEDED:
227262306a36Sopenharmony_ci	case VND_CMD_AUTH_STATE_SESSION_SHUTDOWN:
227362306a36Sopenharmony_ci		edbnode->u.plogi_did.b24 = fcport->d_id.b24;
227462306a36Sopenharmony_ci		break;
227562306a36Sopenharmony_ci	case VND_CMD_AUTH_STATE_ELS_RCVD:
227662306a36Sopenharmony_ci		edbnode->u.els_sid.b24 = fcport->d_id.b24;
227762306a36Sopenharmony_ci		break;
227862306a36Sopenharmony_ci	case VND_CMD_AUTH_STATE_SAUPDATE_COMPL:
227962306a36Sopenharmony_ci		edbnode->u.sa_aen.port_id = fcport->d_id;
228062306a36Sopenharmony_ci		edbnode->u.sa_aen.status =  data;
228162306a36Sopenharmony_ci		edbnode->u.sa_aen.key_type =  data2;
228262306a36Sopenharmony_ci		edbnode->u.sa_aen.version = EDIF_VERSION1;
228362306a36Sopenharmony_ci		break;
228462306a36Sopenharmony_ci	default:
228562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102,
228662306a36Sopenharmony_ci			"%s unknown type: %x\n", __func__, dbtype);
228762306a36Sopenharmony_ci		kfree(edbnode);
228862306a36Sopenharmony_ci		edbnode = NULL;
228962306a36Sopenharmony_ci		break;
229062306a36Sopenharmony_ci	}
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	if (edbnode) {
229362306a36Sopenharmony_ci		if (!qla_edb_node_add(vha, edbnode)) {
229462306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x09102,
229562306a36Sopenharmony_ci			    "%s unable to add dbnode\n", __func__);
229662306a36Sopenharmony_ci			kfree(edbnode);
229762306a36Sopenharmony_ci			return;
229862306a36Sopenharmony_ci		}
229962306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09102,
230062306a36Sopenharmony_ci		    "%s Doorbell produced : type=%d %p\n", __func__, dbtype, edbnode);
230162306a36Sopenharmony_ci		qla_edif_dbell_bsg_done(vha);
230262306a36Sopenharmony_ci		if (fcport)
230362306a36Sopenharmony_ci			fcport->edif.auth_state = dbtype;
230462306a36Sopenharmony_ci	}
230562306a36Sopenharmony_ci}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_civoid
230862306a36Sopenharmony_ciqla_edif_timer(scsi_qla_host_t *vha)
230962306a36Sopenharmony_ci{
231062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	if (!vha->vp_idx && N2N_TOPO(ha) && ha->flags.n2n_fw_acc_sec) {
231362306a36Sopenharmony_ci		if (DBELL_INACTIVE(vha) &&
231462306a36Sopenharmony_ci		    ha->edif_post_stop_cnt_down) {
231562306a36Sopenharmony_ci			ha->edif_post_stop_cnt_down--;
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci			/*
231862306a36Sopenharmony_ci			 * turn off auto 'Plogi Acc + secure=1' feature
231962306a36Sopenharmony_ci			 * Set Add FW option[3]
232062306a36Sopenharmony_ci			 * BIT_15, if.
232162306a36Sopenharmony_ci			 */
232262306a36Sopenharmony_ci			if (ha->edif_post_stop_cnt_down == 0) {
232362306a36Sopenharmony_ci				ql_dbg(ql_dbg_async, vha, 0x911d,
232462306a36Sopenharmony_ci				       "%s chip reset to turn off PLOGI ACC + secure\n",
232562306a36Sopenharmony_ci				       __func__);
232662306a36Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
232762306a36Sopenharmony_ci			}
232862306a36Sopenharmony_ci		} else {
232962306a36Sopenharmony_ci			ha->edif_post_stop_cnt_down = 60;
233062306a36Sopenharmony_ci		}
233162306a36Sopenharmony_ci	}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	if (vha->e_dbell.dbell_bsg_job && time_after_eq(jiffies, vha->e_dbell.bsg_expire))
233462306a36Sopenharmony_ci		qla_edif_dbell_bsg_done(vha);
233562306a36Sopenharmony_ci}
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_cistatic void qla_noop_sp_done(srb_t *sp, int res)
233862306a36Sopenharmony_ci{
233962306a36Sopenharmony_ci	sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
234062306a36Sopenharmony_ci	/* ref: INIT */
234162306a36Sopenharmony_ci	kref_put(&sp->cmd_kref, qla2x00_sp_release);
234262306a36Sopenharmony_ci}
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci/*
234562306a36Sopenharmony_ci * Called from work queue
234662306a36Sopenharmony_ci * build and send the sa_update iocb to delete an rx sa_index
234762306a36Sopenharmony_ci */
234862306a36Sopenharmony_ciint
234962306a36Sopenharmony_ciqla24xx_issue_sa_replace_iocb(scsi_qla_host_t *vha, struct qla_work_evt *e)
235062306a36Sopenharmony_ci{
235162306a36Sopenharmony_ci	srb_t *sp;
235262306a36Sopenharmony_ci	fc_port_t	*fcport = NULL;
235362306a36Sopenharmony_ci	struct srb_iocb *iocb_cmd = NULL;
235462306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
235562306a36Sopenharmony_ci	struct	edif_sa_ctl *sa_ctl = e->u.sa_update.sa_ctl;
235662306a36Sopenharmony_ci	uint16_t nport_handle = e->u.sa_update.nport_handle;
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x70e6,
235962306a36Sopenharmony_ci	    "%s: starting,  sa_ctl: %p\n", __func__, sa_ctl);
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	if (!sa_ctl) {
236262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x70e6,
236362306a36Sopenharmony_ci		    "sa_ctl allocation failed\n");
236462306a36Sopenharmony_ci		rval = -ENOMEM;
236562306a36Sopenharmony_ci		return rval;
236662306a36Sopenharmony_ci	}
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	fcport = sa_ctl->fcport;
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	/* Alloc SRB structure */
237162306a36Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
237262306a36Sopenharmony_ci	if (!sp) {
237362306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x70e6,
237462306a36Sopenharmony_ci		 "SRB allocation failed\n");
237562306a36Sopenharmony_ci		rval = -ENOMEM;
237662306a36Sopenharmony_ci		goto done;
237762306a36Sopenharmony_ci	}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	fcport->flags |= FCF_ASYNC_SENT;
238062306a36Sopenharmony_ci	iocb_cmd = &sp->u.iocb_cmd;
238162306a36Sopenharmony_ci	iocb_cmd->u.sa_update.sa_ctl = sa_ctl;
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x3073,
238462306a36Sopenharmony_ci	    "Enter: SA REPL portid=%06x, sa_ctl %p, index %x, nport_handle: 0x%x\n",
238562306a36Sopenharmony_ci	    fcport->d_id.b24, sa_ctl, sa_ctl->index, nport_handle);
238662306a36Sopenharmony_ci	/*
238762306a36Sopenharmony_ci	 * if this is a sadb cleanup delete, mark it so the isr can
238862306a36Sopenharmony_ci	 * take the correct action
238962306a36Sopenharmony_ci	 */
239062306a36Sopenharmony_ci	if (sa_ctl->flags & EDIF_SA_CTL_FLG_CLEANUP_DEL) {
239162306a36Sopenharmony_ci		/* mark this srb as a cleanup delete */
239262306a36Sopenharmony_ci		sp->flags |= SRB_EDIF_CLEANUP_DELETE;
239362306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x70e6,
239462306a36Sopenharmony_ci		    "%s: sp 0x%p flagged as cleanup delete\n", __func__, sp);
239562306a36Sopenharmony_ci	}
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	sp->type = SRB_SA_REPLACE;
239862306a36Sopenharmony_ci	sp->name = "SA_REPLACE";
239962306a36Sopenharmony_ci	sp->fcport = fcport;
240062306a36Sopenharmony_ci	sp->free = qla2x00_rel_sp;
240162306a36Sopenharmony_ci	sp->done = qla_noop_sp_done;
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci	rval = qla2x00_start_sp(sp);
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
240662306a36Sopenharmony_ci		goto done_free_sp;
240762306a36Sopenharmony_ci	}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci	return rval;
241062306a36Sopenharmony_cidone_free_sp:
241162306a36Sopenharmony_ci	kref_put(&sp->cmd_kref, qla2x00_sp_release);
241262306a36Sopenharmony_ci	fcport->flags &= ~FCF_ASYNC_SENT;
241362306a36Sopenharmony_cidone:
241462306a36Sopenharmony_ci	fcport->flags &= ~FCF_ASYNC_ACTIVE;
241562306a36Sopenharmony_ci	return rval;
241662306a36Sopenharmony_ci}
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_civoid qla24xx_sa_update_iocb(srb_t *sp, struct sa_update_28xx *sa_update_iocb)
241962306a36Sopenharmony_ci{
242062306a36Sopenharmony_ci	int	itr = 0;
242162306a36Sopenharmony_ci	struct	scsi_qla_host		*vha = sp->vha;
242262306a36Sopenharmony_ci	struct	qla_sa_update_frame	*sa_frame =
242362306a36Sopenharmony_ci		&sp->u.iocb_cmd.u.sa_update.sa_frame;
242462306a36Sopenharmony_ci	u8 flags = 0;
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	switch (sa_frame->flags & (SAU_FLG_INV | SAU_FLG_TX)) {
242762306a36Sopenharmony_ci	case 0:
242862306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d,
242962306a36Sopenharmony_ci		    "%s: EDIF SA UPDATE RX IOCB  vha: 0x%p  index: %d\n",
243062306a36Sopenharmony_ci		    __func__, vha, sa_frame->fast_sa_index);
243162306a36Sopenharmony_ci		break;
243262306a36Sopenharmony_ci	case 1:
243362306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d,
243462306a36Sopenharmony_ci		    "%s: EDIF SA DELETE RX IOCB  vha: 0x%p  index: %d\n",
243562306a36Sopenharmony_ci		    __func__, vha, sa_frame->fast_sa_index);
243662306a36Sopenharmony_ci		flags |= SA_FLAG_INVALIDATE;
243762306a36Sopenharmony_ci		break;
243862306a36Sopenharmony_ci	case 2:
243962306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d,
244062306a36Sopenharmony_ci		    "%s: EDIF SA UPDATE TX IOCB  vha: 0x%p  index: %d\n",
244162306a36Sopenharmony_ci		    __func__, vha, sa_frame->fast_sa_index);
244262306a36Sopenharmony_ci		flags |= SA_FLAG_TX;
244362306a36Sopenharmony_ci		break;
244462306a36Sopenharmony_ci	case 3:
244562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911d,
244662306a36Sopenharmony_ci		    "%s: EDIF SA DELETE TX IOCB  vha: 0x%p  index: %d\n",
244762306a36Sopenharmony_ci		    __func__, vha, sa_frame->fast_sa_index);
244862306a36Sopenharmony_ci		flags |= SA_FLAG_TX | SA_FLAG_INVALIDATE;
244962306a36Sopenharmony_ci		break;
245062306a36Sopenharmony_ci	}
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	sa_update_iocb->entry_type = SA_UPDATE_IOCB_TYPE;
245362306a36Sopenharmony_ci	sa_update_iocb->entry_count = 1;
245462306a36Sopenharmony_ci	sa_update_iocb->sys_define = 0;
245562306a36Sopenharmony_ci	sa_update_iocb->entry_status = 0;
245662306a36Sopenharmony_ci	sa_update_iocb->handle = sp->handle;
245762306a36Sopenharmony_ci	sa_update_iocb->u.nport_handle = cpu_to_le16(sp->fcport->loop_id);
245862306a36Sopenharmony_ci	sa_update_iocb->vp_index = sp->fcport->vha->vp_idx;
245962306a36Sopenharmony_ci	sa_update_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
246062306a36Sopenharmony_ci	sa_update_iocb->port_id[1] = sp->fcport->d_id.b.area;
246162306a36Sopenharmony_ci	sa_update_iocb->port_id[2] = sp->fcport->d_id.b.domain;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	sa_update_iocb->flags = flags;
246462306a36Sopenharmony_ci	sa_update_iocb->salt = cpu_to_le32(sa_frame->salt);
246562306a36Sopenharmony_ci	sa_update_iocb->spi = cpu_to_le32(sa_frame->spi);
246662306a36Sopenharmony_ci	sa_update_iocb->sa_index = cpu_to_le16(sa_frame->fast_sa_index);
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	sa_update_iocb->sa_control |= SA_CNTL_ENC_FCSP;
246962306a36Sopenharmony_ci	if (sp->fcport->edif.aes_gmac)
247062306a36Sopenharmony_ci		sa_update_iocb->sa_control |= SA_CNTL_AES_GMAC;
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	if (sa_frame->flags & SAU_FLG_KEY256) {
247362306a36Sopenharmony_ci		sa_update_iocb->sa_control |= SA_CNTL_KEY256;
247462306a36Sopenharmony_ci		for (itr = 0; itr < 32; itr++)
247562306a36Sopenharmony_ci			sa_update_iocb->sa_key[itr] = sa_frame->sa_key[itr];
247662306a36Sopenharmony_ci	} else {
247762306a36Sopenharmony_ci		sa_update_iocb->sa_control |= SA_CNTL_KEY128;
247862306a36Sopenharmony_ci		for (itr = 0; itr < 16; itr++)
247962306a36Sopenharmony_ci			sa_update_iocb->sa_key[itr] = sa_frame->sa_key[itr];
248062306a36Sopenharmony_ci	}
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x921d,
248362306a36Sopenharmony_ci	    "%s SAU Port ID = %02x%02x%02x, flags=%xh, index=%u, ctl=%xh, SPI 0x%x flags 0x%x hdl=%x gmac %d\n",
248462306a36Sopenharmony_ci	    __func__, sa_update_iocb->port_id[2], sa_update_iocb->port_id[1],
248562306a36Sopenharmony_ci	    sa_update_iocb->port_id[0], sa_update_iocb->flags, sa_update_iocb->sa_index,
248662306a36Sopenharmony_ci	    sa_update_iocb->sa_control, sa_update_iocb->spi, sa_frame->flags, sp->handle,
248762306a36Sopenharmony_ci	    sp->fcport->edif.aes_gmac);
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	if (sa_frame->flags & SAU_FLG_TX)
249062306a36Sopenharmony_ci		sp->fcport->edif.tx_sa_pending = 1;
249162306a36Sopenharmony_ci	else
249262306a36Sopenharmony_ci		sp->fcport->edif.rx_sa_pending = 1;
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	sp->fcport->vha->qla_stats.control_requests++;
249562306a36Sopenharmony_ci}
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_civoid
249862306a36Sopenharmony_ciqla24xx_sa_replace_iocb(srb_t *sp, struct sa_update_28xx *sa_update_iocb)
249962306a36Sopenharmony_ci{
250062306a36Sopenharmony_ci	struct	scsi_qla_host		*vha = sp->vha;
250162306a36Sopenharmony_ci	struct srb_iocb *srb_iocb = &sp->u.iocb_cmd;
250262306a36Sopenharmony_ci	struct	edif_sa_ctl		*sa_ctl = srb_iocb->u.sa_update.sa_ctl;
250362306a36Sopenharmony_ci	uint16_t nport_handle = sp->fcport->loop_id;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	sa_update_iocb->entry_type = SA_UPDATE_IOCB_TYPE;
250662306a36Sopenharmony_ci	sa_update_iocb->entry_count = 1;
250762306a36Sopenharmony_ci	sa_update_iocb->sys_define = 0;
250862306a36Sopenharmony_ci	sa_update_iocb->entry_status = 0;
250962306a36Sopenharmony_ci	sa_update_iocb->handle = sp->handle;
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	sa_update_iocb->u.nport_handle = cpu_to_le16(nport_handle);
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	sa_update_iocb->vp_index = sp->fcport->vha->vp_idx;
251462306a36Sopenharmony_ci	sa_update_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
251562306a36Sopenharmony_ci	sa_update_iocb->port_id[1] = sp->fcport->d_id.b.area;
251662306a36Sopenharmony_ci	sa_update_iocb->port_id[2] = sp->fcport->d_id.b.domain;
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	/* Invalidate the index. salt, spi, control & key are ignore */
251962306a36Sopenharmony_ci	sa_update_iocb->flags = SA_FLAG_INVALIDATE;
252062306a36Sopenharmony_ci	sa_update_iocb->salt = 0;
252162306a36Sopenharmony_ci	sa_update_iocb->spi = 0;
252262306a36Sopenharmony_ci	sa_update_iocb->sa_index = cpu_to_le16(sa_ctl->index);
252362306a36Sopenharmony_ci	sa_update_iocb->sa_control = 0;
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x921d,
252662306a36Sopenharmony_ci	    "%s SAU DELETE RX Port ID = %02x:%02x:%02x, lid %d flags=%xh, index=%u, hdl=%x\n",
252762306a36Sopenharmony_ci	    __func__, sa_update_iocb->port_id[2], sa_update_iocb->port_id[1],
252862306a36Sopenharmony_ci	    sa_update_iocb->port_id[0], nport_handle, sa_update_iocb->flags,
252962306a36Sopenharmony_ci	    sa_update_iocb->sa_index, sp->handle);
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	sp->fcport->vha->qla_stats.control_requests++;
253262306a36Sopenharmony_ci}
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_civoid qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
253562306a36Sopenharmony_ci{
253662306a36Sopenharmony_ci	struct purex_entry_24xx *p = *pkt;
253762306a36Sopenharmony_ci	struct enode		*ptr;
253862306a36Sopenharmony_ci	int		sid;
253962306a36Sopenharmony_ci	u16 totlen;
254062306a36Sopenharmony_ci	struct purexevent	*purex;
254162306a36Sopenharmony_ci	struct scsi_qla_host *host = NULL;
254262306a36Sopenharmony_ci	int rc;
254362306a36Sopenharmony_ci	struct fc_port *fcport;
254462306a36Sopenharmony_ci	struct qla_els_pt_arg a;
254562306a36Sopenharmony_ci	be_id_t beid;
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci	memset(&a, 0, sizeof(a));
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci	a.els_opcode = ELS_AUTH_ELS;
255062306a36Sopenharmony_ci	a.nport_handle = p->nport_handle;
255162306a36Sopenharmony_ci	a.rx_xchg_address = p->rx_xchg_addr;
255262306a36Sopenharmony_ci	a.did.b.domain = p->s_id[2];
255362306a36Sopenharmony_ci	a.did.b.area   = p->s_id[1];
255462306a36Sopenharmony_ci	a.did.b.al_pa  = p->s_id[0];
255562306a36Sopenharmony_ci	a.tx_byte_count = a.tx_len = sizeof(struct fc_els_ls_rjt);
255662306a36Sopenharmony_ci	a.tx_addr = vha->hw->elsrej.cdma;
255762306a36Sopenharmony_ci	a.vp_idx = vha->vp_idx;
255862306a36Sopenharmony_ci	a.control_flags = EPD_ELS_RJT;
255962306a36Sopenharmony_ci	a.ox_id = le16_to_cpu(p->ox_id);
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	sid = p->s_id[0] | (p->s_id[1] << 8) | (p->s_id[2] << 16);
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci	totlen = (le16_to_cpu(p->frame_size) & 0x0fff) - PURX_ELS_HEADER_SIZE;
256462306a36Sopenharmony_ci	if (le16_to_cpu(p->status_flags) & 0x8000) {
256562306a36Sopenharmony_ci		totlen = le16_to_cpu(p->trunc_frame_size);
256662306a36Sopenharmony_ci		qla_els_reject_iocb(vha, (*rsp)->qpair, &a);
256762306a36Sopenharmony_ci		__qla_consume_iocb(vha, pkt, rsp);
256862306a36Sopenharmony_ci		return;
256962306a36Sopenharmony_ci	}
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	if (totlen > ELS_MAX_PAYLOAD) {
257262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x0910d,
257362306a36Sopenharmony_ci		    "%s WARNING: verbose ELS frame received (totlen=%x)\n",
257462306a36Sopenharmony_ci		    __func__, totlen);
257562306a36Sopenharmony_ci		qla_els_reject_iocb(vha, (*rsp)->qpair, &a);
257662306a36Sopenharmony_ci		__qla_consume_iocb(vha, pkt, rsp);
257762306a36Sopenharmony_ci		return;
257862306a36Sopenharmony_ci	}
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	if (!vha->hw->flags.edif_enabled) {
258162306a36Sopenharmony_ci		/* edif support not enabled */
258262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x910e, "%s edif not enabled\n",
258362306a36Sopenharmony_ci		    __func__);
258462306a36Sopenharmony_ci		qla_els_reject_iocb(vha, (*rsp)->qpair, &a);
258562306a36Sopenharmony_ci		__qla_consume_iocb(vha, pkt, rsp);
258662306a36Sopenharmony_ci		return;
258762306a36Sopenharmony_ci	}
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	ptr = qla_enode_alloc(vha, N_PUREX);
259062306a36Sopenharmony_ci	if (!ptr) {
259162306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x09109,
259262306a36Sopenharmony_ci		    "WARNING: enode alloc failed for sid=%x\n",
259362306a36Sopenharmony_ci		    sid);
259462306a36Sopenharmony_ci		qla_els_reject_iocb(vha, (*rsp)->qpair, &a);
259562306a36Sopenharmony_ci		__qla_consume_iocb(vha, pkt, rsp);
259662306a36Sopenharmony_ci		return;
259762306a36Sopenharmony_ci	}
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci	purex = &ptr->u.purexinfo;
260062306a36Sopenharmony_ci	purex->pur_info.pur_sid = a.did;
260162306a36Sopenharmony_ci	purex->pur_info.pur_bytes_rcvd = totlen;
260262306a36Sopenharmony_ci	purex->pur_info.pur_rx_xchg_address = le32_to_cpu(p->rx_xchg_addr);
260362306a36Sopenharmony_ci	purex->pur_info.pur_nphdl = le16_to_cpu(p->nport_handle);
260462306a36Sopenharmony_ci	purex->pur_info.pur_did.b.domain =  p->d_id[2];
260562306a36Sopenharmony_ci	purex->pur_info.pur_did.b.area =  p->d_id[1];
260662306a36Sopenharmony_ci	purex->pur_info.pur_did.b.al_pa =  p->d_id[0];
260762306a36Sopenharmony_ci	purex->pur_info.vp_idx = p->vp_idx;
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	a.sid = purex->pur_info.pur_did;
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci	rc = __qla_copy_purex_to_buffer(vha, pkt, rsp, purex->msgp,
261262306a36Sopenharmony_ci		purex->msgp_len);
261362306a36Sopenharmony_ci	if (rc) {
261462306a36Sopenharmony_ci		qla_els_reject_iocb(vha, (*rsp)->qpair, &a);
261562306a36Sopenharmony_ci		qla_enode_free(vha, ptr);
261662306a36Sopenharmony_ci		return;
261762306a36Sopenharmony_ci	}
261862306a36Sopenharmony_ci	beid.al_pa = purex->pur_info.pur_did.b.al_pa;
261962306a36Sopenharmony_ci	beid.area   = purex->pur_info.pur_did.b.area;
262062306a36Sopenharmony_ci	beid.domain = purex->pur_info.pur_did.b.domain;
262162306a36Sopenharmony_ci	host = qla_find_host_by_d_id(vha, beid);
262262306a36Sopenharmony_ci	if (!host) {
262362306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x508b,
262462306a36Sopenharmony_ci		    "%s Drop ELS due to unable to find host %06x\n",
262562306a36Sopenharmony_ci		    __func__, purex->pur_info.pur_did.b24);
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci		qla_els_reject_iocb(vha, (*rsp)->qpair, &a);
262862306a36Sopenharmony_ci		qla_enode_free(vha, ptr);
262962306a36Sopenharmony_ci		return;
263062306a36Sopenharmony_ci	}
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci	fcport = qla2x00_find_fcport_by_pid(host, &purex->pur_info.pur_sid);
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci	if (DBELL_INACTIVE(vha)) {
263562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, host, 0x0910c, "%s e_dbell.db_flags =%x %06x\n",
263662306a36Sopenharmony_ci		    __func__, host->e_dbell.db_flags,
263762306a36Sopenharmony_ci		    fcport ? fcport->d_id.b24 : 0);
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci		qla_els_reject_iocb(host, (*rsp)->qpair, &a);
264062306a36Sopenharmony_ci		qla_enode_free(host, ptr);
264162306a36Sopenharmony_ci		return;
264262306a36Sopenharmony_ci	}
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci	if (fcport && EDIF_SESSION_DOWN(fcport)) {
264562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, host, 0x13b6,
264662306a36Sopenharmony_ci		    "%s terminate exchange. Send logo to 0x%x\n",
264762306a36Sopenharmony_ci		    __func__, a.did.b24);
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci		a.tx_byte_count = a.tx_len = 0;
265062306a36Sopenharmony_ci		a.tx_addr = 0;
265162306a36Sopenharmony_ci		a.control_flags = EPD_RX_XCHG;  /* EPD_RX_XCHG = terminate cmd */
265262306a36Sopenharmony_ci		qla_els_reject_iocb(host, (*rsp)->qpair, &a);
265362306a36Sopenharmony_ci		qla_enode_free(host, ptr);
265462306a36Sopenharmony_ci		/* send logo to let remote port knows to tear down session */
265562306a36Sopenharmony_ci		fcport->send_els_logo = 1;
265662306a36Sopenharmony_ci		qlt_schedule_sess_for_deletion(fcport);
265762306a36Sopenharmony_ci		return;
265862306a36Sopenharmony_ci	}
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	/* add the local enode to the list */
266162306a36Sopenharmony_ci	qla_enode_add(host, ptr);
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, host, 0x0910c,
266462306a36Sopenharmony_ci	    "%s COMPLETE purex->pur_info.pur_bytes_rcvd =%xh s:%06x -> d:%06x xchg=%xh\n",
266562306a36Sopenharmony_ci	    __func__, purex->pur_info.pur_bytes_rcvd, purex->pur_info.pur_sid.b24,
266662306a36Sopenharmony_ci	    purex->pur_info.pur_did.b24, purex->pur_info.pur_rx_xchg_address);
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	qla_edb_eventcreate(host, VND_CMD_AUTH_STATE_ELS_RCVD, sid, 0, NULL);
266962306a36Sopenharmony_ci}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_cistatic uint16_t  qla_edif_get_sa_index_from_freepool(fc_port_t *fcport, int dir)
267262306a36Sopenharmony_ci{
267362306a36Sopenharmony_ci	struct scsi_qla_host *vha = fcport->vha;
267462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
267562306a36Sopenharmony_ci	void *sa_id_map;
267662306a36Sopenharmony_ci	unsigned long flags = 0;
267762306a36Sopenharmony_ci	u16 sa_index;
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif + ql_dbg_verbose, vha, 0x3063,
268062306a36Sopenharmony_ci	    "%s: entry\n", __func__);
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	if (dir)
268362306a36Sopenharmony_ci		sa_id_map = ha->edif_tx_sa_id_map;
268462306a36Sopenharmony_ci	else
268562306a36Sopenharmony_ci		sa_id_map = ha->edif_rx_sa_id_map;
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	spin_lock_irqsave(&ha->sadb_fp_lock, flags);
268862306a36Sopenharmony_ci	sa_index = find_first_zero_bit(sa_id_map, EDIF_NUM_SA_INDEX);
268962306a36Sopenharmony_ci	if (sa_index >=  EDIF_NUM_SA_INDEX) {
269062306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->sadb_fp_lock, flags);
269162306a36Sopenharmony_ci		return INVALID_EDIF_SA_INDEX;
269262306a36Sopenharmony_ci	}
269362306a36Sopenharmony_ci	set_bit(sa_index, sa_id_map);
269462306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->sadb_fp_lock, flags);
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_ci	if (dir)
269762306a36Sopenharmony_ci		sa_index += EDIF_TX_SA_INDEX_BASE;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x3063,
270062306a36Sopenharmony_ci	    "%s: index retrieved from free pool %d\n", __func__, sa_index);
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci	return sa_index;
270362306a36Sopenharmony_ci}
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci/* find an sadb entry for an nport_handle */
270662306a36Sopenharmony_cistatic struct edif_sa_index_entry *
270762306a36Sopenharmony_ciqla_edif_sadb_find_sa_index_entry(uint16_t nport_handle,
270862306a36Sopenharmony_ci		struct list_head *sa_list)
270962306a36Sopenharmony_ci{
271062306a36Sopenharmony_ci	struct edif_sa_index_entry *entry;
271162306a36Sopenharmony_ci	struct edif_sa_index_entry *tentry;
271262306a36Sopenharmony_ci	struct list_head *indx_list = sa_list;
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	list_for_each_entry_safe(entry, tentry, indx_list, next) {
271562306a36Sopenharmony_ci		if (entry->handle == nport_handle)
271662306a36Sopenharmony_ci			return entry;
271762306a36Sopenharmony_ci	}
271862306a36Sopenharmony_ci	return NULL;
271962306a36Sopenharmony_ci}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci/* remove an sa_index from the nport_handle and return it to the free pool */
272262306a36Sopenharmony_cistatic int qla_edif_sadb_delete_sa_index(fc_port_t *fcport, uint16_t nport_handle,
272362306a36Sopenharmony_ci		uint16_t sa_index)
272462306a36Sopenharmony_ci{
272562306a36Sopenharmony_ci	struct edif_sa_index_entry *entry;
272662306a36Sopenharmony_ci	struct list_head *sa_list;
272762306a36Sopenharmony_ci	int dir = (sa_index < EDIF_TX_SA_INDEX_BASE) ? 0 : 1;
272862306a36Sopenharmony_ci	int slot = 0;
272962306a36Sopenharmony_ci	int free_slot_count = 0;
273062306a36Sopenharmony_ci	scsi_qla_host_t *vha = fcport->vha;
273162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
273262306a36Sopenharmony_ci	unsigned long flags = 0;
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x3063,
273562306a36Sopenharmony_ci	    "%s: entry\n", __func__);
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	if (dir)
273862306a36Sopenharmony_ci		sa_list = &ha->sadb_tx_index_list;
273962306a36Sopenharmony_ci	else
274062306a36Sopenharmony_ci		sa_list = &ha->sadb_rx_index_list;
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci	entry = qla_edif_sadb_find_sa_index_entry(nport_handle, sa_list);
274362306a36Sopenharmony_ci	if (!entry) {
274462306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
274562306a36Sopenharmony_ci		    "%s: no entry found for nport_handle 0x%x\n",
274662306a36Sopenharmony_ci		    __func__, nport_handle);
274762306a36Sopenharmony_ci		return -1;
274862306a36Sopenharmony_ci	}
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_ci	spin_lock_irqsave(&ha->sadb_lock, flags);
275162306a36Sopenharmony_ci	/*
275262306a36Sopenharmony_ci	 * each tx/rx direction has up to 2 sa indexes/slots. 1 slot for in flight traffic
275362306a36Sopenharmony_ci	 * the other is use at re-key time.
275462306a36Sopenharmony_ci	 */
275562306a36Sopenharmony_ci	for (slot = 0; slot < 2; slot++) {
275662306a36Sopenharmony_ci		if (entry->sa_pair[slot].sa_index == sa_index) {
275762306a36Sopenharmony_ci			entry->sa_pair[slot].sa_index = INVALID_EDIF_SA_INDEX;
275862306a36Sopenharmony_ci			entry->sa_pair[slot].spi = 0;
275962306a36Sopenharmony_ci			free_slot_count++;
276062306a36Sopenharmony_ci			qla_edif_add_sa_index_to_freepool(fcport, dir, sa_index);
276162306a36Sopenharmony_ci		} else if (entry->sa_pair[slot].sa_index == INVALID_EDIF_SA_INDEX) {
276262306a36Sopenharmony_ci			free_slot_count++;
276362306a36Sopenharmony_ci		}
276462306a36Sopenharmony_ci	}
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	if (free_slot_count == 2) {
276762306a36Sopenharmony_ci		list_del(&entry->next);
276862306a36Sopenharmony_ci		kfree(entry);
276962306a36Sopenharmony_ci	}
277062306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->sadb_lock, flags);
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x3063,
277362306a36Sopenharmony_ci	    "%s: sa_index %d removed, free_slot_count: %d\n",
277462306a36Sopenharmony_ci	    __func__, sa_index, free_slot_count);
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	return 0;
277762306a36Sopenharmony_ci}
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_civoid
278062306a36Sopenharmony_ciqla28xx_sa_update_iocb_entry(scsi_qla_host_t *v, struct req_que *req,
278162306a36Sopenharmony_ci	struct sa_update_28xx *pkt)
278262306a36Sopenharmony_ci{
278362306a36Sopenharmony_ci	const char *func = "SA_UPDATE_RESPONSE_IOCB";
278462306a36Sopenharmony_ci	srb_t *sp;
278562306a36Sopenharmony_ci	struct edif_sa_ctl *sa_ctl;
278662306a36Sopenharmony_ci	int old_sa_deleted = 1;
278762306a36Sopenharmony_ci	uint16_t nport_handle;
278862306a36Sopenharmony_ci	struct scsi_qla_host *vha;
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(v, func, req, pkt);
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci	if (!sp) {
279362306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, v, 0x3063,
279462306a36Sopenharmony_ci			"%s: no sp found for pkt\n", __func__);
279562306a36Sopenharmony_ci		return;
279662306a36Sopenharmony_ci	}
279762306a36Sopenharmony_ci	/* use sp->vha due to npiv */
279862306a36Sopenharmony_ci	vha = sp->vha;
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci	switch (pkt->flags & (SA_FLAG_INVALIDATE | SA_FLAG_TX)) {
280162306a36Sopenharmony_ci	case 0:
280262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
280362306a36Sopenharmony_ci		    "%s: EDIF SA UPDATE RX IOCB  vha: 0x%p  index: %d\n",
280462306a36Sopenharmony_ci		    __func__, vha, pkt->sa_index);
280562306a36Sopenharmony_ci		break;
280662306a36Sopenharmony_ci	case 1:
280762306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
280862306a36Sopenharmony_ci		    "%s: EDIF SA DELETE RX IOCB  vha: 0x%p  index: %d\n",
280962306a36Sopenharmony_ci		    __func__, vha, pkt->sa_index);
281062306a36Sopenharmony_ci		break;
281162306a36Sopenharmony_ci	case 2:
281262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
281362306a36Sopenharmony_ci		    "%s: EDIF SA UPDATE TX IOCB  vha: 0x%p  index: %d\n",
281462306a36Sopenharmony_ci		    __func__, vha, pkt->sa_index);
281562306a36Sopenharmony_ci		break;
281662306a36Sopenharmony_ci	case 3:
281762306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
281862306a36Sopenharmony_ci		    "%s: EDIF SA DELETE TX IOCB  vha: 0x%p  index: %d\n",
281962306a36Sopenharmony_ci		    __func__, vha, pkt->sa_index);
282062306a36Sopenharmony_ci		break;
282162306a36Sopenharmony_ci	}
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci	/*
282462306a36Sopenharmony_ci	 * dig the nport handle out of the iocb, fcport->loop_id can not be trusted
282562306a36Sopenharmony_ci	 * to be correct during cleanup sa_update iocbs.
282662306a36Sopenharmony_ci	 */
282762306a36Sopenharmony_ci	nport_handle = sp->fcport->loop_id;
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x3063,
283062306a36Sopenharmony_ci	    "%s: %8phN comp status=%x old_sa_info=%x new_sa_info=%x lid %d, index=0x%x pkt_flags %xh hdl=%x\n",
283162306a36Sopenharmony_ci	    __func__, sp->fcport->port_name, pkt->u.comp_sts, pkt->old_sa_info, pkt->new_sa_info,
283262306a36Sopenharmony_ci	    nport_handle, pkt->sa_index, pkt->flags, sp->handle);
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci	/* if rx delete, remove the timer */
283562306a36Sopenharmony_ci	if ((pkt->flags & (SA_FLAG_INVALIDATE | SA_FLAG_TX)) ==  SA_FLAG_INVALIDATE) {
283662306a36Sopenharmony_ci		struct edif_list_entry *edif_entry;
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci		sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci		edif_entry = qla_edif_list_find_sa_index(sp->fcport, nport_handle);
284162306a36Sopenharmony_ci		if (edif_entry) {
284262306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x5033,
284362306a36Sopenharmony_ci			    "%s: removing edif_entry %p, new sa_index: 0x%x\n",
284462306a36Sopenharmony_ci			    __func__, edif_entry, pkt->sa_index);
284562306a36Sopenharmony_ci			qla_edif_list_delete_sa_index(sp->fcport, edif_entry);
284662306a36Sopenharmony_ci			timer_shutdown(&edif_entry->timer);
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x5033,
284962306a36Sopenharmony_ci			    "%s: releasing edif_entry %p, new sa_index: 0x%x\n",
285062306a36Sopenharmony_ci			    __func__, edif_entry, pkt->sa_index);
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci			kfree(edif_entry);
285362306a36Sopenharmony_ci		}
285462306a36Sopenharmony_ci	}
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	/*
285762306a36Sopenharmony_ci	 * if this is a delete for either tx or rx, make sure it succeeded.
285862306a36Sopenharmony_ci	 * The new_sa_info field should be 0xffff on success
285962306a36Sopenharmony_ci	 */
286062306a36Sopenharmony_ci	if (pkt->flags & SA_FLAG_INVALIDATE)
286162306a36Sopenharmony_ci		old_sa_deleted = (le16_to_cpu(pkt->new_sa_info) == 0xffff) ? 1 : 0;
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci	/* Process update and delete the same way */
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	/* If this is an sadb cleanup delete, bypass sending events to IPSEC */
286662306a36Sopenharmony_ci	if (sp->flags & SRB_EDIF_CLEANUP_DELETE) {
286762306a36Sopenharmony_ci		sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
286862306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
286962306a36Sopenharmony_ci		    "%s: nph 0x%x, sa_index %d removed from fw\n",
287062306a36Sopenharmony_ci		    __func__, sp->fcport->loop_id, pkt->sa_index);
287162306a36Sopenharmony_ci
287262306a36Sopenharmony_ci	} else if ((pkt->entry_status == 0) && (pkt->u.comp_sts == 0) &&
287362306a36Sopenharmony_ci	    old_sa_deleted) {
287462306a36Sopenharmony_ci		/*
287562306a36Sopenharmony_ci		 * Note: Wa are only keeping track of latest SA,
287662306a36Sopenharmony_ci		 * so we know when we can start enableing encryption per I/O.
287762306a36Sopenharmony_ci		 * If all SA's get deleted, let FW reject the IOCB.
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci		 * TODO: edif: don't set enabled here I think
288062306a36Sopenharmony_ci		 * TODO: edif: prli complete is where it should be set
288162306a36Sopenharmony_ci		 */
288262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif + ql_dbg_verbose, vha, 0x3063,
288362306a36Sopenharmony_ci			"SA(%x)updated for s_id %02x%02x%02x\n",
288462306a36Sopenharmony_ci			pkt->new_sa_info,
288562306a36Sopenharmony_ci			pkt->port_id[2], pkt->port_id[1], pkt->port_id[0]);
288662306a36Sopenharmony_ci		sp->fcport->edif.enable = 1;
288762306a36Sopenharmony_ci		if (pkt->flags & SA_FLAG_TX) {
288862306a36Sopenharmony_ci			sp->fcport->edif.tx_sa_set = 1;
288962306a36Sopenharmony_ci			sp->fcport->edif.tx_sa_pending = 0;
289062306a36Sopenharmony_ci			qla_edb_eventcreate(vha, VND_CMD_AUTH_STATE_SAUPDATE_COMPL,
289162306a36Sopenharmony_ci				QL_VND_SA_STAT_SUCCESS,
289262306a36Sopenharmony_ci				QL_VND_TX_SA_KEY, sp->fcport);
289362306a36Sopenharmony_ci		} else {
289462306a36Sopenharmony_ci			sp->fcport->edif.rx_sa_set = 1;
289562306a36Sopenharmony_ci			sp->fcport->edif.rx_sa_pending = 0;
289662306a36Sopenharmony_ci			qla_edb_eventcreate(vha, VND_CMD_AUTH_STATE_SAUPDATE_COMPL,
289762306a36Sopenharmony_ci				QL_VND_SA_STAT_SUCCESS,
289862306a36Sopenharmony_ci				QL_VND_RX_SA_KEY, sp->fcport);
289962306a36Sopenharmony_ci		}
290062306a36Sopenharmony_ci	} else {
290162306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
290262306a36Sopenharmony_ci		    "%s: %8phN SA update FAILED: sa_index: %d, new_sa_info %d, %02x%02x%02x\n",
290362306a36Sopenharmony_ci		    __func__, sp->fcport->port_name, pkt->sa_index, pkt->new_sa_info,
290462306a36Sopenharmony_ci		    pkt->port_id[2], pkt->port_id[1], pkt->port_id[0]);
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci		if (pkt->flags & SA_FLAG_TX)
290762306a36Sopenharmony_ci			qla_edb_eventcreate(vha, VND_CMD_AUTH_STATE_SAUPDATE_COMPL,
290862306a36Sopenharmony_ci				(le16_to_cpu(pkt->u.comp_sts) << 16) | QL_VND_SA_STAT_FAILED,
290962306a36Sopenharmony_ci				QL_VND_TX_SA_KEY, sp->fcport);
291062306a36Sopenharmony_ci		else
291162306a36Sopenharmony_ci			qla_edb_eventcreate(vha, VND_CMD_AUTH_STATE_SAUPDATE_COMPL,
291262306a36Sopenharmony_ci				(le16_to_cpu(pkt->u.comp_sts) << 16) | QL_VND_SA_STAT_FAILED,
291362306a36Sopenharmony_ci				QL_VND_RX_SA_KEY, sp->fcport);
291462306a36Sopenharmony_ci	}
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci	/* for delete, release sa_ctl, sa_index */
291762306a36Sopenharmony_ci	if (pkt->flags & SA_FLAG_INVALIDATE) {
291862306a36Sopenharmony_ci		/* release the sa_ctl */
291962306a36Sopenharmony_ci		sa_ctl = qla_edif_find_sa_ctl_by_index(sp->fcport,
292062306a36Sopenharmony_ci		    le16_to_cpu(pkt->sa_index), (pkt->flags & SA_FLAG_TX));
292162306a36Sopenharmony_ci		if (sa_ctl &&
292262306a36Sopenharmony_ci		    qla_edif_find_sa_ctl_by_index(sp->fcport, sa_ctl->index,
292362306a36Sopenharmony_ci			(pkt->flags & SA_FLAG_TX)) != NULL) {
292462306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif + ql_dbg_verbose, vha, 0x3063,
292562306a36Sopenharmony_ci			    "%s: freeing sa_ctl for index %d\n",
292662306a36Sopenharmony_ci			    __func__, sa_ctl->index);
292762306a36Sopenharmony_ci			qla_edif_free_sa_ctl(sp->fcport, sa_ctl, sa_ctl->index);
292862306a36Sopenharmony_ci		} else {
292962306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x3063,
293062306a36Sopenharmony_ci			    "%s: sa_ctl NOT freed, sa_ctl: %p\n",
293162306a36Sopenharmony_ci			    __func__, sa_ctl);
293262306a36Sopenharmony_ci		}
293362306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
293462306a36Sopenharmony_ci		    "%s: freeing sa_index %d, nph: 0x%x\n",
293562306a36Sopenharmony_ci		    __func__, le16_to_cpu(pkt->sa_index), nport_handle);
293662306a36Sopenharmony_ci		qla_edif_sadb_delete_sa_index(sp->fcport, nport_handle,
293762306a36Sopenharmony_ci		    le16_to_cpu(pkt->sa_index));
293862306a36Sopenharmony_ci	/*
293962306a36Sopenharmony_ci	 * check for a failed sa_update and remove
294062306a36Sopenharmony_ci	 * the sadb entry.
294162306a36Sopenharmony_ci	 */
294262306a36Sopenharmony_ci	} else if (pkt->u.comp_sts) {
294362306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
294462306a36Sopenharmony_ci		    "%s: freeing sa_index %d, nph: 0x%x\n",
294562306a36Sopenharmony_ci		    __func__, pkt->sa_index, nport_handle);
294662306a36Sopenharmony_ci		qla_edif_sadb_delete_sa_index(sp->fcport, nport_handle,
294762306a36Sopenharmony_ci		    le16_to_cpu(pkt->sa_index));
294862306a36Sopenharmony_ci		switch (le16_to_cpu(pkt->u.comp_sts)) {
294962306a36Sopenharmony_ci		case CS_PORT_EDIF_UNAVAIL:
295062306a36Sopenharmony_ci		case CS_PORT_EDIF_LOGOUT:
295162306a36Sopenharmony_ci			qlt_schedule_sess_for_deletion(sp->fcport);
295262306a36Sopenharmony_ci			break;
295362306a36Sopenharmony_ci		default:
295462306a36Sopenharmony_ci			break;
295562306a36Sopenharmony_ci		}
295662306a36Sopenharmony_ci	}
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_ci	sp->done(sp, 0);
295962306a36Sopenharmony_ci}
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci/**
296262306a36Sopenharmony_ci * qla28xx_start_scsi_edif() - Send a SCSI type 6 command to the ISP
296362306a36Sopenharmony_ci * @sp: command to send to the ISP
296462306a36Sopenharmony_ci *
296562306a36Sopenharmony_ci * Return: non-zero if a failure occurred, else zero.
296662306a36Sopenharmony_ci */
296762306a36Sopenharmony_ciint
296862306a36Sopenharmony_ciqla28xx_start_scsi_edif(srb_t *sp)
296962306a36Sopenharmony_ci{
297062306a36Sopenharmony_ci	int             nseg;
297162306a36Sopenharmony_ci	unsigned long   flags;
297262306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
297362306a36Sopenharmony_ci	uint32_t        *clr_ptr;
297462306a36Sopenharmony_ci	uint32_t        index, i;
297562306a36Sopenharmony_ci	uint32_t        handle;
297662306a36Sopenharmony_ci	uint16_t        cnt;
297762306a36Sopenharmony_ci	int16_t        req_cnt;
297862306a36Sopenharmony_ci	uint16_t        tot_dsds;
297962306a36Sopenharmony_ci	__be32 *fcp_dl;
298062306a36Sopenharmony_ci	uint8_t additional_cdb_len;
298162306a36Sopenharmony_ci	struct ct6_dsd *ctx;
298262306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
298362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
298462306a36Sopenharmony_ci	struct cmd_type_6 *cmd_pkt;
298562306a36Sopenharmony_ci	struct dsd64	*cur_dsd;
298662306a36Sopenharmony_ci	uint8_t		avail_dsds = 0;
298762306a36Sopenharmony_ci	struct scatterlist *sg;
298862306a36Sopenharmony_ci	struct req_que *req = sp->qpair->req;
298962306a36Sopenharmony_ci	spinlock_t *lock = sp->qpair->qp_lock_ptr;
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci	/* Setup device pointers. */
299262306a36Sopenharmony_ci	cmd = GET_CMD_SP(sp);
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ci	/* So we know we haven't pci_map'ed anything yet */
299562306a36Sopenharmony_ci	tot_dsds = 0;
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci	/* Send marker if required */
299862306a36Sopenharmony_ci	if (vha->marker_needed != 0) {
299962306a36Sopenharmony_ci		if (qla2x00_marker(vha, sp->qpair, 0, 0, MK_SYNC_ALL) !=
300062306a36Sopenharmony_ci			QLA_SUCCESS) {
300162306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x300c,
300262306a36Sopenharmony_ci			    "qla2x00_marker failed for cmd=%p.\n", cmd);
300362306a36Sopenharmony_ci			return QLA_FUNCTION_FAILED;
300462306a36Sopenharmony_ci		}
300562306a36Sopenharmony_ci		vha->marker_needed = 0;
300662306a36Sopenharmony_ci	}
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci	/* Acquire ring specific lock */
300962306a36Sopenharmony_ci	spin_lock_irqsave(lock, flags);
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci	/* Check for room in outstanding command list. */
301262306a36Sopenharmony_ci	handle = req->current_outstanding_cmd;
301362306a36Sopenharmony_ci	for (index = 1; index < req->num_outstanding_cmds; index++) {
301462306a36Sopenharmony_ci		handle++;
301562306a36Sopenharmony_ci		if (handle == req->num_outstanding_cmds)
301662306a36Sopenharmony_ci			handle = 1;
301762306a36Sopenharmony_ci		if (!req->outstanding_cmds[handle])
301862306a36Sopenharmony_ci			break;
301962306a36Sopenharmony_ci	}
302062306a36Sopenharmony_ci	if (index == req->num_outstanding_cmds)
302162306a36Sopenharmony_ci		goto queuing_error;
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci	/* Map the sg table so we have an accurate count of sg entries needed */
302462306a36Sopenharmony_ci	if (scsi_sg_count(cmd)) {
302562306a36Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
302662306a36Sopenharmony_ci		    scsi_sg_count(cmd), cmd->sc_data_direction);
302762306a36Sopenharmony_ci		if (unlikely(!nseg))
302862306a36Sopenharmony_ci			goto queuing_error;
302962306a36Sopenharmony_ci	} else {
303062306a36Sopenharmony_ci		nseg = 0;
303162306a36Sopenharmony_ci	}
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci	tot_dsds = nseg;
303462306a36Sopenharmony_ci	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
303762306a36Sopenharmony_ci	sp->iores.exch_cnt = 1;
303862306a36Sopenharmony_ci	sp->iores.iocb_cnt = req_cnt;
303962306a36Sopenharmony_ci	if (qla_get_fw_resources(sp->qpair, &sp->iores))
304062306a36Sopenharmony_ci		goto queuing_error;
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	if (req->cnt < (req_cnt + 2)) {
304362306a36Sopenharmony_ci		cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
304462306a36Sopenharmony_ci		    rd_reg_dword(req->req_q_out);
304562306a36Sopenharmony_ci		if (req->ring_index < cnt)
304662306a36Sopenharmony_ci			req->cnt = cnt - req->ring_index;
304762306a36Sopenharmony_ci		else
304862306a36Sopenharmony_ci			req->cnt = req->length -
304962306a36Sopenharmony_ci			    (req->ring_index - cnt);
305062306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2))
305162306a36Sopenharmony_ci			goto queuing_error;
305262306a36Sopenharmony_ci	}
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci	if (qla_get_buf(vha, sp->qpair, &sp->u.scmd.buf_dsc)) {
305562306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x3011,
305662306a36Sopenharmony_ci		    "Failed to allocate buf for fcp_cmnd for cmd=%p.\n", cmd);
305762306a36Sopenharmony_ci		goto queuing_error;
305862306a36Sopenharmony_ci	}
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_ci	sp->flags |= SRB_GOT_BUF;
306162306a36Sopenharmony_ci	ctx = &sp->u.scmd.ct6_ctx;
306262306a36Sopenharmony_ci	ctx->fcp_cmnd = sp->u.scmd.buf_dsc.buf;
306362306a36Sopenharmony_ci	ctx->fcp_cmnd_dma = sp->u.scmd.buf_dsc.buf_dma;
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	if (cmd->cmd_len > 16) {
306662306a36Sopenharmony_ci		additional_cdb_len = cmd->cmd_len - 16;
306762306a36Sopenharmony_ci		if ((cmd->cmd_len % 4) != 0) {
306862306a36Sopenharmony_ci			/*
306962306a36Sopenharmony_ci			 * SCSI command bigger than 16 bytes must be
307062306a36Sopenharmony_ci			 * multiple of 4
307162306a36Sopenharmony_ci			 */
307262306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x3012,
307362306a36Sopenharmony_ci			    "scsi cmd len %d not multiple of 4 for cmd=%p.\n",
307462306a36Sopenharmony_ci			    cmd->cmd_len, cmd);
307562306a36Sopenharmony_ci			goto queuing_error_fcp_cmnd;
307662306a36Sopenharmony_ci		}
307762306a36Sopenharmony_ci		ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4;
307862306a36Sopenharmony_ci	} else {
307962306a36Sopenharmony_ci		additional_cdb_len = 0;
308062306a36Sopenharmony_ci		ctx->fcp_cmnd_len = 12 + 16 + 4;
308162306a36Sopenharmony_ci	}
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_ci	cmd_pkt = (struct cmd_type_6 *)req->ring_ptr;
308462306a36Sopenharmony_ci	cmd_pkt->handle = make_handle(req->id, handle);
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ci	/*
308762306a36Sopenharmony_ci	 * Zero out remaining portion of packet.
308862306a36Sopenharmony_ci	 * tagged queuing modifier -- default is TSK_SIMPLE (0).
308962306a36Sopenharmony_ci	 */
309062306a36Sopenharmony_ci	clr_ptr = (uint32_t *)cmd_pkt + 2;
309162306a36Sopenharmony_ci	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
309262306a36Sopenharmony_ci	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci	/* No data transfer */
309562306a36Sopenharmony_ci	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
309662306a36Sopenharmony_ci		cmd_pkt->byte_count = cpu_to_le32(0);
309762306a36Sopenharmony_ci		goto no_dsds;
309862306a36Sopenharmony_ci	}
309962306a36Sopenharmony_ci
310062306a36Sopenharmony_ci	/* Set transfer direction */
310162306a36Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
310262306a36Sopenharmony_ci		cmd_pkt->control_flags = cpu_to_le16(CF_WRITE_DATA);
310362306a36Sopenharmony_ci		vha->qla_stats.output_bytes += scsi_bufflen(cmd);
310462306a36Sopenharmony_ci		vha->qla_stats.output_requests++;
310562306a36Sopenharmony_ci		sp->fcport->edif.tx_bytes += scsi_bufflen(cmd);
310662306a36Sopenharmony_ci	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
310762306a36Sopenharmony_ci		cmd_pkt->control_flags = cpu_to_le16(CF_READ_DATA);
310862306a36Sopenharmony_ci		vha->qla_stats.input_bytes += scsi_bufflen(cmd);
310962306a36Sopenharmony_ci		vha->qla_stats.input_requests++;
311062306a36Sopenharmony_ci		sp->fcport->edif.rx_bytes += scsi_bufflen(cmd);
311162306a36Sopenharmony_ci	}
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	cmd_pkt->control_flags |= cpu_to_le16(CF_EN_EDIF);
311462306a36Sopenharmony_ci	cmd_pkt->control_flags &= ~(cpu_to_le16(CF_NEW_SA));
311562306a36Sopenharmony_ci
311662306a36Sopenharmony_ci	/* One DSD is available in the Command Type 6 IOCB */
311762306a36Sopenharmony_ci	avail_dsds = 1;
311862306a36Sopenharmony_ci	cur_dsd = &cmd_pkt->fcp_dsd;
311962306a36Sopenharmony_ci
312062306a36Sopenharmony_ci	/* Load data segments */
312162306a36Sopenharmony_ci	scsi_for_each_sg(cmd, sg, tot_dsds, i) {
312262306a36Sopenharmony_ci		dma_addr_t      sle_dma;
312362306a36Sopenharmony_ci		cont_a64_entry_t *cont_pkt;
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci		/* Allocate additional continuation packets? */
312662306a36Sopenharmony_ci		if (avail_dsds == 0) {
312762306a36Sopenharmony_ci			/*
312862306a36Sopenharmony_ci			 * Five DSDs are available in the Continuation
312962306a36Sopenharmony_ci			 * Type 1 IOCB.
313062306a36Sopenharmony_ci			 */
313162306a36Sopenharmony_ci			cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req);
313262306a36Sopenharmony_ci			cur_dsd = cont_pkt->dsd;
313362306a36Sopenharmony_ci			avail_dsds = 5;
313462306a36Sopenharmony_ci		}
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci		sle_dma = sg_dma_address(sg);
313762306a36Sopenharmony_ci		put_unaligned_le64(sle_dma, &cur_dsd->address);
313862306a36Sopenharmony_ci		cur_dsd->length = cpu_to_le32(sg_dma_len(sg));
313962306a36Sopenharmony_ci		cur_dsd++;
314062306a36Sopenharmony_ci		avail_dsds--;
314162306a36Sopenharmony_ci	}
314262306a36Sopenharmony_ci
314362306a36Sopenharmony_cino_dsds:
314462306a36Sopenharmony_ci	/* Set NPORT-ID and LUN number*/
314562306a36Sopenharmony_ci	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
314662306a36Sopenharmony_ci	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
314762306a36Sopenharmony_ci	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
314862306a36Sopenharmony_ci	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
314962306a36Sopenharmony_ci	cmd_pkt->vp_index = sp->vha->vp_idx;
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_ci	cmd_pkt->entry_type = COMMAND_TYPE_6;
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci	/* Set total data segment count. */
315462306a36Sopenharmony_ci	cmd_pkt->entry_count = (uint8_t)req_cnt;
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
315762306a36Sopenharmony_ci	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci	/* build FCP_CMND IU */
316062306a36Sopenharmony_ci	int_to_scsilun(cmd->device->lun, &ctx->fcp_cmnd->lun);
316162306a36Sopenharmony_ci	ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE)
316462306a36Sopenharmony_ci		ctx->fcp_cmnd->additional_cdb_len |= 1;
316562306a36Sopenharmony_ci	else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
316662306a36Sopenharmony_ci		ctx->fcp_cmnd->additional_cdb_len |= 2;
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	/* Populate the FCP_PRIO. */
316962306a36Sopenharmony_ci	if (ha->flags.fcp_prio_enabled)
317062306a36Sopenharmony_ci		ctx->fcp_cmnd->task_attribute |=
317162306a36Sopenharmony_ci		    sp->fcport->fcp_prio << 3;
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_ci	memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	fcp_dl = (__be32 *)(ctx->fcp_cmnd->cdb + 16 +
317662306a36Sopenharmony_ci	    additional_cdb_len);
317762306a36Sopenharmony_ci	*fcp_dl = htonl((uint32_t)scsi_bufflen(cmd));
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci	cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len);
318062306a36Sopenharmony_ci	put_unaligned_le64(ctx->fcp_cmnd_dma, &cmd_pkt->fcp_cmnd_dseg_address);
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
318362306a36Sopenharmony_ci	/* Set total data segment count. */
318462306a36Sopenharmony_ci	cmd_pkt->entry_count = (uint8_t)req_cnt;
318562306a36Sopenharmony_ci	cmd_pkt->entry_status = 0;
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci	/* Build command packet. */
318862306a36Sopenharmony_ci	req->current_outstanding_cmd = handle;
318962306a36Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
319062306a36Sopenharmony_ci	sp->handle = handle;
319162306a36Sopenharmony_ci	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
319262306a36Sopenharmony_ci	req->cnt -= req_cnt;
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	/* Adjust ring index. */
319562306a36Sopenharmony_ci	wmb();
319662306a36Sopenharmony_ci	req->ring_index++;
319762306a36Sopenharmony_ci	if (req->ring_index == req->length) {
319862306a36Sopenharmony_ci		req->ring_index = 0;
319962306a36Sopenharmony_ci		req->ring_ptr = req->ring;
320062306a36Sopenharmony_ci	} else {
320162306a36Sopenharmony_ci		req->ring_ptr++;
320262306a36Sopenharmony_ci	}
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci	sp->qpair->cmd_cnt++;
320562306a36Sopenharmony_ci	/* Set chip new ring index. */
320662306a36Sopenharmony_ci	wrt_reg_dword(req->req_q_in, req->ring_index);
320762306a36Sopenharmony_ci
320862306a36Sopenharmony_ci	spin_unlock_irqrestore(lock, flags);
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	return QLA_SUCCESS;
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ciqueuing_error_fcp_cmnd:
321362306a36Sopenharmony_ciqueuing_error:
321462306a36Sopenharmony_ci	if (tot_dsds)
321562306a36Sopenharmony_ci		scsi_dma_unmap(cmd);
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	qla_put_buf(sp->qpair, &sp->u.scmd.buf_dsc);
321862306a36Sopenharmony_ci	qla_put_fw_resources(sp->qpair, &sp->iores);
321962306a36Sopenharmony_ci	spin_unlock_irqrestore(lock, flags);
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
322262306a36Sopenharmony_ci}
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci/**********************************************
322562306a36Sopenharmony_ci * edif update/delete sa_index list functions *
322662306a36Sopenharmony_ci **********************************************/
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci/* clear the edif_indx_list for this port */
322962306a36Sopenharmony_civoid qla_edif_list_del(fc_port_t *fcport)
323062306a36Sopenharmony_ci{
323162306a36Sopenharmony_ci	struct edif_list_entry *indx_lst;
323262306a36Sopenharmony_ci	struct edif_list_entry *tindx_lst;
323362306a36Sopenharmony_ci	struct list_head *indx_list = &fcport->edif.edif_indx_list;
323462306a36Sopenharmony_ci	unsigned long flags = 0;
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci	spin_lock_irqsave(&fcport->edif.indx_list_lock, flags);
323762306a36Sopenharmony_ci	list_for_each_entry_safe(indx_lst, tindx_lst, indx_list, next) {
323862306a36Sopenharmony_ci		list_del(&indx_lst->next);
323962306a36Sopenharmony_ci		kfree(indx_lst);
324062306a36Sopenharmony_ci	}
324162306a36Sopenharmony_ci	spin_unlock_irqrestore(&fcport->edif.indx_list_lock, flags);
324262306a36Sopenharmony_ci}
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci/******************
324562306a36Sopenharmony_ci * SADB functions *
324662306a36Sopenharmony_ci ******************/
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci/* allocate/retrieve an sa_index for a given spi */
324962306a36Sopenharmony_cistatic uint16_t qla_edif_sadb_get_sa_index(fc_port_t *fcport,
325062306a36Sopenharmony_ci		struct qla_sa_update_frame *sa_frame)
325162306a36Sopenharmony_ci{
325262306a36Sopenharmony_ci	struct edif_sa_index_entry *entry;
325362306a36Sopenharmony_ci	struct list_head *sa_list;
325462306a36Sopenharmony_ci	uint16_t sa_index;
325562306a36Sopenharmony_ci	int dir = sa_frame->flags & SAU_FLG_TX;
325662306a36Sopenharmony_ci	int slot = 0;
325762306a36Sopenharmony_ci	int free_slot = -1;
325862306a36Sopenharmony_ci	scsi_qla_host_t *vha = fcport->vha;
325962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
326062306a36Sopenharmony_ci	unsigned long flags = 0;
326162306a36Sopenharmony_ci	uint16_t nport_handle = fcport->loop_id;
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x3063,
326462306a36Sopenharmony_ci	    "%s: entry  fc_port: %p, nport_handle: 0x%x\n",
326562306a36Sopenharmony_ci	    __func__, fcport, nport_handle);
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	if (dir)
326862306a36Sopenharmony_ci		sa_list = &ha->sadb_tx_index_list;
326962306a36Sopenharmony_ci	else
327062306a36Sopenharmony_ci		sa_list = &ha->sadb_rx_index_list;
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci	entry = qla_edif_sadb_find_sa_index_entry(nport_handle, sa_list);
327362306a36Sopenharmony_ci	if (!entry) {
327462306a36Sopenharmony_ci		if ((sa_frame->flags & (SAU_FLG_TX | SAU_FLG_INV)) == SAU_FLG_INV) {
327562306a36Sopenharmony_ci			ql_dbg(ql_dbg_edif, vha, 0x3063,
327662306a36Sopenharmony_ci			    "%s: rx delete request with no entry\n", __func__);
327762306a36Sopenharmony_ci			return RX_DELETE_NO_EDIF_SA_INDEX;
327862306a36Sopenharmony_ci		}
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci		/* if there is no entry for this nport, add one */
328162306a36Sopenharmony_ci		entry = kzalloc((sizeof(struct edif_sa_index_entry)), GFP_ATOMIC);
328262306a36Sopenharmony_ci		if (!entry)
328362306a36Sopenharmony_ci			return INVALID_EDIF_SA_INDEX;
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_ci		sa_index = qla_edif_get_sa_index_from_freepool(fcport, dir);
328662306a36Sopenharmony_ci		if (sa_index == INVALID_EDIF_SA_INDEX) {
328762306a36Sopenharmony_ci			kfree(entry);
328862306a36Sopenharmony_ci			return INVALID_EDIF_SA_INDEX;
328962306a36Sopenharmony_ci		}
329062306a36Sopenharmony_ci
329162306a36Sopenharmony_ci		INIT_LIST_HEAD(&entry->next);
329262306a36Sopenharmony_ci		entry->handle = nport_handle;
329362306a36Sopenharmony_ci		entry->fcport = fcport;
329462306a36Sopenharmony_ci		entry->sa_pair[0].spi = sa_frame->spi;
329562306a36Sopenharmony_ci		entry->sa_pair[0].sa_index = sa_index;
329662306a36Sopenharmony_ci		entry->sa_pair[1].spi = 0;
329762306a36Sopenharmony_ci		entry->sa_pair[1].sa_index = INVALID_EDIF_SA_INDEX;
329862306a36Sopenharmony_ci		spin_lock_irqsave(&ha->sadb_lock, flags);
329962306a36Sopenharmony_ci		list_add_tail(&entry->next, sa_list);
330062306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->sadb_lock, flags);
330162306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
330262306a36Sopenharmony_ci		    "%s: Created new sadb entry for nport_handle 0x%x, spi 0x%x, returning sa_index %d\n",
330362306a36Sopenharmony_ci		    __func__, nport_handle, sa_frame->spi, sa_index);
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci		return sa_index;
330662306a36Sopenharmony_ci	}
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	spin_lock_irqsave(&ha->sadb_lock, flags);
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_ci	/* see if we already have an entry for this spi */
331162306a36Sopenharmony_ci	for (slot = 0; slot < 2; slot++) {
331262306a36Sopenharmony_ci		if (entry->sa_pair[slot].sa_index == INVALID_EDIF_SA_INDEX) {
331362306a36Sopenharmony_ci			free_slot = slot;
331462306a36Sopenharmony_ci		} else {
331562306a36Sopenharmony_ci			if (entry->sa_pair[slot].spi == sa_frame->spi) {
331662306a36Sopenharmony_ci				spin_unlock_irqrestore(&ha->sadb_lock, flags);
331762306a36Sopenharmony_ci				ql_dbg(ql_dbg_edif, vha, 0x3063,
331862306a36Sopenharmony_ci				    "%s: sadb slot %d entry for lid 0x%x, spi 0x%x found, sa_index %d\n",
331962306a36Sopenharmony_ci				    __func__, slot, entry->handle, sa_frame->spi,
332062306a36Sopenharmony_ci				    entry->sa_pair[slot].sa_index);
332162306a36Sopenharmony_ci				return entry->sa_pair[slot].sa_index;
332262306a36Sopenharmony_ci			}
332362306a36Sopenharmony_ci		}
332462306a36Sopenharmony_ci	}
332562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->sadb_lock, flags);
332662306a36Sopenharmony_ci
332762306a36Sopenharmony_ci	/* both slots are used */
332862306a36Sopenharmony_ci	if (free_slot == -1) {
332962306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
333062306a36Sopenharmony_ci		    "%s: WARNING: No free slots in sadb for nport_handle 0x%x, spi: 0x%x\n",
333162306a36Sopenharmony_ci		    __func__, entry->handle, sa_frame->spi);
333262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
333362306a36Sopenharmony_ci		    "%s: Slot 0  spi: 0x%x  sa_index: %d,  Slot 1  spi: 0x%x  sa_index: %d\n",
333462306a36Sopenharmony_ci		    __func__, entry->sa_pair[0].spi, entry->sa_pair[0].sa_index,
333562306a36Sopenharmony_ci		    entry->sa_pair[1].spi, entry->sa_pair[1].sa_index);
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci		return INVALID_EDIF_SA_INDEX;
333862306a36Sopenharmony_ci	}
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_ci	/* there is at least one free slot, use it */
334162306a36Sopenharmony_ci	sa_index = qla_edif_get_sa_index_from_freepool(fcport, dir);
334262306a36Sopenharmony_ci	if (sa_index == INVALID_EDIF_SA_INDEX) {
334362306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, fcport->vha, 0x3063,
334462306a36Sopenharmony_ci		    "%s: empty freepool!!\n", __func__);
334562306a36Sopenharmony_ci		return INVALID_EDIF_SA_INDEX;
334662306a36Sopenharmony_ci	}
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci	spin_lock_irqsave(&ha->sadb_lock, flags);
334962306a36Sopenharmony_ci	entry->sa_pair[free_slot].spi = sa_frame->spi;
335062306a36Sopenharmony_ci	entry->sa_pair[free_slot].sa_index = sa_index;
335162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->sadb_lock, flags);
335262306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, fcport->vha, 0x3063,
335362306a36Sopenharmony_ci	    "%s: sadb slot %d entry for nport_handle 0x%x, spi 0x%x added, returning sa_index %d\n",
335462306a36Sopenharmony_ci	    __func__, free_slot, entry->handle, sa_frame->spi, sa_index);
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_ci	return sa_index;
335762306a36Sopenharmony_ci}
335862306a36Sopenharmony_ci
335962306a36Sopenharmony_ci/* release any sadb entries -- only done at teardown */
336062306a36Sopenharmony_civoid qla_edif_sadb_release(struct qla_hw_data *ha)
336162306a36Sopenharmony_ci{
336262306a36Sopenharmony_ci	struct edif_sa_index_entry *entry, *tmp;
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	list_for_each_entry_safe(entry, tmp, &ha->sadb_rx_index_list, next) {
336562306a36Sopenharmony_ci		list_del(&entry->next);
336662306a36Sopenharmony_ci		kfree(entry);
336762306a36Sopenharmony_ci	}
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_ci	list_for_each_entry_safe(entry, tmp, &ha->sadb_tx_index_list, next) {
337062306a36Sopenharmony_ci		list_del(&entry->next);
337162306a36Sopenharmony_ci		kfree(entry);
337262306a36Sopenharmony_ci	}
337362306a36Sopenharmony_ci}
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci/**************************
337662306a36Sopenharmony_ci * sadb freepool functions
337762306a36Sopenharmony_ci **************************/
337862306a36Sopenharmony_ci
337962306a36Sopenharmony_ci/* build the rx and tx sa_index free pools -- only done at fcport init */
338062306a36Sopenharmony_ciint qla_edif_sadb_build_free_pool(struct qla_hw_data *ha)
338162306a36Sopenharmony_ci{
338262306a36Sopenharmony_ci	ha->edif_tx_sa_id_map =
338362306a36Sopenharmony_ci	    kcalloc(BITS_TO_LONGS(EDIF_NUM_SA_INDEX), sizeof(long), GFP_KERNEL);
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	if (!ha->edif_tx_sa_id_map) {
338662306a36Sopenharmony_ci		ql_log_pci(ql_log_fatal, ha->pdev, 0x0009,
338762306a36Sopenharmony_ci		    "Unable to allocate memory for sadb tx.\n");
338862306a36Sopenharmony_ci		return -ENOMEM;
338962306a36Sopenharmony_ci	}
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_ci	ha->edif_rx_sa_id_map =
339262306a36Sopenharmony_ci	    kcalloc(BITS_TO_LONGS(EDIF_NUM_SA_INDEX), sizeof(long), GFP_KERNEL);
339362306a36Sopenharmony_ci	if (!ha->edif_rx_sa_id_map) {
339462306a36Sopenharmony_ci		kfree(ha->edif_tx_sa_id_map);
339562306a36Sopenharmony_ci		ha->edif_tx_sa_id_map = NULL;
339662306a36Sopenharmony_ci		ql_log_pci(ql_log_fatal, ha->pdev, 0x0009,
339762306a36Sopenharmony_ci		    "Unable to allocate memory for sadb rx.\n");
339862306a36Sopenharmony_ci		return -ENOMEM;
339962306a36Sopenharmony_ci	}
340062306a36Sopenharmony_ci	return 0;
340162306a36Sopenharmony_ci}
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci/* release the free pool - only done during fcport teardown */
340462306a36Sopenharmony_civoid qla_edif_sadb_release_free_pool(struct qla_hw_data *ha)
340562306a36Sopenharmony_ci{
340662306a36Sopenharmony_ci	kfree(ha->edif_tx_sa_id_map);
340762306a36Sopenharmony_ci	ha->edif_tx_sa_id_map = NULL;
340862306a36Sopenharmony_ci	kfree(ha->edif_rx_sa_id_map);
340962306a36Sopenharmony_ci	ha->edif_rx_sa_id_map = NULL;
341062306a36Sopenharmony_ci}
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_cistatic void __chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
341362306a36Sopenharmony_ci		fc_port_t *fcport, uint32_t handle, uint16_t sa_index)
341462306a36Sopenharmony_ci{
341562306a36Sopenharmony_ci	struct edif_list_entry *edif_entry;
341662306a36Sopenharmony_ci	struct edif_sa_ctl *sa_ctl;
341762306a36Sopenharmony_ci	uint16_t delete_sa_index = INVALID_EDIF_SA_INDEX;
341862306a36Sopenharmony_ci	unsigned long flags = 0;
341962306a36Sopenharmony_ci	uint16_t nport_handle = fcport->loop_id;
342062306a36Sopenharmony_ci	uint16_t cached_nport_handle;
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_ci	spin_lock_irqsave(&fcport->edif.indx_list_lock, flags);
342362306a36Sopenharmony_ci	edif_entry = qla_edif_list_find_sa_index(fcport, nport_handle);
342462306a36Sopenharmony_ci	if (!edif_entry) {
342562306a36Sopenharmony_ci		spin_unlock_irqrestore(&fcport->edif.indx_list_lock, flags);
342662306a36Sopenharmony_ci		return;		/* no pending delete for this handle */
342762306a36Sopenharmony_ci	}
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	/*
343062306a36Sopenharmony_ci	 * check for no pending delete for this index or iocb does not
343162306a36Sopenharmony_ci	 * match rx sa_index
343262306a36Sopenharmony_ci	 */
343362306a36Sopenharmony_ci	if (edif_entry->delete_sa_index == INVALID_EDIF_SA_INDEX ||
343462306a36Sopenharmony_ci	    edif_entry->update_sa_index != sa_index) {
343562306a36Sopenharmony_ci		spin_unlock_irqrestore(&fcport->edif.indx_list_lock, flags);
343662306a36Sopenharmony_ci		return;
343762306a36Sopenharmony_ci	}
343862306a36Sopenharmony_ci
343962306a36Sopenharmony_ci	/*
344062306a36Sopenharmony_ci	 * wait until we have seen at least EDIF_DELAY_COUNT transfers before
344162306a36Sopenharmony_ci	 * queueing RX delete
344262306a36Sopenharmony_ci	 */
344362306a36Sopenharmony_ci	if (edif_entry->count++ < EDIF_RX_DELETE_FILTER_COUNT) {
344462306a36Sopenharmony_ci		spin_unlock_irqrestore(&fcport->edif.indx_list_lock, flags);
344562306a36Sopenharmony_ci		return;
344662306a36Sopenharmony_ci	}
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_ci	ql_dbg(ql_dbg_edif, vha, 0x5033,
344962306a36Sopenharmony_ci	    "%s: invalidating delete_sa_index,  update_sa_index: 0x%x sa_index: 0x%x, delete_sa_index: 0x%x\n",
345062306a36Sopenharmony_ci	    __func__, edif_entry->update_sa_index, sa_index, edif_entry->delete_sa_index);
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci	delete_sa_index = edif_entry->delete_sa_index;
345362306a36Sopenharmony_ci	edif_entry->delete_sa_index = INVALID_EDIF_SA_INDEX;
345462306a36Sopenharmony_ci	cached_nport_handle = edif_entry->handle;
345562306a36Sopenharmony_ci	spin_unlock_irqrestore(&fcport->edif.indx_list_lock, flags);
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci	/* sanity check on the nport handle */
345862306a36Sopenharmony_ci	if (nport_handle != cached_nport_handle) {
345962306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
346062306a36Sopenharmony_ci		    "%s: POST SA DELETE nport_handle mismatch: lid: 0x%x, edif_entry nph: 0x%x\n",
346162306a36Sopenharmony_ci		    __func__, nport_handle, cached_nport_handle);
346262306a36Sopenharmony_ci	}
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci	/* find the sa_ctl for the delete and schedule the delete */
346562306a36Sopenharmony_ci	sa_ctl = qla_edif_find_sa_ctl_by_index(fcport, delete_sa_index, 0);
346662306a36Sopenharmony_ci	if (sa_ctl) {
346762306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
346862306a36Sopenharmony_ci		    "%s: POST SA DELETE sa_ctl: %p, index recvd %d\n",
346962306a36Sopenharmony_ci		    __func__, sa_ctl, sa_index);
347062306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
347162306a36Sopenharmony_ci		    "delete index %d, update index: %d, nport handle: 0x%x, handle: 0x%x\n",
347262306a36Sopenharmony_ci		    delete_sa_index,
347362306a36Sopenharmony_ci		    edif_entry->update_sa_index, nport_handle, handle);
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_ci		sa_ctl->flags = EDIF_SA_CTL_FLG_DEL;
347662306a36Sopenharmony_ci		set_bit(EDIF_SA_CTL_REPL, &sa_ctl->state);
347762306a36Sopenharmony_ci		qla_post_sa_replace_work(fcport->vha, fcport,
347862306a36Sopenharmony_ci		    nport_handle, sa_ctl);
347962306a36Sopenharmony_ci	} else {
348062306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x3063,
348162306a36Sopenharmony_ci		    "%s: POST SA DELETE sa_ctl not found for delete_sa_index: %d\n",
348262306a36Sopenharmony_ci		    __func__, delete_sa_index);
348362306a36Sopenharmony_ci	}
348462306a36Sopenharmony_ci}
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_civoid qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
348762306a36Sopenharmony_ci		srb_t *sp, struct sts_entry_24xx *sts24)
348862306a36Sopenharmony_ci{
348962306a36Sopenharmony_ci	fc_port_t *fcport = sp->fcport;
349062306a36Sopenharmony_ci	/* sa_index used by this iocb */
349162306a36Sopenharmony_ci	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
349262306a36Sopenharmony_ci	uint32_t handle;
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci	handle = (uint32_t)LSW(sts24->handle);
349562306a36Sopenharmony_ci
349662306a36Sopenharmony_ci	/* find out if this status iosb is for a scsi read */
349762306a36Sopenharmony_ci	if (cmd->sc_data_direction != DMA_FROM_DEVICE)
349862306a36Sopenharmony_ci		return;
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci	return __chk_edif_rx_sa_delete_pending(vha, fcport, handle,
350162306a36Sopenharmony_ci	   le16_to_cpu(sts24->edif_sa_index));
350262306a36Sopenharmony_ci}
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_civoid qlt_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha, fc_port_t *fcport,
350562306a36Sopenharmony_ci		struct ctio7_from_24xx *pkt)
350662306a36Sopenharmony_ci{
350762306a36Sopenharmony_ci	__chk_edif_rx_sa_delete_pending(vha, fcport,
350862306a36Sopenharmony_ci	    pkt->handle, le16_to_cpu(pkt->edif_sa_index));
350962306a36Sopenharmony_ci}
351062306a36Sopenharmony_ci
351162306a36Sopenharmony_cistatic void qla_parse_auth_els_ctl(struct srb *sp)
351262306a36Sopenharmony_ci{
351362306a36Sopenharmony_ci	struct qla_els_pt_arg *a = &sp->u.bsg_cmd.u.els_arg;
351462306a36Sopenharmony_ci	struct bsg_job *bsg_job = sp->u.bsg_cmd.bsg_job;
351562306a36Sopenharmony_ci	struct fc_bsg_request *request = bsg_job->request;
351662306a36Sopenharmony_ci	struct qla_bsg_auth_els_request *p =
351762306a36Sopenharmony_ci	    (struct qla_bsg_auth_els_request *)bsg_job->request;
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_ci	a->tx_len = a->tx_byte_count = sp->remap.req.len;
352062306a36Sopenharmony_ci	a->tx_addr = sp->remap.req.dma;
352162306a36Sopenharmony_ci	a->rx_len = a->rx_byte_count = sp->remap.rsp.len;
352262306a36Sopenharmony_ci	a->rx_addr = sp->remap.rsp.dma;
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci	if (p->e.sub_cmd == SEND_ELS_REPLY) {
352562306a36Sopenharmony_ci		a->control_flags = p->e.extra_control_flags << 13;
352662306a36Sopenharmony_ci		a->rx_xchg_address = cpu_to_le32(p->e.extra_rx_xchg_address);
352762306a36Sopenharmony_ci		if (p->e.extra_control_flags == BSG_CTL_FLAG_LS_ACC)
352862306a36Sopenharmony_ci			a->els_opcode = ELS_LS_ACC;
352962306a36Sopenharmony_ci		else if (p->e.extra_control_flags == BSG_CTL_FLAG_LS_RJT)
353062306a36Sopenharmony_ci			a->els_opcode = ELS_LS_RJT;
353162306a36Sopenharmony_ci	}
353262306a36Sopenharmony_ci	a->did = sp->fcport->d_id;
353362306a36Sopenharmony_ci	a->els_opcode =  request->rqst_data.h_els.command_code;
353462306a36Sopenharmony_ci	a->nport_handle = cpu_to_le16(sp->fcport->loop_id);
353562306a36Sopenharmony_ci	a->vp_idx = sp->vha->vp_idx;
353662306a36Sopenharmony_ci}
353762306a36Sopenharmony_ci
353862306a36Sopenharmony_ciint qla_edif_process_els(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
353962306a36Sopenharmony_ci{
354062306a36Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
354162306a36Sopenharmony_ci	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
354262306a36Sopenharmony_ci	fc_port_t *fcport = NULL;
354362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
354462306a36Sopenharmony_ci	srb_t *sp;
354562306a36Sopenharmony_ci	int rval =  (DID_ERROR << 16), cnt;
354662306a36Sopenharmony_ci	port_id_t d_id;
354762306a36Sopenharmony_ci	struct qla_bsg_auth_els_request *p =
354862306a36Sopenharmony_ci	    (struct qla_bsg_auth_els_request *)bsg_job->request;
354962306a36Sopenharmony_ci	struct qla_bsg_auth_els_reply *rpl =
355062306a36Sopenharmony_ci	    (struct qla_bsg_auth_els_reply *)bsg_job->reply;
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_ci	rpl->version = EDIF_VERSION1;
355362306a36Sopenharmony_ci
355462306a36Sopenharmony_ci	d_id.b.al_pa = bsg_request->rqst_data.h_els.port_id[2];
355562306a36Sopenharmony_ci	d_id.b.area = bsg_request->rqst_data.h_els.port_id[1];
355662306a36Sopenharmony_ci	d_id.b.domain = bsg_request->rqst_data.h_els.port_id[0];
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_ci	/* find matching d_id in fcport list */
355962306a36Sopenharmony_ci	fcport = qla2x00_find_fcport_by_pid(vha, &d_id);
356062306a36Sopenharmony_ci	if (!fcport) {
356162306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x911a,
356262306a36Sopenharmony_ci		    "%s fcport not find online portid=%06x.\n",
356362306a36Sopenharmony_ci		    __func__, d_id.b24);
356462306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
356562306a36Sopenharmony_ci		return -EIO;
356662306a36Sopenharmony_ci	}
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_ci	if (qla_bsg_check(vha, bsg_job, fcport))
356962306a36Sopenharmony_ci		return 0;
357062306a36Sopenharmony_ci
357162306a36Sopenharmony_ci	if (EDIF_SESS_DELETE(fcport)) {
357262306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x910d,
357362306a36Sopenharmony_ci		    "%s ELS code %x, no loop id.\n", __func__,
357462306a36Sopenharmony_ci		    bsg_request->rqst_data.r_els.els_code);
357562306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_BAD_TARGET);
357662306a36Sopenharmony_ci		return -ENXIO;
357762306a36Sopenharmony_ci	}
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_ci	if (!vha->flags.online) {
358062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n");
358162306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_BAD_TARGET);
358262306a36Sopenharmony_ci		rval = -EIO;
358362306a36Sopenharmony_ci		goto done;
358462306a36Sopenharmony_ci	}
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_ci	/* pass through is supported only for ISP 4Gb or higher */
358762306a36Sopenharmony_ci	if (!IS_FWI2_CAPABLE(ha)) {
358862306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7001,
358962306a36Sopenharmony_ci		    "ELS passthru not supported for ISP23xx based adapters.\n");
359062306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_BAD_TARGET);
359162306a36Sopenharmony_ci		rval = -EPERM;
359262306a36Sopenharmony_ci		goto done;
359362306a36Sopenharmony_ci	}
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
359662306a36Sopenharmony_ci	if (!sp) {
359762306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7004,
359862306a36Sopenharmony_ci		    "Failed get sp pid=%06x\n", fcport->d_id.b24);
359962306a36Sopenharmony_ci		rval = -ENOMEM;
360062306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_IMM_RETRY);
360162306a36Sopenharmony_ci		goto done;
360262306a36Sopenharmony_ci	}
360362306a36Sopenharmony_ci
360462306a36Sopenharmony_ci	sp->remap.req.len = bsg_job->request_payload.payload_len;
360562306a36Sopenharmony_ci	sp->remap.req.buf = dma_pool_alloc(ha->purex_dma_pool,
360662306a36Sopenharmony_ci	    GFP_KERNEL, &sp->remap.req.dma);
360762306a36Sopenharmony_ci	if (!sp->remap.req.buf) {
360862306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7005,
360962306a36Sopenharmony_ci		    "Failed allocate request dma len=%x\n",
361062306a36Sopenharmony_ci		    bsg_job->request_payload.payload_len);
361162306a36Sopenharmony_ci		rval = -ENOMEM;
361262306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_IMM_RETRY);
361362306a36Sopenharmony_ci		goto done_free_sp;
361462306a36Sopenharmony_ci	}
361562306a36Sopenharmony_ci
361662306a36Sopenharmony_ci	sp->remap.rsp.len = bsg_job->reply_payload.payload_len;
361762306a36Sopenharmony_ci	sp->remap.rsp.buf = dma_pool_alloc(ha->purex_dma_pool,
361862306a36Sopenharmony_ci	    GFP_KERNEL, &sp->remap.rsp.dma);
361962306a36Sopenharmony_ci	if (!sp->remap.rsp.buf) {
362062306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7006,
362162306a36Sopenharmony_ci		    "Failed allocate response dma len=%x\n",
362262306a36Sopenharmony_ci		    bsg_job->reply_payload.payload_len);
362362306a36Sopenharmony_ci		rval = -ENOMEM;
362462306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_IMM_RETRY);
362562306a36Sopenharmony_ci		goto done_free_remap_req;
362662306a36Sopenharmony_ci	}
362762306a36Sopenharmony_ci	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
362862306a36Sopenharmony_ci	    bsg_job->request_payload.sg_cnt, sp->remap.req.buf,
362962306a36Sopenharmony_ci	    sp->remap.req.len);
363062306a36Sopenharmony_ci	sp->remap.remapped = true;
363162306a36Sopenharmony_ci
363262306a36Sopenharmony_ci	sp->type = SRB_ELS_CMD_HST_NOLOGIN;
363362306a36Sopenharmony_ci	sp->name = "SPCN_BSG_HST_NOLOGIN";
363462306a36Sopenharmony_ci	sp->u.bsg_cmd.bsg_job = bsg_job;
363562306a36Sopenharmony_ci	qla_parse_auth_els_ctl(sp);
363662306a36Sopenharmony_ci
363762306a36Sopenharmony_ci	sp->free = qla2x00_bsg_sp_free;
363862306a36Sopenharmony_ci	sp->done = qla2x00_bsg_job_done;
363962306a36Sopenharmony_ci
364062306a36Sopenharmony_ci	cnt = 0;
364162306a36Sopenharmony_ciretry:
364262306a36Sopenharmony_ci	rval = qla2x00_start_sp(sp);
364362306a36Sopenharmony_ci	switch (rval) {
364462306a36Sopenharmony_ci	case QLA_SUCCESS:
364562306a36Sopenharmony_ci		ql_dbg(ql_dbg_edif, vha, 0x700a,
364662306a36Sopenharmony_ci		       "%s %s %8phN xchg %x ctlflag %x hdl %x reqlen %xh bsg ptr %p\n",
364762306a36Sopenharmony_ci		       __func__, sc_to_str(p->e.sub_cmd), fcport->port_name,
364862306a36Sopenharmony_ci		       p->e.extra_rx_xchg_address, p->e.extra_control_flags,
364962306a36Sopenharmony_ci		       sp->handle, sp->remap.req.len, bsg_job);
365062306a36Sopenharmony_ci		break;
365162306a36Sopenharmony_ci	case EAGAIN:
365262306a36Sopenharmony_ci		msleep(EDIF_MSLEEP_INTERVAL);
365362306a36Sopenharmony_ci		cnt++;
365462306a36Sopenharmony_ci		if (cnt < EDIF_RETRY_COUNT)
365562306a36Sopenharmony_ci			goto retry;
365662306a36Sopenharmony_ci		fallthrough;
365762306a36Sopenharmony_ci	default:
365862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x700e,
365962306a36Sopenharmony_ci		    "%s qla2x00_start_sp failed = %d\n", __func__, rval);
366062306a36Sopenharmony_ci		SET_DID_STATUS(bsg_reply->result, DID_IMM_RETRY);
366162306a36Sopenharmony_ci		rval = -EIO;
366262306a36Sopenharmony_ci		goto done_free_remap_rsp;
366362306a36Sopenharmony_ci	}
366462306a36Sopenharmony_ci	return rval;
366562306a36Sopenharmony_ci
366662306a36Sopenharmony_cidone_free_remap_rsp:
366762306a36Sopenharmony_ci	dma_pool_free(ha->purex_dma_pool, sp->remap.rsp.buf,
366862306a36Sopenharmony_ci	    sp->remap.rsp.dma);
366962306a36Sopenharmony_cidone_free_remap_req:
367062306a36Sopenharmony_ci	dma_pool_free(ha->purex_dma_pool, sp->remap.req.buf,
367162306a36Sopenharmony_ci	    sp->remap.req.dma);
367262306a36Sopenharmony_cidone_free_sp:
367362306a36Sopenharmony_ci	qla2x00_rel_sp(sp);
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_cidone:
367662306a36Sopenharmony_ci	return rval;
367762306a36Sopenharmony_ci}
367862306a36Sopenharmony_ci
367962306a36Sopenharmony_civoid qla_edif_sess_down(struct scsi_qla_host *vha, struct fc_port *sess)
368062306a36Sopenharmony_ci{
368162306a36Sopenharmony_ci	u16 cnt = 0;
368262306a36Sopenharmony_ci
368362306a36Sopenharmony_ci	if (sess->edif.app_sess_online && DBELL_ACTIVE(vha)) {
368462306a36Sopenharmony_ci		ql_dbg(ql_dbg_disc, vha, 0xf09c,
368562306a36Sopenharmony_ci			"%s: sess %8phN send port_offline event\n",
368662306a36Sopenharmony_ci			__func__, sess->port_name);
368762306a36Sopenharmony_ci		sess->edif.app_sess_online = 0;
368862306a36Sopenharmony_ci		sess->edif.sess_down_acked = 0;
368962306a36Sopenharmony_ci		qla_edb_eventcreate(vha, VND_CMD_AUTH_STATE_SESSION_SHUTDOWN,
369062306a36Sopenharmony_ci		    sess->d_id.b24, 0, sess);
369162306a36Sopenharmony_ci		qla2x00_post_aen_work(vha, FCH_EVT_PORT_OFFLINE, sess->d_id.b24);
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_ci		while (!READ_ONCE(sess->edif.sess_down_acked) &&
369462306a36Sopenharmony_ci		       !test_bit(VPORT_DELETE, &vha->dpc_flags)) {
369562306a36Sopenharmony_ci			msleep(100);
369662306a36Sopenharmony_ci			cnt++;
369762306a36Sopenharmony_ci			if (cnt > 100)
369862306a36Sopenharmony_ci				break;
369962306a36Sopenharmony_ci		}
370062306a36Sopenharmony_ci		sess->edif.sess_down_acked = 0;
370162306a36Sopenharmony_ci		ql_dbg(ql_dbg_disc, vha, 0xf09c,
370262306a36Sopenharmony_ci		       "%s: sess %8phN port_offline event completed\n",
370362306a36Sopenharmony_ci		       __func__, sess->port_name);
370462306a36Sopenharmony_ci	}
370562306a36Sopenharmony_ci}
370662306a36Sopenharmony_ci
370762306a36Sopenharmony_civoid qla_edif_clear_appdata(struct scsi_qla_host *vha, struct fc_port *fcport)
370862306a36Sopenharmony_ci{
370962306a36Sopenharmony_ci	if (!(fcport->flags & FCF_FCSP_DEVICE))
371062306a36Sopenharmony_ci		return;
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci	qla_edb_clear(vha, fcport->d_id);
371362306a36Sopenharmony_ci	qla_enode_clear(vha, fcport->d_id);
371462306a36Sopenharmony_ci}
3715