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