18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * qla_target.c SCSI LLD infrastructure for QLogic 22xx/23xx/24xx/25xx 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * based on qla2x00t.c code: 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2004 - 2010 Vladislav Bolkhovitin <vst@vlnb.net> 88c2ecf20Sopenharmony_ci * Copyright (C) 2004 - 2005 Leonid Stoljar 98c2ecf20Sopenharmony_ci * Copyright (C) 2006 Nathaniel Clark <nate@misrule.us> 108c2ecf20Sopenharmony_ci * Copyright (C) 2006 - 2010 ID7 Ltd. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Forward port and refactoring to modern qla2xxx and target/configfs 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Copyright (C) 2010-2013 Nicholas A. Bellinger <nab@kernel.org> 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/init.h> 198c2ecf20Sopenharmony_ci#include <linux/types.h> 208c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 218c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 228c2ecf20Sopenharmony_ci#include <linux/pci.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci#include <linux/list.h> 258c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 268c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 278c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 288c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 298c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "qla_def.h" 328c2ecf20Sopenharmony_ci#include "qla_target.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int ql2xtgt_tape_enable; 358c2ecf20Sopenharmony_cimodule_param(ql2xtgt_tape_enable, int, S_IRUGO|S_IWUSR); 368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql2xtgt_tape_enable, 378c2ecf20Sopenharmony_ci "Enables Sequence level error recovery (aka FC Tape). Default is 0 - no SLER. 1 - Enable SLER."); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic char *qlini_mode = QLA2XXX_INI_MODE_STR_ENABLED; 408c2ecf20Sopenharmony_cimodule_param(qlini_mode, charp, S_IRUGO); 418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(qlini_mode, 428c2ecf20Sopenharmony_ci "Determines when initiator mode will be enabled. Possible values: " 438c2ecf20Sopenharmony_ci "\"exclusive\" - initiator mode will be enabled on load, " 448c2ecf20Sopenharmony_ci "disabled on enabling target mode and then on disabling target mode " 458c2ecf20Sopenharmony_ci "enabled back; " 468c2ecf20Sopenharmony_ci "\"disabled\" - initiator mode will never be enabled; " 478c2ecf20Sopenharmony_ci "\"dual\" - Initiator Modes will be enabled. Target Mode can be activated " 488c2ecf20Sopenharmony_ci "when ready " 498c2ecf20Sopenharmony_ci "\"enabled\" (default) - initiator mode will always stay enabled."); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int ql_dm_tgt_ex_pct = 0; 528c2ecf20Sopenharmony_cimodule_param(ql_dm_tgt_ex_pct, int, S_IRUGO|S_IWUSR); 538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql_dm_tgt_ex_pct, 548c2ecf20Sopenharmony_ci "For Dual Mode (qlini_mode=dual), this parameter determines " 558c2ecf20Sopenharmony_ci "the percentage of exchanges/cmds FW will allocate resources " 568c2ecf20Sopenharmony_ci "for Target mode."); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ciint ql2xuctrlirq = 1; 598c2ecf20Sopenharmony_cimodule_param(ql2xuctrlirq, int, 0644); 608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql2xuctrlirq, 618c2ecf20Sopenharmony_ci "User to control IRQ placement via smp_affinity." 628c2ecf20Sopenharmony_ci "Valid with qlini_mode=disabled." 638c2ecf20Sopenharmony_ci "1(default): enable"); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ciint ql2x_ini_mode = QLA2XXX_INI_MODE_EXCLUSIVE; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int qla_sam_status = SAM_STAT_BUSY; 688c2ecf20Sopenharmony_cistatic int tc_sam_status = SAM_STAT_TASK_SET_FULL; /* target core */ 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 718c2ecf20Sopenharmony_ci * From scsi/fc/fc_fcp.h 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_cienum fcp_resp_rsp_codes { 748c2ecf20Sopenharmony_ci FCP_TMF_CMPL = 0, 758c2ecf20Sopenharmony_ci FCP_DATA_LEN_INVALID = 1, 768c2ecf20Sopenharmony_ci FCP_CMND_FIELDS_INVALID = 2, 778c2ecf20Sopenharmony_ci FCP_DATA_PARAM_MISMATCH = 3, 788c2ecf20Sopenharmony_ci FCP_TMF_REJECTED = 4, 798c2ecf20Sopenharmony_ci FCP_TMF_FAILED = 5, 808c2ecf20Sopenharmony_ci FCP_TMF_INVALID_LUN = 9, 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* 848c2ecf20Sopenharmony_ci * fc_pri_ta from scsi/fc/fc_fcp.h 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci#define FCP_PTA_SIMPLE 0 /* simple task attribute */ 878c2ecf20Sopenharmony_ci#define FCP_PTA_HEADQ 1 /* head of queue task attribute */ 888c2ecf20Sopenharmony_ci#define FCP_PTA_ORDERED 2 /* ordered task attribute */ 898c2ecf20Sopenharmony_ci#define FCP_PTA_ACA 4 /* auto. contingent allegiance */ 908c2ecf20Sopenharmony_ci#define FCP_PTA_MASK 7 /* mask for task attribute field */ 918c2ecf20Sopenharmony_ci#define FCP_PRI_SHIFT 3 /* priority field starts in bit 3 */ 928c2ecf20Sopenharmony_ci#define FCP_PRI_RESVD_MASK 0x80 /* reserved bits in priority field */ 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* 958c2ecf20Sopenharmony_ci * This driver calls qla2x00_alloc_iocbs() and qla2x00_issue_marker(), which 968c2ecf20Sopenharmony_ci * must be called under HW lock and could unlock/lock it inside. 978c2ecf20Sopenharmony_ci * It isn't an issue, since in the current implementation on the time when 988c2ecf20Sopenharmony_ci * those functions are called: 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * - Either context is IRQ and only IRQ handler can modify HW data, 1018c2ecf20Sopenharmony_ci * including rings related fields, 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * - Or access to target mode variables from struct qla_tgt doesn't 1048c2ecf20Sopenharmony_ci * cross those functions boundaries, except tgt_stop, which 1058c2ecf20Sopenharmony_ci * additionally protected by irq_cmd_count. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci/* Predefs for callbacks handed to qla2xxx LLD */ 1088c2ecf20Sopenharmony_cistatic void qlt_24xx_atio_pkt(struct scsi_qla_host *ha, 1098c2ecf20Sopenharmony_ci struct atio_from_isp *pkt, uint8_t); 1108c2ecf20Sopenharmony_cistatic void qlt_response_pkt(struct scsi_qla_host *ha, struct rsp_que *rsp, 1118c2ecf20Sopenharmony_ci response_t *pkt); 1128c2ecf20Sopenharmony_cistatic int qlt_issue_task_mgmt(struct fc_port *sess, u64 lun, 1138c2ecf20Sopenharmony_ci int fn, void *iocb, int flags); 1148c2ecf20Sopenharmony_cistatic void qlt_send_term_exchange(struct qla_qpair *, struct qla_tgt_cmd 1158c2ecf20Sopenharmony_ci *cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort); 1168c2ecf20Sopenharmony_cistatic void qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, 1178c2ecf20Sopenharmony_ci struct atio_from_isp *atio, uint16_t status, int qfull); 1188c2ecf20Sopenharmony_cistatic void qlt_disable_vha(struct scsi_qla_host *vha); 1198c2ecf20Sopenharmony_cistatic void qlt_clear_tgt_db(struct qla_tgt *tgt); 1208c2ecf20Sopenharmony_cistatic void qlt_send_notify_ack(struct qla_qpair *qpair, 1218c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *ntfy, 1228c2ecf20Sopenharmony_ci uint32_t add_flags, uint16_t resp_code, int resp_code_valid, 1238c2ecf20Sopenharmony_ci uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan); 1248c2ecf20Sopenharmony_cistatic void qlt_send_term_imm_notif(struct scsi_qla_host *vha, 1258c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *imm, int ha_locked); 1268c2ecf20Sopenharmony_cistatic struct fc_port *qlt_create_sess(struct scsi_qla_host *vha, 1278c2ecf20Sopenharmony_ci fc_port_t *fcport, bool local); 1288c2ecf20Sopenharmony_civoid qlt_unreg_sess(struct fc_port *sess); 1298c2ecf20Sopenharmony_cistatic void qlt_24xx_handle_abts(struct scsi_qla_host *, 1308c2ecf20Sopenharmony_ci struct abts_recv_from_24xx *); 1318c2ecf20Sopenharmony_cistatic void qlt_send_busy(struct qla_qpair *, struct atio_from_isp *, 1328c2ecf20Sopenharmony_ci uint16_t); 1338c2ecf20Sopenharmony_cistatic int qlt_check_reserve_free_req(struct qla_qpair *qpair, uint32_t); 1348c2ecf20Sopenharmony_cistatic inline uint32_t qlt_make_handle(struct qla_qpair *); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* 1378c2ecf20Sopenharmony_ci * Global Variables 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_cistatic struct kmem_cache *qla_tgt_mgmt_cmd_cachep; 1408c2ecf20Sopenharmony_cistruct kmem_cache *qla_tgt_plogi_cachep; 1418c2ecf20Sopenharmony_cistatic mempool_t *qla_tgt_mgmt_cmd_mempool; 1428c2ecf20Sopenharmony_cistatic struct workqueue_struct *qla_tgt_wq; 1438c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(qla_tgt_mutex); 1448c2ecf20Sopenharmony_cistatic LIST_HEAD(qla_tgt_glist); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic const char *prot_op_str(u32 prot_op) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci switch (prot_op) { 1498c2ecf20Sopenharmony_ci case TARGET_PROT_NORMAL: return "NORMAL"; 1508c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_INSERT: return "DIN_INSERT"; 1518c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_INSERT: return "DOUT_INSERT"; 1528c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_STRIP: return "DIN_STRIP"; 1538c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_STRIP: return "DOUT_STRIP"; 1548c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_PASS: return "DIN_PASS"; 1558c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_PASS: return "DOUT_PASS"; 1568c2ecf20Sopenharmony_ci default: return "UNKNOWN"; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* This API intentionally takes dest as a parameter, rather than returning 1618c2ecf20Sopenharmony_ci * int value to avoid caller forgetting to issue wmb() after the store */ 1628c2ecf20Sopenharmony_civoid qlt_do_generation_tick(struct scsi_qla_host *vha, int *dest) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(vha->hw->pdev); 1658c2ecf20Sopenharmony_ci *dest = atomic_inc_return(&base_vha->generation_tick); 1668c2ecf20Sopenharmony_ci /* memory barrier */ 1678c2ecf20Sopenharmony_ci wmb(); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* Might release hw lock, then reaquire!! */ 1718c2ecf20Sopenharmony_cistatic inline int qlt_issue_marker(struct scsi_qla_host *vha, int vha_locked) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci /* Send marker if required */ 1748c2ecf20Sopenharmony_ci if (unlikely(vha->marker_needed != 0)) { 1758c2ecf20Sopenharmony_ci int rc = qla2x00_issue_marker(vha, vha_locked); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (rc != QLA_SUCCESS) { 1788c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe03d, 1798c2ecf20Sopenharmony_ci "qla_target(%d): issue_marker() failed\n", 1808c2ecf20Sopenharmony_ci vha->vp_idx); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci return rc; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci return QLA_SUCCESS; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic inline 1888c2ecf20Sopenharmony_cistruct scsi_qla_host *qlt_find_host_by_d_id(struct scsi_qla_host *vha, 1898c2ecf20Sopenharmony_ci be_id_t d_id) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct scsi_qla_host *host; 1928c2ecf20Sopenharmony_ci uint32_t key; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (vha->d_id.b.area == d_id.area && 1958c2ecf20Sopenharmony_ci vha->d_id.b.domain == d_id.domain && 1968c2ecf20Sopenharmony_ci vha->d_id.b.al_pa == d_id.al_pa) 1978c2ecf20Sopenharmony_ci return vha; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci key = be_to_port_id(d_id).b24; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci host = btree_lookup32(&vha->hw->tgt.host_map, key); 2028c2ecf20Sopenharmony_ci if (!host) 2038c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt + ql_dbg_verbose, vha, 0xf005, 2048c2ecf20Sopenharmony_ci "Unable to find host %06x\n", key); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return host; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic inline 2108c2ecf20Sopenharmony_cistruct scsi_qla_host *qlt_find_host_by_vp_idx(struct scsi_qla_host *vha, 2118c2ecf20Sopenharmony_ci uint16_t vp_idx) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (vha->vp_idx == vp_idx) 2168c2ecf20Sopenharmony_ci return vha; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci BUG_ON(ha->tgt.tgt_vp_map == NULL); 2198c2ecf20Sopenharmony_ci if (likely(test_bit(vp_idx, ha->vp_idx_map))) 2208c2ecf20Sopenharmony_ci return ha->tgt.tgt_vp_map[vp_idx].vha; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return NULL; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic inline void qlt_incr_num_pend_cmds(struct scsi_qla_host *vha) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci unsigned long flags; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci vha->hw->tgt.num_pend_cmds++; 2328c2ecf20Sopenharmony_ci if (vha->hw->tgt.num_pend_cmds > vha->qla_stats.stat_max_pend_cmds) 2338c2ecf20Sopenharmony_ci vha->qla_stats.stat_max_pend_cmds = 2348c2ecf20Sopenharmony_ci vha->hw->tgt.num_pend_cmds; 2358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_cistatic inline void qlt_decr_num_pend_cmds(struct scsi_qla_host *vha) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci unsigned long flags; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); 2428c2ecf20Sopenharmony_ci vha->hw->tgt.num_pend_cmds--; 2438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void qlt_queue_unknown_atio(scsi_qla_host_t *vha, 2488c2ecf20Sopenharmony_ci struct atio_from_isp *atio, uint8_t ha_locked) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct qla_tgt_sess_op *u; 2518c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 2528c2ecf20Sopenharmony_ci unsigned long flags; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (tgt->tgt_stop) { 2558c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x502c, 2568c2ecf20Sopenharmony_ci "qla_target(%d): dropping unknown ATIO_TYPE7, because tgt is being stopped", 2578c2ecf20Sopenharmony_ci vha->vp_idx); 2588c2ecf20Sopenharmony_ci goto out_term; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci u = kzalloc(sizeof(*u), GFP_ATOMIC); 2628c2ecf20Sopenharmony_ci if (u == NULL) 2638c2ecf20Sopenharmony_ci goto out_term; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci u->vha = vha; 2668c2ecf20Sopenharmony_ci memcpy(&u->atio, atio, sizeof(*atio)); 2678c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&u->cmd_list); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->cmd_list_lock, flags); 2708c2ecf20Sopenharmony_ci list_add_tail(&u->cmd_list, &vha->unknown_atio_list); 2718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->cmd_list_lock, flags); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci schedule_delayed_work(&vha->unknown_atio_work, 1); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ciout: 2768c2ecf20Sopenharmony_ci return; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ciout_term: 2798c2ecf20Sopenharmony_ci qlt_send_term_exchange(vha->hw->base_qpair, NULL, atio, ha_locked, 0); 2808c2ecf20Sopenharmony_ci goto out; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void qlt_try_to_dequeue_unknown_atios(struct scsi_qla_host *vha, 2848c2ecf20Sopenharmony_ci uint8_t ha_locked) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct qla_tgt_sess_op *u, *t; 2878c2ecf20Sopenharmony_ci scsi_qla_host_t *host; 2888c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 2898c2ecf20Sopenharmony_ci unsigned long flags; 2908c2ecf20Sopenharmony_ci uint8_t queued = 0; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci list_for_each_entry_safe(u, t, &vha->unknown_atio_list, cmd_list) { 2938c2ecf20Sopenharmony_ci if (u->aborted) { 2948c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x502e, 2958c2ecf20Sopenharmony_ci "Freeing unknown %s %p, because of Abort\n", 2968c2ecf20Sopenharmony_ci "ATIO_TYPE7", u); 2978c2ecf20Sopenharmony_ci qlt_send_term_exchange(vha->hw->base_qpair, NULL, 2988c2ecf20Sopenharmony_ci &u->atio, ha_locked, 0); 2998c2ecf20Sopenharmony_ci goto abort; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci host = qlt_find_host_by_d_id(vha, u->atio.u.isp24.fcp_hdr.d_id); 3038c2ecf20Sopenharmony_ci if (host != NULL) { 3048c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_async + ql_dbg_verbose, vha, 0x502f, 3058c2ecf20Sopenharmony_ci "Requeuing unknown ATIO_TYPE7 %p\n", u); 3068c2ecf20Sopenharmony_ci qlt_24xx_atio_pkt(host, &u->atio, ha_locked); 3078c2ecf20Sopenharmony_ci } else if (tgt->tgt_stop) { 3088c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_async + ql_dbg_verbose, vha, 0x503a, 3098c2ecf20Sopenharmony_ci "Freeing unknown %s %p, because tgt is being stopped\n", 3108c2ecf20Sopenharmony_ci "ATIO_TYPE7", u); 3118c2ecf20Sopenharmony_ci qlt_send_term_exchange(vha->hw->base_qpair, NULL, 3128c2ecf20Sopenharmony_ci &u->atio, ha_locked, 0); 3138c2ecf20Sopenharmony_ci } else { 3148c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_async + ql_dbg_verbose, vha, 0x503d, 3158c2ecf20Sopenharmony_ci "Reschedule u %p, vha %p, host %p\n", u, vha, host); 3168c2ecf20Sopenharmony_ci if (!queued) { 3178c2ecf20Sopenharmony_ci queued = 1; 3188c2ecf20Sopenharmony_ci schedule_delayed_work(&vha->unknown_atio_work, 3198c2ecf20Sopenharmony_ci 1); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci continue; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ciabort: 3258c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->cmd_list_lock, flags); 3268c2ecf20Sopenharmony_ci list_del(&u->cmd_list); 3278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->cmd_list_lock, flags); 3288c2ecf20Sopenharmony_ci kfree(u); 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_civoid qlt_unknown_atio_work_fn(struct work_struct *work) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = container_of(to_delayed_work(work), 3358c2ecf20Sopenharmony_ci struct scsi_qla_host, unknown_atio_work); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci qlt_try_to_dequeue_unknown_atios(vha, 0); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha, 3418c2ecf20Sopenharmony_ci struct atio_from_isp *atio, uint8_t ha_locked) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe072, 3448c2ecf20Sopenharmony_ci "%s: qla_target(%d): type %x ox_id %04x\n", 3458c2ecf20Sopenharmony_ci __func__, vha->vp_idx, atio->u.raw.entry_type, 3468c2ecf20Sopenharmony_ci be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id)); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci switch (atio->u.raw.entry_type) { 3498c2ecf20Sopenharmony_ci case ATIO_TYPE7: 3508c2ecf20Sopenharmony_ci { 3518c2ecf20Sopenharmony_ci struct scsi_qla_host *host = qlt_find_host_by_d_id(vha, 3528c2ecf20Sopenharmony_ci atio->u.isp24.fcp_hdr.d_id); 3538c2ecf20Sopenharmony_ci if (unlikely(NULL == host)) { 3548c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe03e, 3558c2ecf20Sopenharmony_ci "qla_target(%d): Received ATIO_TYPE7 " 3568c2ecf20Sopenharmony_ci "with unknown d_id %x:%x:%x\n", vha->vp_idx, 3578c2ecf20Sopenharmony_ci atio->u.isp24.fcp_hdr.d_id.domain, 3588c2ecf20Sopenharmony_ci atio->u.isp24.fcp_hdr.d_id.area, 3598c2ecf20Sopenharmony_ci atio->u.isp24.fcp_hdr.d_id.al_pa); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci qlt_queue_unknown_atio(vha, atio, ha_locked); 3638c2ecf20Sopenharmony_ci break; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci if (unlikely(!list_empty(&vha->unknown_atio_list))) 3668c2ecf20Sopenharmony_ci qlt_try_to_dequeue_unknown_atios(vha, ha_locked); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci qlt_24xx_atio_pkt(host, atio, ha_locked); 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci case IMMED_NOTIFY_TYPE: 3738c2ecf20Sopenharmony_ci { 3748c2ecf20Sopenharmony_ci struct scsi_qla_host *host = vha; 3758c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *entry = 3768c2ecf20Sopenharmony_ci (struct imm_ntfy_from_isp *)atio; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci qlt_issue_marker(vha, ha_locked); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if ((entry->u.isp24.vp_index != 0xFF) && 3818c2ecf20Sopenharmony_ci (entry->u.isp24.nport_handle != cpu_to_le16(0xFFFF))) { 3828c2ecf20Sopenharmony_ci host = qlt_find_host_by_vp_idx(vha, 3838c2ecf20Sopenharmony_ci entry->u.isp24.vp_index); 3848c2ecf20Sopenharmony_ci if (unlikely(!host)) { 3858c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe03f, 3868c2ecf20Sopenharmony_ci "qla_target(%d): Received " 3878c2ecf20Sopenharmony_ci "ATIO (IMMED_NOTIFY_TYPE) " 3888c2ecf20Sopenharmony_ci "with unknown vp_index %d\n", 3898c2ecf20Sopenharmony_ci vha->vp_idx, entry->u.isp24.vp_index); 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci qlt_24xx_atio_pkt(host, atio, ha_locked); 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci case VP_RPT_ID_IOCB_TYPE: 3988c2ecf20Sopenharmony_ci qla24xx_report_id_acquisition(vha, 3998c2ecf20Sopenharmony_ci (struct vp_rpt_id_entry_24xx *)atio); 4008c2ecf20Sopenharmony_ci break; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci case ABTS_RECV_24XX: 4038c2ecf20Sopenharmony_ci { 4048c2ecf20Sopenharmony_ci struct abts_recv_from_24xx *entry = 4058c2ecf20Sopenharmony_ci (struct abts_recv_from_24xx *)atio; 4068c2ecf20Sopenharmony_ci struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha, 4078c2ecf20Sopenharmony_ci entry->vp_index); 4088c2ecf20Sopenharmony_ci unsigned long flags; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (unlikely(!host)) { 4118c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe00a, 4128c2ecf20Sopenharmony_ci "qla_target(%d): Response pkt (ABTS_RECV_24XX) " 4138c2ecf20Sopenharmony_ci "received, with unknown vp_index %d\n", 4148c2ecf20Sopenharmony_ci vha->vp_idx, entry->vp_index); 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci if (!ha_locked) 4188c2ecf20Sopenharmony_ci spin_lock_irqsave(&host->hw->hardware_lock, flags); 4198c2ecf20Sopenharmony_ci qlt_24xx_handle_abts(host, (struct abts_recv_from_24xx *)atio); 4208c2ecf20Sopenharmony_ci if (!ha_locked) 4218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&host->hw->hardware_lock, flags); 4228c2ecf20Sopenharmony_ci break; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* case PUREX_IOCB_TYPE: ql2xmvasynctoatio */ 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci default: 4288c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe040, 4298c2ecf20Sopenharmony_ci "qla_target(%d): Received unknown ATIO atio " 4308c2ecf20Sopenharmony_ci "type %x\n", vha->vp_idx, atio->u.raw.entry_type); 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return false; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_civoid qlt_response_pkt_all_vps(struct scsi_qla_host *vha, 4388c2ecf20Sopenharmony_ci struct rsp_que *rsp, response_t *pkt) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci switch (pkt->entry_type) { 4418c2ecf20Sopenharmony_ci case CTIO_CRC2: 4428c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe073, 4438c2ecf20Sopenharmony_ci "qla_target(%d):%s: CRC2 Response pkt\n", 4448c2ecf20Sopenharmony_ci vha->vp_idx, __func__); 4458c2ecf20Sopenharmony_ci fallthrough; 4468c2ecf20Sopenharmony_ci case CTIO_TYPE7: 4478c2ecf20Sopenharmony_ci { 4488c2ecf20Sopenharmony_ci struct ctio7_from_24xx *entry = (struct ctio7_from_24xx *)pkt; 4498c2ecf20Sopenharmony_ci struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha, 4508c2ecf20Sopenharmony_ci entry->vp_index); 4518c2ecf20Sopenharmony_ci if (unlikely(!host)) { 4528c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe041, 4538c2ecf20Sopenharmony_ci "qla_target(%d): Response pkt (CTIO_TYPE7) " 4548c2ecf20Sopenharmony_ci "received, with unknown vp_index %d\n", 4558c2ecf20Sopenharmony_ci vha->vp_idx, entry->vp_index); 4568c2ecf20Sopenharmony_ci break; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci qlt_response_pkt(host, rsp, pkt); 4598c2ecf20Sopenharmony_ci break; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci case IMMED_NOTIFY_TYPE: 4638c2ecf20Sopenharmony_ci { 4648c2ecf20Sopenharmony_ci struct scsi_qla_host *host; 4658c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *entry = 4668c2ecf20Sopenharmony_ci (struct imm_ntfy_from_isp *)pkt; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci host = qlt_find_host_by_vp_idx(vha, entry->u.isp24.vp_index); 4698c2ecf20Sopenharmony_ci if (unlikely(!host)) { 4708c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe042, 4718c2ecf20Sopenharmony_ci "qla_target(%d): Response pkt (IMMED_NOTIFY_TYPE) " 4728c2ecf20Sopenharmony_ci "received, with unknown vp_index %d\n", 4738c2ecf20Sopenharmony_ci vha->vp_idx, entry->u.isp24.vp_index); 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci qlt_response_pkt(host, rsp, pkt); 4778c2ecf20Sopenharmony_ci break; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci case NOTIFY_ACK_TYPE: 4818c2ecf20Sopenharmony_ci { 4828c2ecf20Sopenharmony_ci struct scsi_qla_host *host = vha; 4838c2ecf20Sopenharmony_ci struct nack_to_isp *entry = (struct nack_to_isp *)pkt; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (0xFF != entry->u.isp24.vp_index) { 4868c2ecf20Sopenharmony_ci host = qlt_find_host_by_vp_idx(vha, 4878c2ecf20Sopenharmony_ci entry->u.isp24.vp_index); 4888c2ecf20Sopenharmony_ci if (unlikely(!host)) { 4898c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe043, 4908c2ecf20Sopenharmony_ci "qla_target(%d): Response " 4918c2ecf20Sopenharmony_ci "pkt (NOTIFY_ACK_TYPE) " 4928c2ecf20Sopenharmony_ci "received, with unknown " 4938c2ecf20Sopenharmony_ci "vp_index %d\n", vha->vp_idx, 4948c2ecf20Sopenharmony_ci entry->u.isp24.vp_index); 4958c2ecf20Sopenharmony_ci break; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci qlt_response_pkt(host, rsp, pkt); 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci case ABTS_RECV_24XX: 5038c2ecf20Sopenharmony_ci { 5048c2ecf20Sopenharmony_ci struct abts_recv_from_24xx *entry = 5058c2ecf20Sopenharmony_ci (struct abts_recv_from_24xx *)pkt; 5068c2ecf20Sopenharmony_ci struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha, 5078c2ecf20Sopenharmony_ci entry->vp_index); 5088c2ecf20Sopenharmony_ci if (unlikely(!host)) { 5098c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe044, 5108c2ecf20Sopenharmony_ci "qla_target(%d): Response pkt " 5118c2ecf20Sopenharmony_ci "(ABTS_RECV_24XX) received, with unknown " 5128c2ecf20Sopenharmony_ci "vp_index %d\n", vha->vp_idx, entry->vp_index); 5138c2ecf20Sopenharmony_ci break; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci qlt_response_pkt(host, rsp, pkt); 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci case ABTS_RESP_24XX: 5208c2ecf20Sopenharmony_ci { 5218c2ecf20Sopenharmony_ci struct abts_resp_to_24xx *entry = 5228c2ecf20Sopenharmony_ci (struct abts_resp_to_24xx *)pkt; 5238c2ecf20Sopenharmony_ci struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha, 5248c2ecf20Sopenharmony_ci entry->vp_index); 5258c2ecf20Sopenharmony_ci if (unlikely(!host)) { 5268c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe045, 5278c2ecf20Sopenharmony_ci "qla_target(%d): Response pkt " 5288c2ecf20Sopenharmony_ci "(ABTS_RECV_24XX) received, with unknown " 5298c2ecf20Sopenharmony_ci "vp_index %d\n", vha->vp_idx, entry->vp_index); 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci qlt_response_pkt(host, rsp, pkt); 5338c2ecf20Sopenharmony_ci break; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci default: 5368c2ecf20Sopenharmony_ci qlt_response_pkt(vha, rsp, pkt); 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci/* 5438c2ecf20Sopenharmony_ci * All qlt_plogi_ack_t operations are protected by hardware_lock 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_cistatic int qla24xx_post_nack_work(struct scsi_qla_host *vha, fc_port_t *fcport, 5468c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *ntfy, int type) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct qla_work_evt *e; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_NACK); 5518c2ecf20Sopenharmony_ci if (!e) 5528c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci e->u.nack.fcport = fcport; 5558c2ecf20Sopenharmony_ci e->u.nack.type = type; 5568c2ecf20Sopenharmony_ci memcpy(e->u.nack.iocb, ntfy, sizeof(struct imm_ntfy_from_isp)); 5578c2ecf20Sopenharmony_ci return qla2x00_post_work(vha, e); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic void qla2x00_async_nack_sp_done(srb_t *sp, int res) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 5638c2ecf20Sopenharmony_ci unsigned long flags; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f2, 5668c2ecf20Sopenharmony_ci "Async done-%s res %x %8phC type %d\n", 5678c2ecf20Sopenharmony_ci sp->name, res, sp->fcport->port_name, sp->type); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 5708c2ecf20Sopenharmony_ci sp->fcport->flags &= ~FCF_ASYNC_SENT; 5718c2ecf20Sopenharmony_ci sp->fcport->chip_reset = vha->hw->base_qpair->chip_reset; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci switch (sp->type) { 5748c2ecf20Sopenharmony_ci case SRB_NACK_PLOGI: 5758c2ecf20Sopenharmony_ci sp->fcport->login_gen++; 5768c2ecf20Sopenharmony_ci sp->fcport->fw_login_state = DSC_LS_PLOGI_COMP; 5778c2ecf20Sopenharmony_ci sp->fcport->logout_on_delete = 1; 5788c2ecf20Sopenharmony_ci sp->fcport->plogi_nack_done_deadline = jiffies + HZ; 5798c2ecf20Sopenharmony_ci sp->fcport->send_els_logo = 0; 5808c2ecf20Sopenharmony_ci break; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci case SRB_NACK_PRLI: 5838c2ecf20Sopenharmony_ci sp->fcport->fw_login_state = DSC_LS_PRLI_COMP; 5848c2ecf20Sopenharmony_ci sp->fcport->deleted = 0; 5858c2ecf20Sopenharmony_ci sp->fcport->send_els_logo = 0; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (!sp->fcport->login_succ && 5888c2ecf20Sopenharmony_ci !IS_SW_RESV_ADDR(sp->fcport->d_id)) { 5898c2ecf20Sopenharmony_ci sp->fcport->login_succ = 1; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci vha->fcport_count++; 5928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 5938c2ecf20Sopenharmony_ci qla24xx_sched_upd_fcport(sp->fcport); 5948c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 5958c2ecf20Sopenharmony_ci } else { 5968c2ecf20Sopenharmony_ci sp->fcport->login_retry = 0; 5978c2ecf20Sopenharmony_ci qla2x00_set_fcport_disc_state(sp->fcport, 5988c2ecf20Sopenharmony_ci DSC_LOGIN_COMPLETE); 5998c2ecf20Sopenharmony_ci sp->fcport->deleted = 0; 6008c2ecf20Sopenharmony_ci sp->fcport->logout_on_delete = 1; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci break; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci case SRB_NACK_LOGO: 6058c2ecf20Sopenharmony_ci sp->fcport->login_gen++; 6068c2ecf20Sopenharmony_ci sp->fcport->fw_login_state = DSC_LS_PORT_UNAVAIL; 6078c2ecf20Sopenharmony_ci qlt_logo_completion_handler(sp->fcport, MBS_COMMAND_COMPLETE); 6088c2ecf20Sopenharmony_ci break; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci sp->free(sp); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ciint qla24xx_async_notify_ack(scsi_qla_host_t *vha, fc_port_t *fcport, 6168c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *ntfy, int type) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 6198c2ecf20Sopenharmony_ci srb_t *sp; 6208c2ecf20Sopenharmony_ci char *c = NULL; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci fcport->flags |= FCF_ASYNC_SENT; 6238c2ecf20Sopenharmony_ci switch (type) { 6248c2ecf20Sopenharmony_ci case SRB_NACK_PLOGI: 6258c2ecf20Sopenharmony_ci fcport->fw_login_state = DSC_LS_PLOGI_PEND; 6268c2ecf20Sopenharmony_ci c = "PLOGI"; 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci case SRB_NACK_PRLI: 6298c2ecf20Sopenharmony_ci fcport->fw_login_state = DSC_LS_PRLI_PEND; 6308c2ecf20Sopenharmony_ci fcport->deleted = 0; 6318c2ecf20Sopenharmony_ci c = "PRLI"; 6328c2ecf20Sopenharmony_ci break; 6338c2ecf20Sopenharmony_ci case SRB_NACK_LOGO: 6348c2ecf20Sopenharmony_ci fcport->fw_login_state = DSC_LS_LOGO_PEND; 6358c2ecf20Sopenharmony_ci c = "LOGO"; 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); 6408c2ecf20Sopenharmony_ci if (!sp) 6418c2ecf20Sopenharmony_ci goto done; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci sp->type = type; 6448c2ecf20Sopenharmony_ci sp->name = "nack"; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; 6478c2ecf20Sopenharmony_ci qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha)+2); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci sp->u.iocb_cmd.u.nack.ntfy = ntfy; 6508c2ecf20Sopenharmony_ci sp->done = qla2x00_async_nack_sp_done; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f4, 6538c2ecf20Sopenharmony_ci "Async-%s %8phC hndl %x %s\n", 6548c2ecf20Sopenharmony_ci sp->name, fcport->port_name, sp->handle, c); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci rval = qla2x00_start_sp(sp); 6578c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) 6588c2ecf20Sopenharmony_ci goto done_free_sp; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return rval; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cidone_free_sp: 6638c2ecf20Sopenharmony_ci sp->free(sp); 6648c2ecf20Sopenharmony_cidone: 6658c2ecf20Sopenharmony_ci fcport->flags &= ~FCF_ASYNC_SENT; 6668c2ecf20Sopenharmony_ci return rval; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_civoid qla24xx_do_nack_work(struct scsi_qla_host *vha, struct qla_work_evt *e) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci fc_port_t *t; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci switch (e->u.nack.type) { 6748c2ecf20Sopenharmony_ci case SRB_NACK_PRLI: 6758c2ecf20Sopenharmony_ci t = e->u.nack.fcport; 6768c2ecf20Sopenharmony_ci flush_work(&t->del_work); 6778c2ecf20Sopenharmony_ci flush_work(&t->free_work); 6788c2ecf20Sopenharmony_ci mutex_lock(&vha->vha_tgt.tgt_mutex); 6798c2ecf20Sopenharmony_ci t = qlt_create_sess(vha, e->u.nack.fcport, 0); 6808c2ecf20Sopenharmony_ci mutex_unlock(&vha->vha_tgt.tgt_mutex); 6818c2ecf20Sopenharmony_ci if (t) { 6828c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xd034, 6838c2ecf20Sopenharmony_ci "%s create sess success %p", __func__, t); 6848c2ecf20Sopenharmony_ci /* create sess has an extra kref */ 6858c2ecf20Sopenharmony_ci vha->hw->tgt.tgt_ops->put_sess(e->u.nack.fcport); 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci break; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci qla24xx_async_notify_ack(vha, e->u.nack.fcport, 6908c2ecf20Sopenharmony_ci (struct imm_ntfy_from_isp *)e->u.nack.iocb, e->u.nack.type); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_civoid qla24xx_delete_sess_fn(struct work_struct *work) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci fc_port_t *fcport = container_of(work, struct fc_port, del_work); 6968c2ecf20Sopenharmony_ci struct qla_hw_data *ha = fcport->vha->hw; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (fcport->se_sess) { 6998c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->shutdown_sess(fcport); 7008c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->put_sess(fcport); 7018c2ecf20Sopenharmony_ci } else { 7028c2ecf20Sopenharmony_ci qlt_unreg_sess(fcport); 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci/* 7078c2ecf20Sopenharmony_ci * Called from qla2x00_reg_remote_port() 7088c2ecf20Sopenharmony_ci */ 7098c2ecf20Sopenharmony_civoid qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 7128c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 7138c2ecf20Sopenharmony_ci struct fc_port *sess = fcport; 7148c2ecf20Sopenharmony_ci unsigned long flags; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (!vha->hw->tgt.tgt_ops) 7178c2ecf20Sopenharmony_ci return; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 7208c2ecf20Sopenharmony_ci if (tgt->tgt_stop) { 7218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 7228c2ecf20Sopenharmony_ci return; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (fcport->disc_state == DSC_DELETE_PEND) { 7268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 7278c2ecf20Sopenharmony_ci return; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (!sess->se_sess) { 7318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci mutex_lock(&vha->vha_tgt.tgt_mutex); 7348c2ecf20Sopenharmony_ci sess = qlt_create_sess(vha, fcport, false); 7358c2ecf20Sopenharmony_ci mutex_unlock(&vha->vha_tgt.tgt_mutex); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 7388c2ecf20Sopenharmony_ci } else { 7398c2ecf20Sopenharmony_ci if (fcport->fw_login_state == DSC_LS_PRLI_COMP) { 7408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 7418c2ecf20Sopenharmony_ci return; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&sess->sess_kref)) { 7458c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2107, 7468c2ecf20Sopenharmony_ci "%s: kref_get fail sess %8phC \n", 7478c2ecf20Sopenharmony_ci __func__, sess->port_name); 7488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 7498c2ecf20Sopenharmony_ci return; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04c, 7538c2ecf20Sopenharmony_ci "qla_target(%u): %ssession for port %8phC " 7548c2ecf20Sopenharmony_ci "(loop ID %d) reappeared\n", vha->vp_idx, 7558c2ecf20Sopenharmony_ci sess->local ? "local " : "", sess->port_name, sess->loop_id); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf007, 7588c2ecf20Sopenharmony_ci "Reappeared sess %p\n", sess); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, 7618c2ecf20Sopenharmony_ci fcport->loop_id, 7628c2ecf20Sopenharmony_ci (fcport->flags & FCF_CONF_COMP_SUPPORTED)); 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (sess && sess->local) { 7668c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04d, 7678c2ecf20Sopenharmony_ci "qla_target(%u): local session for " 7688c2ecf20Sopenharmony_ci "port %8phC (loop ID %d) became global\n", vha->vp_idx, 7698c2ecf20Sopenharmony_ci fcport->port_name, sess->loop_id); 7708c2ecf20Sopenharmony_ci sess->local = 0; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->put_sess(sess); 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci/* 7788c2ecf20Sopenharmony_ci * This is a zero-base ref-counting solution, since hardware_lock 7798c2ecf20Sopenharmony_ci * guarantees that ref_count is not modified concurrently. 7808c2ecf20Sopenharmony_ci * Upon successful return content of iocb is undefined 7818c2ecf20Sopenharmony_ci */ 7828c2ecf20Sopenharmony_cistatic struct qlt_plogi_ack_t * 7838c2ecf20Sopenharmony_ciqlt_plogi_ack_find_add(struct scsi_qla_host *vha, port_id_t *id, 7848c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *iocb) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci struct qlt_plogi_ack_t *pla; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci lockdep_assert_held(&vha->hw->hardware_lock); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci list_for_each_entry(pla, &vha->plogi_ack_list, list) { 7918c2ecf20Sopenharmony_ci if (pla->id.b24 == id->b24) { 7928c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x210d, 7938c2ecf20Sopenharmony_ci "%s %d %8phC Term INOT due to new INOT", 7948c2ecf20Sopenharmony_ci __func__, __LINE__, 7958c2ecf20Sopenharmony_ci pla->iocb.u.isp24.port_name); 7968c2ecf20Sopenharmony_ci qlt_send_term_imm_notif(vha, &pla->iocb, 1); 7978c2ecf20Sopenharmony_ci memcpy(&pla->iocb, iocb, sizeof(pla->iocb)); 7988c2ecf20Sopenharmony_ci return pla; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci pla = kmem_cache_zalloc(qla_tgt_plogi_cachep, GFP_ATOMIC); 8038c2ecf20Sopenharmony_ci if (!pla) { 8048c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5088, 8058c2ecf20Sopenharmony_ci "qla_target(%d): Allocation of plogi_ack failed\n", 8068c2ecf20Sopenharmony_ci vha->vp_idx); 8078c2ecf20Sopenharmony_ci return NULL; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci memcpy(&pla->iocb, iocb, sizeof(pla->iocb)); 8118c2ecf20Sopenharmony_ci pla->id = *id; 8128c2ecf20Sopenharmony_ci list_add_tail(&pla->list, &vha->plogi_ack_list); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return pla; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_civoid qlt_plogi_ack_unref(struct scsi_qla_host *vha, 8188c2ecf20Sopenharmony_ci struct qlt_plogi_ack_t *pla) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *iocb = &pla->iocb; 8218c2ecf20Sopenharmony_ci port_id_t port_id; 8228c2ecf20Sopenharmony_ci uint16_t loop_id; 8238c2ecf20Sopenharmony_ci fc_port_t *fcport = pla->fcport; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci BUG_ON(!pla->ref_count); 8268c2ecf20Sopenharmony_ci pla->ref_count--; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (pla->ref_count) 8298c2ecf20Sopenharmony_ci return; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x5089, 8328c2ecf20Sopenharmony_ci "Sending PLOGI ACK to wwn %8phC s_id %02x:%02x:%02x loop_id %#04x" 8338c2ecf20Sopenharmony_ci " exch %#x ox_id %#x\n", iocb->u.isp24.port_name, 8348c2ecf20Sopenharmony_ci iocb->u.isp24.port_id[2], iocb->u.isp24.port_id[1], 8358c2ecf20Sopenharmony_ci iocb->u.isp24.port_id[0], 8368c2ecf20Sopenharmony_ci le16_to_cpu(iocb->u.isp24.nport_handle), 8378c2ecf20Sopenharmony_ci iocb->u.isp24.exchange_address, iocb->ox_id); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci port_id.b.domain = iocb->u.isp24.port_id[2]; 8408c2ecf20Sopenharmony_ci port_id.b.area = iocb->u.isp24.port_id[1]; 8418c2ecf20Sopenharmony_ci port_id.b.al_pa = iocb->u.isp24.port_id[0]; 8428c2ecf20Sopenharmony_ci port_id.b.rsvd_1 = 0; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci loop_id = le16_to_cpu(iocb->u.isp24.nport_handle); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci fcport->loop_id = loop_id; 8478c2ecf20Sopenharmony_ci fcport->d_id = port_id; 8488c2ecf20Sopenharmony_ci if (iocb->u.isp24.status_subcode == ELS_PLOGI) 8498c2ecf20Sopenharmony_ci qla24xx_post_nack_work(vha, fcport, iocb, SRB_NACK_PLOGI); 8508c2ecf20Sopenharmony_ci else 8518c2ecf20Sopenharmony_ci qla24xx_post_nack_work(vha, fcport, iocb, SRB_NACK_PRLI); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 8548c2ecf20Sopenharmony_ci if (fcport->plogi_link[QLT_PLOGI_LINK_SAME_WWN] == pla) 8558c2ecf20Sopenharmony_ci fcport->plogi_link[QLT_PLOGI_LINK_SAME_WWN] = NULL; 8568c2ecf20Sopenharmony_ci if (fcport->plogi_link[QLT_PLOGI_LINK_CONFLICT] == pla) 8578c2ecf20Sopenharmony_ci fcport->plogi_link[QLT_PLOGI_LINK_CONFLICT] = NULL; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci list_del(&pla->list); 8618c2ecf20Sopenharmony_ci kmem_cache_free(qla_tgt_plogi_cachep, pla); 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_civoid 8658c2ecf20Sopenharmony_ciqlt_plogi_ack_link(struct scsi_qla_host *vha, struct qlt_plogi_ack_t *pla, 8668c2ecf20Sopenharmony_ci struct fc_port *sess, enum qlt_plogi_link_t link) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *iocb = &pla->iocb; 8698c2ecf20Sopenharmony_ci /* Inc ref_count first because link might already be pointing at pla */ 8708c2ecf20Sopenharmony_ci pla->ref_count++; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf097, 8738c2ecf20Sopenharmony_ci "Linking sess %p [%d] wwn %8phC with PLOGI ACK to wwn %8phC" 8748c2ecf20Sopenharmony_ci " s_id %02x:%02x:%02x, ref=%d pla %p link %d\n", 8758c2ecf20Sopenharmony_ci sess, link, sess->port_name, 8768c2ecf20Sopenharmony_ci iocb->u.isp24.port_name, iocb->u.isp24.port_id[2], 8778c2ecf20Sopenharmony_ci iocb->u.isp24.port_id[1], iocb->u.isp24.port_id[0], 8788c2ecf20Sopenharmony_ci pla->ref_count, pla, link); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if (link == QLT_PLOGI_LINK_CONFLICT) { 8818c2ecf20Sopenharmony_ci switch (sess->disc_state) { 8828c2ecf20Sopenharmony_ci case DSC_DELETED: 8838c2ecf20Sopenharmony_ci case DSC_DELETE_PEND: 8848c2ecf20Sopenharmony_ci pla->ref_count--; 8858c2ecf20Sopenharmony_ci return; 8868c2ecf20Sopenharmony_ci default: 8878c2ecf20Sopenharmony_ci break; 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (sess->plogi_link[link]) 8928c2ecf20Sopenharmony_ci qlt_plogi_ack_unref(vha, sess->plogi_link[link]); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci if (link == QLT_PLOGI_LINK_SAME_WWN) 8958c2ecf20Sopenharmony_ci pla->fcport = sess; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci sess->plogi_link[link] = pla; 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_citypedef struct { 9018c2ecf20Sopenharmony_ci /* These fields must be initialized by the caller */ 9028c2ecf20Sopenharmony_ci port_id_t id; 9038c2ecf20Sopenharmony_ci /* 9048c2ecf20Sopenharmony_ci * number of cmds dropped while we were waiting for 9058c2ecf20Sopenharmony_ci * initiator to ack LOGO initialize to 1 if LOGO is 9068c2ecf20Sopenharmony_ci * triggered by a command, otherwise, to 0 9078c2ecf20Sopenharmony_ci */ 9088c2ecf20Sopenharmony_ci int cmd_count; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* These fields are used by callee */ 9118c2ecf20Sopenharmony_ci struct list_head list; 9128c2ecf20Sopenharmony_ci} qlt_port_logo_t; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic void 9158c2ecf20Sopenharmony_ciqlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci qlt_port_logo_t *tmp; 9188c2ecf20Sopenharmony_ci int res; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci mutex_lock(&vha->vha_tgt.tgt_mutex); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &vha->logo_list, list) { 9238c2ecf20Sopenharmony_ci if (tmp->id.b24 == logo->id.b24) { 9248c2ecf20Sopenharmony_ci tmp->cmd_count += logo->cmd_count; 9258c2ecf20Sopenharmony_ci mutex_unlock(&vha->vha_tgt.tgt_mutex); 9268c2ecf20Sopenharmony_ci return; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci list_add_tail(&logo->list, &vha->logo_list); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci mutex_unlock(&vha->vha_tgt.tgt_mutex); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci res = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, logo->id); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci mutex_lock(&vha->vha_tgt.tgt_mutex); 9378c2ecf20Sopenharmony_ci list_del(&logo->list); 9388c2ecf20Sopenharmony_ci mutex_unlock(&vha->vha_tgt.tgt_mutex); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf098, 9418c2ecf20Sopenharmony_ci "Finished LOGO to %02x:%02x:%02x, dropped %d cmds, res = %#x\n", 9428c2ecf20Sopenharmony_ci logo->id.b.domain, logo->id.b.area, logo->id.b.al_pa, 9438c2ecf20Sopenharmony_ci logo->cmd_count, res); 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_civoid qlt_free_session_done(struct work_struct *work) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci struct fc_port *sess = container_of(work, struct fc_port, 9498c2ecf20Sopenharmony_ci free_work); 9508c2ecf20Sopenharmony_ci struct qla_tgt *tgt = sess->tgt; 9518c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sess->vha; 9528c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 9538c2ecf20Sopenharmony_ci unsigned long flags; 9548c2ecf20Sopenharmony_ci bool logout_started = false; 9558c2ecf20Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 9568c2ecf20Sopenharmony_ci struct qlt_plogi_ack_t *own = 9578c2ecf20Sopenharmony_ci sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN]; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xf084, 9608c2ecf20Sopenharmony_ci "%s: se_sess %p / sess %p from port %8phC loop_id %#04x" 9618c2ecf20Sopenharmony_ci " s_id %02x:%02x:%02x logout %d keep %d els_logo %d\n", 9628c2ecf20Sopenharmony_ci __func__, sess->se_sess, sess, sess->port_name, sess->loop_id, 9638c2ecf20Sopenharmony_ci sess->d_id.b.domain, sess->d_id.b.area, sess->d_id.b.al_pa, 9648c2ecf20Sopenharmony_ci sess->logout_on_delete, sess->keep_nport_handle, 9658c2ecf20Sopenharmony_ci sess->send_els_logo); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (!IS_SW_RESV_ADDR(sess->d_id)) { 9688c2ecf20Sopenharmony_ci qla2x00_mark_device_lost(vha, sess, 0); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci if (sess->send_els_logo) { 9718c2ecf20Sopenharmony_ci qlt_port_logo_t logo; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci logo.id = sess->d_id; 9748c2ecf20Sopenharmony_ci logo.cmd_count = 0; 9758c2ecf20Sopenharmony_ci if (!own) 9768c2ecf20Sopenharmony_ci qlt_send_first_logo(vha, &logo); 9778c2ecf20Sopenharmony_ci sess->send_els_logo = 0; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (sess->logout_on_delete && sess->loop_id != FC_NO_LOOP_ID) { 9818c2ecf20Sopenharmony_ci int rc; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (!own || 9848c2ecf20Sopenharmony_ci (own && 9858c2ecf20Sopenharmony_ci (own->iocb.u.isp24.status_subcode == ELS_PLOGI))) { 9868c2ecf20Sopenharmony_ci rc = qla2x00_post_async_logout_work(vha, sess, 9878c2ecf20Sopenharmony_ci NULL); 9888c2ecf20Sopenharmony_ci if (rc != QLA_SUCCESS) 9898c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xf085, 9908c2ecf20Sopenharmony_ci "Schedule logo failed sess %p rc %d\n", 9918c2ecf20Sopenharmony_ci sess, rc); 9928c2ecf20Sopenharmony_ci else 9938c2ecf20Sopenharmony_ci logout_started = true; 9948c2ecf20Sopenharmony_ci } else if (own && (own->iocb.u.isp24.status_subcode == 9958c2ecf20Sopenharmony_ci ELS_PRLI) && ha->flags.rida_fmt2) { 9968c2ecf20Sopenharmony_ci rc = qla2x00_post_async_prlo_work(vha, sess, 9978c2ecf20Sopenharmony_ci NULL); 9988c2ecf20Sopenharmony_ci if (rc != QLA_SUCCESS) 9998c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xf085, 10008c2ecf20Sopenharmony_ci "Schedule PRLO failed sess %p rc %d\n", 10018c2ecf20Sopenharmony_ci sess, rc); 10028c2ecf20Sopenharmony_ci else 10038c2ecf20Sopenharmony_ci logout_started = true; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci } /* if sess->logout_on_delete */ 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (sess->nvme_flag & NVME_FLAG_REGISTERED && 10088c2ecf20Sopenharmony_ci !(sess->nvme_flag & NVME_FLAG_DELETING)) { 10098c2ecf20Sopenharmony_ci sess->nvme_flag |= NVME_FLAG_DELETING; 10108c2ecf20Sopenharmony_ci qla_nvme_unregister_remote_port(sess); 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci /* 10158c2ecf20Sopenharmony_ci * Release the target session for FC Nexus from fabric module code. 10168c2ecf20Sopenharmony_ci */ 10178c2ecf20Sopenharmony_ci if (sess->se_sess != NULL) 10188c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->free_session(sess); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (logout_started) { 10218c2ecf20Sopenharmony_ci bool traced = false; 10228c2ecf20Sopenharmony_ci u16 cnt = 0; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci while (!READ_ONCE(sess->logout_completed)) { 10258c2ecf20Sopenharmony_ci if (!traced) { 10268c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xf086, 10278c2ecf20Sopenharmony_ci "%s: waiting for sess %p logout\n", 10288c2ecf20Sopenharmony_ci __func__, sess); 10298c2ecf20Sopenharmony_ci traced = true; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci msleep(100); 10328c2ecf20Sopenharmony_ci cnt++; 10338c2ecf20Sopenharmony_ci if (cnt > 200) 10348c2ecf20Sopenharmony_ci break; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xf087, 10388c2ecf20Sopenharmony_ci "%s: sess %p logout completed\n", __func__, sess); 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (sess->logo_ack_needed) { 10428c2ecf20Sopenharmony_ci sess->logo_ack_needed = 0; 10438c2ecf20Sopenharmony_ci qla24xx_async_notify_ack(vha, sess, 10448c2ecf20Sopenharmony_ci (struct imm_ntfy_from_isp *)sess->iocb, SRB_NACK_LOGO); 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 10488c2ecf20Sopenharmony_ci if (sess->se_sess) { 10498c2ecf20Sopenharmony_ci sess->se_sess = NULL; 10508c2ecf20Sopenharmony_ci if (tgt && !IS_SW_RESV_ADDR(sess->d_id)) 10518c2ecf20Sopenharmony_ci tgt->sess_count--; 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci qla2x00_set_fcport_disc_state(sess, DSC_DELETED); 10558c2ecf20Sopenharmony_ci sess->fw_login_state = DSC_LS_PORT_UNAVAIL; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (sess->login_succ && !IS_SW_RESV_ADDR(sess->d_id)) { 10588c2ecf20Sopenharmony_ci vha->fcport_count--; 10598c2ecf20Sopenharmony_ci sess->login_succ = 0; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci qla2x00_clear_loop_id(sess); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (sess->conflict) { 10658c2ecf20Sopenharmony_ci sess->conflict->login_pause = 0; 10668c2ecf20Sopenharmony_ci sess->conflict = NULL; 10678c2ecf20Sopenharmony_ci if (!test_bit(UNLOADING, &vha->dpc_flags)) 10688c2ecf20Sopenharmony_ci set_bit(RELOGIN_NEEDED, &vha->dpc_flags); 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci { 10728c2ecf20Sopenharmony_ci struct qlt_plogi_ack_t *con = 10738c2ecf20Sopenharmony_ci sess->plogi_link[QLT_PLOGI_LINK_CONFLICT]; 10748c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *iocb; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci own = sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN]; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (con) { 10798c2ecf20Sopenharmony_ci iocb = &con->iocb; 10808c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf099, 10818c2ecf20Sopenharmony_ci "se_sess %p / sess %p port %8phC is gone," 10828c2ecf20Sopenharmony_ci " %s (ref=%d), releasing PLOGI for %8phC (ref=%d)\n", 10838c2ecf20Sopenharmony_ci sess->se_sess, sess, sess->port_name, 10848c2ecf20Sopenharmony_ci own ? "releasing own PLOGI" : "no own PLOGI pending", 10858c2ecf20Sopenharmony_ci own ? own->ref_count : -1, 10868c2ecf20Sopenharmony_ci iocb->u.isp24.port_name, con->ref_count); 10878c2ecf20Sopenharmony_ci qlt_plogi_ack_unref(vha, con); 10888c2ecf20Sopenharmony_ci sess->plogi_link[QLT_PLOGI_LINK_CONFLICT] = NULL; 10898c2ecf20Sopenharmony_ci } else { 10908c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09a, 10918c2ecf20Sopenharmony_ci "se_sess %p / sess %p port %8phC is gone, %s (ref=%d)\n", 10928c2ecf20Sopenharmony_ci sess->se_sess, sess, sess->port_name, 10938c2ecf20Sopenharmony_ci own ? "releasing own PLOGI" : 10948c2ecf20Sopenharmony_ci "no own PLOGI pending", 10958c2ecf20Sopenharmony_ci own ? own->ref_count : -1); 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (own) { 10998c2ecf20Sopenharmony_ci sess->fw_login_state = DSC_LS_PLOGI_PEND; 11008c2ecf20Sopenharmony_ci qlt_plogi_ack_unref(vha, own); 11018c2ecf20Sopenharmony_ci sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN] = NULL; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci sess->explicit_logout = 0; 11068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci qla2x00_dfs_remove_rport(vha, sess); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 11118c2ecf20Sopenharmony_ci sess->flags &= ~FCF_ASYNC_SENT; 11128c2ecf20Sopenharmony_ci sess->deleted = QLA_SESS_DELETED; 11138c2ecf20Sopenharmony_ci sess->free_pending = 0; 11148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xf001, 11178c2ecf20Sopenharmony_ci "Unregistration of sess %p %8phC finished fcp_cnt %d\n", 11188c2ecf20Sopenharmony_ci sess, sess->port_name, vha->fcport_count); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci if (tgt && (tgt->sess_count == 0)) 11218c2ecf20Sopenharmony_ci wake_up_all(&tgt->waitQ); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (!test_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags) && 11248c2ecf20Sopenharmony_ci !(vha->vp_idx && test_bit(VPORT_DELETE, &vha->dpc_flags)) && 11258c2ecf20Sopenharmony_ci (!tgt || !tgt->tgt_stop) && !LOOP_TRANSITION(vha)) { 11268c2ecf20Sopenharmony_ci switch (vha->host->active_mode) { 11278c2ecf20Sopenharmony_ci case MODE_INITIATOR: 11288c2ecf20Sopenharmony_ci case MODE_DUAL: 11298c2ecf20Sopenharmony_ci set_bit(RELOGIN_NEEDED, &vha->dpc_flags); 11308c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(vha); 11318c2ecf20Sopenharmony_ci break; 11328c2ecf20Sopenharmony_ci case MODE_TARGET: 11338c2ecf20Sopenharmony_ci default: 11348c2ecf20Sopenharmony_ci /* no-op */ 11358c2ecf20Sopenharmony_ci break; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci if (vha->fcport_count == 0) 11408c2ecf20Sopenharmony_ci wake_up_all(&vha->fcport_waitQ); 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci/* ha->tgt.sess_lock supposed to be held on entry */ 11448c2ecf20Sopenharmony_civoid qlt_unreg_sess(struct fc_port *sess) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sess->vha; 11478c2ecf20Sopenharmony_ci unsigned long flags; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, sess->vha, 0x210a, 11508c2ecf20Sopenharmony_ci "%s sess %p for deletion %8phC\n", 11518c2ecf20Sopenharmony_ci __func__, sess, sess->port_name); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci spin_lock_irqsave(&sess->vha->work_lock, flags); 11548c2ecf20Sopenharmony_ci if (sess->free_pending) { 11558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sess->vha->work_lock, flags); 11568c2ecf20Sopenharmony_ci return; 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci sess->free_pending = 1; 11598c2ecf20Sopenharmony_ci /* 11608c2ecf20Sopenharmony_ci * Use FCF_ASYNC_SENT flag to block other cmds used in sess 11618c2ecf20Sopenharmony_ci * management from being sent. 11628c2ecf20Sopenharmony_ci */ 11638c2ecf20Sopenharmony_ci sess->flags |= FCF_ASYNC_SENT; 11648c2ecf20Sopenharmony_ci sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; 11658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sess->vha->work_lock, flags); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (sess->se_sess) 11688c2ecf20Sopenharmony_ci vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci qla2x00_set_fcport_disc_state(sess, DSC_DELETE_PEND); 11718c2ecf20Sopenharmony_ci sess->last_rscn_gen = sess->rscn_gen; 11728c2ecf20Sopenharmony_ci sess->last_login_gen = sess->login_gen; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci queue_work(sess->vha->hw->wq, &sess->free_work); 11758c2ecf20Sopenharmony_ci} 11768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_unreg_sess); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_cistatic int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 11818c2ecf20Sopenharmony_ci struct fc_port *sess = NULL; 11828c2ecf20Sopenharmony_ci uint16_t loop_id; 11838c2ecf20Sopenharmony_ci int res = 0; 11848c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *n = (struct imm_ntfy_from_isp *)iocb; 11858c2ecf20Sopenharmony_ci unsigned long flags; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci loop_id = le16_to_cpu(n->u.isp24.nport_handle); 11888c2ecf20Sopenharmony_ci if (loop_id == 0xFFFF) { 11898c2ecf20Sopenharmony_ci /* Global event */ 11908c2ecf20Sopenharmony_ci atomic_inc(&vha->vha_tgt.qla_tgt->tgt_global_resets_count); 11918c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 11928c2ecf20Sopenharmony_ci qlt_clear_tgt_db(vha->vha_tgt.qla_tgt); 11938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 11948c2ecf20Sopenharmony_ci } else { 11958c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 11968c2ecf20Sopenharmony_ci sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id); 11978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe000, 12018c2ecf20Sopenharmony_ci "Using sess for qla_tgt_reset: %p\n", sess); 12028c2ecf20Sopenharmony_ci if (!sess) { 12038c2ecf20Sopenharmony_ci res = -ESRCH; 12048c2ecf20Sopenharmony_ci return res; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe047, 12088c2ecf20Sopenharmony_ci "scsi(%ld): resetting (session %p from port %8phC mcmd %x, " 12098c2ecf20Sopenharmony_ci "loop_id %d)\n", vha->host_no, sess, sess->port_name, 12108c2ecf20Sopenharmony_ci mcmd, loop_id); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci return qlt_issue_task_mgmt(sess, 0, mcmd, iocb, QLA24XX_MGMT_SEND_NACK); 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic void qla24xx_chk_fcp_state(struct fc_port *sess) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci if (sess->chip_reset != sess->vha->hw->base_qpair->chip_reset) { 12188c2ecf20Sopenharmony_ci sess->logout_on_delete = 0; 12198c2ecf20Sopenharmony_ci sess->logo_ack_needed = 0; 12208c2ecf20Sopenharmony_ci sess->fw_login_state = DSC_LS_PORT_UNAVAIL; 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_civoid qlt_schedule_sess_for_deletion(struct fc_port *sess) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci struct qla_tgt *tgt = sess->tgt; 12278c2ecf20Sopenharmony_ci unsigned long flags; 12288c2ecf20Sopenharmony_ci u16 sec; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci switch (sess->disc_state) { 12318c2ecf20Sopenharmony_ci case DSC_DELETE_PEND: 12328c2ecf20Sopenharmony_ci return; 12338c2ecf20Sopenharmony_ci case DSC_DELETED: 12348c2ecf20Sopenharmony_ci if (!sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN] && 12358c2ecf20Sopenharmony_ci !sess->plogi_link[QLT_PLOGI_LINK_CONFLICT]) { 12368c2ecf20Sopenharmony_ci if (tgt && tgt->tgt_stop && tgt->sess_count == 0) 12378c2ecf20Sopenharmony_ci wake_up_all(&tgt->waitQ); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (sess->vha->fcport_count == 0) 12408c2ecf20Sopenharmony_ci wake_up_all(&sess->vha->fcport_waitQ); 12418c2ecf20Sopenharmony_ci return; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci break; 12448c2ecf20Sopenharmony_ci case DSC_UPD_FCPORT: 12458c2ecf20Sopenharmony_ci /* 12468c2ecf20Sopenharmony_ci * This port is not done reporting to upper layer. 12478c2ecf20Sopenharmony_ci * let it finish 12488c2ecf20Sopenharmony_ci */ 12498c2ecf20Sopenharmony_ci sess->next_disc_state = DSC_DELETE_PEND; 12508c2ecf20Sopenharmony_ci sec = jiffies_to_msecs(jiffies - 12518c2ecf20Sopenharmony_ci sess->jiffies_at_registration)/1000; 12528c2ecf20Sopenharmony_ci if (sess->sec_since_registration < sec && sec && !(sec % 5)) { 12538c2ecf20Sopenharmony_ci sess->sec_since_registration = sec; 12548c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, sess->vha, 0xffff, 12558c2ecf20Sopenharmony_ci "%s %8phC : Slow Rport registration(%d Sec)\n", 12568c2ecf20Sopenharmony_ci __func__, sess->port_name, sec); 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci return; 12598c2ecf20Sopenharmony_ci default: 12608c2ecf20Sopenharmony_ci break; 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci spin_lock_irqsave(&sess->vha->work_lock, flags); 12648c2ecf20Sopenharmony_ci if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { 12658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sess->vha->work_lock, flags); 12668c2ecf20Sopenharmony_ci return; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; 12698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sess->vha->work_lock, flags); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci sess->prli_pend_timer = 0; 12728c2ecf20Sopenharmony_ci qla2x00_set_fcport_disc_state(sess, DSC_DELETE_PEND); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci qla24xx_chk_fcp_state(sess); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, sess->vha, 0xe001, 12778c2ecf20Sopenharmony_ci "Scheduling sess %p for deletion %8phC\n", 12788c2ecf20Sopenharmony_ci sess, sess->port_name); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci WARN_ON(!queue_work(sess->vha->hw->wq, &sess->del_work)); 12818c2ecf20Sopenharmony_ci} 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_cistatic void qlt_clear_tgt_db(struct qla_tgt *tgt) 12848c2ecf20Sopenharmony_ci{ 12858c2ecf20Sopenharmony_ci struct fc_port *sess; 12868c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = tgt->vha; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci list_for_each_entry(sess, &vha->vp_fcports, list) { 12898c2ecf20Sopenharmony_ci if (sess->se_sess) 12908c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(sess); 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci /* At this point tgt could be already dead */ 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_cistatic int qla24xx_get_loop_id(struct scsi_qla_host *vha, be_id_t s_id, 12978c2ecf20Sopenharmony_ci uint16_t *loop_id) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 13008c2ecf20Sopenharmony_ci dma_addr_t gid_list_dma; 13018c2ecf20Sopenharmony_ci struct gid_list_info *gid_list, *gid; 13028c2ecf20Sopenharmony_ci int res, rc, i; 13038c2ecf20Sopenharmony_ci uint16_t entries; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci gid_list = dma_alloc_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), 13068c2ecf20Sopenharmony_ci &gid_list_dma, GFP_KERNEL); 13078c2ecf20Sopenharmony_ci if (!gid_list) { 13088c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf044, 13098c2ecf20Sopenharmony_ci "qla_target(%d): DMA Alloc failed of %u\n", 13108c2ecf20Sopenharmony_ci vha->vp_idx, qla2x00_gid_list_size(ha)); 13118c2ecf20Sopenharmony_ci return -ENOMEM; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* Get list of logged in devices */ 13158c2ecf20Sopenharmony_ci rc = qla24xx_gidlist_wait(vha, gid_list, gid_list_dma, &entries); 13168c2ecf20Sopenharmony_ci if (rc != QLA_SUCCESS) { 13178c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf045, 13188c2ecf20Sopenharmony_ci "qla_target(%d): get_id_list() failed: %x\n", 13198c2ecf20Sopenharmony_ci vha->vp_idx, rc); 13208c2ecf20Sopenharmony_ci res = -EBUSY; 13218c2ecf20Sopenharmony_ci goto out_free_id_list; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci gid = gid_list; 13258c2ecf20Sopenharmony_ci res = -ENOENT; 13268c2ecf20Sopenharmony_ci for (i = 0; i < entries; i++) { 13278c2ecf20Sopenharmony_ci if (gid->al_pa == s_id.al_pa && 13288c2ecf20Sopenharmony_ci gid->area == s_id.area && 13298c2ecf20Sopenharmony_ci gid->domain == s_id.domain) { 13308c2ecf20Sopenharmony_ci *loop_id = le16_to_cpu(gid->loop_id); 13318c2ecf20Sopenharmony_ci res = 0; 13328c2ecf20Sopenharmony_ci break; 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci gid = (void *)gid + ha->gid_list_info_size; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ciout_free_id_list: 13388c2ecf20Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), 13398c2ecf20Sopenharmony_ci gid_list, gid_list_dma); 13408c2ecf20Sopenharmony_ci return res; 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci/* 13448c2ecf20Sopenharmony_ci * Adds an extra ref to allow to drop hw lock after adding sess to the list. 13458c2ecf20Sopenharmony_ci * Caller must put it. 13468c2ecf20Sopenharmony_ci */ 13478c2ecf20Sopenharmony_cistatic struct fc_port *qlt_create_sess( 13488c2ecf20Sopenharmony_ci struct scsi_qla_host *vha, 13498c2ecf20Sopenharmony_ci fc_port_t *fcport, 13508c2ecf20Sopenharmony_ci bool local) 13518c2ecf20Sopenharmony_ci{ 13528c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 13538c2ecf20Sopenharmony_ci struct fc_port *sess = fcport; 13548c2ecf20Sopenharmony_ci unsigned long flags; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci if (vha->vha_tgt.qla_tgt->tgt_stop) 13578c2ecf20Sopenharmony_ci return NULL; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci if (fcport->se_sess) { 13608c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&sess->sess_kref)) { 13618c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f6, 13628c2ecf20Sopenharmony_ci "%s: kref_get_unless_zero failed for %8phC\n", 13638c2ecf20Sopenharmony_ci __func__, sess->port_name); 13648c2ecf20Sopenharmony_ci return NULL; 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci return fcport; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci sess->tgt = vha->vha_tgt.qla_tgt; 13698c2ecf20Sopenharmony_ci sess->local = local; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci /* 13728c2ecf20Sopenharmony_ci * Under normal circumstances we want to logout from firmware when 13738c2ecf20Sopenharmony_ci * session eventually ends and release corresponding nport handle. 13748c2ecf20Sopenharmony_ci * In the exception cases (e.g. when new PLOGI is waiting) corresponding 13758c2ecf20Sopenharmony_ci * code will adjust these flags as necessary. 13768c2ecf20Sopenharmony_ci */ 13778c2ecf20Sopenharmony_ci sess->logout_on_delete = 1; 13788c2ecf20Sopenharmony_ci sess->keep_nport_handle = 0; 13798c2ecf20Sopenharmony_ci sess->logout_completed = 0; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (ha->tgt.tgt_ops->check_initiator_node_acl(vha, 13828c2ecf20Sopenharmony_ci &fcport->port_name[0], sess) < 0) { 13838c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf015, 13848c2ecf20Sopenharmony_ci "(%d) %8phC check_initiator_node_acl failed\n", 13858c2ecf20Sopenharmony_ci vha->vp_idx, fcport->port_name); 13868c2ecf20Sopenharmony_ci return NULL; 13878c2ecf20Sopenharmony_ci } else { 13888c2ecf20Sopenharmony_ci kref_init(&fcport->sess_kref); 13898c2ecf20Sopenharmony_ci /* 13908c2ecf20Sopenharmony_ci * Take an extra reference to ->sess_kref here to handle 13918c2ecf20Sopenharmony_ci * fc_port access across ->tgt.sess_lock reaquire. 13928c2ecf20Sopenharmony_ci */ 13938c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&sess->sess_kref)) { 13948c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f7, 13958c2ecf20Sopenharmony_ci "%s: kref_get_unless_zero failed for %8phC\n", 13968c2ecf20Sopenharmony_ci __func__, sess->port_name); 13978c2ecf20Sopenharmony_ci return NULL; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 14018c2ecf20Sopenharmony_ci if (!IS_SW_RESV_ADDR(sess->d_id)) 14028c2ecf20Sopenharmony_ci vha->vha_tgt.qla_tgt->sess_count++; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci qlt_do_generation_tick(vha, &sess->generation); 14058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf006, 14098c2ecf20Sopenharmony_ci "Adding sess %p se_sess %p to tgt %p sess_count %d\n", 14108c2ecf20Sopenharmony_ci sess, sess->se_sess, vha->vha_tgt.qla_tgt, 14118c2ecf20Sopenharmony_ci vha->vha_tgt.qla_tgt->sess_count); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b, 14148c2ecf20Sopenharmony_ci "qla_target(%d): %ssession for wwn %8phC (loop_id %d, " 14158c2ecf20Sopenharmony_ci "s_id %x:%x:%x, confirmed completion %ssupported) added\n", 14168c2ecf20Sopenharmony_ci vha->vp_idx, local ? "local " : "", fcport->port_name, 14178c2ecf20Sopenharmony_ci fcport->loop_id, sess->d_id.b.domain, sess->d_id.b.area, 14188c2ecf20Sopenharmony_ci sess->d_id.b.al_pa, sess->conf_compl_supported ? "" : "not "); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci return sess; 14218c2ecf20Sopenharmony_ci} 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci/* 14248c2ecf20Sopenharmony_ci * max_gen - specifies maximum session generation 14258c2ecf20Sopenharmony_ci * at which this deletion requestion is still valid 14268c2ecf20Sopenharmony_ci */ 14278c2ecf20Sopenharmony_civoid 14288c2ecf20Sopenharmony_ciqlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen) 14298c2ecf20Sopenharmony_ci{ 14308c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 14318c2ecf20Sopenharmony_ci struct fc_port *sess = fcport; 14328c2ecf20Sopenharmony_ci unsigned long flags; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (!vha->hw->tgt.tgt_ops) 14358c2ecf20Sopenharmony_ci return; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci if (!tgt) 14388c2ecf20Sopenharmony_ci return; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 14418c2ecf20Sopenharmony_ci if (tgt->tgt_stop) { 14428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 14438c2ecf20Sopenharmony_ci return; 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci if (!sess->se_sess) { 14468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 14478c2ecf20Sopenharmony_ci return; 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (max_gen - sess->generation < 0) { 14518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 14528c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf092, 14538c2ecf20Sopenharmony_ci "Ignoring stale deletion request for se_sess %p / sess %p" 14548c2ecf20Sopenharmony_ci " for port %8phC, req_gen %d, sess_gen %d\n", 14558c2ecf20Sopenharmony_ci sess->se_sess, sess, sess->port_name, max_gen, 14568c2ecf20Sopenharmony_ci sess->generation); 14578c2ecf20Sopenharmony_ci return; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf008, "qla_tgt_fc_port_deleted %p", sess); 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci sess->local = 1; 14638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 14648c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(sess); 14658c2ecf20Sopenharmony_ci} 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic inline int test_tgt_sess_count(struct qla_tgt *tgt) 14688c2ecf20Sopenharmony_ci{ 14698c2ecf20Sopenharmony_ci struct qla_hw_data *ha = tgt->ha; 14708c2ecf20Sopenharmony_ci unsigned long flags; 14718c2ecf20Sopenharmony_ci int res; 14728c2ecf20Sopenharmony_ci /* 14738c2ecf20Sopenharmony_ci * We need to protect against race, when tgt is freed before or 14748c2ecf20Sopenharmony_ci * inside wake_up() 14758c2ecf20Sopenharmony_ci */ 14768c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 14778c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, tgt->vha, 0xe002, 14788c2ecf20Sopenharmony_ci "tgt %p, sess_count=%d\n", 14798c2ecf20Sopenharmony_ci tgt, tgt->sess_count); 14808c2ecf20Sopenharmony_ci res = (tgt->sess_count == 0); 14818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci return res; 14848c2ecf20Sopenharmony_ci} 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci/* Called by tcm_qla2xxx configfs code */ 14878c2ecf20Sopenharmony_ciint qlt_stop_phase1(struct qla_tgt *tgt) 14888c2ecf20Sopenharmony_ci{ 14898c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = tgt->vha; 14908c2ecf20Sopenharmony_ci struct qla_hw_data *ha = tgt->ha; 14918c2ecf20Sopenharmony_ci unsigned long flags; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci mutex_lock(&ha->optrom_mutex); 14948c2ecf20Sopenharmony_ci mutex_lock(&qla_tgt_mutex); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci if (tgt->tgt_stop || tgt->tgt_stopped) { 14978c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e, 14988c2ecf20Sopenharmony_ci "Already in tgt->tgt_stop or tgt_stopped state\n"); 14998c2ecf20Sopenharmony_ci mutex_unlock(&qla_tgt_mutex); 15008c2ecf20Sopenharmony_ci mutex_unlock(&ha->optrom_mutex); 15018c2ecf20Sopenharmony_ci return -EPERM; 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xe003, "Stopping target for host %ld(%p)\n", 15058c2ecf20Sopenharmony_ci vha->host_no, vha); 15068c2ecf20Sopenharmony_ci /* 15078c2ecf20Sopenharmony_ci * Mutex needed to sync with qla_tgt_fc_port_[added,deleted]. 15088c2ecf20Sopenharmony_ci * Lock is needed, because we still can get an incoming packet. 15098c2ecf20Sopenharmony_ci */ 15108c2ecf20Sopenharmony_ci mutex_lock(&vha->vha_tgt.tgt_mutex); 15118c2ecf20Sopenharmony_ci tgt->tgt_stop = 1; 15128c2ecf20Sopenharmony_ci qlt_clear_tgt_db(tgt); 15138c2ecf20Sopenharmony_ci mutex_unlock(&vha->vha_tgt.tgt_mutex); 15148c2ecf20Sopenharmony_ci mutex_unlock(&qla_tgt_mutex); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf009, 15178c2ecf20Sopenharmony_ci "Waiting for sess works (tgt %p)", tgt); 15188c2ecf20Sopenharmony_ci spin_lock_irqsave(&tgt->sess_work_lock, flags); 15198c2ecf20Sopenharmony_ci while (!list_empty(&tgt->sess_works_list)) { 15208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tgt->sess_work_lock, flags); 15218c2ecf20Sopenharmony_ci flush_scheduled_work(); 15228c2ecf20Sopenharmony_ci spin_lock_irqsave(&tgt->sess_work_lock, flags); 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tgt->sess_work_lock, flags); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00a, 15278c2ecf20Sopenharmony_ci "Waiting for tgt %p: sess_count=%d\n", tgt, tgt->sess_count); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci wait_event_timeout(tgt->waitQ, test_tgt_sess_count(tgt), 10*HZ); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci /* Big hammer */ 15328c2ecf20Sopenharmony_ci if (!ha->flags.host_shutting_down && 15338c2ecf20Sopenharmony_ci (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha))) 15348c2ecf20Sopenharmony_ci qlt_disable_vha(vha); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci /* Wait for sessions to clear out (just in case) */ 15378c2ecf20Sopenharmony_ci wait_event_timeout(tgt->waitQ, test_tgt_sess_count(tgt), 10*HZ); 15388c2ecf20Sopenharmony_ci mutex_unlock(&ha->optrom_mutex); 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci return 0; 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_stop_phase1); 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci/* Called by tcm_qla2xxx configfs code */ 15458c2ecf20Sopenharmony_civoid qlt_stop_phase2(struct qla_tgt *tgt) 15468c2ecf20Sopenharmony_ci{ 15478c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = tgt->vha; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (tgt->tgt_stopped) { 15508c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04f, 15518c2ecf20Sopenharmony_ci "Already in tgt->tgt_stopped state\n"); 15528c2ecf20Sopenharmony_ci dump_stack(); 15538c2ecf20Sopenharmony_ci return; 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci if (!tgt->tgt_stop) { 15568c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00b, 15578c2ecf20Sopenharmony_ci "%s: phase1 stop is not completed\n", __func__); 15588c2ecf20Sopenharmony_ci dump_stack(); 15598c2ecf20Sopenharmony_ci return; 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci mutex_lock(&tgt->ha->optrom_mutex); 15638c2ecf20Sopenharmony_ci mutex_lock(&vha->vha_tgt.tgt_mutex); 15648c2ecf20Sopenharmony_ci tgt->tgt_stop = 0; 15658c2ecf20Sopenharmony_ci tgt->tgt_stopped = 1; 15668c2ecf20Sopenharmony_ci mutex_unlock(&vha->vha_tgt.tgt_mutex); 15678c2ecf20Sopenharmony_ci mutex_unlock(&tgt->ha->optrom_mutex); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00c, "Stop of tgt %p finished\n", 15708c2ecf20Sopenharmony_ci tgt); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci switch (vha->qlini_mode) { 15738c2ecf20Sopenharmony_ci case QLA2XXX_INI_MODE_EXCLUSIVE: 15748c2ecf20Sopenharmony_ci vha->flags.online = 1; 15758c2ecf20Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 15768c2ecf20Sopenharmony_ci break; 15778c2ecf20Sopenharmony_ci default: 15788c2ecf20Sopenharmony_ci break; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci} 15818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_stop_phase2); 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci/* Called from qlt_remove_target() -> qla2x00_remove_one() */ 15848c2ecf20Sopenharmony_cistatic void qlt_release(struct qla_tgt *tgt) 15858c2ecf20Sopenharmony_ci{ 15868c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = tgt->vha; 15878c2ecf20Sopenharmony_ci void *node; 15888c2ecf20Sopenharmony_ci u64 key = 0; 15898c2ecf20Sopenharmony_ci u16 i; 15908c2ecf20Sopenharmony_ci struct qla_qpair_hint *h; 15918c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (!tgt->tgt_stop && !tgt->tgt_stopped) 15948c2ecf20Sopenharmony_ci qlt_stop_phase1(tgt); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if (!tgt->tgt_stopped) 15978c2ecf20Sopenharmony_ci qlt_stop_phase2(tgt); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci for (i = 0; i < vha->hw->max_qpairs + 1; i++) { 16008c2ecf20Sopenharmony_ci unsigned long flags; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci h = &tgt->qphints[i]; 16038c2ecf20Sopenharmony_ci if (h->qpair) { 16048c2ecf20Sopenharmony_ci spin_lock_irqsave(h->qpair->qp_lock_ptr, flags); 16058c2ecf20Sopenharmony_ci list_del(&h->hint_elem); 16068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(h->qpair->qp_lock_ptr, flags); 16078c2ecf20Sopenharmony_ci h->qpair = NULL; 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci kfree(tgt->qphints); 16118c2ecf20Sopenharmony_ci mutex_lock(&qla_tgt_mutex); 16128c2ecf20Sopenharmony_ci list_del(&vha->vha_tgt.qla_tgt->tgt_list_entry); 16138c2ecf20Sopenharmony_ci mutex_unlock(&qla_tgt_mutex); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci btree_for_each_safe64(&tgt->lun_qpair_map, key, node) 16168c2ecf20Sopenharmony_ci btree_remove64(&tgt->lun_qpair_map, key); 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci btree_destroy64(&tgt->lun_qpair_map); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if (vha->vp_idx) 16218c2ecf20Sopenharmony_ci if (ha->tgt.tgt_ops && 16228c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->remove_target && 16238c2ecf20Sopenharmony_ci vha->vha_tgt.target_lport_ptr) 16248c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->remove_target(vha); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci vha->vha_tgt.qla_tgt = NULL; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00d, 16298c2ecf20Sopenharmony_ci "Release of tgt %p finished\n", tgt); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci kfree(tgt); 16328c2ecf20Sopenharmony_ci} 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 16358c2ecf20Sopenharmony_cistatic int qlt_sched_sess_work(struct qla_tgt *tgt, int type, 16368c2ecf20Sopenharmony_ci const void *param, unsigned int param_size) 16378c2ecf20Sopenharmony_ci{ 16388c2ecf20Sopenharmony_ci struct qla_tgt_sess_work_param *prm; 16398c2ecf20Sopenharmony_ci unsigned long flags; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci prm = kzalloc(sizeof(*prm), GFP_ATOMIC); 16428c2ecf20Sopenharmony_ci if (!prm) { 16438c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf050, 16448c2ecf20Sopenharmony_ci "qla_target(%d): Unable to create session " 16458c2ecf20Sopenharmony_ci "work, command will be refused", 0); 16468c2ecf20Sopenharmony_ci return -ENOMEM; 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf00e, 16508c2ecf20Sopenharmony_ci "Scheduling work (type %d, prm %p)" 16518c2ecf20Sopenharmony_ci " to find session for param %p (size %d, tgt %p)\n", 16528c2ecf20Sopenharmony_ci type, prm, param, param_size, tgt); 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci prm->type = type; 16558c2ecf20Sopenharmony_ci memcpy(&prm->tm_iocb, param, param_size); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci spin_lock_irqsave(&tgt->sess_work_lock, flags); 16588c2ecf20Sopenharmony_ci list_add_tail(&prm->sess_works_list_entry, &tgt->sess_works_list); 16598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tgt->sess_work_lock, flags); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci schedule_work(&tgt->sess_work); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci return 0; 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci/* 16678c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 16688c2ecf20Sopenharmony_ci */ 16698c2ecf20Sopenharmony_cistatic void qlt_send_notify_ack(struct qla_qpair *qpair, 16708c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *ntfy, 16718c2ecf20Sopenharmony_ci uint32_t add_flags, uint16_t resp_code, int resp_code_valid, 16728c2ecf20Sopenharmony_ci uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan) 16738c2ecf20Sopenharmony_ci{ 16748c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = qpair->vha; 16758c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 16768c2ecf20Sopenharmony_ci request_t *pkt; 16778c2ecf20Sopenharmony_ci struct nack_to_isp *nack; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci if (!ha->flags.fw_started) 16808c2ecf20Sopenharmony_ci return; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe004, "Sending NOTIFY_ACK (ha=%p)\n", ha); 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci pkt = (request_t *)__qla2x00_alloc_iocbs(qpair, NULL); 16858c2ecf20Sopenharmony_ci if (!pkt) { 16868c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe049, 16878c2ecf20Sopenharmony_ci "qla_target(%d): %s failed: unable to allocate " 16888c2ecf20Sopenharmony_ci "request packet\n", vha->vp_idx, __func__); 16898c2ecf20Sopenharmony_ci return; 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci if (vha->vha_tgt.qla_tgt != NULL) 16938c2ecf20Sopenharmony_ci vha->vha_tgt.qla_tgt->notify_ack_expected++; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci pkt->entry_type = NOTIFY_ACK_TYPE; 16968c2ecf20Sopenharmony_ci pkt->entry_count = 1; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci nack = (struct nack_to_isp *)pkt; 16998c2ecf20Sopenharmony_ci nack->ox_id = ntfy->ox_id; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci nack->u.isp24.handle = QLA_TGT_SKIP_HANDLE; 17028c2ecf20Sopenharmony_ci nack->u.isp24.nport_handle = ntfy->u.isp24.nport_handle; 17038c2ecf20Sopenharmony_ci if (le16_to_cpu(ntfy->u.isp24.status) == IMM_NTFY_ELS) { 17048c2ecf20Sopenharmony_ci nack->u.isp24.flags = ntfy->u.isp24.flags & 17058c2ecf20Sopenharmony_ci cpu_to_le16(NOTIFY24XX_FLAGS_PUREX_IOCB); 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci nack->u.isp24.srr_rx_id = ntfy->u.isp24.srr_rx_id; 17088c2ecf20Sopenharmony_ci nack->u.isp24.status = ntfy->u.isp24.status; 17098c2ecf20Sopenharmony_ci nack->u.isp24.status_subcode = ntfy->u.isp24.status_subcode; 17108c2ecf20Sopenharmony_ci nack->u.isp24.fw_handle = ntfy->u.isp24.fw_handle; 17118c2ecf20Sopenharmony_ci nack->u.isp24.exchange_address = ntfy->u.isp24.exchange_address; 17128c2ecf20Sopenharmony_ci nack->u.isp24.srr_rel_offs = ntfy->u.isp24.srr_rel_offs; 17138c2ecf20Sopenharmony_ci nack->u.isp24.srr_ui = ntfy->u.isp24.srr_ui; 17148c2ecf20Sopenharmony_ci nack->u.isp24.srr_flags = cpu_to_le16(srr_flags); 17158c2ecf20Sopenharmony_ci nack->u.isp24.srr_reject_code = srr_reject_code; 17168c2ecf20Sopenharmony_ci nack->u.isp24.srr_reject_code_expl = srr_explan; 17178c2ecf20Sopenharmony_ci nack->u.isp24.vp_index = ntfy->u.isp24.vp_index; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe005, 17208c2ecf20Sopenharmony_ci "qla_target(%d): Sending 24xx Notify Ack %d\n", 17218c2ecf20Sopenharmony_ci vha->vp_idx, nack->u.isp24.status); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci /* Memory Barrier */ 17248c2ecf20Sopenharmony_ci wmb(); 17258c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, qpair->req); 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_cistatic int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd) 17298c2ecf20Sopenharmony_ci{ 17308c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = mcmd->vha; 17318c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 17328c2ecf20Sopenharmony_ci struct abts_resp_to_24xx *resp; 17338c2ecf20Sopenharmony_ci __le32 f_ctl; 17348c2ecf20Sopenharmony_ci uint32_t h; 17358c2ecf20Sopenharmony_ci uint8_t *p; 17368c2ecf20Sopenharmony_ci int rc; 17378c2ecf20Sopenharmony_ci struct abts_recv_from_24xx *abts = &mcmd->orig_iocb.abts; 17388c2ecf20Sopenharmony_ci struct qla_qpair *qpair = mcmd->qpair; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe006, 17418c2ecf20Sopenharmony_ci "Sending task mgmt ABTS response (ha=%p, status=%x)\n", 17428c2ecf20Sopenharmony_ci ha, mcmd->fc_tm_rsp); 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci rc = qlt_check_reserve_free_req(qpair, 1); 17458c2ecf20Sopenharmony_ci if (rc) { 17468c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe04a, 17478c2ecf20Sopenharmony_ci "qla_target(%d): %s failed: unable to allocate request packet\n", 17488c2ecf20Sopenharmony_ci vha->vp_idx, __func__); 17498c2ecf20Sopenharmony_ci return -EAGAIN; 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci resp = (struct abts_resp_to_24xx *)qpair->req->ring_ptr; 17538c2ecf20Sopenharmony_ci memset(resp, 0, sizeof(*resp)); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci h = qlt_make_handle(qpair); 17568c2ecf20Sopenharmony_ci if (unlikely(h == QLA_TGT_NULL_HANDLE)) { 17578c2ecf20Sopenharmony_ci /* 17588c2ecf20Sopenharmony_ci * CTIO type 7 from the firmware doesn't provide a way to 17598c2ecf20Sopenharmony_ci * know the initiator's LOOP ID, hence we can't find 17608c2ecf20Sopenharmony_ci * the session and, so, the command. 17618c2ecf20Sopenharmony_ci */ 17628c2ecf20Sopenharmony_ci return -EAGAIN; 17638c2ecf20Sopenharmony_ci } else { 17648c2ecf20Sopenharmony_ci qpair->req->outstanding_cmds[h] = (srb_t *)mcmd; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci resp->handle = make_handle(qpair->req->id, h); 17688c2ecf20Sopenharmony_ci resp->entry_type = ABTS_RESP_24XX; 17698c2ecf20Sopenharmony_ci resp->entry_count = 1; 17708c2ecf20Sopenharmony_ci resp->nport_handle = abts->nport_handle; 17718c2ecf20Sopenharmony_ci resp->vp_index = vha->vp_idx; 17728c2ecf20Sopenharmony_ci resp->sof_type = abts->sof_type; 17738c2ecf20Sopenharmony_ci resp->exchange_address = abts->exchange_address; 17748c2ecf20Sopenharmony_ci resp->fcp_hdr_le = abts->fcp_hdr_le; 17758c2ecf20Sopenharmony_ci f_ctl = cpu_to_le32(F_CTL_EXCH_CONTEXT_RESP | 17768c2ecf20Sopenharmony_ci F_CTL_LAST_SEQ | F_CTL_END_SEQ | 17778c2ecf20Sopenharmony_ci F_CTL_SEQ_INITIATIVE); 17788c2ecf20Sopenharmony_ci p = (uint8_t *)&f_ctl; 17798c2ecf20Sopenharmony_ci resp->fcp_hdr_le.f_ctl[0] = *p++; 17808c2ecf20Sopenharmony_ci resp->fcp_hdr_le.f_ctl[1] = *p++; 17818c2ecf20Sopenharmony_ci resp->fcp_hdr_le.f_ctl[2] = *p; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci resp->fcp_hdr_le.d_id = abts->fcp_hdr_le.s_id; 17848c2ecf20Sopenharmony_ci resp->fcp_hdr_le.s_id = abts->fcp_hdr_le.d_id; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci resp->exchange_addr_to_abort = abts->exchange_addr_to_abort; 17878c2ecf20Sopenharmony_ci if (mcmd->fc_tm_rsp == FCP_TMF_CMPL) { 17888c2ecf20Sopenharmony_ci resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_ACC; 17898c2ecf20Sopenharmony_ci resp->payload.ba_acct.seq_id_valid = SEQ_ID_INVALID; 17908c2ecf20Sopenharmony_ci resp->payload.ba_acct.low_seq_cnt = 0x0000; 17918c2ecf20Sopenharmony_ci resp->payload.ba_acct.high_seq_cnt = cpu_to_le16(0xFFFF); 17928c2ecf20Sopenharmony_ci resp->payload.ba_acct.ox_id = abts->fcp_hdr_le.ox_id; 17938c2ecf20Sopenharmony_ci resp->payload.ba_acct.rx_id = abts->fcp_hdr_le.rx_id; 17948c2ecf20Sopenharmony_ci } else { 17958c2ecf20Sopenharmony_ci resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_RJT; 17968c2ecf20Sopenharmony_ci resp->payload.ba_rjt.reason_code = 17978c2ecf20Sopenharmony_ci BA_RJT_REASON_CODE_UNABLE_TO_PERFORM; 17988c2ecf20Sopenharmony_ci /* Other bytes are zero */ 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci vha->vha_tgt.qla_tgt->abts_resp_expected++; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci /* Memory Barrier */ 18048c2ecf20Sopenharmony_ci wmb(); 18058c2ecf20Sopenharmony_ci if (qpair->reqq_start_iocbs) 18068c2ecf20Sopenharmony_ci qpair->reqq_start_iocbs(qpair); 18078c2ecf20Sopenharmony_ci else 18088c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, qpair->req); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci return rc; 18118c2ecf20Sopenharmony_ci} 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci/* 18148c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 18158c2ecf20Sopenharmony_ci */ 18168c2ecf20Sopenharmony_cistatic void qlt_24xx_send_abts_resp(struct qla_qpair *qpair, 18178c2ecf20Sopenharmony_ci struct abts_recv_from_24xx *abts, uint32_t status, 18188c2ecf20Sopenharmony_ci bool ids_reversed) 18198c2ecf20Sopenharmony_ci{ 18208c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = qpair->vha; 18218c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 18228c2ecf20Sopenharmony_ci struct abts_resp_to_24xx *resp; 18238c2ecf20Sopenharmony_ci __le32 f_ctl; 18248c2ecf20Sopenharmony_ci uint8_t *p; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe006, 18278c2ecf20Sopenharmony_ci "Sending task mgmt ABTS response (ha=%p, atio=%p, status=%x\n", 18288c2ecf20Sopenharmony_ci ha, abts, status); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci resp = (struct abts_resp_to_24xx *)qla2x00_alloc_iocbs_ready(qpair, 18318c2ecf20Sopenharmony_ci NULL); 18328c2ecf20Sopenharmony_ci if (!resp) { 18338c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe04a, 18348c2ecf20Sopenharmony_ci "qla_target(%d): %s failed: unable to allocate " 18358c2ecf20Sopenharmony_ci "request packet", vha->vp_idx, __func__); 18368c2ecf20Sopenharmony_ci return; 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci resp->entry_type = ABTS_RESP_24XX; 18408c2ecf20Sopenharmony_ci resp->handle = QLA_TGT_SKIP_HANDLE; 18418c2ecf20Sopenharmony_ci resp->entry_count = 1; 18428c2ecf20Sopenharmony_ci resp->nport_handle = abts->nport_handle; 18438c2ecf20Sopenharmony_ci resp->vp_index = vha->vp_idx; 18448c2ecf20Sopenharmony_ci resp->sof_type = abts->sof_type; 18458c2ecf20Sopenharmony_ci resp->exchange_address = abts->exchange_address; 18468c2ecf20Sopenharmony_ci resp->fcp_hdr_le = abts->fcp_hdr_le; 18478c2ecf20Sopenharmony_ci f_ctl = cpu_to_le32(F_CTL_EXCH_CONTEXT_RESP | 18488c2ecf20Sopenharmony_ci F_CTL_LAST_SEQ | F_CTL_END_SEQ | 18498c2ecf20Sopenharmony_ci F_CTL_SEQ_INITIATIVE); 18508c2ecf20Sopenharmony_ci p = (uint8_t *)&f_ctl; 18518c2ecf20Sopenharmony_ci resp->fcp_hdr_le.f_ctl[0] = *p++; 18528c2ecf20Sopenharmony_ci resp->fcp_hdr_le.f_ctl[1] = *p++; 18538c2ecf20Sopenharmony_ci resp->fcp_hdr_le.f_ctl[2] = *p; 18548c2ecf20Sopenharmony_ci if (ids_reversed) { 18558c2ecf20Sopenharmony_ci resp->fcp_hdr_le.d_id = abts->fcp_hdr_le.d_id; 18568c2ecf20Sopenharmony_ci resp->fcp_hdr_le.s_id = abts->fcp_hdr_le.s_id; 18578c2ecf20Sopenharmony_ci } else { 18588c2ecf20Sopenharmony_ci resp->fcp_hdr_le.d_id = abts->fcp_hdr_le.s_id; 18598c2ecf20Sopenharmony_ci resp->fcp_hdr_le.s_id = abts->fcp_hdr_le.d_id; 18608c2ecf20Sopenharmony_ci } 18618c2ecf20Sopenharmony_ci resp->exchange_addr_to_abort = abts->exchange_addr_to_abort; 18628c2ecf20Sopenharmony_ci if (status == FCP_TMF_CMPL) { 18638c2ecf20Sopenharmony_ci resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_ACC; 18648c2ecf20Sopenharmony_ci resp->payload.ba_acct.seq_id_valid = SEQ_ID_INVALID; 18658c2ecf20Sopenharmony_ci resp->payload.ba_acct.low_seq_cnt = 0x0000; 18668c2ecf20Sopenharmony_ci resp->payload.ba_acct.high_seq_cnt = cpu_to_le16(0xFFFF); 18678c2ecf20Sopenharmony_ci resp->payload.ba_acct.ox_id = abts->fcp_hdr_le.ox_id; 18688c2ecf20Sopenharmony_ci resp->payload.ba_acct.rx_id = abts->fcp_hdr_le.rx_id; 18698c2ecf20Sopenharmony_ci } else { 18708c2ecf20Sopenharmony_ci resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_RJT; 18718c2ecf20Sopenharmony_ci resp->payload.ba_rjt.reason_code = 18728c2ecf20Sopenharmony_ci BA_RJT_REASON_CODE_UNABLE_TO_PERFORM; 18738c2ecf20Sopenharmony_ci /* Other bytes are zero */ 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci vha->vha_tgt.qla_tgt->abts_resp_expected++; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci /* Memory Barrier */ 18798c2ecf20Sopenharmony_ci wmb(); 18808c2ecf20Sopenharmony_ci if (qpair->reqq_start_iocbs) 18818c2ecf20Sopenharmony_ci qpair->reqq_start_iocbs(qpair); 18828c2ecf20Sopenharmony_ci else 18838c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, qpair->req); 18848c2ecf20Sopenharmony_ci} 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci/* 18878c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 18888c2ecf20Sopenharmony_ci */ 18898c2ecf20Sopenharmony_cistatic void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, 18908c2ecf20Sopenharmony_ci struct qla_qpair *qpair, response_t *pkt, struct qla_tgt_mgmt_cmd *mcmd) 18918c2ecf20Sopenharmony_ci{ 18928c2ecf20Sopenharmony_ci struct ctio7_to_24xx *ctio; 18938c2ecf20Sopenharmony_ci u16 tmp; 18948c2ecf20Sopenharmony_ci struct abts_recv_from_24xx *entry; 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready(qpair, NULL); 18978c2ecf20Sopenharmony_ci if (ctio == NULL) { 18988c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe04b, 18998c2ecf20Sopenharmony_ci "qla_target(%d): %s failed: unable to allocate " 19008c2ecf20Sopenharmony_ci "request packet\n", vha->vp_idx, __func__); 19018c2ecf20Sopenharmony_ci return; 19028c2ecf20Sopenharmony_ci } 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (mcmd) 19058c2ecf20Sopenharmony_ci /* abts from remote port */ 19068c2ecf20Sopenharmony_ci entry = &mcmd->orig_iocb.abts; 19078c2ecf20Sopenharmony_ci else 19088c2ecf20Sopenharmony_ci /* abts from this driver. */ 19098c2ecf20Sopenharmony_ci entry = (struct abts_recv_from_24xx *)pkt; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci /* 19128c2ecf20Sopenharmony_ci * We've got on entrance firmware's response on by us generated 19138c2ecf20Sopenharmony_ci * ABTS response. So, in it ID fields are reversed. 19148c2ecf20Sopenharmony_ci */ 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci ctio->entry_type = CTIO_TYPE7; 19178c2ecf20Sopenharmony_ci ctio->entry_count = 1; 19188c2ecf20Sopenharmony_ci ctio->nport_handle = entry->nport_handle; 19198c2ecf20Sopenharmony_ci ctio->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; 19208c2ecf20Sopenharmony_ci ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); 19218c2ecf20Sopenharmony_ci ctio->vp_index = vha->vp_idx; 19228c2ecf20Sopenharmony_ci ctio->exchange_addr = entry->exchange_addr_to_abort; 19238c2ecf20Sopenharmony_ci tmp = (CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_TERMINATE); 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci if (mcmd) { 19268c2ecf20Sopenharmony_ci ctio->initiator_id = entry->fcp_hdr_le.s_id; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci if (mcmd->flags & QLA24XX_MGMT_ABORT_IO_ATTR_VALID) 19298c2ecf20Sopenharmony_ci tmp |= (mcmd->abort_io_attr << 9); 19308c2ecf20Sopenharmony_ci else if (qpair->retry_term_cnt & 1) 19318c2ecf20Sopenharmony_ci tmp |= (0x4 << 9); 19328c2ecf20Sopenharmony_ci } else { 19338c2ecf20Sopenharmony_ci ctio->initiator_id = entry->fcp_hdr_le.d_id; 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci if (qpair->retry_term_cnt & 1) 19368c2ecf20Sopenharmony_ci tmp |= (0x4 << 9); 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci ctio->u.status1.flags = cpu_to_le16(tmp); 19398c2ecf20Sopenharmony_ci ctio->u.status1.ox_id = entry->fcp_hdr_le.ox_id; 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe007, 19428c2ecf20Sopenharmony_ci "Sending retry TERM EXCH CTIO7 flags %04xh oxid %04xh attr valid %x\n", 19438c2ecf20Sopenharmony_ci le16_to_cpu(ctio->u.status1.flags), 19448c2ecf20Sopenharmony_ci le16_to_cpu(ctio->u.status1.ox_id), 19458c2ecf20Sopenharmony_ci (mcmd && mcmd->flags & QLA24XX_MGMT_ABORT_IO_ATTR_VALID) ? 1 : 0); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci /* Memory Barrier */ 19488c2ecf20Sopenharmony_ci wmb(); 19498c2ecf20Sopenharmony_ci if (qpair->reqq_start_iocbs) 19508c2ecf20Sopenharmony_ci qpair->reqq_start_iocbs(qpair); 19518c2ecf20Sopenharmony_ci else 19528c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, qpair->req); 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci if (mcmd) 19558c2ecf20Sopenharmony_ci qlt_build_abts_resp_iocb(mcmd); 19568c2ecf20Sopenharmony_ci else 19578c2ecf20Sopenharmony_ci qlt_24xx_send_abts_resp(qpair, 19588c2ecf20Sopenharmony_ci (struct abts_recv_from_24xx *)entry, FCP_TMF_CMPL, true); 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci} 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci/* drop cmds for the given lun 19638c2ecf20Sopenharmony_ci * XXX only looks for cmds on the port through which lun reset was recieved 19648c2ecf20Sopenharmony_ci * XXX does not go through the list of other port (which may have cmds 19658c2ecf20Sopenharmony_ci * for the same lun) 19668c2ecf20Sopenharmony_ci */ 19678c2ecf20Sopenharmony_cistatic void abort_cmds_for_lun(struct scsi_qla_host *vha, u64 lun, be_id_t s_id) 19688c2ecf20Sopenharmony_ci{ 19698c2ecf20Sopenharmony_ci struct qla_tgt_sess_op *op; 19708c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd; 19718c2ecf20Sopenharmony_ci uint32_t key; 19728c2ecf20Sopenharmony_ci unsigned long flags; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci key = sid_to_key(s_id); 19758c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->cmd_list_lock, flags); 19768c2ecf20Sopenharmony_ci list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) { 19778c2ecf20Sopenharmony_ci uint32_t op_key; 19788c2ecf20Sopenharmony_ci u64 op_lun; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id); 19818c2ecf20Sopenharmony_ci op_lun = scsilun_to_int( 19828c2ecf20Sopenharmony_ci (struct scsi_lun *)&op->atio.u.isp24.fcp_cmnd.lun); 19838c2ecf20Sopenharmony_ci if (op_key == key && op_lun == lun) 19848c2ecf20Sopenharmony_ci op->aborted = true; 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci list_for_each_entry(op, &vha->unknown_atio_list, cmd_list) { 19888c2ecf20Sopenharmony_ci uint32_t op_key; 19898c2ecf20Sopenharmony_ci u64 op_lun; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id); 19928c2ecf20Sopenharmony_ci op_lun = scsilun_to_int( 19938c2ecf20Sopenharmony_ci (struct scsi_lun *)&op->atio.u.isp24.fcp_cmnd.lun); 19948c2ecf20Sopenharmony_ci if (op_key == key && op_lun == lun) 19958c2ecf20Sopenharmony_ci op->aborted = true; 19968c2ecf20Sopenharmony_ci } 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) { 19998c2ecf20Sopenharmony_ci uint32_t cmd_key; 20008c2ecf20Sopenharmony_ci u64 cmd_lun; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id); 20038c2ecf20Sopenharmony_ci cmd_lun = scsilun_to_int( 20048c2ecf20Sopenharmony_ci (struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun); 20058c2ecf20Sopenharmony_ci if (cmd_key == key && cmd_lun == lun) 20068c2ecf20Sopenharmony_ci cmd->aborted = 1; 20078c2ecf20Sopenharmony_ci } 20088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->cmd_list_lock, flags); 20098c2ecf20Sopenharmony_ci} 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_cistatic struct qla_qpair_hint *qlt_find_qphint(struct scsi_qla_host *vha, 20128c2ecf20Sopenharmony_ci uint64_t unpacked_lun) 20138c2ecf20Sopenharmony_ci{ 20148c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 20158c2ecf20Sopenharmony_ci struct qla_qpair_hint *h = NULL; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci if (vha->flags.qpairs_available) { 20188c2ecf20Sopenharmony_ci h = btree_lookup64(&tgt->lun_qpair_map, unpacked_lun); 20198c2ecf20Sopenharmony_ci if (!h) 20208c2ecf20Sopenharmony_ci h = &tgt->qphints[0]; 20218c2ecf20Sopenharmony_ci } else { 20228c2ecf20Sopenharmony_ci h = &tgt->qphints[0]; 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci return h; 20268c2ecf20Sopenharmony_ci} 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_cistatic void qlt_do_tmr_work(struct work_struct *work) 20298c2ecf20Sopenharmony_ci{ 20308c2ecf20Sopenharmony_ci struct qla_tgt_mgmt_cmd *mcmd = 20318c2ecf20Sopenharmony_ci container_of(work, struct qla_tgt_mgmt_cmd, work); 20328c2ecf20Sopenharmony_ci struct qla_hw_data *ha = mcmd->vha->hw; 20338c2ecf20Sopenharmony_ci int rc; 20348c2ecf20Sopenharmony_ci uint32_t tag; 20358c2ecf20Sopenharmony_ci unsigned long flags; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci switch (mcmd->tmr_func) { 20388c2ecf20Sopenharmony_ci case QLA_TGT_ABTS: 20398c2ecf20Sopenharmony_ci tag = le32_to_cpu(mcmd->orig_iocb.abts.exchange_addr_to_abort); 20408c2ecf20Sopenharmony_ci break; 20418c2ecf20Sopenharmony_ci default: 20428c2ecf20Sopenharmony_ci tag = 0; 20438c2ecf20Sopenharmony_ci break; 20448c2ecf20Sopenharmony_ci } 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci rc = ha->tgt.tgt_ops->handle_tmr(mcmd, mcmd->unpacked_lun, 20478c2ecf20Sopenharmony_ci mcmd->tmr_func, tag); 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci if (rc != 0) { 20508c2ecf20Sopenharmony_ci spin_lock_irqsave(mcmd->qpair->qp_lock_ptr, flags); 20518c2ecf20Sopenharmony_ci switch (mcmd->tmr_func) { 20528c2ecf20Sopenharmony_ci case QLA_TGT_ABTS: 20538c2ecf20Sopenharmony_ci mcmd->fc_tm_rsp = FCP_TMF_REJECTED; 20548c2ecf20Sopenharmony_ci qlt_build_abts_resp_iocb(mcmd); 20558c2ecf20Sopenharmony_ci break; 20568c2ecf20Sopenharmony_ci case QLA_TGT_LUN_RESET: 20578c2ecf20Sopenharmony_ci case QLA_TGT_CLEAR_TS: 20588c2ecf20Sopenharmony_ci case QLA_TGT_ABORT_TS: 20598c2ecf20Sopenharmony_ci case QLA_TGT_CLEAR_ACA: 20608c2ecf20Sopenharmony_ci case QLA_TGT_TARGET_RESET: 20618c2ecf20Sopenharmony_ci qlt_send_busy(mcmd->qpair, &mcmd->orig_iocb.atio, 20628c2ecf20Sopenharmony_ci qla_sam_status); 20638c2ecf20Sopenharmony_ci break; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci case QLA_TGT_ABORT_ALL: 20668c2ecf20Sopenharmony_ci case QLA_TGT_NEXUS_LOSS_SESS: 20678c2ecf20Sopenharmony_ci case QLA_TGT_NEXUS_LOSS: 20688c2ecf20Sopenharmony_ci qlt_send_notify_ack(mcmd->qpair, 20698c2ecf20Sopenharmony_ci &mcmd->orig_iocb.imm_ntfy, 0, 0, 0, 0, 0, 0); 20708c2ecf20Sopenharmony_ci break; 20718c2ecf20Sopenharmony_ci } 20728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(mcmd->qpair->qp_lock_ptr, flags); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, mcmd->vha, 0xf052, 20758c2ecf20Sopenharmony_ci "qla_target(%d): tgt_ops->handle_tmr() failed: %d\n", 20768c2ecf20Sopenharmony_ci mcmd->vha->vp_idx, rc); 20778c2ecf20Sopenharmony_ci mempool_free(mcmd, qla_tgt_mgmt_cmd_mempool); 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci} 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 20828c2ecf20Sopenharmony_cistatic int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, 20838c2ecf20Sopenharmony_ci struct abts_recv_from_24xx *abts, struct fc_port *sess) 20848c2ecf20Sopenharmony_ci{ 20858c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 20868c2ecf20Sopenharmony_ci struct qla_tgt_mgmt_cmd *mcmd; 20878c2ecf20Sopenharmony_ci struct qla_qpair_hint *h = &vha->vha_tgt.qla_tgt->qphints[0]; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f, 20908c2ecf20Sopenharmony_ci "qla_target(%d): task abort (tag=%d)\n", 20918c2ecf20Sopenharmony_ci vha->vp_idx, abts->exchange_addr_to_abort); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci mcmd = mempool_alloc(qla_tgt_mgmt_cmd_mempool, GFP_ATOMIC); 20948c2ecf20Sopenharmony_ci if (mcmd == NULL) { 20958c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf051, 20968c2ecf20Sopenharmony_ci "qla_target(%d): %s: Allocation of ABORT cmd failed", 20978c2ecf20Sopenharmony_ci vha->vp_idx, __func__); 20988c2ecf20Sopenharmony_ci return -ENOMEM; 20998c2ecf20Sopenharmony_ci } 21008c2ecf20Sopenharmony_ci memset(mcmd, 0, sizeof(*mcmd)); 21018c2ecf20Sopenharmony_ci mcmd->cmd_type = TYPE_TGT_TMCMD; 21028c2ecf20Sopenharmony_ci mcmd->sess = sess; 21038c2ecf20Sopenharmony_ci memcpy(&mcmd->orig_iocb.abts, abts, sizeof(mcmd->orig_iocb.abts)); 21048c2ecf20Sopenharmony_ci mcmd->reset_count = ha->base_qpair->chip_reset; 21058c2ecf20Sopenharmony_ci mcmd->tmr_func = QLA_TGT_ABTS; 21068c2ecf20Sopenharmony_ci mcmd->qpair = h->qpair; 21078c2ecf20Sopenharmony_ci mcmd->vha = vha; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci /* 21108c2ecf20Sopenharmony_ci * LUN is looked up by target-core internally based on the passed 21118c2ecf20Sopenharmony_ci * abts->exchange_addr_to_abort tag. 21128c2ecf20Sopenharmony_ci */ 21138c2ecf20Sopenharmony_ci mcmd->se_cmd.cpuid = h->cpuid; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci if (ha->tgt.tgt_ops->find_cmd_by_tag) { 21168c2ecf20Sopenharmony_ci struct qla_tgt_cmd *abort_cmd; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci abort_cmd = ha->tgt.tgt_ops->find_cmd_by_tag(sess, 21198c2ecf20Sopenharmony_ci le32_to_cpu(abts->exchange_addr_to_abort)); 21208c2ecf20Sopenharmony_ci if (abort_cmd && abort_cmd->qpair) { 21218c2ecf20Sopenharmony_ci mcmd->qpair = abort_cmd->qpair; 21228c2ecf20Sopenharmony_ci mcmd->se_cmd.cpuid = abort_cmd->se_cmd.cpuid; 21238c2ecf20Sopenharmony_ci mcmd->abort_io_attr = abort_cmd->atio.u.isp24.attr; 21248c2ecf20Sopenharmony_ci mcmd->flags = QLA24XX_MGMT_ABORT_IO_ATTR_VALID; 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci } 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci INIT_WORK(&mcmd->work, qlt_do_tmr_work); 21298c2ecf20Sopenharmony_ci queue_work_on(mcmd->se_cmd.cpuid, qla_tgt_wq, &mcmd->work); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci return 0; 21328c2ecf20Sopenharmony_ci} 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci/* 21358c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 21368c2ecf20Sopenharmony_ci */ 21378c2ecf20Sopenharmony_cistatic void qlt_24xx_handle_abts(struct scsi_qla_host *vha, 21388c2ecf20Sopenharmony_ci struct abts_recv_from_24xx *abts) 21398c2ecf20Sopenharmony_ci{ 21408c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 21418c2ecf20Sopenharmony_ci struct fc_port *sess; 21428c2ecf20Sopenharmony_ci uint32_t tag = le32_to_cpu(abts->exchange_addr_to_abort); 21438c2ecf20Sopenharmony_ci be_id_t s_id; 21448c2ecf20Sopenharmony_ci int rc; 21458c2ecf20Sopenharmony_ci unsigned long flags; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci if (le32_to_cpu(abts->fcp_hdr_le.parameter) & ABTS_PARAM_ABORT_SEQ) { 21488c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf053, 21498c2ecf20Sopenharmony_ci "qla_target(%d): ABTS: Abort Sequence not " 21508c2ecf20Sopenharmony_ci "supported\n", vha->vp_idx); 21518c2ecf20Sopenharmony_ci qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_REJECTED, 21528c2ecf20Sopenharmony_ci false); 21538c2ecf20Sopenharmony_ci return; 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci if (tag == ATIO_EXCHANGE_ADDRESS_UNKNOWN) { 21578c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf010, 21588c2ecf20Sopenharmony_ci "qla_target(%d): ABTS: Unknown Exchange " 21598c2ecf20Sopenharmony_ci "Address received\n", vha->vp_idx); 21608c2ecf20Sopenharmony_ci qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_REJECTED, 21618c2ecf20Sopenharmony_ci false); 21628c2ecf20Sopenharmony_ci return; 21638c2ecf20Sopenharmony_ci } 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf011, 21668c2ecf20Sopenharmony_ci "qla_target(%d): task abort (s_id=%x:%x:%x, " 21678c2ecf20Sopenharmony_ci "tag=%d, param=%x)\n", vha->vp_idx, abts->fcp_hdr_le.s_id.domain, 21688c2ecf20Sopenharmony_ci abts->fcp_hdr_le.s_id.area, abts->fcp_hdr_le.s_id.al_pa, tag, 21698c2ecf20Sopenharmony_ci le32_to_cpu(abts->fcp_hdr_le.parameter)); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci s_id = le_id_to_be(abts->fcp_hdr_le.s_id); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 21748c2ecf20Sopenharmony_ci sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); 21758c2ecf20Sopenharmony_ci if (!sess) { 21768c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf012, 21778c2ecf20Sopenharmony_ci "qla_target(%d): task abort for non-existent session\n", 21788c2ecf20Sopenharmony_ci vha->vp_idx); 21798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_REJECTED, 21828c2ecf20Sopenharmony_ci false); 21838c2ecf20Sopenharmony_ci return; 21848c2ecf20Sopenharmony_ci } 21858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci if (sess->deleted) { 21898c2ecf20Sopenharmony_ci qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_REJECTED, 21908c2ecf20Sopenharmony_ci false); 21918c2ecf20Sopenharmony_ci return; 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci rc = __qlt_24xx_handle_abts(vha, abts, sess); 21958c2ecf20Sopenharmony_ci if (rc != 0) { 21968c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf054, 21978c2ecf20Sopenharmony_ci "qla_target(%d): __qlt_24xx_handle_abts() failed: %d\n", 21988c2ecf20Sopenharmony_ci vha->vp_idx, rc); 21998c2ecf20Sopenharmony_ci qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_REJECTED, 22008c2ecf20Sopenharmony_ci false); 22018c2ecf20Sopenharmony_ci return; 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci/* 22068c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 22078c2ecf20Sopenharmony_ci */ 22088c2ecf20Sopenharmony_cistatic void qlt_24xx_send_task_mgmt_ctio(struct qla_qpair *qpair, 22098c2ecf20Sopenharmony_ci struct qla_tgt_mgmt_cmd *mcmd, uint32_t resp_code) 22108c2ecf20Sopenharmony_ci{ 22118c2ecf20Sopenharmony_ci struct scsi_qla_host *ha = mcmd->vha; 22128c2ecf20Sopenharmony_ci struct atio_from_isp *atio = &mcmd->orig_iocb.atio; 22138c2ecf20Sopenharmony_ci struct ctio7_to_24xx *ctio; 22148c2ecf20Sopenharmony_ci uint16_t temp; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, ha, 0xe008, 22178c2ecf20Sopenharmony_ci "Sending task mgmt CTIO7 (ha=%p, atio=%p, resp_code=%x\n", 22188c2ecf20Sopenharmony_ci ha, atio, resp_code); 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci ctio = (struct ctio7_to_24xx *)__qla2x00_alloc_iocbs(qpair, NULL); 22228c2ecf20Sopenharmony_ci if (ctio == NULL) { 22238c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, ha, 0xe04c, 22248c2ecf20Sopenharmony_ci "qla_target(%d): %s failed: unable to allocate " 22258c2ecf20Sopenharmony_ci "request packet\n", ha->vp_idx, __func__); 22268c2ecf20Sopenharmony_ci return; 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci ctio->entry_type = CTIO_TYPE7; 22308c2ecf20Sopenharmony_ci ctio->entry_count = 1; 22318c2ecf20Sopenharmony_ci ctio->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; 22328c2ecf20Sopenharmony_ci ctio->nport_handle = cpu_to_le16(mcmd->sess->loop_id); 22338c2ecf20Sopenharmony_ci ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); 22348c2ecf20Sopenharmony_ci ctio->vp_index = ha->vp_idx; 22358c2ecf20Sopenharmony_ci ctio->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); 22368c2ecf20Sopenharmony_ci ctio->exchange_addr = atio->u.isp24.exchange_addr; 22378c2ecf20Sopenharmony_ci temp = (atio->u.isp24.attr << 9)| 22388c2ecf20Sopenharmony_ci CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS; 22398c2ecf20Sopenharmony_ci ctio->u.status1.flags = cpu_to_le16(temp); 22408c2ecf20Sopenharmony_ci temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); 22418c2ecf20Sopenharmony_ci ctio->u.status1.ox_id = cpu_to_le16(temp); 22428c2ecf20Sopenharmony_ci ctio->u.status1.scsi_status = 22438c2ecf20Sopenharmony_ci cpu_to_le16(SS_RESPONSE_INFO_LEN_VALID); 22448c2ecf20Sopenharmony_ci ctio->u.status1.response_len = cpu_to_le16(8); 22458c2ecf20Sopenharmony_ci ctio->u.status1.sense_data[0] = resp_code; 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci /* Memory Barrier */ 22488c2ecf20Sopenharmony_ci wmb(); 22498c2ecf20Sopenharmony_ci if (qpair->reqq_start_iocbs) 22508c2ecf20Sopenharmony_ci qpair->reqq_start_iocbs(qpair); 22518c2ecf20Sopenharmony_ci else 22528c2ecf20Sopenharmony_ci qla2x00_start_iocbs(ha, qpair->req); 22538c2ecf20Sopenharmony_ci} 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_civoid qlt_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd) 22568c2ecf20Sopenharmony_ci{ 22578c2ecf20Sopenharmony_ci mempool_free(mcmd, qla_tgt_mgmt_cmd_mempool); 22588c2ecf20Sopenharmony_ci} 22598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_free_mcmd); 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci/* 22628c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then 22638c2ecf20Sopenharmony_ci * reacquire 22648c2ecf20Sopenharmony_ci */ 22658c2ecf20Sopenharmony_civoid qlt_send_resp_ctio(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, 22668c2ecf20Sopenharmony_ci uint8_t scsi_status, uint8_t sense_key, uint8_t asc, uint8_t ascq) 22678c2ecf20Sopenharmony_ci{ 22688c2ecf20Sopenharmony_ci struct atio_from_isp *atio = &cmd->atio; 22698c2ecf20Sopenharmony_ci struct ctio7_to_24xx *ctio; 22708c2ecf20Sopenharmony_ci uint16_t temp; 22718c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = cmd->vha; 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_dif, vha, 0x3066, 22748c2ecf20Sopenharmony_ci "Sending response CTIO7 (vha=%p, atio=%p, scsi_status=%02x, " 22758c2ecf20Sopenharmony_ci "sense_key=%02x, asc=%02x, ascq=%02x", 22768c2ecf20Sopenharmony_ci vha, atio, scsi_status, sense_key, asc, ascq); 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs(vha, NULL); 22798c2ecf20Sopenharmony_ci if (!ctio) { 22808c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x3067, 22818c2ecf20Sopenharmony_ci "qla2x00t(%ld): %s failed: unable to allocate request packet", 22828c2ecf20Sopenharmony_ci vha->host_no, __func__); 22838c2ecf20Sopenharmony_ci goto out; 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci ctio->entry_type = CTIO_TYPE7; 22878c2ecf20Sopenharmony_ci ctio->entry_count = 1; 22888c2ecf20Sopenharmony_ci ctio->handle = QLA_TGT_SKIP_HANDLE; 22898c2ecf20Sopenharmony_ci ctio->nport_handle = cpu_to_le16(cmd->sess->loop_id); 22908c2ecf20Sopenharmony_ci ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); 22918c2ecf20Sopenharmony_ci ctio->vp_index = vha->vp_idx; 22928c2ecf20Sopenharmony_ci ctio->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); 22938c2ecf20Sopenharmony_ci ctio->exchange_addr = atio->u.isp24.exchange_addr; 22948c2ecf20Sopenharmony_ci temp = (atio->u.isp24.attr << 9) | 22958c2ecf20Sopenharmony_ci CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS; 22968c2ecf20Sopenharmony_ci ctio->u.status1.flags = cpu_to_le16(temp); 22978c2ecf20Sopenharmony_ci temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); 22988c2ecf20Sopenharmony_ci ctio->u.status1.ox_id = cpu_to_le16(temp); 22998c2ecf20Sopenharmony_ci ctio->u.status1.scsi_status = 23008c2ecf20Sopenharmony_ci cpu_to_le16(SS_RESPONSE_INFO_LEN_VALID | scsi_status); 23018c2ecf20Sopenharmony_ci ctio->u.status1.response_len = cpu_to_le16(18); 23028c2ecf20Sopenharmony_ci ctio->u.status1.residual = cpu_to_le32(get_datalen_for_atio(atio)); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci if (ctio->u.status1.residual != 0) 23058c2ecf20Sopenharmony_ci ctio->u.status1.scsi_status |= 23068c2ecf20Sopenharmony_ci cpu_to_le16(SS_RESIDUAL_UNDER); 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci /* Fixed format sense data. */ 23098c2ecf20Sopenharmony_ci ctio->u.status1.sense_data[0] = 0x70; 23108c2ecf20Sopenharmony_ci ctio->u.status1.sense_data[2] = sense_key; 23118c2ecf20Sopenharmony_ci /* Additional sense length */ 23128c2ecf20Sopenharmony_ci ctio->u.status1.sense_data[7] = 0xa; 23138c2ecf20Sopenharmony_ci /* ASC and ASCQ */ 23148c2ecf20Sopenharmony_ci ctio->u.status1.sense_data[12] = asc; 23158c2ecf20Sopenharmony_ci ctio->u.status1.sense_data[13] = ascq; 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci /* Memory Barrier */ 23188c2ecf20Sopenharmony_ci wmb(); 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci if (qpair->reqq_start_iocbs) 23218c2ecf20Sopenharmony_ci qpair->reqq_start_iocbs(qpair); 23228c2ecf20Sopenharmony_ci else 23238c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, qpair->req); 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ciout: 23268c2ecf20Sopenharmony_ci return; 23278c2ecf20Sopenharmony_ci} 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci/* callback from target fabric module code */ 23308c2ecf20Sopenharmony_civoid qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) 23318c2ecf20Sopenharmony_ci{ 23328c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = mcmd->sess->vha; 23338c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 23348c2ecf20Sopenharmony_ci unsigned long flags; 23358c2ecf20Sopenharmony_ci struct qla_qpair *qpair = mcmd->qpair; 23368c2ecf20Sopenharmony_ci bool free_mcmd = true; 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf013, 23398c2ecf20Sopenharmony_ci "TM response mcmd (%p) status %#x state %#x", 23408c2ecf20Sopenharmony_ci mcmd, mcmd->fc_tm_rsp, mcmd->flags); 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci if (!vha->flags.online || mcmd->reset_count != qpair->chip_reset) { 23458c2ecf20Sopenharmony_ci /* 23468c2ecf20Sopenharmony_ci * Either the port is not online or this request was from 23478c2ecf20Sopenharmony_ci * previous life, just abort the processing. 23488c2ecf20Sopenharmony_ci */ 23498c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0xe100, 23508c2ecf20Sopenharmony_ci "RESET-TMR online/active/old-count/new-count = %d/%d/%d/%d.\n", 23518c2ecf20Sopenharmony_ci vha->flags.online, qla2x00_reset_active(vha), 23528c2ecf20Sopenharmony_ci mcmd->reset_count, qpair->chip_reset); 23538c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->free_mcmd(mcmd); 23548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 23558c2ecf20Sopenharmony_ci return; 23568c2ecf20Sopenharmony_ci } 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci if (mcmd->flags == QLA24XX_MGMT_SEND_NACK) { 23598c2ecf20Sopenharmony_ci switch (mcmd->orig_iocb.imm_ntfy.u.isp24.status_subcode) { 23608c2ecf20Sopenharmony_ci case ELS_LOGO: 23618c2ecf20Sopenharmony_ci case ELS_PRLO: 23628c2ecf20Sopenharmony_ci case ELS_TPRLO: 23638c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2106, 23648c2ecf20Sopenharmony_ci "TM response logo %8phC status %#x state %#x", 23658c2ecf20Sopenharmony_ci mcmd->sess->port_name, mcmd->fc_tm_rsp, 23668c2ecf20Sopenharmony_ci mcmd->flags); 23678c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(mcmd->sess); 23688c2ecf20Sopenharmony_ci break; 23698c2ecf20Sopenharmony_ci default: 23708c2ecf20Sopenharmony_ci qlt_send_notify_ack(vha->hw->base_qpair, 23718c2ecf20Sopenharmony_ci &mcmd->orig_iocb.imm_ntfy, 0, 0, 0, 0, 0, 0); 23728c2ecf20Sopenharmony_ci break; 23738c2ecf20Sopenharmony_ci } 23748c2ecf20Sopenharmony_ci } else { 23758c2ecf20Sopenharmony_ci if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX) { 23768c2ecf20Sopenharmony_ci qlt_build_abts_resp_iocb(mcmd); 23778c2ecf20Sopenharmony_ci free_mcmd = false; 23788c2ecf20Sopenharmony_ci } else 23798c2ecf20Sopenharmony_ci qlt_24xx_send_task_mgmt_ctio(qpair, mcmd, 23808c2ecf20Sopenharmony_ci mcmd->fc_tm_rsp); 23818c2ecf20Sopenharmony_ci } 23828c2ecf20Sopenharmony_ci /* 23838c2ecf20Sopenharmony_ci * Make the callback for ->free_mcmd() to queue_work() and invoke 23848c2ecf20Sopenharmony_ci * target_put_sess_cmd() to drop cmd_kref to 1. The final 23858c2ecf20Sopenharmony_ci * target_put_sess_cmd() call will be made from TFO->check_stop_free() 23868c2ecf20Sopenharmony_ci * -> tcm_qla2xxx_check_stop_free() to release the TMR associated se_cmd 23878c2ecf20Sopenharmony_ci * descriptor after TFO->queue_tm_rsp() -> tcm_qla2xxx_queue_tm_rsp() -> 23888c2ecf20Sopenharmony_ci * qlt_xmit_tm_rsp() returns here.. 23898c2ecf20Sopenharmony_ci */ 23908c2ecf20Sopenharmony_ci if (free_mcmd) 23918c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->free_mcmd(mcmd); 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 23948c2ecf20Sopenharmony_ci} 23958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_xmit_tm_rsp); 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci/* No locks */ 23988c2ecf20Sopenharmony_cistatic int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm) 23998c2ecf20Sopenharmony_ci{ 24008c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd = prm->cmd; 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci BUG_ON(cmd->sg_cnt == 0); 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci prm->sg = (struct scatterlist *)cmd->sg; 24058c2ecf20Sopenharmony_ci prm->seg_cnt = dma_map_sg(&cmd->qpair->pdev->dev, cmd->sg, 24068c2ecf20Sopenharmony_ci cmd->sg_cnt, cmd->dma_data_direction); 24078c2ecf20Sopenharmony_ci if (unlikely(prm->seg_cnt == 0)) 24088c2ecf20Sopenharmony_ci goto out_err; 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci prm->cmd->sg_mapped = 1; 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci if (cmd->se_cmd.prot_op == TARGET_PROT_NORMAL) { 24138c2ecf20Sopenharmony_ci /* 24148c2ecf20Sopenharmony_ci * If greater than four sg entries then we need to allocate 24158c2ecf20Sopenharmony_ci * the continuation entries 24168c2ecf20Sopenharmony_ci */ 24178c2ecf20Sopenharmony_ci if (prm->seg_cnt > QLA_TGT_DATASEGS_PER_CMD_24XX) 24188c2ecf20Sopenharmony_ci prm->req_cnt += DIV_ROUND_UP(prm->seg_cnt - 24198c2ecf20Sopenharmony_ci QLA_TGT_DATASEGS_PER_CMD_24XX, 24208c2ecf20Sopenharmony_ci QLA_TGT_DATASEGS_PER_CONT_24XX); 24218c2ecf20Sopenharmony_ci } else { 24228c2ecf20Sopenharmony_ci /* DIF */ 24238c2ecf20Sopenharmony_ci if ((cmd->se_cmd.prot_op == TARGET_PROT_DIN_INSERT) || 24248c2ecf20Sopenharmony_ci (cmd->se_cmd.prot_op == TARGET_PROT_DOUT_STRIP)) { 24258c2ecf20Sopenharmony_ci prm->seg_cnt = DIV_ROUND_UP(cmd->bufflen, cmd->blk_sz); 24268c2ecf20Sopenharmony_ci prm->tot_dsds = prm->seg_cnt; 24278c2ecf20Sopenharmony_ci } else 24288c2ecf20Sopenharmony_ci prm->tot_dsds = prm->seg_cnt; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci if (cmd->prot_sg_cnt) { 24318c2ecf20Sopenharmony_ci prm->prot_sg = cmd->prot_sg; 24328c2ecf20Sopenharmony_ci prm->prot_seg_cnt = dma_map_sg(&cmd->qpair->pdev->dev, 24338c2ecf20Sopenharmony_ci cmd->prot_sg, cmd->prot_sg_cnt, 24348c2ecf20Sopenharmony_ci cmd->dma_data_direction); 24358c2ecf20Sopenharmony_ci if (unlikely(prm->prot_seg_cnt == 0)) 24368c2ecf20Sopenharmony_ci goto out_err; 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci if ((cmd->se_cmd.prot_op == TARGET_PROT_DIN_INSERT) || 24398c2ecf20Sopenharmony_ci (cmd->se_cmd.prot_op == TARGET_PROT_DOUT_STRIP)) { 24408c2ecf20Sopenharmony_ci /* Dif Bundling not support here */ 24418c2ecf20Sopenharmony_ci prm->prot_seg_cnt = DIV_ROUND_UP(cmd->bufflen, 24428c2ecf20Sopenharmony_ci cmd->blk_sz); 24438c2ecf20Sopenharmony_ci prm->tot_dsds += prm->prot_seg_cnt; 24448c2ecf20Sopenharmony_ci } else 24458c2ecf20Sopenharmony_ci prm->tot_dsds += prm->prot_seg_cnt; 24468c2ecf20Sopenharmony_ci } 24478c2ecf20Sopenharmony_ci } 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci return 0; 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ciout_err: 24528c2ecf20Sopenharmony_ci ql_dbg_qp(ql_dbg_tgt, prm->cmd->qpair, 0xe04d, 24538c2ecf20Sopenharmony_ci "qla_target(%d): PCI mapping failed: sg_cnt=%d", 24548c2ecf20Sopenharmony_ci 0, prm->cmd->sg_cnt); 24558c2ecf20Sopenharmony_ci return -1; 24568c2ecf20Sopenharmony_ci} 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_cistatic void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) 24598c2ecf20Sopenharmony_ci{ 24608c2ecf20Sopenharmony_ci struct qla_hw_data *ha; 24618c2ecf20Sopenharmony_ci struct qla_qpair *qpair; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci if (!cmd->sg_mapped) 24648c2ecf20Sopenharmony_ci return; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci qpair = cmd->qpair; 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci dma_unmap_sg(&qpair->pdev->dev, cmd->sg, cmd->sg_cnt, 24698c2ecf20Sopenharmony_ci cmd->dma_data_direction); 24708c2ecf20Sopenharmony_ci cmd->sg_mapped = 0; 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci if (cmd->prot_sg_cnt) 24738c2ecf20Sopenharmony_ci dma_unmap_sg(&qpair->pdev->dev, cmd->prot_sg, cmd->prot_sg_cnt, 24748c2ecf20Sopenharmony_ci cmd->dma_data_direction); 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci if (!cmd->ctx) 24778c2ecf20Sopenharmony_ci return; 24788c2ecf20Sopenharmony_ci ha = vha->hw; 24798c2ecf20Sopenharmony_ci if (cmd->ctx_dsd_alloced) 24808c2ecf20Sopenharmony_ci qla2x00_clean_dsd_pool(ha, cmd->ctx); 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci dma_pool_free(ha->dl_dma_pool, cmd->ctx, cmd->ctx->crc_ctx_dma); 24838c2ecf20Sopenharmony_ci} 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_cistatic int qlt_check_reserve_free_req(struct qla_qpair *qpair, 24868c2ecf20Sopenharmony_ci uint32_t req_cnt) 24878c2ecf20Sopenharmony_ci{ 24888c2ecf20Sopenharmony_ci uint32_t cnt; 24898c2ecf20Sopenharmony_ci struct req_que *req = qpair->req; 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 24928c2ecf20Sopenharmony_ci cnt = (uint16_t)(qpair->use_shadow_reg ? *req->out_ptr : 24938c2ecf20Sopenharmony_ci rd_reg_dword_relaxed(req->req_q_out)); 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci if (req->ring_index < cnt) 24968c2ecf20Sopenharmony_ci req->cnt = cnt - req->ring_index; 24978c2ecf20Sopenharmony_ci else 24988c2ecf20Sopenharmony_ci req->cnt = req->length - (req->ring_index - cnt); 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci if (unlikely(req->cnt < (req_cnt + 2))) 25018c2ecf20Sopenharmony_ci return -EAGAIN; 25028c2ecf20Sopenharmony_ci } 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci req->cnt -= req_cnt; 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci return 0; 25078c2ecf20Sopenharmony_ci} 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci/* 25108c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 25118c2ecf20Sopenharmony_ci */ 25128c2ecf20Sopenharmony_cistatic inline void *qlt_get_req_pkt(struct req_que *req) 25138c2ecf20Sopenharmony_ci{ 25148c2ecf20Sopenharmony_ci /* Adjust ring index. */ 25158c2ecf20Sopenharmony_ci req->ring_index++; 25168c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 25178c2ecf20Sopenharmony_ci req->ring_index = 0; 25188c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 25198c2ecf20Sopenharmony_ci } else { 25208c2ecf20Sopenharmony_ci req->ring_ptr++; 25218c2ecf20Sopenharmony_ci } 25228c2ecf20Sopenharmony_ci return (cont_entry_t *)req->ring_ptr; 25238c2ecf20Sopenharmony_ci} 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 25268c2ecf20Sopenharmony_cistatic inline uint32_t qlt_make_handle(struct qla_qpair *qpair) 25278c2ecf20Sopenharmony_ci{ 25288c2ecf20Sopenharmony_ci uint32_t h; 25298c2ecf20Sopenharmony_ci int index; 25308c2ecf20Sopenharmony_ci uint8_t found = 0; 25318c2ecf20Sopenharmony_ci struct req_que *req = qpair->req; 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci h = req->current_outstanding_cmd; 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci for (index = 1; index < req->num_outstanding_cmds; index++) { 25368c2ecf20Sopenharmony_ci h++; 25378c2ecf20Sopenharmony_ci if (h == req->num_outstanding_cmds) 25388c2ecf20Sopenharmony_ci h = 1; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci if (h == QLA_TGT_SKIP_HANDLE) 25418c2ecf20Sopenharmony_ci continue; 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci if (!req->outstanding_cmds[h]) { 25448c2ecf20Sopenharmony_ci found = 1; 25458c2ecf20Sopenharmony_ci break; 25468c2ecf20Sopenharmony_ci } 25478c2ecf20Sopenharmony_ci } 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci if (found) { 25508c2ecf20Sopenharmony_ci req->current_outstanding_cmd = h; 25518c2ecf20Sopenharmony_ci } else { 25528c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, qpair->vha, 0x305b, 25538c2ecf20Sopenharmony_ci "qla_target(%d): Ran out of empty cmd slots\n", 25548c2ecf20Sopenharmony_ci qpair->vha->vp_idx); 25558c2ecf20Sopenharmony_ci h = QLA_TGT_NULL_HANDLE; 25568c2ecf20Sopenharmony_ci } 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci return h; 25598c2ecf20Sopenharmony_ci} 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 25628c2ecf20Sopenharmony_cistatic int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair, 25638c2ecf20Sopenharmony_ci struct qla_tgt_prm *prm) 25648c2ecf20Sopenharmony_ci{ 25658c2ecf20Sopenharmony_ci uint32_t h; 25668c2ecf20Sopenharmony_ci struct ctio7_to_24xx *pkt; 25678c2ecf20Sopenharmony_ci struct atio_from_isp *atio = &prm->cmd->atio; 25688c2ecf20Sopenharmony_ci uint16_t temp; 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci pkt = (struct ctio7_to_24xx *)qpair->req->ring_ptr; 25718c2ecf20Sopenharmony_ci prm->pkt = pkt; 25728c2ecf20Sopenharmony_ci memset(pkt, 0, sizeof(*pkt)); 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci pkt->entry_type = CTIO_TYPE7; 25758c2ecf20Sopenharmony_ci pkt->entry_count = (uint8_t)prm->req_cnt; 25768c2ecf20Sopenharmony_ci pkt->vp_index = prm->cmd->vp_idx; 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci h = qlt_make_handle(qpair); 25798c2ecf20Sopenharmony_ci if (unlikely(h == QLA_TGT_NULL_HANDLE)) { 25808c2ecf20Sopenharmony_ci /* 25818c2ecf20Sopenharmony_ci * CTIO type 7 from the firmware doesn't provide a way to 25828c2ecf20Sopenharmony_ci * know the initiator's LOOP ID, hence we can't find 25838c2ecf20Sopenharmony_ci * the session and, so, the command. 25848c2ecf20Sopenharmony_ci */ 25858c2ecf20Sopenharmony_ci return -EAGAIN; 25868c2ecf20Sopenharmony_ci } else 25878c2ecf20Sopenharmony_ci qpair->req->outstanding_cmds[h] = (srb_t *)prm->cmd; 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci pkt->handle = make_handle(qpair->req->id, h); 25908c2ecf20Sopenharmony_ci pkt->handle |= CTIO_COMPLETION_HANDLE_MARK; 25918c2ecf20Sopenharmony_ci pkt->nport_handle = cpu_to_le16(prm->cmd->loop_id); 25928c2ecf20Sopenharmony_ci pkt->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); 25938c2ecf20Sopenharmony_ci pkt->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); 25948c2ecf20Sopenharmony_ci pkt->exchange_addr = atio->u.isp24.exchange_addr; 25958c2ecf20Sopenharmony_ci temp = atio->u.isp24.attr << 9; 25968c2ecf20Sopenharmony_ci pkt->u.status0.flags |= cpu_to_le16(temp); 25978c2ecf20Sopenharmony_ci temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); 25988c2ecf20Sopenharmony_ci pkt->u.status0.ox_id = cpu_to_le16(temp); 25998c2ecf20Sopenharmony_ci pkt->u.status0.relative_offset = cpu_to_le32(prm->cmd->offset); 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci return 0; 26028c2ecf20Sopenharmony_ci} 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci/* 26058c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. We have already made sure 26068c2ecf20Sopenharmony_ci * that there is sufficient amount of request entries to not drop it. 26078c2ecf20Sopenharmony_ci */ 26088c2ecf20Sopenharmony_cistatic void qlt_load_cont_data_segments(struct qla_tgt_prm *prm) 26098c2ecf20Sopenharmony_ci{ 26108c2ecf20Sopenharmony_ci int cnt; 26118c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd; 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci /* Build continuation packets */ 26148c2ecf20Sopenharmony_ci while (prm->seg_cnt > 0) { 26158c2ecf20Sopenharmony_ci cont_a64_entry_t *cont_pkt64 = 26168c2ecf20Sopenharmony_ci (cont_a64_entry_t *)qlt_get_req_pkt( 26178c2ecf20Sopenharmony_ci prm->cmd->qpair->req); 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci /* 26208c2ecf20Sopenharmony_ci * Make sure that from cont_pkt64 none of 26218c2ecf20Sopenharmony_ci * 64-bit specific fields used for 32-bit 26228c2ecf20Sopenharmony_ci * addressing. Cast to (cont_entry_t *) for 26238c2ecf20Sopenharmony_ci * that. 26248c2ecf20Sopenharmony_ci */ 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci memset(cont_pkt64, 0, sizeof(*cont_pkt64)); 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci cont_pkt64->entry_count = 1; 26298c2ecf20Sopenharmony_ci cont_pkt64->sys_define = 0; 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci cont_pkt64->entry_type = CONTINUE_A64_TYPE; 26328c2ecf20Sopenharmony_ci cur_dsd = cont_pkt64->dsd; 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci /* Load continuation entry data segments */ 26358c2ecf20Sopenharmony_ci for (cnt = 0; 26368c2ecf20Sopenharmony_ci cnt < QLA_TGT_DATASEGS_PER_CONT_24XX && prm->seg_cnt; 26378c2ecf20Sopenharmony_ci cnt++, prm->seg_cnt--) { 26388c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, prm->sg); 26398c2ecf20Sopenharmony_ci prm->sg = sg_next(prm->sg); 26408c2ecf20Sopenharmony_ci } 26418c2ecf20Sopenharmony_ci } 26428c2ecf20Sopenharmony_ci} 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci/* 26458c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. We have already made sure 26468c2ecf20Sopenharmony_ci * that there is sufficient amount of request entries to not drop it. 26478c2ecf20Sopenharmony_ci */ 26488c2ecf20Sopenharmony_cistatic void qlt_load_data_segments(struct qla_tgt_prm *prm) 26498c2ecf20Sopenharmony_ci{ 26508c2ecf20Sopenharmony_ci int cnt; 26518c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd; 26528c2ecf20Sopenharmony_ci struct ctio7_to_24xx *pkt24 = (struct ctio7_to_24xx *)prm->pkt; 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci pkt24->u.status0.transfer_length = cpu_to_le32(prm->cmd->bufflen); 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci /* Setup packet address segment pointer */ 26578c2ecf20Sopenharmony_ci cur_dsd = &pkt24->u.status0.dsd; 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci /* Set total data segment count */ 26608c2ecf20Sopenharmony_ci if (prm->seg_cnt) 26618c2ecf20Sopenharmony_ci pkt24->dseg_count = cpu_to_le16(prm->seg_cnt); 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci if (prm->seg_cnt == 0) { 26648c2ecf20Sopenharmony_ci /* No data transfer */ 26658c2ecf20Sopenharmony_ci cur_dsd->address = 0; 26668c2ecf20Sopenharmony_ci cur_dsd->length = 0; 26678c2ecf20Sopenharmony_ci return; 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci /* If scatter gather */ 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_ci /* Load command entry data segments */ 26738c2ecf20Sopenharmony_ci for (cnt = 0; 26748c2ecf20Sopenharmony_ci (cnt < QLA_TGT_DATASEGS_PER_CMD_24XX) && prm->seg_cnt; 26758c2ecf20Sopenharmony_ci cnt++, prm->seg_cnt--) { 26768c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, prm->sg); 26778c2ecf20Sopenharmony_ci prm->sg = sg_next(prm->sg); 26788c2ecf20Sopenharmony_ci } 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci qlt_load_cont_data_segments(prm); 26818c2ecf20Sopenharmony_ci} 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_cistatic inline int qlt_has_data(struct qla_tgt_cmd *cmd) 26848c2ecf20Sopenharmony_ci{ 26858c2ecf20Sopenharmony_ci return cmd->bufflen > 0; 26868c2ecf20Sopenharmony_ci} 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_cistatic void qlt_print_dif_err(struct qla_tgt_prm *prm) 26898c2ecf20Sopenharmony_ci{ 26908c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd; 26918c2ecf20Sopenharmony_ci struct scsi_qla_host *vha; 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci /* asc 0x10=dif error */ 26948c2ecf20Sopenharmony_ci if (prm->sense_buffer && (prm->sense_buffer[12] == 0x10)) { 26958c2ecf20Sopenharmony_ci cmd = prm->cmd; 26968c2ecf20Sopenharmony_ci vha = cmd->vha; 26978c2ecf20Sopenharmony_ci /* ASCQ */ 26988c2ecf20Sopenharmony_ci switch (prm->sense_buffer[13]) { 26998c2ecf20Sopenharmony_ci case 1: 27008c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_dif, vha, 0xe00b, 27018c2ecf20Sopenharmony_ci "BE detected Guard TAG ERR: lba[0x%llx|%lld] len[0x%x] " 27028c2ecf20Sopenharmony_ci "se_cmd=%p tag[%x]", 27038c2ecf20Sopenharmony_ci cmd->lba, cmd->lba, cmd->num_blks, &cmd->se_cmd, 27048c2ecf20Sopenharmony_ci cmd->atio.u.isp24.exchange_addr); 27058c2ecf20Sopenharmony_ci break; 27068c2ecf20Sopenharmony_ci case 2: 27078c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_dif, vha, 0xe00c, 27088c2ecf20Sopenharmony_ci "BE detected APP TAG ERR: lba[0x%llx|%lld] len[0x%x] " 27098c2ecf20Sopenharmony_ci "se_cmd=%p tag[%x]", 27108c2ecf20Sopenharmony_ci cmd->lba, cmd->lba, cmd->num_blks, &cmd->se_cmd, 27118c2ecf20Sopenharmony_ci cmd->atio.u.isp24.exchange_addr); 27128c2ecf20Sopenharmony_ci break; 27138c2ecf20Sopenharmony_ci case 3: 27148c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_dif, vha, 0xe00f, 27158c2ecf20Sopenharmony_ci "BE detected REF TAG ERR: lba[0x%llx|%lld] len[0x%x] " 27168c2ecf20Sopenharmony_ci "se_cmd=%p tag[%x]", 27178c2ecf20Sopenharmony_ci cmd->lba, cmd->lba, cmd->num_blks, &cmd->se_cmd, 27188c2ecf20Sopenharmony_ci cmd->atio.u.isp24.exchange_addr); 27198c2ecf20Sopenharmony_ci break; 27208c2ecf20Sopenharmony_ci default: 27218c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_dif, vha, 0xe010, 27228c2ecf20Sopenharmony_ci "BE detected Dif ERR: lba[%llx|%lld] len[%x] " 27238c2ecf20Sopenharmony_ci "se_cmd=%p tag[%x]", 27248c2ecf20Sopenharmony_ci cmd->lba, cmd->lba, cmd->num_blks, &cmd->se_cmd, 27258c2ecf20Sopenharmony_ci cmd->atio.u.isp24.exchange_addr); 27268c2ecf20Sopenharmony_ci break; 27278c2ecf20Sopenharmony_ci } 27288c2ecf20Sopenharmony_ci ql_dump_buffer(ql_dbg_tgt_dif, vha, 0xe011, cmd->cdb, 16); 27298c2ecf20Sopenharmony_ci } 27308c2ecf20Sopenharmony_ci} 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci/* 27338c2ecf20Sopenharmony_ci * Called without ha->hardware_lock held 27348c2ecf20Sopenharmony_ci */ 27358c2ecf20Sopenharmony_cistatic int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, 27368c2ecf20Sopenharmony_ci struct qla_tgt_prm *prm, int xmit_type, uint8_t scsi_status, 27378c2ecf20Sopenharmony_ci uint32_t *full_req_cnt) 27388c2ecf20Sopenharmony_ci{ 27398c2ecf20Sopenharmony_ci struct se_cmd *se_cmd = &cmd->se_cmd; 27408c2ecf20Sopenharmony_ci struct qla_qpair *qpair = cmd->qpair; 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci prm->cmd = cmd; 27438c2ecf20Sopenharmony_ci prm->tgt = cmd->tgt; 27448c2ecf20Sopenharmony_ci prm->pkt = NULL; 27458c2ecf20Sopenharmony_ci prm->rq_result = scsi_status; 27468c2ecf20Sopenharmony_ci prm->sense_buffer = &cmd->sense_buffer[0]; 27478c2ecf20Sopenharmony_ci prm->sense_buffer_len = TRANSPORT_SENSE_BUFFER; 27488c2ecf20Sopenharmony_ci prm->sg = NULL; 27498c2ecf20Sopenharmony_ci prm->seg_cnt = -1; 27508c2ecf20Sopenharmony_ci prm->req_cnt = 1; 27518c2ecf20Sopenharmony_ci prm->residual = 0; 27528c2ecf20Sopenharmony_ci prm->add_status_pkt = 0; 27538c2ecf20Sopenharmony_ci prm->prot_sg = NULL; 27548c2ecf20Sopenharmony_ci prm->prot_seg_cnt = 0; 27558c2ecf20Sopenharmony_ci prm->tot_dsds = 0; 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_ci if ((xmit_type & QLA_TGT_XMIT_DATA) && qlt_has_data(cmd)) { 27588c2ecf20Sopenharmony_ci if (qlt_pci_map_calc_cnt(prm) != 0) 27598c2ecf20Sopenharmony_ci return -EAGAIN; 27608c2ecf20Sopenharmony_ci } 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci *full_req_cnt = prm->req_cnt; 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { 27658c2ecf20Sopenharmony_ci prm->residual = se_cmd->residual_count; 27668c2ecf20Sopenharmony_ci ql_dbg_qp(ql_dbg_io + ql_dbg_verbose, qpair, 0x305c, 27678c2ecf20Sopenharmony_ci "Residual underflow: %d (tag %lld, op %x, bufflen %d, rq_result %x)\n", 27688c2ecf20Sopenharmony_ci prm->residual, se_cmd->tag, 27698c2ecf20Sopenharmony_ci se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, 27708c2ecf20Sopenharmony_ci cmd->bufflen, prm->rq_result); 27718c2ecf20Sopenharmony_ci prm->rq_result |= SS_RESIDUAL_UNDER; 27728c2ecf20Sopenharmony_ci } else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { 27738c2ecf20Sopenharmony_ci prm->residual = se_cmd->residual_count; 27748c2ecf20Sopenharmony_ci ql_dbg_qp(ql_dbg_io, qpair, 0x305d, 27758c2ecf20Sopenharmony_ci "Residual overflow: %d (tag %lld, op %x, bufflen %d, rq_result %x)\n", 27768c2ecf20Sopenharmony_ci prm->residual, se_cmd->tag, se_cmd->t_task_cdb ? 27778c2ecf20Sopenharmony_ci se_cmd->t_task_cdb[0] : 0, cmd->bufflen, prm->rq_result); 27788c2ecf20Sopenharmony_ci prm->rq_result |= SS_RESIDUAL_OVER; 27798c2ecf20Sopenharmony_ci } 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci if (xmit_type & QLA_TGT_XMIT_STATUS) { 27828c2ecf20Sopenharmony_ci /* 27838c2ecf20Sopenharmony_ci * If QLA_TGT_XMIT_DATA is not set, add_status_pkt will be 27848c2ecf20Sopenharmony_ci * ignored in *xmit_response() below 27858c2ecf20Sopenharmony_ci */ 27868c2ecf20Sopenharmony_ci if (qlt_has_data(cmd)) { 27878c2ecf20Sopenharmony_ci if (QLA_TGT_SENSE_VALID(prm->sense_buffer) || 27888c2ecf20Sopenharmony_ci (IS_FWI2_CAPABLE(cmd->vha->hw) && 27898c2ecf20Sopenharmony_ci (prm->rq_result != 0))) { 27908c2ecf20Sopenharmony_ci prm->add_status_pkt = 1; 27918c2ecf20Sopenharmony_ci (*full_req_cnt)++; 27928c2ecf20Sopenharmony_ci } 27938c2ecf20Sopenharmony_ci } 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci return 0; 27978c2ecf20Sopenharmony_ci} 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_cistatic inline int qlt_need_explicit_conf(struct qla_tgt_cmd *cmd, 28008c2ecf20Sopenharmony_ci int sending_sense) 28018c2ecf20Sopenharmony_ci{ 28028c2ecf20Sopenharmony_ci if (cmd->qpair->enable_class_2) 28038c2ecf20Sopenharmony_ci return 0; 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci if (sending_sense) 28068c2ecf20Sopenharmony_ci return cmd->conf_compl_supported; 28078c2ecf20Sopenharmony_ci else 28088c2ecf20Sopenharmony_ci return cmd->qpair->enable_explicit_conf && 28098c2ecf20Sopenharmony_ci cmd->conf_compl_supported; 28108c2ecf20Sopenharmony_ci} 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_cistatic void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio, 28138c2ecf20Sopenharmony_ci struct qla_tgt_prm *prm) 28148c2ecf20Sopenharmony_ci{ 28158c2ecf20Sopenharmony_ci prm->sense_buffer_len = min_t(uint32_t, prm->sense_buffer_len, 28168c2ecf20Sopenharmony_ci (uint32_t)sizeof(ctio->u.status1.sense_data)); 28178c2ecf20Sopenharmony_ci ctio->u.status0.flags |= cpu_to_le16(CTIO7_FLAGS_SEND_STATUS); 28188c2ecf20Sopenharmony_ci if (qlt_need_explicit_conf(prm->cmd, 0)) { 28198c2ecf20Sopenharmony_ci ctio->u.status0.flags |= cpu_to_le16( 28208c2ecf20Sopenharmony_ci CTIO7_FLAGS_EXPLICIT_CONFORM | 28218c2ecf20Sopenharmony_ci CTIO7_FLAGS_CONFORM_REQ); 28228c2ecf20Sopenharmony_ci } 28238c2ecf20Sopenharmony_ci ctio->u.status0.residual = cpu_to_le32(prm->residual); 28248c2ecf20Sopenharmony_ci ctio->u.status0.scsi_status = cpu_to_le16(prm->rq_result); 28258c2ecf20Sopenharmony_ci if (QLA_TGT_SENSE_VALID(prm->sense_buffer)) { 28268c2ecf20Sopenharmony_ci int i; 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci if (qlt_need_explicit_conf(prm->cmd, 1)) { 28298c2ecf20Sopenharmony_ci if ((prm->rq_result & SS_SCSI_STATUS_BYTE) != 0) { 28308c2ecf20Sopenharmony_ci ql_dbg_qp(ql_dbg_tgt, prm->cmd->qpair, 0xe017, 28318c2ecf20Sopenharmony_ci "Skipping EXPLICIT_CONFORM and " 28328c2ecf20Sopenharmony_ci "CTIO7_FLAGS_CONFORM_REQ for FCP READ w/ " 28338c2ecf20Sopenharmony_ci "non GOOD status\n"); 28348c2ecf20Sopenharmony_ci goto skip_explict_conf; 28358c2ecf20Sopenharmony_ci } 28368c2ecf20Sopenharmony_ci ctio->u.status1.flags |= cpu_to_le16( 28378c2ecf20Sopenharmony_ci CTIO7_FLAGS_EXPLICIT_CONFORM | 28388c2ecf20Sopenharmony_ci CTIO7_FLAGS_CONFORM_REQ); 28398c2ecf20Sopenharmony_ci } 28408c2ecf20Sopenharmony_ciskip_explict_conf: 28418c2ecf20Sopenharmony_ci ctio->u.status1.flags &= 28428c2ecf20Sopenharmony_ci ~cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_0); 28438c2ecf20Sopenharmony_ci ctio->u.status1.flags |= 28448c2ecf20Sopenharmony_ci cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1); 28458c2ecf20Sopenharmony_ci ctio->u.status1.scsi_status |= 28468c2ecf20Sopenharmony_ci cpu_to_le16(SS_SENSE_LEN_VALID); 28478c2ecf20Sopenharmony_ci ctio->u.status1.sense_length = 28488c2ecf20Sopenharmony_ci cpu_to_le16(prm->sense_buffer_len); 28498c2ecf20Sopenharmony_ci for (i = 0; i < prm->sense_buffer_len/4; i++) { 28508c2ecf20Sopenharmony_ci uint32_t v; 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci v = get_unaligned_be32( 28538c2ecf20Sopenharmony_ci &((uint32_t *)prm->sense_buffer)[i]); 28548c2ecf20Sopenharmony_ci put_unaligned_le32(v, 28558c2ecf20Sopenharmony_ci &((uint32_t *)ctio->u.status1.sense_data)[i]); 28568c2ecf20Sopenharmony_ci } 28578c2ecf20Sopenharmony_ci qlt_print_dif_err(prm); 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci } else { 28608c2ecf20Sopenharmony_ci ctio->u.status1.flags &= 28618c2ecf20Sopenharmony_ci ~cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_0); 28628c2ecf20Sopenharmony_ci ctio->u.status1.flags |= 28638c2ecf20Sopenharmony_ci cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1); 28648c2ecf20Sopenharmony_ci ctio->u.status1.sense_length = 0; 28658c2ecf20Sopenharmony_ci memset(ctio->u.status1.sense_data, 0, 28668c2ecf20Sopenharmony_ci sizeof(ctio->u.status1.sense_data)); 28678c2ecf20Sopenharmony_ci } 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci /* Sense with len > 24, is it possible ??? */ 28708c2ecf20Sopenharmony_ci} 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_cistatic inline int 28738c2ecf20Sopenharmony_ciqlt_hba_err_chk_enabled(struct se_cmd *se_cmd) 28748c2ecf20Sopenharmony_ci{ 28758c2ecf20Sopenharmony_ci switch (se_cmd->prot_op) { 28768c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_INSERT: 28778c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_STRIP: 28788c2ecf20Sopenharmony_ci if (ql2xenablehba_err_chk >= 1) 28798c2ecf20Sopenharmony_ci return 1; 28808c2ecf20Sopenharmony_ci break; 28818c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_PASS: 28828c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_PASS: 28838c2ecf20Sopenharmony_ci if (ql2xenablehba_err_chk >= 2) 28848c2ecf20Sopenharmony_ci return 1; 28858c2ecf20Sopenharmony_ci break; 28868c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_INSERT: 28878c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_STRIP: 28888c2ecf20Sopenharmony_ci return 1; 28898c2ecf20Sopenharmony_ci default: 28908c2ecf20Sopenharmony_ci break; 28918c2ecf20Sopenharmony_ci } 28928c2ecf20Sopenharmony_ci return 0; 28938c2ecf20Sopenharmony_ci} 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_cistatic inline int 28968c2ecf20Sopenharmony_ciqla_tgt_ref_mask_check(struct se_cmd *se_cmd) 28978c2ecf20Sopenharmony_ci{ 28988c2ecf20Sopenharmony_ci switch (se_cmd->prot_op) { 28998c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_INSERT: 29008c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_INSERT: 29018c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_STRIP: 29028c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_STRIP: 29038c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_PASS: 29048c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_PASS: 29058c2ecf20Sopenharmony_ci return 1; 29068c2ecf20Sopenharmony_ci default: 29078c2ecf20Sopenharmony_ci return 0; 29088c2ecf20Sopenharmony_ci } 29098c2ecf20Sopenharmony_ci return 0; 29108c2ecf20Sopenharmony_ci} 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci/* 29138c2ecf20Sopenharmony_ci * qla_tgt_set_dif_tags - Extract Ref and App tags from SCSI command 29148c2ecf20Sopenharmony_ci */ 29158c2ecf20Sopenharmony_cistatic void 29168c2ecf20Sopenharmony_ciqla_tgt_set_dif_tags(struct qla_tgt_cmd *cmd, struct crc_context *ctx, 29178c2ecf20Sopenharmony_ci uint16_t *pfw_prot_opts) 29188c2ecf20Sopenharmony_ci{ 29198c2ecf20Sopenharmony_ci struct se_cmd *se_cmd = &cmd->se_cmd; 29208c2ecf20Sopenharmony_ci uint32_t lba = 0xffffffff & se_cmd->t_task_lba; 29218c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = cmd->tgt->vha; 29228c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 29238c2ecf20Sopenharmony_ci uint32_t t32 = 0; 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci /* 29268c2ecf20Sopenharmony_ci * wait till Mode Sense/Select cmd, modepage Ah, subpage 2 29278c2ecf20Sopenharmony_ci * have been immplemented by TCM, before AppTag is avail. 29288c2ecf20Sopenharmony_ci * Look for modesense_handlers[] 29298c2ecf20Sopenharmony_ci */ 29308c2ecf20Sopenharmony_ci ctx->app_tag = 0; 29318c2ecf20Sopenharmony_ci ctx->app_tag_mask[0] = 0x0; 29328c2ecf20Sopenharmony_ci ctx->app_tag_mask[1] = 0x0; 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci if (IS_PI_UNINIT_CAPABLE(ha)) { 29358c2ecf20Sopenharmony_ci if ((se_cmd->prot_type == TARGET_DIF_TYPE1_PROT) || 29368c2ecf20Sopenharmony_ci (se_cmd->prot_type == TARGET_DIF_TYPE2_PROT)) 29378c2ecf20Sopenharmony_ci *pfw_prot_opts |= PO_DIS_VALD_APP_ESC; 29388c2ecf20Sopenharmony_ci else if (se_cmd->prot_type == TARGET_DIF_TYPE3_PROT) 29398c2ecf20Sopenharmony_ci *pfw_prot_opts |= PO_DIS_VALD_APP_REF_ESC; 29408c2ecf20Sopenharmony_ci } 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci t32 = ha->tgt.tgt_ops->get_dif_tags(cmd, pfw_prot_opts); 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci switch (se_cmd->prot_type) { 29458c2ecf20Sopenharmony_ci case TARGET_DIF_TYPE0_PROT: 29468c2ecf20Sopenharmony_ci /* 29478c2ecf20Sopenharmony_ci * No check for ql2xenablehba_err_chk, as it 29488c2ecf20Sopenharmony_ci * would be an I/O error if hba tag generation 29498c2ecf20Sopenharmony_ci * is not done. 29508c2ecf20Sopenharmony_ci */ 29518c2ecf20Sopenharmony_ci ctx->ref_tag = cpu_to_le32(lba); 29528c2ecf20Sopenharmony_ci /* enable ALL bytes of the ref tag */ 29538c2ecf20Sopenharmony_ci ctx->ref_tag_mask[0] = 0xff; 29548c2ecf20Sopenharmony_ci ctx->ref_tag_mask[1] = 0xff; 29558c2ecf20Sopenharmony_ci ctx->ref_tag_mask[2] = 0xff; 29568c2ecf20Sopenharmony_ci ctx->ref_tag_mask[3] = 0xff; 29578c2ecf20Sopenharmony_ci break; 29588c2ecf20Sopenharmony_ci case TARGET_DIF_TYPE1_PROT: 29598c2ecf20Sopenharmony_ci /* 29608c2ecf20Sopenharmony_ci * For TYPE 1 protection: 16 bit GUARD tag, 32 bit 29618c2ecf20Sopenharmony_ci * REF tag, and 16 bit app tag. 29628c2ecf20Sopenharmony_ci */ 29638c2ecf20Sopenharmony_ci ctx->ref_tag = cpu_to_le32(lba); 29648c2ecf20Sopenharmony_ci if (!qla_tgt_ref_mask_check(se_cmd) || 29658c2ecf20Sopenharmony_ci !(ha->tgt.tgt_ops->chk_dif_tags(t32))) { 29668c2ecf20Sopenharmony_ci *pfw_prot_opts |= PO_DIS_REF_TAG_VALD; 29678c2ecf20Sopenharmony_ci break; 29688c2ecf20Sopenharmony_ci } 29698c2ecf20Sopenharmony_ci /* enable ALL bytes of the ref tag */ 29708c2ecf20Sopenharmony_ci ctx->ref_tag_mask[0] = 0xff; 29718c2ecf20Sopenharmony_ci ctx->ref_tag_mask[1] = 0xff; 29728c2ecf20Sopenharmony_ci ctx->ref_tag_mask[2] = 0xff; 29738c2ecf20Sopenharmony_ci ctx->ref_tag_mask[3] = 0xff; 29748c2ecf20Sopenharmony_ci break; 29758c2ecf20Sopenharmony_ci case TARGET_DIF_TYPE2_PROT: 29768c2ecf20Sopenharmony_ci /* 29778c2ecf20Sopenharmony_ci * For TYPE 2 protection: 16 bit GUARD + 32 bit REF 29788c2ecf20Sopenharmony_ci * tag has to match LBA in CDB + N 29798c2ecf20Sopenharmony_ci */ 29808c2ecf20Sopenharmony_ci ctx->ref_tag = cpu_to_le32(lba); 29818c2ecf20Sopenharmony_ci if (!qla_tgt_ref_mask_check(se_cmd) || 29828c2ecf20Sopenharmony_ci !(ha->tgt.tgt_ops->chk_dif_tags(t32))) { 29838c2ecf20Sopenharmony_ci *pfw_prot_opts |= PO_DIS_REF_TAG_VALD; 29848c2ecf20Sopenharmony_ci break; 29858c2ecf20Sopenharmony_ci } 29868c2ecf20Sopenharmony_ci /* enable ALL bytes of the ref tag */ 29878c2ecf20Sopenharmony_ci ctx->ref_tag_mask[0] = 0xff; 29888c2ecf20Sopenharmony_ci ctx->ref_tag_mask[1] = 0xff; 29898c2ecf20Sopenharmony_ci ctx->ref_tag_mask[2] = 0xff; 29908c2ecf20Sopenharmony_ci ctx->ref_tag_mask[3] = 0xff; 29918c2ecf20Sopenharmony_ci break; 29928c2ecf20Sopenharmony_ci case TARGET_DIF_TYPE3_PROT: 29938c2ecf20Sopenharmony_ci /* For TYPE 3 protection: 16 bit GUARD only */ 29948c2ecf20Sopenharmony_ci *pfw_prot_opts |= PO_DIS_REF_TAG_VALD; 29958c2ecf20Sopenharmony_ci ctx->ref_tag_mask[0] = ctx->ref_tag_mask[1] = 29968c2ecf20Sopenharmony_ci ctx->ref_tag_mask[2] = ctx->ref_tag_mask[3] = 0x00; 29978c2ecf20Sopenharmony_ci break; 29988c2ecf20Sopenharmony_ci } 29998c2ecf20Sopenharmony_ci} 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_cistatic inline int 30028c2ecf20Sopenharmony_ciqlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) 30038c2ecf20Sopenharmony_ci{ 30048c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd; 30058c2ecf20Sopenharmony_ci uint32_t transfer_length = 0; 30068c2ecf20Sopenharmony_ci uint32_t data_bytes; 30078c2ecf20Sopenharmony_ci uint32_t dif_bytes; 30088c2ecf20Sopenharmony_ci uint8_t bundling = 1; 30098c2ecf20Sopenharmony_ci struct crc_context *crc_ctx_pkt = NULL; 30108c2ecf20Sopenharmony_ci struct qla_hw_data *ha; 30118c2ecf20Sopenharmony_ci struct ctio_crc2_to_fw *pkt; 30128c2ecf20Sopenharmony_ci dma_addr_t crc_ctx_dma; 30138c2ecf20Sopenharmony_ci uint16_t fw_prot_opts = 0; 30148c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd = prm->cmd; 30158c2ecf20Sopenharmony_ci struct se_cmd *se_cmd = &cmd->se_cmd; 30168c2ecf20Sopenharmony_ci uint32_t h; 30178c2ecf20Sopenharmony_ci struct atio_from_isp *atio = &prm->cmd->atio; 30188c2ecf20Sopenharmony_ci struct qla_tc_param tc; 30198c2ecf20Sopenharmony_ci uint16_t t16; 30208c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = cmd->vha; 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci ha = vha->hw; 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci pkt = (struct ctio_crc2_to_fw *)qpair->req->ring_ptr; 30258c2ecf20Sopenharmony_ci prm->pkt = pkt; 30268c2ecf20Sopenharmony_ci memset(pkt, 0, sizeof(*pkt)); 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci ql_dbg_qp(ql_dbg_tgt, cmd->qpair, 0xe071, 30298c2ecf20Sopenharmony_ci "qla_target(%d):%s: se_cmd[%p] CRC2 prot_op[0x%x] cmd prot sg:cnt[%p:%x] lba[%llu]\n", 30308c2ecf20Sopenharmony_ci cmd->vp_idx, __func__, se_cmd, se_cmd->prot_op, 30318c2ecf20Sopenharmony_ci prm->prot_sg, prm->prot_seg_cnt, se_cmd->t_task_lba); 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci if ((se_cmd->prot_op == TARGET_PROT_DIN_INSERT) || 30348c2ecf20Sopenharmony_ci (se_cmd->prot_op == TARGET_PROT_DOUT_STRIP)) 30358c2ecf20Sopenharmony_ci bundling = 0; 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci /* Compute dif len and adjust data len to incude protection */ 30388c2ecf20Sopenharmony_ci data_bytes = cmd->bufflen; 30398c2ecf20Sopenharmony_ci dif_bytes = (data_bytes / cmd->blk_sz) * 8; 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci switch (se_cmd->prot_op) { 30428c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_INSERT: 30438c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_STRIP: 30448c2ecf20Sopenharmony_ci transfer_length = data_bytes; 30458c2ecf20Sopenharmony_ci if (cmd->prot_sg_cnt) 30468c2ecf20Sopenharmony_ci data_bytes += dif_bytes; 30478c2ecf20Sopenharmony_ci break; 30488c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_STRIP: 30498c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_INSERT: 30508c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_PASS: 30518c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_PASS: 30528c2ecf20Sopenharmony_ci transfer_length = data_bytes + dif_bytes; 30538c2ecf20Sopenharmony_ci break; 30548c2ecf20Sopenharmony_ci default: 30558c2ecf20Sopenharmony_ci BUG(); 30568c2ecf20Sopenharmony_ci break; 30578c2ecf20Sopenharmony_ci } 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci if (!qlt_hba_err_chk_enabled(se_cmd)) 30608c2ecf20Sopenharmony_ci fw_prot_opts |= 0x10; /* Disable Guard tag checking */ 30618c2ecf20Sopenharmony_ci /* HBA error checking enabled */ 30628c2ecf20Sopenharmony_ci else if (IS_PI_UNINIT_CAPABLE(ha)) { 30638c2ecf20Sopenharmony_ci if ((se_cmd->prot_type == TARGET_DIF_TYPE1_PROT) || 30648c2ecf20Sopenharmony_ci (se_cmd->prot_type == TARGET_DIF_TYPE2_PROT)) 30658c2ecf20Sopenharmony_ci fw_prot_opts |= PO_DIS_VALD_APP_ESC; 30668c2ecf20Sopenharmony_ci else if (se_cmd->prot_type == TARGET_DIF_TYPE3_PROT) 30678c2ecf20Sopenharmony_ci fw_prot_opts |= PO_DIS_VALD_APP_REF_ESC; 30688c2ecf20Sopenharmony_ci } 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci switch (se_cmd->prot_op) { 30718c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_INSERT: 30728c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_INSERT: 30738c2ecf20Sopenharmony_ci fw_prot_opts |= PO_MODE_DIF_INSERT; 30748c2ecf20Sopenharmony_ci break; 30758c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_STRIP: 30768c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_STRIP: 30778c2ecf20Sopenharmony_ci fw_prot_opts |= PO_MODE_DIF_REMOVE; 30788c2ecf20Sopenharmony_ci break; 30798c2ecf20Sopenharmony_ci case TARGET_PROT_DIN_PASS: 30808c2ecf20Sopenharmony_ci case TARGET_PROT_DOUT_PASS: 30818c2ecf20Sopenharmony_ci fw_prot_opts |= PO_MODE_DIF_PASS; 30828c2ecf20Sopenharmony_ci /* FUTURE: does tcm require T10CRC<->IPCKSUM conversion? */ 30838c2ecf20Sopenharmony_ci break; 30848c2ecf20Sopenharmony_ci default:/* Normal Request */ 30858c2ecf20Sopenharmony_ci fw_prot_opts |= PO_MODE_DIF_PASS; 30868c2ecf20Sopenharmony_ci break; 30878c2ecf20Sopenharmony_ci } 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci /* ---- PKT ---- */ 30908c2ecf20Sopenharmony_ci /* Update entry type to indicate Command Type CRC_2 IOCB */ 30918c2ecf20Sopenharmony_ci pkt->entry_type = CTIO_CRC2; 30928c2ecf20Sopenharmony_ci pkt->entry_count = 1; 30938c2ecf20Sopenharmony_ci pkt->vp_index = cmd->vp_idx; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci h = qlt_make_handle(qpair); 30968c2ecf20Sopenharmony_ci if (unlikely(h == QLA_TGT_NULL_HANDLE)) { 30978c2ecf20Sopenharmony_ci /* 30988c2ecf20Sopenharmony_ci * CTIO type 7 from the firmware doesn't provide a way to 30998c2ecf20Sopenharmony_ci * know the initiator's LOOP ID, hence we can't find 31008c2ecf20Sopenharmony_ci * the session and, so, the command. 31018c2ecf20Sopenharmony_ci */ 31028c2ecf20Sopenharmony_ci return -EAGAIN; 31038c2ecf20Sopenharmony_ci } else 31048c2ecf20Sopenharmony_ci qpair->req->outstanding_cmds[h] = (srb_t *)prm->cmd; 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci pkt->handle = make_handle(qpair->req->id, h); 31078c2ecf20Sopenharmony_ci pkt->handle |= CTIO_COMPLETION_HANDLE_MARK; 31088c2ecf20Sopenharmony_ci pkt->nport_handle = cpu_to_le16(prm->cmd->loop_id); 31098c2ecf20Sopenharmony_ci pkt->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); 31108c2ecf20Sopenharmony_ci pkt->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); 31118c2ecf20Sopenharmony_ci pkt->exchange_addr = atio->u.isp24.exchange_addr; 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci /* silence compile warning */ 31148c2ecf20Sopenharmony_ci t16 = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); 31158c2ecf20Sopenharmony_ci pkt->ox_id = cpu_to_le16(t16); 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci t16 = (atio->u.isp24.attr << 9); 31188c2ecf20Sopenharmony_ci pkt->flags |= cpu_to_le16(t16); 31198c2ecf20Sopenharmony_ci pkt->relative_offset = cpu_to_le32(prm->cmd->offset); 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci /* Set transfer direction */ 31228c2ecf20Sopenharmony_ci if (cmd->dma_data_direction == DMA_TO_DEVICE) 31238c2ecf20Sopenharmony_ci pkt->flags = cpu_to_le16(CTIO7_FLAGS_DATA_IN); 31248c2ecf20Sopenharmony_ci else if (cmd->dma_data_direction == DMA_FROM_DEVICE) 31258c2ecf20Sopenharmony_ci pkt->flags = cpu_to_le16(CTIO7_FLAGS_DATA_OUT); 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci pkt->dseg_count = cpu_to_le16(prm->tot_dsds); 31288c2ecf20Sopenharmony_ci /* Fibre channel byte count */ 31298c2ecf20Sopenharmony_ci pkt->transfer_length = cpu_to_le32(transfer_length); 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci /* ----- CRC context -------- */ 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci /* Allocate CRC context from global pool */ 31348c2ecf20Sopenharmony_ci crc_ctx_pkt = cmd->ctx = 31358c2ecf20Sopenharmony_ci dma_pool_zalloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma); 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci if (!crc_ctx_pkt) 31388c2ecf20Sopenharmony_ci goto crc_queuing_error; 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci crc_ctx_pkt->crc_ctx_dma = crc_ctx_dma; 31418c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list); 31428c2ecf20Sopenharmony_ci 31438c2ecf20Sopenharmony_ci /* Set handle */ 31448c2ecf20Sopenharmony_ci crc_ctx_pkt->handle = pkt->handle; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci qla_tgt_set_dif_tags(cmd, crc_ctx_pkt, &fw_prot_opts); 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci put_unaligned_le64(crc_ctx_dma, &pkt->crc_context_address); 31498c2ecf20Sopenharmony_ci pkt->crc_context_len = cpu_to_le16(CRC_CONTEXT_LEN_FW); 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci if (!bundling) { 31528c2ecf20Sopenharmony_ci cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd[0]; 31538c2ecf20Sopenharmony_ci } else { 31548c2ecf20Sopenharmony_ci /* 31558c2ecf20Sopenharmony_ci * Configure Bundling if we need to fetch interlaving 31568c2ecf20Sopenharmony_ci * protection PCI accesses 31578c2ecf20Sopenharmony_ci */ 31588c2ecf20Sopenharmony_ci fw_prot_opts |= PO_ENABLE_DIF_BUNDLING; 31598c2ecf20Sopenharmony_ci crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes); 31608c2ecf20Sopenharmony_ci crc_ctx_pkt->u.bundling.dseg_count = 31618c2ecf20Sopenharmony_ci cpu_to_le16(prm->tot_dsds - prm->prot_seg_cnt); 31628c2ecf20Sopenharmony_ci cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd[0]; 31638c2ecf20Sopenharmony_ci } 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci /* Finish the common fields of CRC pkt */ 31668c2ecf20Sopenharmony_ci crc_ctx_pkt->blk_size = cpu_to_le16(cmd->blk_sz); 31678c2ecf20Sopenharmony_ci crc_ctx_pkt->prot_opts = cpu_to_le16(fw_prot_opts); 31688c2ecf20Sopenharmony_ci crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes); 31698c2ecf20Sopenharmony_ci crc_ctx_pkt->guard_seed = cpu_to_le16(0); 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci memset((uint8_t *)&tc, 0 , sizeof(tc)); 31728c2ecf20Sopenharmony_ci tc.vha = vha; 31738c2ecf20Sopenharmony_ci tc.blk_sz = cmd->blk_sz; 31748c2ecf20Sopenharmony_ci tc.bufflen = cmd->bufflen; 31758c2ecf20Sopenharmony_ci tc.sg = cmd->sg; 31768c2ecf20Sopenharmony_ci tc.prot_sg = cmd->prot_sg; 31778c2ecf20Sopenharmony_ci tc.ctx = crc_ctx_pkt; 31788c2ecf20Sopenharmony_ci tc.ctx_dsd_alloced = &cmd->ctx_dsd_alloced; 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci /* Walks data segments */ 31818c2ecf20Sopenharmony_ci pkt->flags |= cpu_to_le16(CTIO7_FLAGS_DSD_PTR); 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci if (!bundling && prm->prot_seg_cnt) { 31848c2ecf20Sopenharmony_ci if (qla24xx_walk_and_build_sglist_no_difb(ha, NULL, cur_dsd, 31858c2ecf20Sopenharmony_ci prm->tot_dsds, &tc)) 31868c2ecf20Sopenharmony_ci goto crc_queuing_error; 31878c2ecf20Sopenharmony_ci } else if (qla24xx_walk_and_build_sglist(ha, NULL, cur_dsd, 31888c2ecf20Sopenharmony_ci (prm->tot_dsds - prm->prot_seg_cnt), &tc)) 31898c2ecf20Sopenharmony_ci goto crc_queuing_error; 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci if (bundling && prm->prot_seg_cnt) { 31928c2ecf20Sopenharmony_ci /* Walks dif segments */ 31938c2ecf20Sopenharmony_ci pkt->add_flags |= CTIO_CRC2_AF_DIF_DSD_ENA; 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci cur_dsd = &crc_ctx_pkt->u.bundling.dif_dsd; 31968c2ecf20Sopenharmony_ci if (qla24xx_walk_and_build_prot_sglist(ha, NULL, cur_dsd, 31978c2ecf20Sopenharmony_ci prm->prot_seg_cnt, cmd)) 31988c2ecf20Sopenharmony_ci goto crc_queuing_error; 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci return QLA_SUCCESS; 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_cicrc_queuing_error: 32038c2ecf20Sopenharmony_ci /* Cleanup will be performed by the caller */ 32048c2ecf20Sopenharmony_ci qpair->req->outstanding_cmds[h] = NULL; 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 32078c2ecf20Sopenharmony_ci} 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci/* 32108c2ecf20Sopenharmony_ci * Callback to setup response of xmit_type of QLA_TGT_XMIT_DATA and * 32118c2ecf20Sopenharmony_ci * QLA_TGT_XMIT_STATUS for >= 24xx silicon 32128c2ecf20Sopenharmony_ci */ 32138c2ecf20Sopenharmony_ciint qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, 32148c2ecf20Sopenharmony_ci uint8_t scsi_status) 32158c2ecf20Sopenharmony_ci{ 32168c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = cmd->vha; 32178c2ecf20Sopenharmony_ci struct qla_qpair *qpair = cmd->qpair; 32188c2ecf20Sopenharmony_ci struct ctio7_to_24xx *pkt; 32198c2ecf20Sopenharmony_ci struct qla_tgt_prm prm; 32208c2ecf20Sopenharmony_ci uint32_t full_req_cnt = 0; 32218c2ecf20Sopenharmony_ci unsigned long flags = 0; 32228c2ecf20Sopenharmony_ci int res; 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) || 32258c2ecf20Sopenharmony_ci (cmd->sess && cmd->sess->deleted)) { 32268c2ecf20Sopenharmony_ci cmd->state = QLA_TGT_STATE_PROCESSED; 32278c2ecf20Sopenharmony_ci return 0; 32288c2ecf20Sopenharmony_ci } 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci ql_dbg_qp(ql_dbg_tgt, qpair, 0xe018, 32318c2ecf20Sopenharmony_ci "is_send_status=%d, cmd->bufflen=%d, cmd->sg_cnt=%d, cmd->dma_data_direction=%d se_cmd[%p] qp %d\n", 32328c2ecf20Sopenharmony_ci (xmit_type & QLA_TGT_XMIT_STATUS) ? 32338c2ecf20Sopenharmony_ci 1 : 0, cmd->bufflen, cmd->sg_cnt, cmd->dma_data_direction, 32348c2ecf20Sopenharmony_ci &cmd->se_cmd, qpair->id); 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status, 32378c2ecf20Sopenharmony_ci &full_req_cnt); 32388c2ecf20Sopenharmony_ci if (unlikely(res != 0)) { 32398c2ecf20Sopenharmony_ci return res; 32408c2ecf20Sopenharmony_ci } 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci if (xmit_type == QLA_TGT_XMIT_STATUS) 32458c2ecf20Sopenharmony_ci qpair->tgt_counters.core_qla_snd_status++; 32468c2ecf20Sopenharmony_ci else 32478c2ecf20Sopenharmony_ci qpair->tgt_counters.core_qla_que_buf++; 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci if (!qpair->fw_started || cmd->reset_count != qpair->chip_reset) { 32508c2ecf20Sopenharmony_ci /* 32518c2ecf20Sopenharmony_ci * Either the port is not online or this request was from 32528c2ecf20Sopenharmony_ci * previous life, just abort the processing. 32538c2ecf20Sopenharmony_ci */ 32548c2ecf20Sopenharmony_ci cmd->state = QLA_TGT_STATE_PROCESSED; 32558c2ecf20Sopenharmony_ci ql_dbg_qp(ql_dbg_async, qpair, 0xe101, 32568c2ecf20Sopenharmony_ci "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n", 32578c2ecf20Sopenharmony_ci vha->flags.online, qla2x00_reset_active(vha), 32588c2ecf20Sopenharmony_ci cmd->reset_count, qpair->chip_reset); 32598c2ecf20Sopenharmony_ci res = 0; 32608c2ecf20Sopenharmony_ci goto out_unmap_unlock; 32618c2ecf20Sopenharmony_ci } 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_ci /* Does F/W have an IOCBs for this request */ 32648c2ecf20Sopenharmony_ci res = qlt_check_reserve_free_req(qpair, full_req_cnt); 32658c2ecf20Sopenharmony_ci if (unlikely(res)) 32668c2ecf20Sopenharmony_ci goto out_unmap_unlock; 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_ci if (cmd->se_cmd.prot_op && (xmit_type & QLA_TGT_XMIT_DATA)) 32698c2ecf20Sopenharmony_ci res = qlt_build_ctio_crc2_pkt(qpair, &prm); 32708c2ecf20Sopenharmony_ci else 32718c2ecf20Sopenharmony_ci res = qlt_24xx_build_ctio_pkt(qpair, &prm); 32728c2ecf20Sopenharmony_ci if (unlikely(res != 0)) { 32738c2ecf20Sopenharmony_ci qpair->req->cnt += full_req_cnt; 32748c2ecf20Sopenharmony_ci goto out_unmap_unlock; 32758c2ecf20Sopenharmony_ci } 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ci pkt = (struct ctio7_to_24xx *)prm.pkt; 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci if (qlt_has_data(cmd) && (xmit_type & QLA_TGT_XMIT_DATA)) { 32808c2ecf20Sopenharmony_ci pkt->u.status0.flags |= 32818c2ecf20Sopenharmony_ci cpu_to_le16(CTIO7_FLAGS_DATA_IN | 32828c2ecf20Sopenharmony_ci CTIO7_FLAGS_STATUS_MODE_0); 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci if (cmd->se_cmd.prot_op == TARGET_PROT_NORMAL) 32858c2ecf20Sopenharmony_ci qlt_load_data_segments(&prm); 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci if (prm.add_status_pkt == 0) { 32888c2ecf20Sopenharmony_ci if (xmit_type & QLA_TGT_XMIT_STATUS) { 32898c2ecf20Sopenharmony_ci pkt->u.status0.scsi_status = 32908c2ecf20Sopenharmony_ci cpu_to_le16(prm.rq_result); 32918c2ecf20Sopenharmony_ci pkt->u.status0.residual = 32928c2ecf20Sopenharmony_ci cpu_to_le32(prm.residual); 32938c2ecf20Sopenharmony_ci pkt->u.status0.flags |= cpu_to_le16( 32948c2ecf20Sopenharmony_ci CTIO7_FLAGS_SEND_STATUS); 32958c2ecf20Sopenharmony_ci if (qlt_need_explicit_conf(cmd, 0)) { 32968c2ecf20Sopenharmony_ci pkt->u.status0.flags |= 32978c2ecf20Sopenharmony_ci cpu_to_le16( 32988c2ecf20Sopenharmony_ci CTIO7_FLAGS_EXPLICIT_CONFORM | 32998c2ecf20Sopenharmony_ci CTIO7_FLAGS_CONFORM_REQ); 33008c2ecf20Sopenharmony_ci } 33018c2ecf20Sopenharmony_ci } 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci } else { 33048c2ecf20Sopenharmony_ci /* 33058c2ecf20Sopenharmony_ci * We have already made sure that there is sufficient 33068c2ecf20Sopenharmony_ci * amount of request entries to not drop HW lock in 33078c2ecf20Sopenharmony_ci * req_pkt(). 33088c2ecf20Sopenharmony_ci */ 33098c2ecf20Sopenharmony_ci struct ctio7_to_24xx *ctio = 33108c2ecf20Sopenharmony_ci (struct ctio7_to_24xx *)qlt_get_req_pkt( 33118c2ecf20Sopenharmony_ci qpair->req); 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_ci ql_dbg_qp(ql_dbg_tgt, qpair, 0x305e, 33148c2ecf20Sopenharmony_ci "Building additional status packet 0x%p.\n", 33158c2ecf20Sopenharmony_ci ctio); 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci /* 33188c2ecf20Sopenharmony_ci * T10Dif: ctio_crc2_to_fw overlay ontop of 33198c2ecf20Sopenharmony_ci * ctio7_to_24xx 33208c2ecf20Sopenharmony_ci */ 33218c2ecf20Sopenharmony_ci memcpy(ctio, pkt, sizeof(*ctio)); 33228c2ecf20Sopenharmony_ci /* reset back to CTIO7 */ 33238c2ecf20Sopenharmony_ci ctio->entry_count = 1; 33248c2ecf20Sopenharmony_ci ctio->entry_type = CTIO_TYPE7; 33258c2ecf20Sopenharmony_ci ctio->dseg_count = 0; 33268c2ecf20Sopenharmony_ci ctio->u.status1.flags &= ~cpu_to_le16( 33278c2ecf20Sopenharmony_ci CTIO7_FLAGS_DATA_IN); 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci /* Real finish is ctio_m1's finish */ 33308c2ecf20Sopenharmony_ci pkt->handle |= CTIO_INTERMEDIATE_HANDLE_MARK; 33318c2ecf20Sopenharmony_ci pkt->u.status0.flags |= cpu_to_le16( 33328c2ecf20Sopenharmony_ci CTIO7_FLAGS_DONT_RET_CTIO); 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci /* qlt_24xx_init_ctio_to_isp will correct 33358c2ecf20Sopenharmony_ci * all neccessary fields that's part of CTIO7. 33368c2ecf20Sopenharmony_ci * There should be no residual of CTIO-CRC2 data. 33378c2ecf20Sopenharmony_ci */ 33388c2ecf20Sopenharmony_ci qlt_24xx_init_ctio_to_isp((struct ctio7_to_24xx *)ctio, 33398c2ecf20Sopenharmony_ci &prm); 33408c2ecf20Sopenharmony_ci } 33418c2ecf20Sopenharmony_ci } else 33428c2ecf20Sopenharmony_ci qlt_24xx_init_ctio_to_isp(pkt, &prm); 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci cmd->state = QLA_TGT_STATE_PROCESSED; /* Mid-level is done processing */ 33468c2ecf20Sopenharmony_ci cmd->cmd_sent_to_fw = 1; 33478c2ecf20Sopenharmony_ci cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags); 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ci /* Memory Barrier */ 33508c2ecf20Sopenharmony_ci wmb(); 33518c2ecf20Sopenharmony_ci if (qpair->reqq_start_iocbs) 33528c2ecf20Sopenharmony_ci qpair->reqq_start_iocbs(qpair); 33538c2ecf20Sopenharmony_ci else 33548c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, qpair->req); 33558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci return 0; 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ciout_unmap_unlock: 33608c2ecf20Sopenharmony_ci qlt_unmap_sg(vha, cmd); 33618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci return res; 33648c2ecf20Sopenharmony_ci} 33658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_xmit_response); 33668c2ecf20Sopenharmony_ci 33678c2ecf20Sopenharmony_ciint qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) 33688c2ecf20Sopenharmony_ci{ 33698c2ecf20Sopenharmony_ci struct ctio7_to_24xx *pkt; 33708c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = cmd->vha; 33718c2ecf20Sopenharmony_ci struct qla_tgt *tgt = cmd->tgt; 33728c2ecf20Sopenharmony_ci struct qla_tgt_prm prm; 33738c2ecf20Sopenharmony_ci unsigned long flags = 0; 33748c2ecf20Sopenharmony_ci int res = 0; 33758c2ecf20Sopenharmony_ci struct qla_qpair *qpair = cmd->qpair; 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci memset(&prm, 0, sizeof(prm)); 33788c2ecf20Sopenharmony_ci prm.cmd = cmd; 33798c2ecf20Sopenharmony_ci prm.tgt = tgt; 33808c2ecf20Sopenharmony_ci prm.sg = NULL; 33818c2ecf20Sopenharmony_ci prm.req_cnt = 1; 33828c2ecf20Sopenharmony_ci 33838c2ecf20Sopenharmony_ci if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) || 33848c2ecf20Sopenharmony_ci (cmd->sess && cmd->sess->deleted)) { 33858c2ecf20Sopenharmony_ci /* 33868c2ecf20Sopenharmony_ci * Either the port is not online or this request was from 33878c2ecf20Sopenharmony_ci * previous life, just abort the processing. 33888c2ecf20Sopenharmony_ci */ 33898c2ecf20Sopenharmony_ci cmd->aborted = 1; 33908c2ecf20Sopenharmony_ci cmd->write_data_transferred = 0; 33918c2ecf20Sopenharmony_ci cmd->state = QLA_TGT_STATE_DATA_IN; 33928c2ecf20Sopenharmony_ci vha->hw->tgt.tgt_ops->handle_data(cmd); 33938c2ecf20Sopenharmony_ci ql_dbg_qp(ql_dbg_async, qpair, 0xe102, 33948c2ecf20Sopenharmony_ci "RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n", 33958c2ecf20Sopenharmony_ci vha->flags.online, qla2x00_reset_active(vha), 33968c2ecf20Sopenharmony_ci cmd->reset_count, qpair->chip_reset); 33978c2ecf20Sopenharmony_ci return 0; 33988c2ecf20Sopenharmony_ci } 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ci /* Calculate number of entries and segments required */ 34018c2ecf20Sopenharmony_ci if (qlt_pci_map_calc_cnt(&prm) != 0) 34028c2ecf20Sopenharmony_ci return -EAGAIN; 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 34058c2ecf20Sopenharmony_ci /* Does F/W have an IOCBs for this request */ 34068c2ecf20Sopenharmony_ci res = qlt_check_reserve_free_req(qpair, prm.req_cnt); 34078c2ecf20Sopenharmony_ci if (res != 0) 34088c2ecf20Sopenharmony_ci goto out_unlock_free_unmap; 34098c2ecf20Sopenharmony_ci if (cmd->se_cmd.prot_op) 34108c2ecf20Sopenharmony_ci res = qlt_build_ctio_crc2_pkt(qpair, &prm); 34118c2ecf20Sopenharmony_ci else 34128c2ecf20Sopenharmony_ci res = qlt_24xx_build_ctio_pkt(qpair, &prm); 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci if (unlikely(res != 0)) { 34158c2ecf20Sopenharmony_ci qpair->req->cnt += prm.req_cnt; 34168c2ecf20Sopenharmony_ci goto out_unlock_free_unmap; 34178c2ecf20Sopenharmony_ci } 34188c2ecf20Sopenharmony_ci 34198c2ecf20Sopenharmony_ci pkt = (struct ctio7_to_24xx *)prm.pkt; 34208c2ecf20Sopenharmony_ci pkt->u.status0.flags |= cpu_to_le16(CTIO7_FLAGS_DATA_OUT | 34218c2ecf20Sopenharmony_ci CTIO7_FLAGS_STATUS_MODE_0); 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci if (cmd->se_cmd.prot_op == TARGET_PROT_NORMAL) 34248c2ecf20Sopenharmony_ci qlt_load_data_segments(&prm); 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci cmd->state = QLA_TGT_STATE_NEED_DATA; 34278c2ecf20Sopenharmony_ci cmd->cmd_sent_to_fw = 1; 34288c2ecf20Sopenharmony_ci cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags); 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci /* Memory Barrier */ 34318c2ecf20Sopenharmony_ci wmb(); 34328c2ecf20Sopenharmony_ci if (qpair->reqq_start_iocbs) 34338c2ecf20Sopenharmony_ci qpair->reqq_start_iocbs(qpair); 34348c2ecf20Sopenharmony_ci else 34358c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, qpair->req); 34368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 34378c2ecf20Sopenharmony_ci 34388c2ecf20Sopenharmony_ci return res; 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ciout_unlock_free_unmap: 34418c2ecf20Sopenharmony_ci qlt_unmap_sg(vha, cmd); 34428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_ci return res; 34458c2ecf20Sopenharmony_ci} 34468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_rdy_to_xfer); 34478c2ecf20Sopenharmony_ci 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci/* 34508c2ecf20Sopenharmony_ci * it is assumed either hardware_lock or qpair lock is held. 34518c2ecf20Sopenharmony_ci */ 34528c2ecf20Sopenharmony_cistatic void 34538c2ecf20Sopenharmony_ciqlt_handle_dif_error(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, 34548c2ecf20Sopenharmony_ci struct ctio_crc_from_fw *sts) 34558c2ecf20Sopenharmony_ci{ 34568c2ecf20Sopenharmony_ci uint8_t *ap = &sts->actual_dif[0]; 34578c2ecf20Sopenharmony_ci uint8_t *ep = &sts->expected_dif[0]; 34588c2ecf20Sopenharmony_ci uint64_t lba = cmd->se_cmd.t_task_lba; 34598c2ecf20Sopenharmony_ci uint8_t scsi_status, sense_key, asc, ascq; 34608c2ecf20Sopenharmony_ci unsigned long flags; 34618c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = cmd->vha; 34628c2ecf20Sopenharmony_ci 34638c2ecf20Sopenharmony_ci cmd->trc_flags |= TRC_DIF_ERR; 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci cmd->a_guard = get_unaligned_be16(ap + 0); 34668c2ecf20Sopenharmony_ci cmd->a_app_tag = get_unaligned_be16(ap + 2); 34678c2ecf20Sopenharmony_ci cmd->a_ref_tag = get_unaligned_be32(ap + 4); 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci cmd->e_guard = get_unaligned_be16(ep + 0); 34708c2ecf20Sopenharmony_ci cmd->e_app_tag = get_unaligned_be16(ep + 2); 34718c2ecf20Sopenharmony_ci cmd->e_ref_tag = get_unaligned_be32(ep + 4); 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_dif, vha, 0xf075, 34748c2ecf20Sopenharmony_ci "%s: aborted %d state %d\n", __func__, cmd->aborted, cmd->state); 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci scsi_status = sense_key = asc = ascq = 0; 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_ci /* check appl tag */ 34798c2ecf20Sopenharmony_ci if (cmd->e_app_tag != cmd->a_app_tag) { 34808c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_dif, vha, 0xe00d, 34818c2ecf20Sopenharmony_ci "App Tag ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] Ref[%x|%x], App[%x|%x], Guard [%x|%x] cmd=%p ox_id[%04x]", 34828c2ecf20Sopenharmony_ci cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks, 34838c2ecf20Sopenharmony_ci cmd->a_ref_tag, cmd->e_ref_tag, cmd->a_app_tag, 34848c2ecf20Sopenharmony_ci cmd->e_app_tag, cmd->a_guard, cmd->e_guard, cmd, 34858c2ecf20Sopenharmony_ci cmd->atio.u.isp24.fcp_hdr.ox_id); 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_ci cmd->dif_err_code = DIF_ERR_APP; 34888c2ecf20Sopenharmony_ci scsi_status = SAM_STAT_CHECK_CONDITION; 34898c2ecf20Sopenharmony_ci sense_key = ABORTED_COMMAND; 34908c2ecf20Sopenharmony_ci asc = 0x10; 34918c2ecf20Sopenharmony_ci ascq = 0x2; 34928c2ecf20Sopenharmony_ci } 34938c2ecf20Sopenharmony_ci 34948c2ecf20Sopenharmony_ci /* check ref tag */ 34958c2ecf20Sopenharmony_ci if (cmd->e_ref_tag != cmd->a_ref_tag) { 34968c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_dif, vha, 0xe00e, 34978c2ecf20Sopenharmony_ci "Ref Tag ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] Ref[%x|%x], App[%x|%x], Guard[%x|%x] cmd=%p ox_id[%04x] ", 34988c2ecf20Sopenharmony_ci cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks, 34998c2ecf20Sopenharmony_ci cmd->a_ref_tag, cmd->e_ref_tag, cmd->a_app_tag, 35008c2ecf20Sopenharmony_ci cmd->e_app_tag, cmd->a_guard, cmd->e_guard, cmd, 35018c2ecf20Sopenharmony_ci cmd->atio.u.isp24.fcp_hdr.ox_id); 35028c2ecf20Sopenharmony_ci 35038c2ecf20Sopenharmony_ci cmd->dif_err_code = DIF_ERR_REF; 35048c2ecf20Sopenharmony_ci scsi_status = SAM_STAT_CHECK_CONDITION; 35058c2ecf20Sopenharmony_ci sense_key = ABORTED_COMMAND; 35068c2ecf20Sopenharmony_ci asc = 0x10; 35078c2ecf20Sopenharmony_ci ascq = 0x3; 35088c2ecf20Sopenharmony_ci goto out; 35098c2ecf20Sopenharmony_ci } 35108c2ecf20Sopenharmony_ci 35118c2ecf20Sopenharmony_ci /* check guard */ 35128c2ecf20Sopenharmony_ci if (cmd->e_guard != cmd->a_guard) { 35138c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_dif, vha, 0xe012, 35148c2ecf20Sopenharmony_ci "Guard ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] Ref[%x|%x], App[%x|%x], Guard [%x|%x] cmd=%p ox_id[%04x]", 35158c2ecf20Sopenharmony_ci cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks, 35168c2ecf20Sopenharmony_ci cmd->a_ref_tag, cmd->e_ref_tag, cmd->a_app_tag, 35178c2ecf20Sopenharmony_ci cmd->e_app_tag, cmd->a_guard, cmd->e_guard, cmd, 35188c2ecf20Sopenharmony_ci cmd->atio.u.isp24.fcp_hdr.ox_id); 35198c2ecf20Sopenharmony_ci 35208c2ecf20Sopenharmony_ci cmd->dif_err_code = DIF_ERR_GRD; 35218c2ecf20Sopenharmony_ci scsi_status = SAM_STAT_CHECK_CONDITION; 35228c2ecf20Sopenharmony_ci sense_key = ABORTED_COMMAND; 35238c2ecf20Sopenharmony_ci asc = 0x10; 35248c2ecf20Sopenharmony_ci ascq = 0x1; 35258c2ecf20Sopenharmony_ci } 35268c2ecf20Sopenharmony_ciout: 35278c2ecf20Sopenharmony_ci switch (cmd->state) { 35288c2ecf20Sopenharmony_ci case QLA_TGT_STATE_NEED_DATA: 35298c2ecf20Sopenharmony_ci /* handle_data will load DIF error code */ 35308c2ecf20Sopenharmony_ci cmd->state = QLA_TGT_STATE_DATA_IN; 35318c2ecf20Sopenharmony_ci vha->hw->tgt.tgt_ops->handle_data(cmd); 35328c2ecf20Sopenharmony_ci break; 35338c2ecf20Sopenharmony_ci default: 35348c2ecf20Sopenharmony_ci spin_lock_irqsave(&cmd->cmd_lock, flags); 35358c2ecf20Sopenharmony_ci if (cmd->aborted) { 35368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd->cmd_lock, flags); 35378c2ecf20Sopenharmony_ci vha->hw->tgt.tgt_ops->free_cmd(cmd); 35388c2ecf20Sopenharmony_ci break; 35398c2ecf20Sopenharmony_ci } 35408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd->cmd_lock, flags); 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci qlt_send_resp_ctio(qpair, cmd, scsi_status, sense_key, asc, 35438c2ecf20Sopenharmony_ci ascq); 35448c2ecf20Sopenharmony_ci /* assume scsi status gets out on the wire. 35458c2ecf20Sopenharmony_ci * Will not wait for completion. 35468c2ecf20Sopenharmony_ci */ 35478c2ecf20Sopenharmony_ci vha->hw->tgt.tgt_ops->free_cmd(cmd); 35488c2ecf20Sopenharmony_ci break; 35498c2ecf20Sopenharmony_ci } 35508c2ecf20Sopenharmony_ci} 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_ci/* If hardware_lock held on entry, might drop it, then reaquire */ 35538c2ecf20Sopenharmony_ci/* This function sends the appropriate CTIO to ISP 2xxx or 24xx */ 35548c2ecf20Sopenharmony_cistatic int __qlt_send_term_imm_notif(struct scsi_qla_host *vha, 35558c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *ntfy) 35568c2ecf20Sopenharmony_ci{ 35578c2ecf20Sopenharmony_ci struct nack_to_isp *nack; 35588c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 35598c2ecf20Sopenharmony_ci request_t *pkt; 35608c2ecf20Sopenharmony_ci int ret = 0; 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_tmr, vha, 0xe01c, 35638c2ecf20Sopenharmony_ci "Sending TERM ELS CTIO (ha=%p)\n", ha); 35648c2ecf20Sopenharmony_ci 35658c2ecf20Sopenharmony_ci pkt = (request_t *)qla2x00_alloc_iocbs(vha, NULL); 35668c2ecf20Sopenharmony_ci if (pkt == NULL) { 35678c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe080, 35688c2ecf20Sopenharmony_ci "qla_target(%d): %s failed: unable to allocate " 35698c2ecf20Sopenharmony_ci "request packet\n", vha->vp_idx, __func__); 35708c2ecf20Sopenharmony_ci return -ENOMEM; 35718c2ecf20Sopenharmony_ci } 35728c2ecf20Sopenharmony_ci 35738c2ecf20Sopenharmony_ci pkt->entry_type = NOTIFY_ACK_TYPE; 35748c2ecf20Sopenharmony_ci pkt->entry_count = 1; 35758c2ecf20Sopenharmony_ci pkt->handle = QLA_TGT_SKIP_HANDLE; 35768c2ecf20Sopenharmony_ci 35778c2ecf20Sopenharmony_ci nack = (struct nack_to_isp *)pkt; 35788c2ecf20Sopenharmony_ci nack->ox_id = ntfy->ox_id; 35798c2ecf20Sopenharmony_ci 35808c2ecf20Sopenharmony_ci nack->u.isp24.nport_handle = ntfy->u.isp24.nport_handle; 35818c2ecf20Sopenharmony_ci if (le16_to_cpu(ntfy->u.isp24.status) == IMM_NTFY_ELS) { 35828c2ecf20Sopenharmony_ci nack->u.isp24.flags = ntfy->u.isp24.flags & 35838c2ecf20Sopenharmony_ci cpu_to_le16(NOTIFY24XX_FLAGS_PUREX_IOCB); 35848c2ecf20Sopenharmony_ci } 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_ci /* terminate */ 35878c2ecf20Sopenharmony_ci nack->u.isp24.flags |= 35888c2ecf20Sopenharmony_ci __constant_cpu_to_le16(NOTIFY_ACK_FLAGS_TERMINATE); 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci nack->u.isp24.srr_rx_id = ntfy->u.isp24.srr_rx_id; 35918c2ecf20Sopenharmony_ci nack->u.isp24.status = ntfy->u.isp24.status; 35928c2ecf20Sopenharmony_ci nack->u.isp24.status_subcode = ntfy->u.isp24.status_subcode; 35938c2ecf20Sopenharmony_ci nack->u.isp24.fw_handle = ntfy->u.isp24.fw_handle; 35948c2ecf20Sopenharmony_ci nack->u.isp24.exchange_address = ntfy->u.isp24.exchange_address; 35958c2ecf20Sopenharmony_ci nack->u.isp24.srr_rel_offs = ntfy->u.isp24.srr_rel_offs; 35968c2ecf20Sopenharmony_ci nack->u.isp24.srr_ui = ntfy->u.isp24.srr_ui; 35978c2ecf20Sopenharmony_ci nack->u.isp24.vp_index = ntfy->u.isp24.vp_index; 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, vha->req); 36008c2ecf20Sopenharmony_ci return ret; 36018c2ecf20Sopenharmony_ci} 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_cistatic void qlt_send_term_imm_notif(struct scsi_qla_host *vha, 36048c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *imm, int ha_locked) 36058c2ecf20Sopenharmony_ci{ 36068c2ecf20Sopenharmony_ci int rc; 36078c2ecf20Sopenharmony_ci 36088c2ecf20Sopenharmony_ci WARN_ON_ONCE(!ha_locked); 36098c2ecf20Sopenharmony_ci rc = __qlt_send_term_imm_notif(vha, imm); 36108c2ecf20Sopenharmony_ci pr_debug("rc = %d\n", rc); 36118c2ecf20Sopenharmony_ci} 36128c2ecf20Sopenharmony_ci 36138c2ecf20Sopenharmony_ci/* 36148c2ecf20Sopenharmony_ci * If hardware_lock held on entry, might drop it, then reaquire 36158c2ecf20Sopenharmony_ci * This function sends the appropriate CTIO to ISP 2xxx or 24xx 36168c2ecf20Sopenharmony_ci */ 36178c2ecf20Sopenharmony_cistatic int __qlt_send_term_exchange(struct qla_qpair *qpair, 36188c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd, 36198c2ecf20Sopenharmony_ci struct atio_from_isp *atio) 36208c2ecf20Sopenharmony_ci{ 36218c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = qpair->vha; 36228c2ecf20Sopenharmony_ci struct ctio7_to_24xx *ctio24; 36238c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 36248c2ecf20Sopenharmony_ci request_t *pkt; 36258c2ecf20Sopenharmony_ci int ret = 0; 36268c2ecf20Sopenharmony_ci uint16_t temp; 36278c2ecf20Sopenharmony_ci 36288c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe009, "Sending TERM EXCH CTIO (ha=%p)\n", ha); 36298c2ecf20Sopenharmony_ci 36308c2ecf20Sopenharmony_ci if (cmd) 36318c2ecf20Sopenharmony_ci vha = cmd->vha; 36328c2ecf20Sopenharmony_ci 36338c2ecf20Sopenharmony_ci pkt = (request_t *)qla2x00_alloc_iocbs_ready(qpair, NULL); 36348c2ecf20Sopenharmony_ci if (pkt == NULL) { 36358c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe050, 36368c2ecf20Sopenharmony_ci "qla_target(%d): %s failed: unable to allocate " 36378c2ecf20Sopenharmony_ci "request packet\n", vha->vp_idx, __func__); 36388c2ecf20Sopenharmony_ci return -ENOMEM; 36398c2ecf20Sopenharmony_ci } 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_ci if (cmd != NULL) { 36428c2ecf20Sopenharmony_ci if (cmd->state < QLA_TGT_STATE_PROCESSED) { 36438c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe051, 36448c2ecf20Sopenharmony_ci "qla_target(%d): Terminating cmd %p with " 36458c2ecf20Sopenharmony_ci "incorrect state %d\n", vha->vp_idx, cmd, 36468c2ecf20Sopenharmony_ci cmd->state); 36478c2ecf20Sopenharmony_ci } else 36488c2ecf20Sopenharmony_ci ret = 1; 36498c2ecf20Sopenharmony_ci } 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci qpair->tgt_counters.num_term_xchg_sent++; 36528c2ecf20Sopenharmony_ci pkt->entry_count = 1; 36538c2ecf20Sopenharmony_ci pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ci ctio24 = (struct ctio7_to_24xx *)pkt; 36568c2ecf20Sopenharmony_ci ctio24->entry_type = CTIO_TYPE7; 36578c2ecf20Sopenharmony_ci ctio24->nport_handle = cpu_to_le16(CTIO7_NHANDLE_UNRECOGNIZED); 36588c2ecf20Sopenharmony_ci ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); 36598c2ecf20Sopenharmony_ci ctio24->vp_index = vha->vp_idx; 36608c2ecf20Sopenharmony_ci ctio24->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); 36618c2ecf20Sopenharmony_ci ctio24->exchange_addr = atio->u.isp24.exchange_addr; 36628c2ecf20Sopenharmony_ci temp = (atio->u.isp24.attr << 9) | CTIO7_FLAGS_STATUS_MODE_1 | 36638c2ecf20Sopenharmony_ci CTIO7_FLAGS_TERMINATE; 36648c2ecf20Sopenharmony_ci ctio24->u.status1.flags = cpu_to_le16(temp); 36658c2ecf20Sopenharmony_ci temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); 36668c2ecf20Sopenharmony_ci ctio24->u.status1.ox_id = cpu_to_le16(temp); 36678c2ecf20Sopenharmony_ci 36688c2ecf20Sopenharmony_ci /* Memory Barrier */ 36698c2ecf20Sopenharmony_ci wmb(); 36708c2ecf20Sopenharmony_ci if (qpair->reqq_start_iocbs) 36718c2ecf20Sopenharmony_ci qpair->reqq_start_iocbs(qpair); 36728c2ecf20Sopenharmony_ci else 36738c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, qpair->req); 36748c2ecf20Sopenharmony_ci return ret; 36758c2ecf20Sopenharmony_ci} 36768c2ecf20Sopenharmony_ci 36778c2ecf20Sopenharmony_cistatic void qlt_send_term_exchange(struct qla_qpair *qpair, 36788c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked, 36798c2ecf20Sopenharmony_ci int ul_abort) 36808c2ecf20Sopenharmony_ci{ 36818c2ecf20Sopenharmony_ci struct scsi_qla_host *vha; 36828c2ecf20Sopenharmony_ci unsigned long flags = 0; 36838c2ecf20Sopenharmony_ci int rc; 36848c2ecf20Sopenharmony_ci 36858c2ecf20Sopenharmony_ci /* why use different vha? NPIV */ 36868c2ecf20Sopenharmony_ci if (cmd) 36878c2ecf20Sopenharmony_ci vha = cmd->vha; 36888c2ecf20Sopenharmony_ci else 36898c2ecf20Sopenharmony_ci vha = qpair->vha; 36908c2ecf20Sopenharmony_ci 36918c2ecf20Sopenharmony_ci if (ha_locked) { 36928c2ecf20Sopenharmony_ci rc = __qlt_send_term_exchange(qpair, cmd, atio); 36938c2ecf20Sopenharmony_ci if (rc == -ENOMEM) 36948c2ecf20Sopenharmony_ci qlt_alloc_qfull_cmd(vha, atio, 0, 0); 36958c2ecf20Sopenharmony_ci goto done; 36968c2ecf20Sopenharmony_ci } 36978c2ecf20Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 36988c2ecf20Sopenharmony_ci rc = __qlt_send_term_exchange(qpair, cmd, atio); 36998c2ecf20Sopenharmony_ci if (rc == -ENOMEM) 37008c2ecf20Sopenharmony_ci qlt_alloc_qfull_cmd(vha, atio, 0, 0); 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_cidone: 37038c2ecf20Sopenharmony_ci if (cmd && !ul_abort && !cmd->aborted) { 37048c2ecf20Sopenharmony_ci if (cmd->sg_mapped) 37058c2ecf20Sopenharmony_ci qlt_unmap_sg(vha, cmd); 37068c2ecf20Sopenharmony_ci vha->hw->tgt.tgt_ops->free_cmd(cmd); 37078c2ecf20Sopenharmony_ci } 37088c2ecf20Sopenharmony_ci 37098c2ecf20Sopenharmony_ci if (!ha_locked) 37108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 37118c2ecf20Sopenharmony_ci 37128c2ecf20Sopenharmony_ci return; 37138c2ecf20Sopenharmony_ci} 37148c2ecf20Sopenharmony_ci 37158c2ecf20Sopenharmony_cistatic void qlt_init_term_exchange(struct scsi_qla_host *vha) 37168c2ecf20Sopenharmony_ci{ 37178c2ecf20Sopenharmony_ci struct list_head free_list; 37188c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd, *tcmd; 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_ci vha->hw->tgt.leak_exchg_thresh_hold = 37218c2ecf20Sopenharmony_ci (vha->hw->cur_fw_xcb_count/100) * LEAK_EXCHG_THRESH_HOLD_PERCENT; 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_ci cmd = tcmd = NULL; 37248c2ecf20Sopenharmony_ci if (!list_empty(&vha->hw->tgt.q_full_list)) { 37258c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&free_list); 37268c2ecf20Sopenharmony_ci list_splice_init(&vha->hw->tgt.q_full_list, &free_list); 37278c2ecf20Sopenharmony_ci 37288c2ecf20Sopenharmony_ci list_for_each_entry_safe(cmd, tcmd, &free_list, cmd_list) { 37298c2ecf20Sopenharmony_ci list_del(&cmd->cmd_list); 37308c2ecf20Sopenharmony_ci /* This cmd was never sent to TCM. There is no need 37318c2ecf20Sopenharmony_ci * to schedule free or call free_cmd 37328c2ecf20Sopenharmony_ci */ 37338c2ecf20Sopenharmony_ci qlt_free_cmd(cmd); 37348c2ecf20Sopenharmony_ci vha->hw->tgt.num_qfull_cmds_alloc--; 37358c2ecf20Sopenharmony_ci } 37368c2ecf20Sopenharmony_ci } 37378c2ecf20Sopenharmony_ci vha->hw->tgt.num_qfull_cmds_dropped = 0; 37388c2ecf20Sopenharmony_ci} 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_cistatic void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha) 37418c2ecf20Sopenharmony_ci{ 37428c2ecf20Sopenharmony_ci uint32_t total_leaked; 37438c2ecf20Sopenharmony_ci 37448c2ecf20Sopenharmony_ci total_leaked = vha->hw->tgt.num_qfull_cmds_dropped; 37458c2ecf20Sopenharmony_ci 37468c2ecf20Sopenharmony_ci if (vha->hw->tgt.leak_exchg_thresh_hold && 37478c2ecf20Sopenharmony_ci (total_leaked > vha->hw->tgt.leak_exchg_thresh_hold)) { 37488c2ecf20Sopenharmony_ci 37498c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe079, 37508c2ecf20Sopenharmony_ci "Chip reset due to exchange starvation: %d/%d.\n", 37518c2ecf20Sopenharmony_ci total_leaked, vha->hw->cur_fw_xcb_count); 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci if (IS_P3P_TYPE(vha->hw)) 37548c2ecf20Sopenharmony_ci set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); 37558c2ecf20Sopenharmony_ci else 37568c2ecf20Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 37578c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(vha); 37588c2ecf20Sopenharmony_ci } 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ci} 37618c2ecf20Sopenharmony_ci 37628c2ecf20Sopenharmony_ciint qlt_abort_cmd(struct qla_tgt_cmd *cmd) 37638c2ecf20Sopenharmony_ci{ 37648c2ecf20Sopenharmony_ci struct qla_tgt *tgt = cmd->tgt; 37658c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = tgt->vha; 37668c2ecf20Sopenharmony_ci struct se_cmd *se_cmd = &cmd->se_cmd; 37678c2ecf20Sopenharmony_ci unsigned long flags; 37688c2ecf20Sopenharmony_ci 37698c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014, 37708c2ecf20Sopenharmony_ci "qla_target(%d): terminating exchange for aborted cmd=%p " 37718c2ecf20Sopenharmony_ci "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd, 37728c2ecf20Sopenharmony_ci se_cmd->tag); 37738c2ecf20Sopenharmony_ci 37748c2ecf20Sopenharmony_ci spin_lock_irqsave(&cmd->cmd_lock, flags); 37758c2ecf20Sopenharmony_ci if (cmd->aborted) { 37768c2ecf20Sopenharmony_ci if (cmd->sg_mapped) 37778c2ecf20Sopenharmony_ci qlt_unmap_sg(vha, cmd); 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd->cmd_lock, flags); 37808c2ecf20Sopenharmony_ci /* 37818c2ecf20Sopenharmony_ci * It's normal to see 2 calls in this path: 37828c2ecf20Sopenharmony_ci * 1) XFER Rdy completion + CMD_T_ABORT 37838c2ecf20Sopenharmony_ci * 2) TCM TMR - drain_state_list 37848c2ecf20Sopenharmony_ci */ 37858c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf016, 37868c2ecf20Sopenharmony_ci "multiple abort. %p transport_state %x, t_state %x, " 37878c2ecf20Sopenharmony_ci "se_cmd_flags %x\n", cmd, cmd->se_cmd.transport_state, 37888c2ecf20Sopenharmony_ci cmd->se_cmd.t_state, cmd->se_cmd.se_cmd_flags); 37898c2ecf20Sopenharmony_ci return -EIO; 37908c2ecf20Sopenharmony_ci } 37918c2ecf20Sopenharmony_ci cmd->aborted = 1; 37928c2ecf20Sopenharmony_ci cmd->trc_flags |= TRC_ABORT; 37938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd->cmd_lock, flags); 37948c2ecf20Sopenharmony_ci 37958c2ecf20Sopenharmony_ci qlt_send_term_exchange(cmd->qpair, cmd, &cmd->atio, 0, 1); 37968c2ecf20Sopenharmony_ci return 0; 37978c2ecf20Sopenharmony_ci} 37988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_abort_cmd); 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_civoid qlt_free_cmd(struct qla_tgt_cmd *cmd) 38018c2ecf20Sopenharmony_ci{ 38028c2ecf20Sopenharmony_ci struct fc_port *sess = cmd->sess; 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, cmd->vha, 0xe074, 38058c2ecf20Sopenharmony_ci "%s: se_cmd[%p] ox_id %04x\n", 38068c2ecf20Sopenharmony_ci __func__, &cmd->se_cmd, 38078c2ecf20Sopenharmony_ci be16_to_cpu(cmd->atio.u.isp24.fcp_hdr.ox_id)); 38088c2ecf20Sopenharmony_ci 38098c2ecf20Sopenharmony_ci BUG_ON(cmd->cmd_in_wq); 38108c2ecf20Sopenharmony_ci 38118c2ecf20Sopenharmony_ci if (!cmd->q_full) 38128c2ecf20Sopenharmony_ci qlt_decr_num_pend_cmds(cmd->vha); 38138c2ecf20Sopenharmony_ci 38148c2ecf20Sopenharmony_ci BUG_ON(cmd->sg_mapped); 38158c2ecf20Sopenharmony_ci cmd->jiffies_at_free = get_jiffies_64(); 38168c2ecf20Sopenharmony_ci if (unlikely(cmd->free_sg)) 38178c2ecf20Sopenharmony_ci kfree(cmd->sg); 38188c2ecf20Sopenharmony_ci 38198c2ecf20Sopenharmony_ci if (!sess || !sess->se_sess) { 38208c2ecf20Sopenharmony_ci WARN_ON(1); 38218c2ecf20Sopenharmony_ci return; 38228c2ecf20Sopenharmony_ci } 38238c2ecf20Sopenharmony_ci cmd->jiffies_at_free = get_jiffies_64(); 38248c2ecf20Sopenharmony_ci cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd); 38258c2ecf20Sopenharmony_ci} 38268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_free_cmd); 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_ci/* 38298c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 38308c2ecf20Sopenharmony_ci */ 38318c2ecf20Sopenharmony_cistatic int qlt_term_ctio_exchange(struct qla_qpair *qpair, void *ctio, 38328c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd, uint32_t status) 38338c2ecf20Sopenharmony_ci{ 38348c2ecf20Sopenharmony_ci int term = 0; 38358c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = qpair->vha; 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci if (cmd->se_cmd.prot_op) 38388c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_dif, vha, 0xe013, 38398c2ecf20Sopenharmony_ci "Term DIF cmd: lba[0x%llx|%lld] len[0x%x] " 38408c2ecf20Sopenharmony_ci "se_cmd=%p tag[%x] op %#x/%s", 38418c2ecf20Sopenharmony_ci cmd->lba, cmd->lba, 38428c2ecf20Sopenharmony_ci cmd->num_blks, &cmd->se_cmd, 38438c2ecf20Sopenharmony_ci cmd->atio.u.isp24.exchange_addr, 38448c2ecf20Sopenharmony_ci cmd->se_cmd.prot_op, 38458c2ecf20Sopenharmony_ci prot_op_str(cmd->se_cmd.prot_op)); 38468c2ecf20Sopenharmony_ci 38478c2ecf20Sopenharmony_ci if (ctio != NULL) { 38488c2ecf20Sopenharmony_ci struct ctio7_from_24xx *c = (struct ctio7_from_24xx *)ctio; 38498c2ecf20Sopenharmony_ci 38508c2ecf20Sopenharmony_ci term = !(c->flags & 38518c2ecf20Sopenharmony_ci cpu_to_le16(OF_TERM_EXCH)); 38528c2ecf20Sopenharmony_ci } else 38538c2ecf20Sopenharmony_ci term = 1; 38548c2ecf20Sopenharmony_ci 38558c2ecf20Sopenharmony_ci if (term) 38568c2ecf20Sopenharmony_ci qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1, 0); 38578c2ecf20Sopenharmony_ci 38588c2ecf20Sopenharmony_ci return term; 38598c2ecf20Sopenharmony_ci} 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci 38628c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 38638c2ecf20Sopenharmony_cistatic void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, 38648c2ecf20Sopenharmony_ci struct rsp_que *rsp, uint32_t handle, void *ctio) 38658c2ecf20Sopenharmony_ci{ 38668c2ecf20Sopenharmony_ci void *cmd = NULL; 38678c2ecf20Sopenharmony_ci struct req_que *req; 38688c2ecf20Sopenharmony_ci int qid = GET_QID(handle); 38698c2ecf20Sopenharmony_ci uint32_t h = handle & ~QLA_TGT_HANDLE_MASK; 38708c2ecf20Sopenharmony_ci 38718c2ecf20Sopenharmony_ci if (unlikely(h == QLA_TGT_SKIP_HANDLE)) 38728c2ecf20Sopenharmony_ci return NULL; 38738c2ecf20Sopenharmony_ci 38748c2ecf20Sopenharmony_ci if (qid == rsp->req->id) { 38758c2ecf20Sopenharmony_ci req = rsp->req; 38768c2ecf20Sopenharmony_ci } else if (vha->hw->req_q_map[qid]) { 38778c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0x1000a, 38788c2ecf20Sopenharmony_ci "qla_target(%d): CTIO completion with different QID %d handle %x\n", 38798c2ecf20Sopenharmony_ci vha->vp_idx, rsp->id, handle); 38808c2ecf20Sopenharmony_ci req = vha->hw->req_q_map[qid]; 38818c2ecf20Sopenharmony_ci } else { 38828c2ecf20Sopenharmony_ci return NULL; 38838c2ecf20Sopenharmony_ci } 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ci h &= QLA_CMD_HANDLE_MASK; 38868c2ecf20Sopenharmony_ci 38878c2ecf20Sopenharmony_ci if (h != QLA_TGT_NULL_HANDLE) { 38888c2ecf20Sopenharmony_ci if (unlikely(h >= req->num_outstanding_cmds)) { 38898c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe052, 38908c2ecf20Sopenharmony_ci "qla_target(%d): Wrong handle %x received\n", 38918c2ecf20Sopenharmony_ci vha->vp_idx, handle); 38928c2ecf20Sopenharmony_ci return NULL; 38938c2ecf20Sopenharmony_ci } 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci cmd = req->outstanding_cmds[h]; 38968c2ecf20Sopenharmony_ci if (unlikely(cmd == NULL)) { 38978c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0xe053, 38988c2ecf20Sopenharmony_ci "qla_target(%d): Suspicious: unable to find the command with handle %x req->id %d rsp->id %d\n", 38998c2ecf20Sopenharmony_ci vha->vp_idx, handle, req->id, rsp->id); 39008c2ecf20Sopenharmony_ci return NULL; 39018c2ecf20Sopenharmony_ci } 39028c2ecf20Sopenharmony_ci req->outstanding_cmds[h] = NULL; 39038c2ecf20Sopenharmony_ci } else if (ctio != NULL) { 39048c2ecf20Sopenharmony_ci /* We can't get loop ID from CTIO7 */ 39058c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe054, 39068c2ecf20Sopenharmony_ci "qla_target(%d): Wrong CTIO received: QLA24xx doesn't " 39078c2ecf20Sopenharmony_ci "support NULL handles\n", vha->vp_idx); 39088c2ecf20Sopenharmony_ci return NULL; 39098c2ecf20Sopenharmony_ci } 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci return cmd; 39128c2ecf20Sopenharmony_ci} 39138c2ecf20Sopenharmony_ci 39148c2ecf20Sopenharmony_ci/* 39158c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 39168c2ecf20Sopenharmony_ci */ 39178c2ecf20Sopenharmony_cistatic void qlt_do_ctio_completion(struct scsi_qla_host *vha, 39188c2ecf20Sopenharmony_ci struct rsp_que *rsp, uint32_t handle, uint32_t status, void *ctio) 39198c2ecf20Sopenharmony_ci{ 39208c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 39218c2ecf20Sopenharmony_ci struct se_cmd *se_cmd; 39228c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd; 39238c2ecf20Sopenharmony_ci struct qla_qpair *qpair = rsp->qpair; 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ci if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) { 39268c2ecf20Sopenharmony_ci /* That could happen only in case of an error/reset/abort */ 39278c2ecf20Sopenharmony_ci if (status != CTIO_SUCCESS) { 39288c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01d, 39298c2ecf20Sopenharmony_ci "Intermediate CTIO received" 39308c2ecf20Sopenharmony_ci " (status %x)\n", status); 39318c2ecf20Sopenharmony_ci } 39328c2ecf20Sopenharmony_ci return; 39338c2ecf20Sopenharmony_ci } 39348c2ecf20Sopenharmony_ci 39358c2ecf20Sopenharmony_ci cmd = qlt_ctio_to_cmd(vha, rsp, handle, ctio); 39368c2ecf20Sopenharmony_ci if (cmd == NULL) 39378c2ecf20Sopenharmony_ci return; 39388c2ecf20Sopenharmony_ci 39398c2ecf20Sopenharmony_ci se_cmd = &cmd->se_cmd; 39408c2ecf20Sopenharmony_ci cmd->cmd_sent_to_fw = 0; 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci qlt_unmap_sg(vha, cmd); 39438c2ecf20Sopenharmony_ci 39448c2ecf20Sopenharmony_ci if (unlikely(status != CTIO_SUCCESS)) { 39458c2ecf20Sopenharmony_ci switch (status & 0xFFFF) { 39468c2ecf20Sopenharmony_ci case CTIO_INVALID_RX_ID: 39478c2ecf20Sopenharmony_ci if (printk_ratelimit()) 39488c2ecf20Sopenharmony_ci dev_info(&vha->hw->pdev->dev, 39498c2ecf20Sopenharmony_ci "qla_target(%d): CTIO with INVALID_RX_ID ATIO attr %x CTIO Flags %x|%x\n", 39508c2ecf20Sopenharmony_ci vha->vp_idx, cmd->atio.u.isp24.attr, 39518c2ecf20Sopenharmony_ci ((cmd->ctio_flags >> 9) & 0xf), 39528c2ecf20Sopenharmony_ci cmd->ctio_flags); 39538c2ecf20Sopenharmony_ci 39548c2ecf20Sopenharmony_ci break; 39558c2ecf20Sopenharmony_ci case CTIO_LIP_RESET: 39568c2ecf20Sopenharmony_ci case CTIO_TARGET_RESET: 39578c2ecf20Sopenharmony_ci case CTIO_ABORTED: 39588c2ecf20Sopenharmony_ci /* driver request abort via Terminate exchange */ 39598c2ecf20Sopenharmony_ci case CTIO_TIMEOUT: 39608c2ecf20Sopenharmony_ci /* They are OK */ 39618c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058, 39628c2ecf20Sopenharmony_ci "qla_target(%d): CTIO with " 39638c2ecf20Sopenharmony_ci "status %#x received, state %x, se_cmd %p, " 39648c2ecf20Sopenharmony_ci "(LIP_RESET=e, ABORTED=2, TARGET_RESET=17, " 39658c2ecf20Sopenharmony_ci "TIMEOUT=b, INVALID_RX_ID=8)\n", vha->vp_idx, 39668c2ecf20Sopenharmony_ci status, cmd->state, se_cmd); 39678c2ecf20Sopenharmony_ci break; 39688c2ecf20Sopenharmony_ci 39698c2ecf20Sopenharmony_ci case CTIO_PORT_LOGGED_OUT: 39708c2ecf20Sopenharmony_ci case CTIO_PORT_UNAVAILABLE: 39718c2ecf20Sopenharmony_ci { 39728c2ecf20Sopenharmony_ci int logged_out = 39738c2ecf20Sopenharmony_ci (status & 0xFFFF) == CTIO_PORT_LOGGED_OUT; 39748c2ecf20Sopenharmony_ci 39758c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059, 39768c2ecf20Sopenharmony_ci "qla_target(%d): CTIO with %s status %x " 39778c2ecf20Sopenharmony_ci "received (state %x, se_cmd %p)\n", vha->vp_idx, 39788c2ecf20Sopenharmony_ci logged_out ? "PORT LOGGED OUT" : "PORT UNAVAILABLE", 39798c2ecf20Sopenharmony_ci status, cmd->state, se_cmd); 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci if (logged_out && cmd->sess) { 39828c2ecf20Sopenharmony_ci /* 39838c2ecf20Sopenharmony_ci * Session is already logged out, but we need 39848c2ecf20Sopenharmony_ci * to notify initiator, who's not aware of this 39858c2ecf20Sopenharmony_ci */ 39868c2ecf20Sopenharmony_ci cmd->sess->send_els_logo = 1; 39878c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f8, 39888c2ecf20Sopenharmony_ci "%s %d %8phC post del sess\n", 39898c2ecf20Sopenharmony_ci __func__, __LINE__, cmd->sess->port_name); 39908c2ecf20Sopenharmony_ci 39918c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(cmd->sess); 39928c2ecf20Sopenharmony_ci } 39938c2ecf20Sopenharmony_ci break; 39948c2ecf20Sopenharmony_ci } 39958c2ecf20Sopenharmony_ci case CTIO_DIF_ERROR: { 39968c2ecf20Sopenharmony_ci struct ctio_crc_from_fw *crc = 39978c2ecf20Sopenharmony_ci (struct ctio_crc_from_fw *)ctio; 39988c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf073, 39998c2ecf20Sopenharmony_ci "qla_target(%d): CTIO with DIF_ERROR status %x " 40008c2ecf20Sopenharmony_ci "received (state %x, ulp_cmd %p) actual_dif[0x%llx] " 40018c2ecf20Sopenharmony_ci "expect_dif[0x%llx]\n", 40028c2ecf20Sopenharmony_ci vha->vp_idx, status, cmd->state, se_cmd, 40038c2ecf20Sopenharmony_ci *((u64 *)&crc->actual_dif[0]), 40048c2ecf20Sopenharmony_ci *((u64 *)&crc->expected_dif[0])); 40058c2ecf20Sopenharmony_ci 40068c2ecf20Sopenharmony_ci qlt_handle_dif_error(qpair, cmd, ctio); 40078c2ecf20Sopenharmony_ci return; 40088c2ecf20Sopenharmony_ci } 40098c2ecf20Sopenharmony_ci default: 40108c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05b, 40118c2ecf20Sopenharmony_ci "qla_target(%d): CTIO with error status 0x%x received (state %x, se_cmd %p\n", 40128c2ecf20Sopenharmony_ci vha->vp_idx, status, cmd->state, se_cmd); 40138c2ecf20Sopenharmony_ci break; 40148c2ecf20Sopenharmony_ci } 40158c2ecf20Sopenharmony_ci 40168c2ecf20Sopenharmony_ci 40178c2ecf20Sopenharmony_ci /* "cmd->aborted" means 40188c2ecf20Sopenharmony_ci * cmd is already aborted/terminated, we don't 40198c2ecf20Sopenharmony_ci * need to terminate again. The exchange is already 40208c2ecf20Sopenharmony_ci * cleaned up/freed at FW level. Just cleanup at driver 40218c2ecf20Sopenharmony_ci * level. 40228c2ecf20Sopenharmony_ci */ 40238c2ecf20Sopenharmony_ci if ((cmd->state != QLA_TGT_STATE_NEED_DATA) && 40248c2ecf20Sopenharmony_ci (!cmd->aborted)) { 40258c2ecf20Sopenharmony_ci cmd->trc_flags |= TRC_CTIO_ERR; 40268c2ecf20Sopenharmony_ci if (qlt_term_ctio_exchange(qpair, ctio, cmd, status)) 40278c2ecf20Sopenharmony_ci return; 40288c2ecf20Sopenharmony_ci } 40298c2ecf20Sopenharmony_ci } 40308c2ecf20Sopenharmony_ci 40318c2ecf20Sopenharmony_ci if (cmd->state == QLA_TGT_STATE_PROCESSED) { 40328c2ecf20Sopenharmony_ci cmd->trc_flags |= TRC_CTIO_DONE; 40338c2ecf20Sopenharmony_ci } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) { 40348c2ecf20Sopenharmony_ci cmd->state = QLA_TGT_STATE_DATA_IN; 40358c2ecf20Sopenharmony_ci 40368c2ecf20Sopenharmony_ci if (status == CTIO_SUCCESS) 40378c2ecf20Sopenharmony_ci cmd->write_data_transferred = 1; 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->handle_data(cmd); 40408c2ecf20Sopenharmony_ci return; 40418c2ecf20Sopenharmony_ci } else if (cmd->aborted) { 40428c2ecf20Sopenharmony_ci cmd->trc_flags |= TRC_CTIO_ABORTED; 40438c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e, 40448c2ecf20Sopenharmony_ci "Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag); 40458c2ecf20Sopenharmony_ci } else { 40468c2ecf20Sopenharmony_ci cmd->trc_flags |= TRC_CTIO_STRANGE; 40478c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05c, 40488c2ecf20Sopenharmony_ci "qla_target(%d): A command in state (%d) should " 40498c2ecf20Sopenharmony_ci "not return a CTIO complete\n", vha->vp_idx, cmd->state); 40508c2ecf20Sopenharmony_ci } 40518c2ecf20Sopenharmony_ci 40528c2ecf20Sopenharmony_ci if (unlikely(status != CTIO_SUCCESS) && 40538c2ecf20Sopenharmony_ci !cmd->aborted) { 40548c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01f, "Finishing failed CTIO\n"); 40558c2ecf20Sopenharmony_ci dump_stack(); 40568c2ecf20Sopenharmony_ci } 40578c2ecf20Sopenharmony_ci 40588c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->free_cmd(cmd); 40598c2ecf20Sopenharmony_ci} 40608c2ecf20Sopenharmony_ci 40618c2ecf20Sopenharmony_cistatic inline int qlt_get_fcp_task_attr(struct scsi_qla_host *vha, 40628c2ecf20Sopenharmony_ci uint8_t task_codes) 40638c2ecf20Sopenharmony_ci{ 40648c2ecf20Sopenharmony_ci int fcp_task_attr; 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_ci switch (task_codes) { 40678c2ecf20Sopenharmony_ci case ATIO_SIMPLE_QUEUE: 40688c2ecf20Sopenharmony_ci fcp_task_attr = TCM_SIMPLE_TAG; 40698c2ecf20Sopenharmony_ci break; 40708c2ecf20Sopenharmony_ci case ATIO_HEAD_OF_QUEUE: 40718c2ecf20Sopenharmony_ci fcp_task_attr = TCM_HEAD_TAG; 40728c2ecf20Sopenharmony_ci break; 40738c2ecf20Sopenharmony_ci case ATIO_ORDERED_QUEUE: 40748c2ecf20Sopenharmony_ci fcp_task_attr = TCM_ORDERED_TAG; 40758c2ecf20Sopenharmony_ci break; 40768c2ecf20Sopenharmony_ci case ATIO_ACA_QUEUE: 40778c2ecf20Sopenharmony_ci fcp_task_attr = TCM_ACA_TAG; 40788c2ecf20Sopenharmony_ci break; 40798c2ecf20Sopenharmony_ci case ATIO_UNTAGGED: 40808c2ecf20Sopenharmony_ci fcp_task_attr = TCM_SIMPLE_TAG; 40818c2ecf20Sopenharmony_ci break; 40828c2ecf20Sopenharmony_ci default: 40838c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05d, 40848c2ecf20Sopenharmony_ci "qla_target: unknown task code %x, use ORDERED instead\n", 40858c2ecf20Sopenharmony_ci task_codes); 40868c2ecf20Sopenharmony_ci fcp_task_attr = TCM_ORDERED_TAG; 40878c2ecf20Sopenharmony_ci break; 40888c2ecf20Sopenharmony_ci } 40898c2ecf20Sopenharmony_ci 40908c2ecf20Sopenharmony_ci return fcp_task_attr; 40918c2ecf20Sopenharmony_ci} 40928c2ecf20Sopenharmony_ci 40938c2ecf20Sopenharmony_ci/* 40948c2ecf20Sopenharmony_ci * Process context for I/O path into tcm_qla2xxx code 40958c2ecf20Sopenharmony_ci */ 40968c2ecf20Sopenharmony_cistatic void __qlt_do_work(struct qla_tgt_cmd *cmd) 40978c2ecf20Sopenharmony_ci{ 40988c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = cmd->vha; 40998c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 41008c2ecf20Sopenharmony_ci struct fc_port *sess = cmd->sess; 41018c2ecf20Sopenharmony_ci struct atio_from_isp *atio = &cmd->atio; 41028c2ecf20Sopenharmony_ci unsigned char *cdb; 41038c2ecf20Sopenharmony_ci unsigned long flags; 41048c2ecf20Sopenharmony_ci uint32_t data_length; 41058c2ecf20Sopenharmony_ci int ret, fcp_task_attr, data_dir, bidi = 0; 41068c2ecf20Sopenharmony_ci struct qla_qpair *qpair = cmd->qpair; 41078c2ecf20Sopenharmony_ci 41088c2ecf20Sopenharmony_ci cmd->cmd_in_wq = 0; 41098c2ecf20Sopenharmony_ci cmd->trc_flags |= TRC_DO_WORK; 41108c2ecf20Sopenharmony_ci 41118c2ecf20Sopenharmony_ci if (cmd->aborted) { 41128c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082, 41138c2ecf20Sopenharmony_ci "cmd with tag %u is aborted\n", 41148c2ecf20Sopenharmony_ci cmd->atio.u.isp24.exchange_addr); 41158c2ecf20Sopenharmony_ci goto out_term; 41168c2ecf20Sopenharmony_ci } 41178c2ecf20Sopenharmony_ci 41188c2ecf20Sopenharmony_ci spin_lock_init(&cmd->cmd_lock); 41198c2ecf20Sopenharmony_ci cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; 41208c2ecf20Sopenharmony_ci cmd->se_cmd.tag = le32_to_cpu(atio->u.isp24.exchange_addr); 41218c2ecf20Sopenharmony_ci 41228c2ecf20Sopenharmony_ci if (atio->u.isp24.fcp_cmnd.rddata && 41238c2ecf20Sopenharmony_ci atio->u.isp24.fcp_cmnd.wrdata) { 41248c2ecf20Sopenharmony_ci bidi = 1; 41258c2ecf20Sopenharmony_ci data_dir = DMA_TO_DEVICE; 41268c2ecf20Sopenharmony_ci } else if (atio->u.isp24.fcp_cmnd.rddata) 41278c2ecf20Sopenharmony_ci data_dir = DMA_FROM_DEVICE; 41288c2ecf20Sopenharmony_ci else if (atio->u.isp24.fcp_cmnd.wrdata) 41298c2ecf20Sopenharmony_ci data_dir = DMA_TO_DEVICE; 41308c2ecf20Sopenharmony_ci else 41318c2ecf20Sopenharmony_ci data_dir = DMA_NONE; 41328c2ecf20Sopenharmony_ci 41338c2ecf20Sopenharmony_ci fcp_task_attr = qlt_get_fcp_task_attr(vha, 41348c2ecf20Sopenharmony_ci atio->u.isp24.fcp_cmnd.task_attr); 41358c2ecf20Sopenharmony_ci data_length = get_datalen_for_atio(atio); 41368c2ecf20Sopenharmony_ci 41378c2ecf20Sopenharmony_ci ret = ha->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length, 41388c2ecf20Sopenharmony_ci fcp_task_attr, data_dir, bidi); 41398c2ecf20Sopenharmony_ci if (ret != 0) 41408c2ecf20Sopenharmony_ci goto out_term; 41418c2ecf20Sopenharmony_ci /* 41428c2ecf20Sopenharmony_ci * Drop extra session reference from qlt_handle_cmd_for_atio(). 41438c2ecf20Sopenharmony_ci */ 41448c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->put_sess(sess); 41458c2ecf20Sopenharmony_ci return; 41468c2ecf20Sopenharmony_ci 41478c2ecf20Sopenharmony_ciout_term: 41488c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3060, "Terminating work cmd %p", cmd); 41498c2ecf20Sopenharmony_ci /* 41508c2ecf20Sopenharmony_ci * cmd has not sent to target yet, so pass NULL as the second 41518c2ecf20Sopenharmony_ci * argument to qlt_send_term_exchange() and free the memory here. 41528c2ecf20Sopenharmony_ci */ 41538c2ecf20Sopenharmony_ci cmd->trc_flags |= TRC_DO_WORK_ERR; 41548c2ecf20Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 41558c2ecf20Sopenharmony_ci qlt_send_term_exchange(qpair, NULL, &cmd->atio, 1, 0); 41568c2ecf20Sopenharmony_ci 41578c2ecf20Sopenharmony_ci qlt_decr_num_pend_cmds(vha); 41588c2ecf20Sopenharmony_ci cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd); 41598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 41608c2ecf20Sopenharmony_ci 41618c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->put_sess(sess); 41628c2ecf20Sopenharmony_ci} 41638c2ecf20Sopenharmony_ci 41648c2ecf20Sopenharmony_cistatic void qlt_do_work(struct work_struct *work) 41658c2ecf20Sopenharmony_ci{ 41668c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); 41678c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = cmd->vha; 41688c2ecf20Sopenharmony_ci unsigned long flags; 41698c2ecf20Sopenharmony_ci 41708c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->cmd_list_lock, flags); 41718c2ecf20Sopenharmony_ci list_del(&cmd->cmd_list); 41728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->cmd_list_lock, flags); 41738c2ecf20Sopenharmony_ci 41748c2ecf20Sopenharmony_ci __qlt_do_work(cmd); 41758c2ecf20Sopenharmony_ci} 41768c2ecf20Sopenharmony_ci 41778c2ecf20Sopenharmony_civoid qlt_clr_qp_table(struct scsi_qla_host *vha) 41788c2ecf20Sopenharmony_ci{ 41798c2ecf20Sopenharmony_ci unsigned long flags; 41808c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 41818c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 41828c2ecf20Sopenharmony_ci void *node; 41838c2ecf20Sopenharmony_ci u64 key = 0; 41848c2ecf20Sopenharmony_ci 41858c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x706c, 41868c2ecf20Sopenharmony_ci "User update Number of Active Qpairs %d\n", 41878c2ecf20Sopenharmony_ci ha->tgt.num_act_qpairs); 41888c2ecf20Sopenharmony_ci 41898c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.atio_lock, flags); 41908c2ecf20Sopenharmony_ci 41918c2ecf20Sopenharmony_ci btree_for_each_safe64(&tgt->lun_qpair_map, key, node) 41928c2ecf20Sopenharmony_ci btree_remove64(&tgt->lun_qpair_map, key); 41938c2ecf20Sopenharmony_ci 41948c2ecf20Sopenharmony_ci ha->base_qpair->lun_cnt = 0; 41958c2ecf20Sopenharmony_ci for (key = 0; key < ha->max_qpairs; key++) 41968c2ecf20Sopenharmony_ci if (ha->queue_pair_map[key]) 41978c2ecf20Sopenharmony_ci ha->queue_pair_map[key]->lun_cnt = 0; 41988c2ecf20Sopenharmony_ci 41998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.atio_lock, flags); 42008c2ecf20Sopenharmony_ci} 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_cistatic void qlt_assign_qpair(struct scsi_qla_host *vha, 42038c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd) 42048c2ecf20Sopenharmony_ci{ 42058c2ecf20Sopenharmony_ci struct qla_qpair *qpair, *qp; 42068c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 42078c2ecf20Sopenharmony_ci struct qla_qpair_hint *h; 42088c2ecf20Sopenharmony_ci 42098c2ecf20Sopenharmony_ci if (vha->flags.qpairs_available) { 42108c2ecf20Sopenharmony_ci h = btree_lookup64(&tgt->lun_qpair_map, cmd->unpacked_lun); 42118c2ecf20Sopenharmony_ci if (unlikely(!h)) { 42128c2ecf20Sopenharmony_ci /* spread lun to qpair ratio evently */ 42138c2ecf20Sopenharmony_ci int lcnt = 0, rc; 42148c2ecf20Sopenharmony_ci struct scsi_qla_host *base_vha = 42158c2ecf20Sopenharmony_ci pci_get_drvdata(vha->hw->pdev); 42168c2ecf20Sopenharmony_ci 42178c2ecf20Sopenharmony_ci qpair = vha->hw->base_qpair; 42188c2ecf20Sopenharmony_ci if (qpair->lun_cnt == 0) { 42198c2ecf20Sopenharmony_ci qpair->lun_cnt++; 42208c2ecf20Sopenharmony_ci h = qla_qpair_to_hint(tgt, qpair); 42218c2ecf20Sopenharmony_ci BUG_ON(!h); 42228c2ecf20Sopenharmony_ci rc = btree_insert64(&tgt->lun_qpair_map, 42238c2ecf20Sopenharmony_ci cmd->unpacked_lun, h, GFP_ATOMIC); 42248c2ecf20Sopenharmony_ci if (rc) { 42258c2ecf20Sopenharmony_ci qpair->lun_cnt--; 42268c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xd037, 42278c2ecf20Sopenharmony_ci "Unable to insert lun %llx into lun_qpair_map\n", 42288c2ecf20Sopenharmony_ci cmd->unpacked_lun); 42298c2ecf20Sopenharmony_ci } 42308c2ecf20Sopenharmony_ci goto out; 42318c2ecf20Sopenharmony_ci } else { 42328c2ecf20Sopenharmony_ci lcnt = qpair->lun_cnt; 42338c2ecf20Sopenharmony_ci } 42348c2ecf20Sopenharmony_ci 42358c2ecf20Sopenharmony_ci h = NULL; 42368c2ecf20Sopenharmony_ci list_for_each_entry(qp, &base_vha->qp_list, 42378c2ecf20Sopenharmony_ci qp_list_elem) { 42388c2ecf20Sopenharmony_ci if (qp->lun_cnt == 0) { 42398c2ecf20Sopenharmony_ci qp->lun_cnt++; 42408c2ecf20Sopenharmony_ci h = qla_qpair_to_hint(tgt, qp); 42418c2ecf20Sopenharmony_ci BUG_ON(!h); 42428c2ecf20Sopenharmony_ci rc = btree_insert64(&tgt->lun_qpair_map, 42438c2ecf20Sopenharmony_ci cmd->unpacked_lun, h, GFP_ATOMIC); 42448c2ecf20Sopenharmony_ci if (rc) { 42458c2ecf20Sopenharmony_ci qp->lun_cnt--; 42468c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xd038, 42478c2ecf20Sopenharmony_ci "Unable to insert lun %llx into lun_qpair_map\n", 42488c2ecf20Sopenharmony_ci cmd->unpacked_lun); 42498c2ecf20Sopenharmony_ci } 42508c2ecf20Sopenharmony_ci qpair = qp; 42518c2ecf20Sopenharmony_ci goto out; 42528c2ecf20Sopenharmony_ci } else { 42538c2ecf20Sopenharmony_ci if (qp->lun_cnt < lcnt) { 42548c2ecf20Sopenharmony_ci lcnt = qp->lun_cnt; 42558c2ecf20Sopenharmony_ci qpair = qp; 42568c2ecf20Sopenharmony_ci continue; 42578c2ecf20Sopenharmony_ci } 42588c2ecf20Sopenharmony_ci } 42598c2ecf20Sopenharmony_ci } 42608c2ecf20Sopenharmony_ci BUG_ON(!qpair); 42618c2ecf20Sopenharmony_ci qpair->lun_cnt++; 42628c2ecf20Sopenharmony_ci h = qla_qpair_to_hint(tgt, qpair); 42638c2ecf20Sopenharmony_ci BUG_ON(!h); 42648c2ecf20Sopenharmony_ci rc = btree_insert64(&tgt->lun_qpair_map, 42658c2ecf20Sopenharmony_ci cmd->unpacked_lun, h, GFP_ATOMIC); 42668c2ecf20Sopenharmony_ci if (rc) { 42678c2ecf20Sopenharmony_ci qpair->lun_cnt--; 42688c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xd039, 42698c2ecf20Sopenharmony_ci "Unable to insert lun %llx into lun_qpair_map\n", 42708c2ecf20Sopenharmony_ci cmd->unpacked_lun); 42718c2ecf20Sopenharmony_ci } 42728c2ecf20Sopenharmony_ci } 42738c2ecf20Sopenharmony_ci } else { 42748c2ecf20Sopenharmony_ci h = &tgt->qphints[0]; 42758c2ecf20Sopenharmony_ci } 42768c2ecf20Sopenharmony_ciout: 42778c2ecf20Sopenharmony_ci cmd->qpair = h->qpair; 42788c2ecf20Sopenharmony_ci cmd->se_cmd.cpuid = h->cpuid; 42798c2ecf20Sopenharmony_ci} 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_cistatic struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, 42828c2ecf20Sopenharmony_ci struct fc_port *sess, 42838c2ecf20Sopenharmony_ci struct atio_from_isp *atio) 42848c2ecf20Sopenharmony_ci{ 42858c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd; 42868c2ecf20Sopenharmony_ci 42878c2ecf20Sopenharmony_ci cmd = vha->hw->tgt.tgt_ops->get_cmd(sess); 42888c2ecf20Sopenharmony_ci if (!cmd) 42898c2ecf20Sopenharmony_ci return NULL; 42908c2ecf20Sopenharmony_ci 42918c2ecf20Sopenharmony_ci cmd->cmd_type = TYPE_TGT_CMD; 42928c2ecf20Sopenharmony_ci memcpy(&cmd->atio, atio, sizeof(*atio)); 42938c2ecf20Sopenharmony_ci cmd->state = QLA_TGT_STATE_NEW; 42948c2ecf20Sopenharmony_ci cmd->tgt = vha->vha_tgt.qla_tgt; 42958c2ecf20Sopenharmony_ci qlt_incr_num_pend_cmds(vha); 42968c2ecf20Sopenharmony_ci cmd->vha = vha; 42978c2ecf20Sopenharmony_ci cmd->sess = sess; 42988c2ecf20Sopenharmony_ci cmd->loop_id = sess->loop_id; 42998c2ecf20Sopenharmony_ci cmd->conf_compl_supported = sess->conf_compl_supported; 43008c2ecf20Sopenharmony_ci 43018c2ecf20Sopenharmony_ci cmd->trc_flags = 0; 43028c2ecf20Sopenharmony_ci cmd->jiffies_at_alloc = get_jiffies_64(); 43038c2ecf20Sopenharmony_ci 43048c2ecf20Sopenharmony_ci cmd->unpacked_lun = scsilun_to_int( 43058c2ecf20Sopenharmony_ci (struct scsi_lun *)&atio->u.isp24.fcp_cmnd.lun); 43068c2ecf20Sopenharmony_ci qlt_assign_qpair(vha, cmd); 43078c2ecf20Sopenharmony_ci cmd->reset_count = vha->hw->base_qpair->chip_reset; 43088c2ecf20Sopenharmony_ci cmd->vp_idx = vha->vp_idx; 43098c2ecf20Sopenharmony_ci 43108c2ecf20Sopenharmony_ci return cmd; 43118c2ecf20Sopenharmony_ci} 43128c2ecf20Sopenharmony_ci 43138c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 43148c2ecf20Sopenharmony_cistatic int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, 43158c2ecf20Sopenharmony_ci struct atio_from_isp *atio) 43168c2ecf20Sopenharmony_ci{ 43178c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 43188c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 43198c2ecf20Sopenharmony_ci struct fc_port *sess; 43208c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd; 43218c2ecf20Sopenharmony_ci unsigned long flags; 43228c2ecf20Sopenharmony_ci port_id_t id; 43238c2ecf20Sopenharmony_ci 43248c2ecf20Sopenharmony_ci if (unlikely(tgt->tgt_stop)) { 43258c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3061, 43268c2ecf20Sopenharmony_ci "New command while device %p is shutting down\n", tgt); 43278c2ecf20Sopenharmony_ci return -ENODEV; 43288c2ecf20Sopenharmony_ci } 43298c2ecf20Sopenharmony_ci 43308c2ecf20Sopenharmony_ci id = be_to_port_id(atio->u.isp24.fcp_hdr.s_id); 43318c2ecf20Sopenharmony_ci if (IS_SW_RESV_ADDR(id)) 43328c2ecf20Sopenharmony_ci return -EBUSY; 43338c2ecf20Sopenharmony_ci 43348c2ecf20Sopenharmony_ci sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id); 43358c2ecf20Sopenharmony_ci if (unlikely(!sess)) 43368c2ecf20Sopenharmony_ci return -EFAULT; 43378c2ecf20Sopenharmony_ci 43388c2ecf20Sopenharmony_ci /* Another WWN used to have our s_id. Our PLOGI scheduled its 43398c2ecf20Sopenharmony_ci * session deletion, but it's still in sess_del_work wq */ 43408c2ecf20Sopenharmony_ci if (sess->deleted) { 43418c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf002, 43428c2ecf20Sopenharmony_ci "New command while old session %p is being deleted\n", 43438c2ecf20Sopenharmony_ci sess); 43448c2ecf20Sopenharmony_ci return -EFAULT; 43458c2ecf20Sopenharmony_ci } 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_ci /* 43488c2ecf20Sopenharmony_ci * Do kref_get() before returning + dropping qla_hw_data->hardware_lock. 43498c2ecf20Sopenharmony_ci */ 43508c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&sess->sess_kref)) { 43518c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004, 43528c2ecf20Sopenharmony_ci "%s: kref_get fail, %8phC oxid %x \n", 43538c2ecf20Sopenharmony_ci __func__, sess->port_name, 43548c2ecf20Sopenharmony_ci be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id)); 43558c2ecf20Sopenharmony_ci return -EFAULT; 43568c2ecf20Sopenharmony_ci } 43578c2ecf20Sopenharmony_ci 43588c2ecf20Sopenharmony_ci cmd = qlt_get_tag(vha, sess, atio); 43598c2ecf20Sopenharmony_ci if (!cmd) { 43608c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3062, 43618c2ecf20Sopenharmony_ci "qla_target(%d): Allocation of cmd failed\n", vha->vp_idx); 43628c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->put_sess(sess); 43638c2ecf20Sopenharmony_ci return -EBUSY; 43648c2ecf20Sopenharmony_ci } 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_ci cmd->cmd_in_wq = 1; 43678c2ecf20Sopenharmony_ci cmd->trc_flags |= TRC_NEW_CMD; 43688c2ecf20Sopenharmony_ci 43698c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->cmd_list_lock, flags); 43708c2ecf20Sopenharmony_ci list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list); 43718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->cmd_list_lock, flags); 43728c2ecf20Sopenharmony_ci 43738c2ecf20Sopenharmony_ci INIT_WORK(&cmd->work, qlt_do_work); 43748c2ecf20Sopenharmony_ci if (vha->flags.qpairs_available) { 43758c2ecf20Sopenharmony_ci queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq, &cmd->work); 43768c2ecf20Sopenharmony_ci } else if (ha->msix_count) { 43778c2ecf20Sopenharmony_ci if (cmd->atio.u.isp24.fcp_cmnd.rddata) 43788c2ecf20Sopenharmony_ci queue_work_on(smp_processor_id(), qla_tgt_wq, 43798c2ecf20Sopenharmony_ci &cmd->work); 43808c2ecf20Sopenharmony_ci else 43818c2ecf20Sopenharmony_ci queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq, 43828c2ecf20Sopenharmony_ci &cmd->work); 43838c2ecf20Sopenharmony_ci } else { 43848c2ecf20Sopenharmony_ci queue_work(qla_tgt_wq, &cmd->work); 43858c2ecf20Sopenharmony_ci } 43868c2ecf20Sopenharmony_ci 43878c2ecf20Sopenharmony_ci return 0; 43888c2ecf20Sopenharmony_ci} 43898c2ecf20Sopenharmony_ci 43908c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 43918c2ecf20Sopenharmony_cistatic int qlt_issue_task_mgmt(struct fc_port *sess, u64 lun, 43928c2ecf20Sopenharmony_ci int fn, void *iocb, int flags) 43938c2ecf20Sopenharmony_ci{ 43948c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sess->vha; 43958c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 43968c2ecf20Sopenharmony_ci struct qla_tgt_mgmt_cmd *mcmd; 43978c2ecf20Sopenharmony_ci struct atio_from_isp *a = (struct atio_from_isp *)iocb; 43988c2ecf20Sopenharmony_ci struct qla_qpair_hint *h = &vha->vha_tgt.qla_tgt->qphints[0]; 43998c2ecf20Sopenharmony_ci 44008c2ecf20Sopenharmony_ci mcmd = mempool_alloc(qla_tgt_mgmt_cmd_mempool, GFP_ATOMIC); 44018c2ecf20Sopenharmony_ci if (!mcmd) { 44028c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_tmr, vha, 0x10009, 44038c2ecf20Sopenharmony_ci "qla_target(%d): Allocation of management " 44048c2ecf20Sopenharmony_ci "command failed, some commands and their data could " 44058c2ecf20Sopenharmony_ci "leak\n", vha->vp_idx); 44068c2ecf20Sopenharmony_ci return -ENOMEM; 44078c2ecf20Sopenharmony_ci } 44088c2ecf20Sopenharmony_ci memset(mcmd, 0, sizeof(*mcmd)); 44098c2ecf20Sopenharmony_ci mcmd->sess = sess; 44108c2ecf20Sopenharmony_ci 44118c2ecf20Sopenharmony_ci if (iocb) { 44128c2ecf20Sopenharmony_ci memcpy(&mcmd->orig_iocb.imm_ntfy, iocb, 44138c2ecf20Sopenharmony_ci sizeof(mcmd->orig_iocb.imm_ntfy)); 44148c2ecf20Sopenharmony_ci } 44158c2ecf20Sopenharmony_ci mcmd->tmr_func = fn; 44168c2ecf20Sopenharmony_ci mcmd->flags = flags; 44178c2ecf20Sopenharmony_ci mcmd->reset_count = ha->base_qpair->chip_reset; 44188c2ecf20Sopenharmony_ci mcmd->qpair = h->qpair; 44198c2ecf20Sopenharmony_ci mcmd->vha = vha; 44208c2ecf20Sopenharmony_ci mcmd->se_cmd.cpuid = h->cpuid; 44218c2ecf20Sopenharmony_ci mcmd->unpacked_lun = lun; 44228c2ecf20Sopenharmony_ci 44238c2ecf20Sopenharmony_ci switch (fn) { 44248c2ecf20Sopenharmony_ci case QLA_TGT_LUN_RESET: 44258c2ecf20Sopenharmony_ci case QLA_TGT_CLEAR_TS: 44268c2ecf20Sopenharmony_ci case QLA_TGT_ABORT_TS: 44278c2ecf20Sopenharmony_ci abort_cmds_for_lun(vha, lun, a->u.isp24.fcp_hdr.s_id); 44288c2ecf20Sopenharmony_ci fallthrough; 44298c2ecf20Sopenharmony_ci case QLA_TGT_CLEAR_ACA: 44308c2ecf20Sopenharmony_ci h = qlt_find_qphint(vha, mcmd->unpacked_lun); 44318c2ecf20Sopenharmony_ci mcmd->qpair = h->qpair; 44328c2ecf20Sopenharmony_ci mcmd->se_cmd.cpuid = h->cpuid; 44338c2ecf20Sopenharmony_ci break; 44348c2ecf20Sopenharmony_ci 44358c2ecf20Sopenharmony_ci case QLA_TGT_TARGET_RESET: 44368c2ecf20Sopenharmony_ci case QLA_TGT_NEXUS_LOSS_SESS: 44378c2ecf20Sopenharmony_ci case QLA_TGT_NEXUS_LOSS: 44388c2ecf20Sopenharmony_ci case QLA_TGT_ABORT_ALL: 44398c2ecf20Sopenharmony_ci default: 44408c2ecf20Sopenharmony_ci /* no-op */ 44418c2ecf20Sopenharmony_ci break; 44428c2ecf20Sopenharmony_ci } 44438c2ecf20Sopenharmony_ci 44448c2ecf20Sopenharmony_ci INIT_WORK(&mcmd->work, qlt_do_tmr_work); 44458c2ecf20Sopenharmony_ci queue_work_on(mcmd->se_cmd.cpuid, qla_tgt_wq, 44468c2ecf20Sopenharmony_ci &mcmd->work); 44478c2ecf20Sopenharmony_ci 44488c2ecf20Sopenharmony_ci return 0; 44498c2ecf20Sopenharmony_ci} 44508c2ecf20Sopenharmony_ci 44518c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 44528c2ecf20Sopenharmony_cistatic int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb) 44538c2ecf20Sopenharmony_ci{ 44548c2ecf20Sopenharmony_ci struct atio_from_isp *a = (struct atio_from_isp *)iocb; 44558c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 44568c2ecf20Sopenharmony_ci struct fc_port *sess; 44578c2ecf20Sopenharmony_ci u64 unpacked_lun; 44588c2ecf20Sopenharmony_ci int fn; 44598c2ecf20Sopenharmony_ci unsigned long flags; 44608c2ecf20Sopenharmony_ci 44618c2ecf20Sopenharmony_ci fn = a->u.isp24.fcp_cmnd.task_mgmt_flags; 44628c2ecf20Sopenharmony_ci 44638c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 44648c2ecf20Sopenharmony_ci sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, 44658c2ecf20Sopenharmony_ci a->u.isp24.fcp_hdr.s_id); 44668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 44678c2ecf20Sopenharmony_ci 44688c2ecf20Sopenharmony_ci unpacked_lun = 44698c2ecf20Sopenharmony_ci scsilun_to_int((struct scsi_lun *)&a->u.isp24.fcp_cmnd.lun); 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_ci if (sess == NULL || sess->deleted) 44728c2ecf20Sopenharmony_ci return -EFAULT; 44738c2ecf20Sopenharmony_ci 44748c2ecf20Sopenharmony_ci return qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); 44758c2ecf20Sopenharmony_ci} 44768c2ecf20Sopenharmony_ci 44778c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 44788c2ecf20Sopenharmony_cistatic int __qlt_abort_task(struct scsi_qla_host *vha, 44798c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *iocb, struct fc_port *sess) 44808c2ecf20Sopenharmony_ci{ 44818c2ecf20Sopenharmony_ci struct atio_from_isp *a = (struct atio_from_isp *)iocb; 44828c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 44838c2ecf20Sopenharmony_ci struct qla_tgt_mgmt_cmd *mcmd; 44848c2ecf20Sopenharmony_ci u64 unpacked_lun; 44858c2ecf20Sopenharmony_ci int rc; 44868c2ecf20Sopenharmony_ci 44878c2ecf20Sopenharmony_ci mcmd = mempool_alloc(qla_tgt_mgmt_cmd_mempool, GFP_ATOMIC); 44888c2ecf20Sopenharmony_ci if (mcmd == NULL) { 44898c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05f, 44908c2ecf20Sopenharmony_ci "qla_target(%d): %s: Allocation of ABORT cmd failed\n", 44918c2ecf20Sopenharmony_ci vha->vp_idx, __func__); 44928c2ecf20Sopenharmony_ci return -ENOMEM; 44938c2ecf20Sopenharmony_ci } 44948c2ecf20Sopenharmony_ci memset(mcmd, 0, sizeof(*mcmd)); 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_ci mcmd->sess = sess; 44978c2ecf20Sopenharmony_ci memcpy(&mcmd->orig_iocb.imm_ntfy, iocb, 44988c2ecf20Sopenharmony_ci sizeof(mcmd->orig_iocb.imm_ntfy)); 44998c2ecf20Sopenharmony_ci 45008c2ecf20Sopenharmony_ci unpacked_lun = 45018c2ecf20Sopenharmony_ci scsilun_to_int((struct scsi_lun *)&a->u.isp24.fcp_cmnd.lun); 45028c2ecf20Sopenharmony_ci mcmd->reset_count = ha->base_qpair->chip_reset; 45038c2ecf20Sopenharmony_ci mcmd->tmr_func = QLA_TGT_2G_ABORT_TASK; 45048c2ecf20Sopenharmony_ci mcmd->qpair = ha->base_qpair; 45058c2ecf20Sopenharmony_ci 45068c2ecf20Sopenharmony_ci rc = ha->tgt.tgt_ops->handle_tmr(mcmd, unpacked_lun, mcmd->tmr_func, 45078c2ecf20Sopenharmony_ci le16_to_cpu(iocb->u.isp2x.seq_id)); 45088c2ecf20Sopenharmony_ci if (rc != 0) { 45098c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf060, 45108c2ecf20Sopenharmony_ci "qla_target(%d): tgt_ops->handle_tmr() failed: %d\n", 45118c2ecf20Sopenharmony_ci vha->vp_idx, rc); 45128c2ecf20Sopenharmony_ci mempool_free(mcmd, qla_tgt_mgmt_cmd_mempool); 45138c2ecf20Sopenharmony_ci return -EFAULT; 45148c2ecf20Sopenharmony_ci } 45158c2ecf20Sopenharmony_ci 45168c2ecf20Sopenharmony_ci return 0; 45178c2ecf20Sopenharmony_ci} 45188c2ecf20Sopenharmony_ci 45198c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 45208c2ecf20Sopenharmony_cistatic int qlt_abort_task(struct scsi_qla_host *vha, 45218c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *iocb) 45228c2ecf20Sopenharmony_ci{ 45238c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 45248c2ecf20Sopenharmony_ci struct fc_port *sess; 45258c2ecf20Sopenharmony_ci int loop_id; 45268c2ecf20Sopenharmony_ci unsigned long flags; 45278c2ecf20Sopenharmony_ci 45288c2ecf20Sopenharmony_ci loop_id = GET_TARGET_ID(ha, (struct atio_from_isp *)iocb); 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 45318c2ecf20Sopenharmony_ci sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id); 45328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 45338c2ecf20Sopenharmony_ci 45348c2ecf20Sopenharmony_ci if (sess == NULL) { 45358c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf025, 45368c2ecf20Sopenharmony_ci "qla_target(%d): task abort for unexisting " 45378c2ecf20Sopenharmony_ci "session\n", vha->vp_idx); 45388c2ecf20Sopenharmony_ci return qlt_sched_sess_work(vha->vha_tgt.qla_tgt, 45398c2ecf20Sopenharmony_ci QLA_TGT_SESS_WORK_ABORT, iocb, sizeof(*iocb)); 45408c2ecf20Sopenharmony_ci } 45418c2ecf20Sopenharmony_ci 45428c2ecf20Sopenharmony_ci return __qlt_abort_task(vha, iocb, sess); 45438c2ecf20Sopenharmony_ci} 45448c2ecf20Sopenharmony_ci 45458c2ecf20Sopenharmony_civoid qlt_logo_completion_handler(fc_port_t *fcport, int rc) 45468c2ecf20Sopenharmony_ci{ 45478c2ecf20Sopenharmony_ci if (rc != MBS_COMMAND_COMPLETE) { 45488c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, fcport->vha, 0xf093, 45498c2ecf20Sopenharmony_ci "%s: se_sess %p / sess %p from" 45508c2ecf20Sopenharmony_ci " port %8phC loop_id %#04x s_id %02x:%02x:%02x" 45518c2ecf20Sopenharmony_ci " LOGO failed: %#x\n", 45528c2ecf20Sopenharmony_ci __func__, 45538c2ecf20Sopenharmony_ci fcport->se_sess, 45548c2ecf20Sopenharmony_ci fcport, 45558c2ecf20Sopenharmony_ci fcport->port_name, fcport->loop_id, 45568c2ecf20Sopenharmony_ci fcport->d_id.b.domain, fcport->d_id.b.area, 45578c2ecf20Sopenharmony_ci fcport->d_id.b.al_pa, rc); 45588c2ecf20Sopenharmony_ci } 45598c2ecf20Sopenharmony_ci 45608c2ecf20Sopenharmony_ci fcport->logout_completed = 1; 45618c2ecf20Sopenharmony_ci} 45628c2ecf20Sopenharmony_ci 45638c2ecf20Sopenharmony_ci/* 45648c2ecf20Sopenharmony_ci* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list) 45658c2ecf20Sopenharmony_ci* 45668c2ecf20Sopenharmony_ci* Schedules sessions with matching port_id/loop_id but different wwn for 45678c2ecf20Sopenharmony_ci* deletion. Returns existing session with matching wwn if present. 45688c2ecf20Sopenharmony_ci* Null otherwise. 45698c2ecf20Sopenharmony_ci*/ 45708c2ecf20Sopenharmony_cistruct fc_port * 45718c2ecf20Sopenharmony_ciqlt_find_sess_invalidate_other(scsi_qla_host_t *vha, uint64_t wwn, 45728c2ecf20Sopenharmony_ci port_id_t port_id, uint16_t loop_id, struct fc_port **conflict_sess) 45738c2ecf20Sopenharmony_ci{ 45748c2ecf20Sopenharmony_ci struct fc_port *sess = NULL, *other_sess; 45758c2ecf20Sopenharmony_ci uint64_t other_wwn; 45768c2ecf20Sopenharmony_ci 45778c2ecf20Sopenharmony_ci *conflict_sess = NULL; 45788c2ecf20Sopenharmony_ci 45798c2ecf20Sopenharmony_ci list_for_each_entry(other_sess, &vha->vp_fcports, list) { 45808c2ecf20Sopenharmony_ci 45818c2ecf20Sopenharmony_ci other_wwn = wwn_to_u64(other_sess->port_name); 45828c2ecf20Sopenharmony_ci 45838c2ecf20Sopenharmony_ci if (wwn == other_wwn) { 45848c2ecf20Sopenharmony_ci WARN_ON(sess); 45858c2ecf20Sopenharmony_ci sess = other_sess; 45868c2ecf20Sopenharmony_ci continue; 45878c2ecf20Sopenharmony_ci } 45888c2ecf20Sopenharmony_ci 45898c2ecf20Sopenharmony_ci /* find other sess with nport_id collision */ 45908c2ecf20Sopenharmony_ci if (port_id.b24 == other_sess->d_id.b24) { 45918c2ecf20Sopenharmony_ci if (loop_id != other_sess->loop_id) { 45928c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x1000c, 45938c2ecf20Sopenharmony_ci "Invalidating sess %p loop_id %d wwn %llx.\n", 45948c2ecf20Sopenharmony_ci other_sess, other_sess->loop_id, other_wwn); 45958c2ecf20Sopenharmony_ci 45968c2ecf20Sopenharmony_ci /* 45978c2ecf20Sopenharmony_ci * logout_on_delete is set by default, but another 45988c2ecf20Sopenharmony_ci * session that has the same s_id/loop_id combo 45998c2ecf20Sopenharmony_ci * might have cleared it when requested this session 46008c2ecf20Sopenharmony_ci * deletion, so don't touch it 46018c2ecf20Sopenharmony_ci */ 46028c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(other_sess); 46038c2ecf20Sopenharmony_ci } else { 46048c2ecf20Sopenharmony_ci /* 46058c2ecf20Sopenharmony_ci * Another wwn used to have our s_id/loop_id 46068c2ecf20Sopenharmony_ci * kill the session, but don't free the loop_id 46078c2ecf20Sopenharmony_ci */ 46088c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xf01b, 46098c2ecf20Sopenharmony_ci "Invalidating sess %p loop_id %d wwn %llx.\n", 46108c2ecf20Sopenharmony_ci other_sess, other_sess->loop_id, other_wwn); 46118c2ecf20Sopenharmony_ci 46128c2ecf20Sopenharmony_ci other_sess->keep_nport_handle = 1; 46138c2ecf20Sopenharmony_ci if (other_sess->disc_state != DSC_DELETED) 46148c2ecf20Sopenharmony_ci *conflict_sess = other_sess; 46158c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(other_sess); 46168c2ecf20Sopenharmony_ci } 46178c2ecf20Sopenharmony_ci continue; 46188c2ecf20Sopenharmony_ci } 46198c2ecf20Sopenharmony_ci 46208c2ecf20Sopenharmony_ci /* find other sess with nport handle collision */ 46218c2ecf20Sopenharmony_ci if ((loop_id == other_sess->loop_id) && 46228c2ecf20Sopenharmony_ci (loop_id != FC_NO_LOOP_ID)) { 46238c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x1000d, 46248c2ecf20Sopenharmony_ci "Invalidating sess %p loop_id %d wwn %llx.\n", 46258c2ecf20Sopenharmony_ci other_sess, other_sess->loop_id, other_wwn); 46268c2ecf20Sopenharmony_ci 46278c2ecf20Sopenharmony_ci /* Same loop_id but different s_id 46288c2ecf20Sopenharmony_ci * Ok to kill and logout */ 46298c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(other_sess); 46308c2ecf20Sopenharmony_ci } 46318c2ecf20Sopenharmony_ci } 46328c2ecf20Sopenharmony_ci 46338c2ecf20Sopenharmony_ci return sess; 46348c2ecf20Sopenharmony_ci} 46358c2ecf20Sopenharmony_ci 46368c2ecf20Sopenharmony_ci/* Abort any commands for this s_id waiting on qla_tgt_wq workqueue */ 46378c2ecf20Sopenharmony_cistatic int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id) 46388c2ecf20Sopenharmony_ci{ 46398c2ecf20Sopenharmony_ci struct qla_tgt_sess_op *op; 46408c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd; 46418c2ecf20Sopenharmony_ci uint32_t key; 46428c2ecf20Sopenharmony_ci int count = 0; 46438c2ecf20Sopenharmony_ci unsigned long flags; 46448c2ecf20Sopenharmony_ci 46458c2ecf20Sopenharmony_ci key = (((u32)s_id->b.domain << 16) | 46468c2ecf20Sopenharmony_ci ((u32)s_id->b.area << 8) | 46478c2ecf20Sopenharmony_ci ((u32)s_id->b.al_pa)); 46488c2ecf20Sopenharmony_ci 46498c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->cmd_list_lock, flags); 46508c2ecf20Sopenharmony_ci list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) { 46518c2ecf20Sopenharmony_ci uint32_t op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id); 46528c2ecf20Sopenharmony_ci 46538c2ecf20Sopenharmony_ci if (op_key == key) { 46548c2ecf20Sopenharmony_ci op->aborted = true; 46558c2ecf20Sopenharmony_ci count++; 46568c2ecf20Sopenharmony_ci } 46578c2ecf20Sopenharmony_ci } 46588c2ecf20Sopenharmony_ci 46598c2ecf20Sopenharmony_ci list_for_each_entry(op, &vha->unknown_atio_list, cmd_list) { 46608c2ecf20Sopenharmony_ci uint32_t op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id); 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_ci if (op_key == key) { 46638c2ecf20Sopenharmony_ci op->aborted = true; 46648c2ecf20Sopenharmony_ci count++; 46658c2ecf20Sopenharmony_ci } 46668c2ecf20Sopenharmony_ci } 46678c2ecf20Sopenharmony_ci 46688c2ecf20Sopenharmony_ci list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) { 46698c2ecf20Sopenharmony_ci uint32_t cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id); 46708c2ecf20Sopenharmony_ci 46718c2ecf20Sopenharmony_ci if (cmd_key == key) { 46728c2ecf20Sopenharmony_ci cmd->aborted = 1; 46738c2ecf20Sopenharmony_ci count++; 46748c2ecf20Sopenharmony_ci } 46758c2ecf20Sopenharmony_ci } 46768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->cmd_list_lock, flags); 46778c2ecf20Sopenharmony_ci 46788c2ecf20Sopenharmony_ci return count; 46798c2ecf20Sopenharmony_ci} 46808c2ecf20Sopenharmony_ci 46818c2ecf20Sopenharmony_cistatic int qlt_handle_login(struct scsi_qla_host *vha, 46828c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *iocb) 46838c2ecf20Sopenharmony_ci{ 46848c2ecf20Sopenharmony_ci struct fc_port *sess = NULL, *conflict_sess = NULL; 46858c2ecf20Sopenharmony_ci uint64_t wwn; 46868c2ecf20Sopenharmony_ci port_id_t port_id; 46878c2ecf20Sopenharmony_ci uint16_t loop_id, wd3_lo; 46888c2ecf20Sopenharmony_ci int res = 0; 46898c2ecf20Sopenharmony_ci struct qlt_plogi_ack_t *pla; 46908c2ecf20Sopenharmony_ci unsigned long flags; 46918c2ecf20Sopenharmony_ci 46928c2ecf20Sopenharmony_ci lockdep_assert_held(&vha->hw->hardware_lock); 46938c2ecf20Sopenharmony_ci 46948c2ecf20Sopenharmony_ci wwn = wwn_to_u64(iocb->u.isp24.port_name); 46958c2ecf20Sopenharmony_ci 46968c2ecf20Sopenharmony_ci port_id.b.domain = iocb->u.isp24.port_id[2]; 46978c2ecf20Sopenharmony_ci port_id.b.area = iocb->u.isp24.port_id[1]; 46988c2ecf20Sopenharmony_ci port_id.b.al_pa = iocb->u.isp24.port_id[0]; 46998c2ecf20Sopenharmony_ci port_id.b.rsvd_1 = 0; 47008c2ecf20Sopenharmony_ci 47018c2ecf20Sopenharmony_ci loop_id = le16_to_cpu(iocb->u.isp24.nport_handle); 47028c2ecf20Sopenharmony_ci 47038c2ecf20Sopenharmony_ci /* Mark all stale commands sitting in qla_tgt_wq for deletion */ 47048c2ecf20Sopenharmony_ci abort_cmds_for_s_id(vha, &port_id); 47058c2ecf20Sopenharmony_ci 47068c2ecf20Sopenharmony_ci if (wwn) { 47078c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 47088c2ecf20Sopenharmony_ci sess = qlt_find_sess_invalidate_other(vha, wwn, 47098c2ecf20Sopenharmony_ci port_id, loop_id, &conflict_sess); 47108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 47118c2ecf20Sopenharmony_ci } else { 47128c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 47138c2ecf20Sopenharmony_ci "%s %d Term INOT due to WWN=0 lid=%d, NportID %06X ", 47148c2ecf20Sopenharmony_ci __func__, __LINE__, loop_id, port_id.b24); 47158c2ecf20Sopenharmony_ci qlt_send_term_imm_notif(vha, iocb, 1); 47168c2ecf20Sopenharmony_ci goto out; 47178c2ecf20Sopenharmony_ci } 47188c2ecf20Sopenharmony_ci 47198c2ecf20Sopenharmony_ci if (IS_SW_RESV_ADDR(port_id)) { 47208c2ecf20Sopenharmony_ci res = 1; 47218c2ecf20Sopenharmony_ci goto out; 47228c2ecf20Sopenharmony_ci } 47238c2ecf20Sopenharmony_ci 47248c2ecf20Sopenharmony_ci pla = qlt_plogi_ack_find_add(vha, &port_id, iocb); 47258c2ecf20Sopenharmony_ci if (!pla) { 47268c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, 47278c2ecf20Sopenharmony_ci "%s %d %8phC Term INOT due to mem alloc fail", 47288c2ecf20Sopenharmony_ci __func__, __LINE__, 47298c2ecf20Sopenharmony_ci iocb->u.isp24.port_name); 47308c2ecf20Sopenharmony_ci qlt_send_term_imm_notif(vha, iocb, 1); 47318c2ecf20Sopenharmony_ci goto out; 47328c2ecf20Sopenharmony_ci } 47338c2ecf20Sopenharmony_ci 47348c2ecf20Sopenharmony_ci if (conflict_sess) { 47358c2ecf20Sopenharmony_ci conflict_sess->login_gen++; 47368c2ecf20Sopenharmony_ci qlt_plogi_ack_link(vha, pla, conflict_sess, 47378c2ecf20Sopenharmony_ci QLT_PLOGI_LINK_CONFLICT); 47388c2ecf20Sopenharmony_ci } 47398c2ecf20Sopenharmony_ci 47408c2ecf20Sopenharmony_ci if (!sess) { 47418c2ecf20Sopenharmony_ci pla->ref_count++; 47428c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 47438c2ecf20Sopenharmony_ci "%s %d %8phC post new sess\n", 47448c2ecf20Sopenharmony_ci __func__, __LINE__, iocb->u.isp24.port_name); 47458c2ecf20Sopenharmony_ci if (iocb->u.isp24.status_subcode == ELS_PLOGI) 47468c2ecf20Sopenharmony_ci qla24xx_post_newsess_work(vha, &port_id, 47478c2ecf20Sopenharmony_ci iocb->u.isp24.port_name, 47488c2ecf20Sopenharmony_ci iocb->u.isp24.u.plogi.node_name, 47498c2ecf20Sopenharmony_ci pla, 0); 47508c2ecf20Sopenharmony_ci else 47518c2ecf20Sopenharmony_ci qla24xx_post_newsess_work(vha, &port_id, 47528c2ecf20Sopenharmony_ci iocb->u.isp24.port_name, NULL, 47538c2ecf20Sopenharmony_ci pla, 0); 47548c2ecf20Sopenharmony_ci 47558c2ecf20Sopenharmony_ci goto out; 47568c2ecf20Sopenharmony_ci } 47578c2ecf20Sopenharmony_ci 47588c2ecf20Sopenharmony_ci if (sess->disc_state == DSC_UPD_FCPORT) { 47598c2ecf20Sopenharmony_ci u16 sec; 47608c2ecf20Sopenharmony_ci 47618c2ecf20Sopenharmony_ci /* 47628c2ecf20Sopenharmony_ci * Remote port registration is still going on from 47638c2ecf20Sopenharmony_ci * previous login. Allow it to finish before we 47648c2ecf20Sopenharmony_ci * accept the new login. 47658c2ecf20Sopenharmony_ci */ 47668c2ecf20Sopenharmony_ci sess->next_disc_state = DSC_DELETE_PEND; 47678c2ecf20Sopenharmony_ci sec = jiffies_to_msecs(jiffies - 47688c2ecf20Sopenharmony_ci sess->jiffies_at_registration) / 1000; 47698c2ecf20Sopenharmony_ci if (sess->sec_since_registration < sec && sec && 47708c2ecf20Sopenharmony_ci !(sec % 5)) { 47718c2ecf20Sopenharmony_ci sess->sec_since_registration = sec; 47728c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 47738c2ecf20Sopenharmony_ci "%s %8phC - Slow Rport registration (%d Sec)\n", 47748c2ecf20Sopenharmony_ci __func__, sess->port_name, sec); 47758c2ecf20Sopenharmony_ci } 47768c2ecf20Sopenharmony_ci 47778c2ecf20Sopenharmony_ci if (!conflict_sess) { 47788c2ecf20Sopenharmony_ci list_del(&pla->list); 47798c2ecf20Sopenharmony_ci kmem_cache_free(qla_tgt_plogi_cachep, pla); 47808c2ecf20Sopenharmony_ci } 47818c2ecf20Sopenharmony_ci 47828c2ecf20Sopenharmony_ci qlt_send_term_imm_notif(vha, iocb, 1); 47838c2ecf20Sopenharmony_ci goto out; 47848c2ecf20Sopenharmony_ci } 47858c2ecf20Sopenharmony_ci 47868c2ecf20Sopenharmony_ci qlt_plogi_ack_link(vha, pla, sess, QLT_PLOGI_LINK_SAME_WWN); 47878c2ecf20Sopenharmony_ci sess->d_id = port_id; 47888c2ecf20Sopenharmony_ci sess->login_gen++; 47898c2ecf20Sopenharmony_ci 47908c2ecf20Sopenharmony_ci if (iocb->u.isp24.status_subcode == ELS_PRLI) { 47918c2ecf20Sopenharmony_ci sess->fw_login_state = DSC_LS_PRLI_PEND; 47928c2ecf20Sopenharmony_ci sess->local = 0; 47938c2ecf20Sopenharmony_ci sess->loop_id = loop_id; 47948c2ecf20Sopenharmony_ci sess->d_id = port_id; 47958c2ecf20Sopenharmony_ci sess->fw_login_state = DSC_LS_PRLI_PEND; 47968c2ecf20Sopenharmony_ci wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo); 47978c2ecf20Sopenharmony_ci 47988c2ecf20Sopenharmony_ci if (wd3_lo & BIT_7) 47998c2ecf20Sopenharmony_ci sess->conf_compl_supported = 1; 48008c2ecf20Sopenharmony_ci 48018c2ecf20Sopenharmony_ci if ((wd3_lo & BIT_4) == 0) 48028c2ecf20Sopenharmony_ci sess->port_type = FCT_INITIATOR; 48038c2ecf20Sopenharmony_ci else 48048c2ecf20Sopenharmony_ci sess->port_type = FCT_TARGET; 48058c2ecf20Sopenharmony_ci 48068c2ecf20Sopenharmony_ci } else 48078c2ecf20Sopenharmony_ci sess->fw_login_state = DSC_LS_PLOGI_PEND; 48088c2ecf20Sopenharmony_ci 48098c2ecf20Sopenharmony_ci 48108c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f9, 48118c2ecf20Sopenharmony_ci "%s %d %8phC DS %d\n", 48128c2ecf20Sopenharmony_ci __func__, __LINE__, sess->port_name, sess->disc_state); 48138c2ecf20Sopenharmony_ci 48148c2ecf20Sopenharmony_ci switch (sess->disc_state) { 48158c2ecf20Sopenharmony_ci case DSC_DELETED: 48168c2ecf20Sopenharmony_ci case DSC_LOGIN_PEND: 48178c2ecf20Sopenharmony_ci qlt_plogi_ack_unref(vha, pla); 48188c2ecf20Sopenharmony_ci break; 48198c2ecf20Sopenharmony_ci 48208c2ecf20Sopenharmony_ci default: 48218c2ecf20Sopenharmony_ci /* 48228c2ecf20Sopenharmony_ci * Under normal circumstances we want to release nport handle 48238c2ecf20Sopenharmony_ci * during LOGO process to avoid nport handle leaks inside FW. 48248c2ecf20Sopenharmony_ci * The exception is when LOGO is done while another PLOGI with 48258c2ecf20Sopenharmony_ci * the same nport handle is waiting as might be the case here. 48268c2ecf20Sopenharmony_ci * Note: there is always a possibily of a race where session 48278c2ecf20Sopenharmony_ci * deletion has already started for other reasons (e.g. ACL 48288c2ecf20Sopenharmony_ci * removal) and now PLOGI arrives: 48298c2ecf20Sopenharmony_ci * 1. if PLOGI arrived in FW after nport handle has been freed, 48308c2ecf20Sopenharmony_ci * FW must have assigned this PLOGI a new/same handle and we 48318c2ecf20Sopenharmony_ci * can proceed ACK'ing it as usual when session deletion 48328c2ecf20Sopenharmony_ci * completes. 48338c2ecf20Sopenharmony_ci * 2. if PLOGI arrived in FW before LOGO with LCF_FREE_NPORT 48348c2ecf20Sopenharmony_ci * bit reached it, the handle has now been released. We'll 48358c2ecf20Sopenharmony_ci * get an error when we ACK this PLOGI. Nothing will be sent 48368c2ecf20Sopenharmony_ci * back to initiator. Initiator should eventually retry 48378c2ecf20Sopenharmony_ci * PLOGI and situation will correct itself. 48388c2ecf20Sopenharmony_ci */ 48398c2ecf20Sopenharmony_ci sess->keep_nport_handle = ((sess->loop_id == loop_id) && 48408c2ecf20Sopenharmony_ci (sess->d_id.b24 == port_id.b24)); 48418c2ecf20Sopenharmony_ci 48428c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f9, 48438c2ecf20Sopenharmony_ci "%s %d %8phC post del sess\n", 48448c2ecf20Sopenharmony_ci __func__, __LINE__, sess->port_name); 48458c2ecf20Sopenharmony_ci 48468c2ecf20Sopenharmony_ci 48478c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(sess); 48488c2ecf20Sopenharmony_ci break; 48498c2ecf20Sopenharmony_ci } 48508c2ecf20Sopenharmony_ciout: 48518c2ecf20Sopenharmony_ci return res; 48528c2ecf20Sopenharmony_ci} 48538c2ecf20Sopenharmony_ci 48548c2ecf20Sopenharmony_ci/* 48558c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 48568c2ecf20Sopenharmony_ci */ 48578c2ecf20Sopenharmony_cistatic int qlt_24xx_handle_els(struct scsi_qla_host *vha, 48588c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *iocb) 48598c2ecf20Sopenharmony_ci{ 48608c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 48618c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 48628c2ecf20Sopenharmony_ci struct fc_port *sess = NULL, *conflict_sess = NULL; 48638c2ecf20Sopenharmony_ci uint64_t wwn; 48648c2ecf20Sopenharmony_ci port_id_t port_id; 48658c2ecf20Sopenharmony_ci uint16_t loop_id; 48668c2ecf20Sopenharmony_ci uint16_t wd3_lo; 48678c2ecf20Sopenharmony_ci int res = 0; 48688c2ecf20Sopenharmony_ci unsigned long flags; 48698c2ecf20Sopenharmony_ci 48708c2ecf20Sopenharmony_ci lockdep_assert_held(&ha->hardware_lock); 48718c2ecf20Sopenharmony_ci 48728c2ecf20Sopenharmony_ci wwn = wwn_to_u64(iocb->u.isp24.port_name); 48738c2ecf20Sopenharmony_ci 48748c2ecf20Sopenharmony_ci port_id.b.domain = iocb->u.isp24.port_id[2]; 48758c2ecf20Sopenharmony_ci port_id.b.area = iocb->u.isp24.port_id[1]; 48768c2ecf20Sopenharmony_ci port_id.b.al_pa = iocb->u.isp24.port_id[0]; 48778c2ecf20Sopenharmony_ci port_id.b.rsvd_1 = 0; 48788c2ecf20Sopenharmony_ci 48798c2ecf20Sopenharmony_ci loop_id = le16_to_cpu(iocb->u.isp24.nport_handle); 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xf026, 48828c2ecf20Sopenharmony_ci "qla_target(%d): Port ID: %02x:%02x:%02x ELS opcode: 0x%02x lid %d %8phC\n", 48838c2ecf20Sopenharmony_ci vha->vp_idx, iocb->u.isp24.port_id[2], 48848c2ecf20Sopenharmony_ci iocb->u.isp24.port_id[1], iocb->u.isp24.port_id[0], 48858c2ecf20Sopenharmony_ci iocb->u.isp24.status_subcode, loop_id, 48868c2ecf20Sopenharmony_ci iocb->u.isp24.port_name); 48878c2ecf20Sopenharmony_ci 48888c2ecf20Sopenharmony_ci /* res = 1 means ack at the end of thread 48898c2ecf20Sopenharmony_ci * res = 0 means ack async/later. 48908c2ecf20Sopenharmony_ci */ 48918c2ecf20Sopenharmony_ci switch (iocb->u.isp24.status_subcode) { 48928c2ecf20Sopenharmony_ci case ELS_PLOGI: 48938c2ecf20Sopenharmony_ci res = qlt_handle_login(vha, iocb); 48948c2ecf20Sopenharmony_ci break; 48958c2ecf20Sopenharmony_ci 48968c2ecf20Sopenharmony_ci case ELS_PRLI: 48978c2ecf20Sopenharmony_ci if (N2N_TOPO(ha)) { 48988c2ecf20Sopenharmony_ci sess = qla2x00_find_fcport_by_wwpn(vha, 48998c2ecf20Sopenharmony_ci iocb->u.isp24.port_name, 1); 49008c2ecf20Sopenharmony_ci 49018c2ecf20Sopenharmony_ci if (sess && sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN]) { 49028c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 49038c2ecf20Sopenharmony_ci "%s %d %8phC Term PRLI due to PLOGI ACK not completed\n", 49048c2ecf20Sopenharmony_ci __func__, __LINE__, 49058c2ecf20Sopenharmony_ci iocb->u.isp24.port_name); 49068c2ecf20Sopenharmony_ci qlt_send_term_imm_notif(vha, iocb, 1); 49078c2ecf20Sopenharmony_ci break; 49088c2ecf20Sopenharmony_ci } 49098c2ecf20Sopenharmony_ci 49108c2ecf20Sopenharmony_ci res = qlt_handle_login(vha, iocb); 49118c2ecf20Sopenharmony_ci break; 49128c2ecf20Sopenharmony_ci } 49138c2ecf20Sopenharmony_ci 49148c2ecf20Sopenharmony_ci if (IS_SW_RESV_ADDR(port_id)) { 49158c2ecf20Sopenharmony_ci res = 1; 49168c2ecf20Sopenharmony_ci break; 49178c2ecf20Sopenharmony_ci } 49188c2ecf20Sopenharmony_ci 49198c2ecf20Sopenharmony_ci wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo); 49208c2ecf20Sopenharmony_ci 49218c2ecf20Sopenharmony_ci if (wwn) { 49228c2ecf20Sopenharmony_ci spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags); 49238c2ecf20Sopenharmony_ci sess = qlt_find_sess_invalidate_other(vha, wwn, port_id, 49248c2ecf20Sopenharmony_ci loop_id, &conflict_sess); 49258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags); 49268c2ecf20Sopenharmony_ci } 49278c2ecf20Sopenharmony_ci 49288c2ecf20Sopenharmony_ci if (conflict_sess) { 49298c2ecf20Sopenharmony_ci switch (conflict_sess->disc_state) { 49308c2ecf20Sopenharmony_ci case DSC_DELETED: 49318c2ecf20Sopenharmony_ci case DSC_DELETE_PEND: 49328c2ecf20Sopenharmony_ci break; 49338c2ecf20Sopenharmony_ci default: 49348c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09b, 49358c2ecf20Sopenharmony_ci "PRLI with conflicting sess %p port %8phC\n", 49368c2ecf20Sopenharmony_ci conflict_sess, conflict_sess->port_name); 49378c2ecf20Sopenharmony_ci conflict_sess->fw_login_state = 49388c2ecf20Sopenharmony_ci DSC_LS_PORT_UNAVAIL; 49398c2ecf20Sopenharmony_ci qlt_send_term_imm_notif(vha, iocb, 1); 49408c2ecf20Sopenharmony_ci res = 0; 49418c2ecf20Sopenharmony_ci break; 49428c2ecf20Sopenharmony_ci } 49438c2ecf20Sopenharmony_ci } 49448c2ecf20Sopenharmony_ci 49458c2ecf20Sopenharmony_ci if (sess != NULL) { 49468c2ecf20Sopenharmony_ci bool delete = false; 49478c2ecf20Sopenharmony_ci int sec; 49488c2ecf20Sopenharmony_ci 49498c2ecf20Sopenharmony_ci spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags); 49508c2ecf20Sopenharmony_ci switch (sess->fw_login_state) { 49518c2ecf20Sopenharmony_ci case DSC_LS_PLOGI_PEND: 49528c2ecf20Sopenharmony_ci case DSC_LS_PLOGI_COMP: 49538c2ecf20Sopenharmony_ci case DSC_LS_PRLI_COMP: 49548c2ecf20Sopenharmony_ci break; 49558c2ecf20Sopenharmony_ci default: 49568c2ecf20Sopenharmony_ci delete = true; 49578c2ecf20Sopenharmony_ci break; 49588c2ecf20Sopenharmony_ci } 49598c2ecf20Sopenharmony_ci 49608c2ecf20Sopenharmony_ci switch (sess->disc_state) { 49618c2ecf20Sopenharmony_ci case DSC_UPD_FCPORT: 49628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, 49638c2ecf20Sopenharmony_ci flags); 49648c2ecf20Sopenharmony_ci 49658c2ecf20Sopenharmony_ci sec = jiffies_to_msecs(jiffies - 49668c2ecf20Sopenharmony_ci sess->jiffies_at_registration)/1000; 49678c2ecf20Sopenharmony_ci if (sess->sec_since_registration < sec && sec && 49688c2ecf20Sopenharmony_ci !(sec % 5)) { 49698c2ecf20Sopenharmony_ci sess->sec_since_registration = sec; 49708c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, sess->vha, 0xffff, 49718c2ecf20Sopenharmony_ci "%s %8phC : Slow Rport registration(%d Sec)\n", 49728c2ecf20Sopenharmony_ci __func__, sess->port_name, sec); 49738c2ecf20Sopenharmony_ci } 49748c2ecf20Sopenharmony_ci qlt_send_term_imm_notif(vha, iocb, 1); 49758c2ecf20Sopenharmony_ci return 0; 49768c2ecf20Sopenharmony_ci 49778c2ecf20Sopenharmony_ci case DSC_LOGIN_PEND: 49788c2ecf20Sopenharmony_ci case DSC_GPDB: 49798c2ecf20Sopenharmony_ci case DSC_LOGIN_COMPLETE: 49808c2ecf20Sopenharmony_ci case DSC_ADISC: 49818c2ecf20Sopenharmony_ci delete = false; 49828c2ecf20Sopenharmony_ci break; 49838c2ecf20Sopenharmony_ci default: 49848c2ecf20Sopenharmony_ci break; 49858c2ecf20Sopenharmony_ci } 49868c2ecf20Sopenharmony_ci 49878c2ecf20Sopenharmony_ci if (delete) { 49888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, 49898c2ecf20Sopenharmony_ci flags); 49908c2ecf20Sopenharmony_ci /* 49918c2ecf20Sopenharmony_ci * Impatient initiator sent PRLI before last 49928c2ecf20Sopenharmony_ci * PLOGI could finish. Will force him to re-try, 49938c2ecf20Sopenharmony_ci * while last one finishes. 49948c2ecf20Sopenharmony_ci */ 49958c2ecf20Sopenharmony_ci ql_log(ql_log_warn, sess->vha, 0xf095, 49968c2ecf20Sopenharmony_ci "sess %p PRLI received, before plogi ack.\n", 49978c2ecf20Sopenharmony_ci sess); 49988c2ecf20Sopenharmony_ci qlt_send_term_imm_notif(vha, iocb, 1); 49998c2ecf20Sopenharmony_ci res = 0; 50008c2ecf20Sopenharmony_ci break; 50018c2ecf20Sopenharmony_ci } 50028c2ecf20Sopenharmony_ci 50038c2ecf20Sopenharmony_ci /* 50048c2ecf20Sopenharmony_ci * This shouldn't happen under normal circumstances, 50058c2ecf20Sopenharmony_ci * since we have deleted the old session during PLOGI 50068c2ecf20Sopenharmony_ci */ 50078c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf096, 50088c2ecf20Sopenharmony_ci "PRLI (loop_id %#04x) for existing sess %p (loop_id %#04x)\n", 50098c2ecf20Sopenharmony_ci sess->loop_id, sess, iocb->u.isp24.nport_handle); 50108c2ecf20Sopenharmony_ci 50118c2ecf20Sopenharmony_ci sess->local = 0; 50128c2ecf20Sopenharmony_ci sess->loop_id = loop_id; 50138c2ecf20Sopenharmony_ci sess->d_id = port_id; 50148c2ecf20Sopenharmony_ci sess->fw_login_state = DSC_LS_PRLI_PEND; 50158c2ecf20Sopenharmony_ci 50168c2ecf20Sopenharmony_ci if (wd3_lo & BIT_7) 50178c2ecf20Sopenharmony_ci sess->conf_compl_supported = 1; 50188c2ecf20Sopenharmony_ci 50198c2ecf20Sopenharmony_ci if ((wd3_lo & BIT_4) == 0) 50208c2ecf20Sopenharmony_ci sess->port_type = FCT_INITIATOR; 50218c2ecf20Sopenharmony_ci else 50228c2ecf20Sopenharmony_ci sess->port_type = FCT_TARGET; 50238c2ecf20Sopenharmony_ci 50248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags); 50258c2ecf20Sopenharmony_ci } 50268c2ecf20Sopenharmony_ci res = 1; /* send notify ack */ 50278c2ecf20Sopenharmony_ci 50288c2ecf20Sopenharmony_ci /* Make session global (not used in fabric mode) */ 50298c2ecf20Sopenharmony_ci if (ha->current_topology != ISP_CFG_F) { 50308c2ecf20Sopenharmony_ci if (sess) { 50318c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20fa, 50328c2ecf20Sopenharmony_ci "%s %d %8phC post nack\n", 50338c2ecf20Sopenharmony_ci __func__, __LINE__, sess->port_name); 50348c2ecf20Sopenharmony_ci qla24xx_post_nack_work(vha, sess, iocb, 50358c2ecf20Sopenharmony_ci SRB_NACK_PRLI); 50368c2ecf20Sopenharmony_ci res = 0; 50378c2ecf20Sopenharmony_ci } else { 50388c2ecf20Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 50398c2ecf20Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 50408c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(vha); 50418c2ecf20Sopenharmony_ci } 50428c2ecf20Sopenharmony_ci } else { 50438c2ecf20Sopenharmony_ci if (sess) { 50448c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20fb, 50458c2ecf20Sopenharmony_ci "%s %d %8phC post nack\n", 50468c2ecf20Sopenharmony_ci __func__, __LINE__, sess->port_name); 50478c2ecf20Sopenharmony_ci qla24xx_post_nack_work(vha, sess, iocb, 50488c2ecf20Sopenharmony_ci SRB_NACK_PRLI); 50498c2ecf20Sopenharmony_ci res = 0; 50508c2ecf20Sopenharmony_ci } 50518c2ecf20Sopenharmony_ci } 50528c2ecf20Sopenharmony_ci break; 50538c2ecf20Sopenharmony_ci 50548c2ecf20Sopenharmony_ci case ELS_TPRLO: 50558c2ecf20Sopenharmony_ci if (le16_to_cpu(iocb->u.isp24.flags) & 50568c2ecf20Sopenharmony_ci NOTIFY24XX_FLAGS_GLOBAL_TPRLO) { 50578c2ecf20Sopenharmony_ci loop_id = 0xFFFF; 50588c2ecf20Sopenharmony_ci qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS); 50598c2ecf20Sopenharmony_ci res = 1; 50608c2ecf20Sopenharmony_ci break; 50618c2ecf20Sopenharmony_ci } 50628c2ecf20Sopenharmony_ci fallthrough; 50638c2ecf20Sopenharmony_ci case ELS_LOGO: 50648c2ecf20Sopenharmony_ci case ELS_PRLO: 50658c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 50668c2ecf20Sopenharmony_ci sess = qla2x00_find_fcport_by_loopid(vha, loop_id); 50678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 50688c2ecf20Sopenharmony_ci 50698c2ecf20Sopenharmony_ci if (sess) { 50708c2ecf20Sopenharmony_ci sess->login_gen++; 50718c2ecf20Sopenharmony_ci sess->fw_login_state = DSC_LS_LOGO_PEND; 50728c2ecf20Sopenharmony_ci sess->logo_ack_needed = 1; 50738c2ecf20Sopenharmony_ci memcpy(sess->iocb, iocb, IOCB_SIZE); 50748c2ecf20Sopenharmony_ci } 50758c2ecf20Sopenharmony_ci 50768c2ecf20Sopenharmony_ci res = qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS_SESS); 50778c2ecf20Sopenharmony_ci 50788c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20fc, 50798c2ecf20Sopenharmony_ci "%s: logo %llx res %d sess %p ", 50808c2ecf20Sopenharmony_ci __func__, wwn, res, sess); 50818c2ecf20Sopenharmony_ci if (res == 0) { 50828c2ecf20Sopenharmony_ci /* 50838c2ecf20Sopenharmony_ci * cmd went upper layer, look for qlt_xmit_tm_rsp() 50848c2ecf20Sopenharmony_ci * for LOGO_ACK & sess delete 50858c2ecf20Sopenharmony_ci */ 50868c2ecf20Sopenharmony_ci BUG_ON(!sess); 50878c2ecf20Sopenharmony_ci res = 0; 50888c2ecf20Sopenharmony_ci } else { 50898c2ecf20Sopenharmony_ci /* cmd did not go to upper layer. */ 50908c2ecf20Sopenharmony_ci if (sess) { 50918c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(sess); 50928c2ecf20Sopenharmony_ci res = 0; 50938c2ecf20Sopenharmony_ci } 50948c2ecf20Sopenharmony_ci /* else logo will be ack */ 50958c2ecf20Sopenharmony_ci } 50968c2ecf20Sopenharmony_ci break; 50978c2ecf20Sopenharmony_ci case ELS_PDISC: 50988c2ecf20Sopenharmony_ci case ELS_ADISC: 50998c2ecf20Sopenharmony_ci { 51008c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 51018c2ecf20Sopenharmony_ci 51028c2ecf20Sopenharmony_ci if (tgt->link_reinit_iocb_pending) { 51038c2ecf20Sopenharmony_ci qlt_send_notify_ack(ha->base_qpair, 51048c2ecf20Sopenharmony_ci &tgt->link_reinit_iocb, 0, 0, 0, 0, 0, 0); 51058c2ecf20Sopenharmony_ci tgt->link_reinit_iocb_pending = 0; 51068c2ecf20Sopenharmony_ci } 51078c2ecf20Sopenharmony_ci 51088c2ecf20Sopenharmony_ci sess = qla2x00_find_fcport_by_wwpn(vha, 51098c2ecf20Sopenharmony_ci iocb->u.isp24.port_name, 1); 51108c2ecf20Sopenharmony_ci if (sess) { 51118c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20fd, 51128c2ecf20Sopenharmony_ci "sess %p lid %d|%d DS %d LS %d\n", 51138c2ecf20Sopenharmony_ci sess, sess->loop_id, loop_id, 51148c2ecf20Sopenharmony_ci sess->disc_state, sess->fw_login_state); 51158c2ecf20Sopenharmony_ci } 51168c2ecf20Sopenharmony_ci 51178c2ecf20Sopenharmony_ci res = 1; /* send notify ack */ 51188c2ecf20Sopenharmony_ci break; 51198c2ecf20Sopenharmony_ci } 51208c2ecf20Sopenharmony_ci 51218c2ecf20Sopenharmony_ci case ELS_FLOGI: /* should never happen */ 51228c2ecf20Sopenharmony_ci default: 51238c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf061, 51248c2ecf20Sopenharmony_ci "qla_target(%d): Unsupported ELS command %x " 51258c2ecf20Sopenharmony_ci "received\n", vha->vp_idx, iocb->u.isp24.status_subcode); 51268c2ecf20Sopenharmony_ci res = qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS_SESS); 51278c2ecf20Sopenharmony_ci break; 51288c2ecf20Sopenharmony_ci } 51298c2ecf20Sopenharmony_ci 51308c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xf026, 51318c2ecf20Sopenharmony_ci "qla_target(%d): Exit ELS opcode: 0x%02x res %d\n", 51328c2ecf20Sopenharmony_ci vha->vp_idx, iocb->u.isp24.status_subcode, res); 51338c2ecf20Sopenharmony_ci 51348c2ecf20Sopenharmony_ci return res; 51358c2ecf20Sopenharmony_ci} 51368c2ecf20Sopenharmony_ci 51378c2ecf20Sopenharmony_ci/* 51388c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 51398c2ecf20Sopenharmony_ci */ 51408c2ecf20Sopenharmony_cistatic void qlt_handle_imm_notify(struct scsi_qla_host *vha, 51418c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *iocb) 51428c2ecf20Sopenharmony_ci{ 51438c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 51448c2ecf20Sopenharmony_ci uint32_t add_flags = 0; 51458c2ecf20Sopenharmony_ci int send_notify_ack = 1; 51468c2ecf20Sopenharmony_ci uint16_t status; 51478c2ecf20Sopenharmony_ci 51488c2ecf20Sopenharmony_ci lockdep_assert_held(&ha->hardware_lock); 51498c2ecf20Sopenharmony_ci 51508c2ecf20Sopenharmony_ci status = le16_to_cpu(iocb->u.isp2x.status); 51518c2ecf20Sopenharmony_ci switch (status) { 51528c2ecf20Sopenharmony_ci case IMM_NTFY_LIP_RESET: 51538c2ecf20Sopenharmony_ci { 51548c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf032, 51558c2ecf20Sopenharmony_ci "qla_target(%d): LIP reset (loop %#x), subcode %x\n", 51568c2ecf20Sopenharmony_ci vha->vp_idx, le16_to_cpu(iocb->u.isp24.nport_handle), 51578c2ecf20Sopenharmony_ci iocb->u.isp24.status_subcode); 51588c2ecf20Sopenharmony_ci 51598c2ecf20Sopenharmony_ci if (qlt_reset(vha, iocb, QLA_TGT_ABORT_ALL) == 0) 51608c2ecf20Sopenharmony_ci send_notify_ack = 0; 51618c2ecf20Sopenharmony_ci break; 51628c2ecf20Sopenharmony_ci } 51638c2ecf20Sopenharmony_ci 51648c2ecf20Sopenharmony_ci case IMM_NTFY_LIP_LINK_REINIT: 51658c2ecf20Sopenharmony_ci { 51668c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 51678c2ecf20Sopenharmony_ci 51688c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf033, 51698c2ecf20Sopenharmony_ci "qla_target(%d): LINK REINIT (loop %#x, " 51708c2ecf20Sopenharmony_ci "subcode %x)\n", vha->vp_idx, 51718c2ecf20Sopenharmony_ci le16_to_cpu(iocb->u.isp24.nport_handle), 51728c2ecf20Sopenharmony_ci iocb->u.isp24.status_subcode); 51738c2ecf20Sopenharmony_ci if (tgt->link_reinit_iocb_pending) { 51748c2ecf20Sopenharmony_ci qlt_send_notify_ack(ha->base_qpair, 51758c2ecf20Sopenharmony_ci &tgt->link_reinit_iocb, 0, 0, 0, 0, 0, 0); 51768c2ecf20Sopenharmony_ci } 51778c2ecf20Sopenharmony_ci memcpy(&tgt->link_reinit_iocb, iocb, sizeof(*iocb)); 51788c2ecf20Sopenharmony_ci tgt->link_reinit_iocb_pending = 1; 51798c2ecf20Sopenharmony_ci /* 51808c2ecf20Sopenharmony_ci * QLogic requires to wait after LINK REINIT for possible 51818c2ecf20Sopenharmony_ci * PDISC or ADISC ELS commands 51828c2ecf20Sopenharmony_ci */ 51838c2ecf20Sopenharmony_ci send_notify_ack = 0; 51848c2ecf20Sopenharmony_ci break; 51858c2ecf20Sopenharmony_ci } 51868c2ecf20Sopenharmony_ci 51878c2ecf20Sopenharmony_ci case IMM_NTFY_PORT_LOGOUT: 51888c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf034, 51898c2ecf20Sopenharmony_ci "qla_target(%d): Port logout (loop " 51908c2ecf20Sopenharmony_ci "%#x, subcode %x)\n", vha->vp_idx, 51918c2ecf20Sopenharmony_ci le16_to_cpu(iocb->u.isp24.nport_handle), 51928c2ecf20Sopenharmony_ci iocb->u.isp24.status_subcode); 51938c2ecf20Sopenharmony_ci 51948c2ecf20Sopenharmony_ci if (qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS_SESS) == 0) 51958c2ecf20Sopenharmony_ci send_notify_ack = 0; 51968c2ecf20Sopenharmony_ci /* The sessions will be cleared in the callback, if needed */ 51978c2ecf20Sopenharmony_ci break; 51988c2ecf20Sopenharmony_ci 51998c2ecf20Sopenharmony_ci case IMM_NTFY_GLBL_TPRLO: 52008c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf035, 52018c2ecf20Sopenharmony_ci "qla_target(%d): Global TPRLO (%x)\n", vha->vp_idx, status); 52028c2ecf20Sopenharmony_ci if (qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS) == 0) 52038c2ecf20Sopenharmony_ci send_notify_ack = 0; 52048c2ecf20Sopenharmony_ci /* The sessions will be cleared in the callback, if needed */ 52058c2ecf20Sopenharmony_ci break; 52068c2ecf20Sopenharmony_ci 52078c2ecf20Sopenharmony_ci case IMM_NTFY_PORT_CONFIG: 52088c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf036, 52098c2ecf20Sopenharmony_ci "qla_target(%d): Port config changed (%x)\n", vha->vp_idx, 52108c2ecf20Sopenharmony_ci status); 52118c2ecf20Sopenharmony_ci if (qlt_reset(vha, iocb, QLA_TGT_ABORT_ALL) == 0) 52128c2ecf20Sopenharmony_ci send_notify_ack = 0; 52138c2ecf20Sopenharmony_ci /* The sessions will be cleared in the callback, if needed */ 52148c2ecf20Sopenharmony_ci break; 52158c2ecf20Sopenharmony_ci 52168c2ecf20Sopenharmony_ci case IMM_NTFY_GLBL_LOGO: 52178c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06a, 52188c2ecf20Sopenharmony_ci "qla_target(%d): Link failure detected\n", 52198c2ecf20Sopenharmony_ci vha->vp_idx); 52208c2ecf20Sopenharmony_ci /* I_T nexus loss */ 52218c2ecf20Sopenharmony_ci if (qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS) == 0) 52228c2ecf20Sopenharmony_ci send_notify_ack = 0; 52238c2ecf20Sopenharmony_ci break; 52248c2ecf20Sopenharmony_ci 52258c2ecf20Sopenharmony_ci case IMM_NTFY_IOCB_OVERFLOW: 52268c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06b, 52278c2ecf20Sopenharmony_ci "qla_target(%d): Cannot provide requested " 52288c2ecf20Sopenharmony_ci "capability (IOCB overflowed the immediate notify " 52298c2ecf20Sopenharmony_ci "resource count)\n", vha->vp_idx); 52308c2ecf20Sopenharmony_ci break; 52318c2ecf20Sopenharmony_ci 52328c2ecf20Sopenharmony_ci case IMM_NTFY_ABORT_TASK: 52338c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf037, 52348c2ecf20Sopenharmony_ci "qla_target(%d): Abort Task (S %08x I %#x -> " 52358c2ecf20Sopenharmony_ci "L %#x)\n", vha->vp_idx, 52368c2ecf20Sopenharmony_ci le16_to_cpu(iocb->u.isp2x.seq_id), 52378c2ecf20Sopenharmony_ci GET_TARGET_ID(ha, (struct atio_from_isp *)iocb), 52388c2ecf20Sopenharmony_ci le16_to_cpu(iocb->u.isp2x.lun)); 52398c2ecf20Sopenharmony_ci if (qlt_abort_task(vha, iocb) == 0) 52408c2ecf20Sopenharmony_ci send_notify_ack = 0; 52418c2ecf20Sopenharmony_ci break; 52428c2ecf20Sopenharmony_ci 52438c2ecf20Sopenharmony_ci case IMM_NTFY_RESOURCE: 52448c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06c, 52458c2ecf20Sopenharmony_ci "qla_target(%d): Out of resources, host %ld\n", 52468c2ecf20Sopenharmony_ci vha->vp_idx, vha->host_no); 52478c2ecf20Sopenharmony_ci break; 52488c2ecf20Sopenharmony_ci 52498c2ecf20Sopenharmony_ci case IMM_NTFY_MSG_RX: 52508c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf038, 52518c2ecf20Sopenharmony_ci "qla_target(%d): Immediate notify task %x\n", 52528c2ecf20Sopenharmony_ci vha->vp_idx, iocb->u.isp2x.task_flags); 52538c2ecf20Sopenharmony_ci break; 52548c2ecf20Sopenharmony_ci 52558c2ecf20Sopenharmony_ci case IMM_NTFY_ELS: 52568c2ecf20Sopenharmony_ci if (qlt_24xx_handle_els(vha, iocb) == 0) 52578c2ecf20Sopenharmony_ci send_notify_ack = 0; 52588c2ecf20Sopenharmony_ci break; 52598c2ecf20Sopenharmony_ci default: 52608c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06d, 52618c2ecf20Sopenharmony_ci "qla_target(%d): Received unknown immediate " 52628c2ecf20Sopenharmony_ci "notify status %x\n", vha->vp_idx, status); 52638c2ecf20Sopenharmony_ci break; 52648c2ecf20Sopenharmony_ci } 52658c2ecf20Sopenharmony_ci 52668c2ecf20Sopenharmony_ci if (send_notify_ack) 52678c2ecf20Sopenharmony_ci qlt_send_notify_ack(ha->base_qpair, iocb, add_flags, 0, 0, 0, 52688c2ecf20Sopenharmony_ci 0, 0); 52698c2ecf20Sopenharmony_ci} 52708c2ecf20Sopenharmony_ci 52718c2ecf20Sopenharmony_ci/* 52728c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 52738c2ecf20Sopenharmony_ci * This function sends busy to ISP 2xxx or 24xx. 52748c2ecf20Sopenharmony_ci */ 52758c2ecf20Sopenharmony_cistatic int __qlt_send_busy(struct qla_qpair *qpair, 52768c2ecf20Sopenharmony_ci struct atio_from_isp *atio, uint16_t status) 52778c2ecf20Sopenharmony_ci{ 52788c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = qpair->vha; 52798c2ecf20Sopenharmony_ci struct ctio7_to_24xx *ctio24; 52808c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 52818c2ecf20Sopenharmony_ci request_t *pkt; 52828c2ecf20Sopenharmony_ci struct fc_port *sess = NULL; 52838c2ecf20Sopenharmony_ci unsigned long flags; 52848c2ecf20Sopenharmony_ci u16 temp; 52858c2ecf20Sopenharmony_ci port_id_t id; 52868c2ecf20Sopenharmony_ci 52878c2ecf20Sopenharmony_ci id = be_to_port_id(atio->u.isp24.fcp_hdr.s_id); 52888c2ecf20Sopenharmony_ci 52898c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 52908c2ecf20Sopenharmony_ci sess = qla2x00_find_fcport_by_nportid(vha, &id, 1); 52918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 52928c2ecf20Sopenharmony_ci if (!sess) { 52938c2ecf20Sopenharmony_ci qlt_send_term_exchange(qpair, NULL, atio, 1, 0); 52948c2ecf20Sopenharmony_ci return 0; 52958c2ecf20Sopenharmony_ci } 52968c2ecf20Sopenharmony_ci /* Sending marker isn't necessary, since we called from ISR */ 52978c2ecf20Sopenharmony_ci 52988c2ecf20Sopenharmony_ci pkt = (request_t *)__qla2x00_alloc_iocbs(qpair, NULL); 52998c2ecf20Sopenharmony_ci if (!pkt) { 53008c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3063, 53018c2ecf20Sopenharmony_ci "qla_target(%d): %s failed: unable to allocate " 53028c2ecf20Sopenharmony_ci "request packet", vha->vp_idx, __func__); 53038c2ecf20Sopenharmony_ci return -ENOMEM; 53048c2ecf20Sopenharmony_ci } 53058c2ecf20Sopenharmony_ci 53068c2ecf20Sopenharmony_ci qpair->tgt_counters.num_q_full_sent++; 53078c2ecf20Sopenharmony_ci pkt->entry_count = 1; 53088c2ecf20Sopenharmony_ci pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; 53098c2ecf20Sopenharmony_ci 53108c2ecf20Sopenharmony_ci ctio24 = (struct ctio7_to_24xx *)pkt; 53118c2ecf20Sopenharmony_ci ctio24->entry_type = CTIO_TYPE7; 53128c2ecf20Sopenharmony_ci ctio24->nport_handle = cpu_to_le16(sess->loop_id); 53138c2ecf20Sopenharmony_ci ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); 53148c2ecf20Sopenharmony_ci ctio24->vp_index = vha->vp_idx; 53158c2ecf20Sopenharmony_ci ctio24->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); 53168c2ecf20Sopenharmony_ci ctio24->exchange_addr = atio->u.isp24.exchange_addr; 53178c2ecf20Sopenharmony_ci temp = (atio->u.isp24.attr << 9) | 53188c2ecf20Sopenharmony_ci CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS | 53198c2ecf20Sopenharmony_ci CTIO7_FLAGS_DONT_RET_CTIO; 53208c2ecf20Sopenharmony_ci ctio24->u.status1.flags = cpu_to_le16(temp); 53218c2ecf20Sopenharmony_ci /* 53228c2ecf20Sopenharmony_ci * CTIO from fw w/o se_cmd doesn't provide enough info to retry it, 53238c2ecf20Sopenharmony_ci * if the explicit conformation is used. 53248c2ecf20Sopenharmony_ci */ 53258c2ecf20Sopenharmony_ci ctio24->u.status1.ox_id = 53268c2ecf20Sopenharmony_ci cpu_to_le16(be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id)); 53278c2ecf20Sopenharmony_ci ctio24->u.status1.scsi_status = cpu_to_le16(status); 53288c2ecf20Sopenharmony_ci 53298c2ecf20Sopenharmony_ci ctio24->u.status1.residual = cpu_to_le32(get_datalen_for_atio(atio)); 53308c2ecf20Sopenharmony_ci 53318c2ecf20Sopenharmony_ci if (ctio24->u.status1.residual != 0) 53328c2ecf20Sopenharmony_ci ctio24->u.status1.scsi_status |= cpu_to_le16(SS_RESIDUAL_UNDER); 53338c2ecf20Sopenharmony_ci 53348c2ecf20Sopenharmony_ci /* Memory Barrier */ 53358c2ecf20Sopenharmony_ci wmb(); 53368c2ecf20Sopenharmony_ci if (qpair->reqq_start_iocbs) 53378c2ecf20Sopenharmony_ci qpair->reqq_start_iocbs(qpair); 53388c2ecf20Sopenharmony_ci else 53398c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, qpair->req); 53408c2ecf20Sopenharmony_ci return 0; 53418c2ecf20Sopenharmony_ci} 53428c2ecf20Sopenharmony_ci 53438c2ecf20Sopenharmony_ci/* 53448c2ecf20Sopenharmony_ci * This routine is used to allocate a command for either a QFull condition 53458c2ecf20Sopenharmony_ci * (ie reply SAM_STAT_BUSY) or to terminate an exchange that did not go 53468c2ecf20Sopenharmony_ci * out previously. 53478c2ecf20Sopenharmony_ci */ 53488c2ecf20Sopenharmony_cistatic void 53498c2ecf20Sopenharmony_ciqlt_alloc_qfull_cmd(struct scsi_qla_host *vha, 53508c2ecf20Sopenharmony_ci struct atio_from_isp *atio, uint16_t status, int qfull) 53518c2ecf20Sopenharmony_ci{ 53528c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 53538c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 53548c2ecf20Sopenharmony_ci struct fc_port *sess; 53558c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd; 53568c2ecf20Sopenharmony_ci unsigned long flags; 53578c2ecf20Sopenharmony_ci 53588c2ecf20Sopenharmony_ci if (unlikely(tgt->tgt_stop)) { 53598c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x300a, 53608c2ecf20Sopenharmony_ci "New command while device %p is shutting down\n", tgt); 53618c2ecf20Sopenharmony_ci return; 53628c2ecf20Sopenharmony_ci } 53638c2ecf20Sopenharmony_ci 53648c2ecf20Sopenharmony_ci if ((vha->hw->tgt.num_qfull_cmds_alloc + 1) > MAX_QFULL_CMDS_ALLOC) { 53658c2ecf20Sopenharmony_ci vha->hw->tgt.num_qfull_cmds_dropped++; 53668c2ecf20Sopenharmony_ci if (vha->hw->tgt.num_qfull_cmds_dropped > 53678c2ecf20Sopenharmony_ci vha->qla_stats.stat_max_qfull_cmds_dropped) 53688c2ecf20Sopenharmony_ci vha->qla_stats.stat_max_qfull_cmds_dropped = 53698c2ecf20Sopenharmony_ci vha->hw->tgt.num_qfull_cmds_dropped; 53708c2ecf20Sopenharmony_ci 53718c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3068, 53728c2ecf20Sopenharmony_ci "qla_target(%d): %s: QFull CMD dropped[%d]\n", 53738c2ecf20Sopenharmony_ci vha->vp_idx, __func__, 53748c2ecf20Sopenharmony_ci vha->hw->tgt.num_qfull_cmds_dropped); 53758c2ecf20Sopenharmony_ci 53768c2ecf20Sopenharmony_ci qlt_chk_exch_leak_thresh_hold(vha); 53778c2ecf20Sopenharmony_ci return; 53788c2ecf20Sopenharmony_ci } 53798c2ecf20Sopenharmony_ci 53808c2ecf20Sopenharmony_ci sess = ha->tgt.tgt_ops->find_sess_by_s_id 53818c2ecf20Sopenharmony_ci (vha, atio->u.isp24.fcp_hdr.s_id); 53828c2ecf20Sopenharmony_ci if (!sess) 53838c2ecf20Sopenharmony_ci return; 53848c2ecf20Sopenharmony_ci 53858c2ecf20Sopenharmony_ci cmd = ha->tgt.tgt_ops->get_cmd(sess); 53868c2ecf20Sopenharmony_ci if (!cmd) { 53878c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3009, 53888c2ecf20Sopenharmony_ci "qla_target(%d): %s: Allocation of cmd failed\n", 53898c2ecf20Sopenharmony_ci vha->vp_idx, __func__); 53908c2ecf20Sopenharmony_ci 53918c2ecf20Sopenharmony_ci vha->hw->tgt.num_qfull_cmds_dropped++; 53928c2ecf20Sopenharmony_ci if (vha->hw->tgt.num_qfull_cmds_dropped > 53938c2ecf20Sopenharmony_ci vha->qla_stats.stat_max_qfull_cmds_dropped) 53948c2ecf20Sopenharmony_ci vha->qla_stats.stat_max_qfull_cmds_dropped = 53958c2ecf20Sopenharmony_ci vha->hw->tgt.num_qfull_cmds_dropped; 53968c2ecf20Sopenharmony_ci 53978c2ecf20Sopenharmony_ci qlt_chk_exch_leak_thresh_hold(vha); 53988c2ecf20Sopenharmony_ci return; 53998c2ecf20Sopenharmony_ci } 54008c2ecf20Sopenharmony_ci 54018c2ecf20Sopenharmony_ci qlt_incr_num_pend_cmds(vha); 54028c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cmd->cmd_list); 54038c2ecf20Sopenharmony_ci memcpy(&cmd->atio, atio, sizeof(*atio)); 54048c2ecf20Sopenharmony_ci 54058c2ecf20Sopenharmony_ci cmd->tgt = vha->vha_tgt.qla_tgt; 54068c2ecf20Sopenharmony_ci cmd->vha = vha; 54078c2ecf20Sopenharmony_ci cmd->reset_count = ha->base_qpair->chip_reset; 54088c2ecf20Sopenharmony_ci cmd->q_full = 1; 54098c2ecf20Sopenharmony_ci cmd->qpair = ha->base_qpair; 54108c2ecf20Sopenharmony_ci 54118c2ecf20Sopenharmony_ci if (qfull) { 54128c2ecf20Sopenharmony_ci cmd->q_full = 1; 54138c2ecf20Sopenharmony_ci /* NOTE: borrowing the state field to carry the status */ 54148c2ecf20Sopenharmony_ci cmd->state = status; 54158c2ecf20Sopenharmony_ci } else 54168c2ecf20Sopenharmony_ci cmd->term_exchg = 1; 54178c2ecf20Sopenharmony_ci 54188c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); 54198c2ecf20Sopenharmony_ci list_add_tail(&cmd->cmd_list, &vha->hw->tgt.q_full_list); 54208c2ecf20Sopenharmony_ci 54218c2ecf20Sopenharmony_ci vha->hw->tgt.num_qfull_cmds_alloc++; 54228c2ecf20Sopenharmony_ci if (vha->hw->tgt.num_qfull_cmds_alloc > 54238c2ecf20Sopenharmony_ci vha->qla_stats.stat_max_qfull_cmds_alloc) 54248c2ecf20Sopenharmony_ci vha->qla_stats.stat_max_qfull_cmds_alloc = 54258c2ecf20Sopenharmony_ci vha->hw->tgt.num_qfull_cmds_alloc; 54268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); 54278c2ecf20Sopenharmony_ci} 54288c2ecf20Sopenharmony_ci 54298c2ecf20Sopenharmony_ciint 54308c2ecf20Sopenharmony_ciqlt_free_qfull_cmds(struct qla_qpair *qpair) 54318c2ecf20Sopenharmony_ci{ 54328c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = qpair->vha; 54338c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 54348c2ecf20Sopenharmony_ci unsigned long flags; 54358c2ecf20Sopenharmony_ci struct qla_tgt_cmd *cmd, *tcmd; 54368c2ecf20Sopenharmony_ci struct list_head free_list, q_full_list; 54378c2ecf20Sopenharmony_ci int rc = 0; 54388c2ecf20Sopenharmony_ci 54398c2ecf20Sopenharmony_ci if (list_empty(&ha->tgt.q_full_list)) 54408c2ecf20Sopenharmony_ci return 0; 54418c2ecf20Sopenharmony_ci 54428c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&free_list); 54438c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&q_full_list); 54448c2ecf20Sopenharmony_ci 54458c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); 54468c2ecf20Sopenharmony_ci if (list_empty(&ha->tgt.q_full_list)) { 54478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); 54488c2ecf20Sopenharmony_ci return 0; 54498c2ecf20Sopenharmony_ci } 54508c2ecf20Sopenharmony_ci 54518c2ecf20Sopenharmony_ci list_splice_init(&vha->hw->tgt.q_full_list, &q_full_list); 54528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); 54538c2ecf20Sopenharmony_ci 54548c2ecf20Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 54558c2ecf20Sopenharmony_ci list_for_each_entry_safe(cmd, tcmd, &q_full_list, cmd_list) { 54568c2ecf20Sopenharmony_ci if (cmd->q_full) 54578c2ecf20Sopenharmony_ci /* cmd->state is a borrowed field to hold status */ 54588c2ecf20Sopenharmony_ci rc = __qlt_send_busy(qpair, &cmd->atio, cmd->state); 54598c2ecf20Sopenharmony_ci else if (cmd->term_exchg) 54608c2ecf20Sopenharmony_ci rc = __qlt_send_term_exchange(qpair, NULL, &cmd->atio); 54618c2ecf20Sopenharmony_ci 54628c2ecf20Sopenharmony_ci if (rc == -ENOMEM) 54638c2ecf20Sopenharmony_ci break; 54648c2ecf20Sopenharmony_ci 54658c2ecf20Sopenharmony_ci if (cmd->q_full) 54668c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3006, 54678c2ecf20Sopenharmony_ci "%s: busy sent for ox_id[%04x]\n", __func__, 54688c2ecf20Sopenharmony_ci be16_to_cpu(cmd->atio.u.isp24.fcp_hdr.ox_id)); 54698c2ecf20Sopenharmony_ci else if (cmd->term_exchg) 54708c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3007, 54718c2ecf20Sopenharmony_ci "%s: Term exchg sent for ox_id[%04x]\n", __func__, 54728c2ecf20Sopenharmony_ci be16_to_cpu(cmd->atio.u.isp24.fcp_hdr.ox_id)); 54738c2ecf20Sopenharmony_ci else 54748c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3008, 54758c2ecf20Sopenharmony_ci "%s: Unexpected cmd in QFull list %p\n", __func__, 54768c2ecf20Sopenharmony_ci cmd); 54778c2ecf20Sopenharmony_ci 54788c2ecf20Sopenharmony_ci list_del(&cmd->cmd_list); 54798c2ecf20Sopenharmony_ci list_add_tail(&cmd->cmd_list, &free_list); 54808c2ecf20Sopenharmony_ci 54818c2ecf20Sopenharmony_ci /* piggy back on hardware_lock for protection */ 54828c2ecf20Sopenharmony_ci vha->hw->tgt.num_qfull_cmds_alloc--; 54838c2ecf20Sopenharmony_ci } 54848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 54858c2ecf20Sopenharmony_ci 54868c2ecf20Sopenharmony_ci cmd = NULL; 54878c2ecf20Sopenharmony_ci 54888c2ecf20Sopenharmony_ci list_for_each_entry_safe(cmd, tcmd, &free_list, cmd_list) { 54898c2ecf20Sopenharmony_ci list_del(&cmd->cmd_list); 54908c2ecf20Sopenharmony_ci /* This cmd was never sent to TCM. There is no need 54918c2ecf20Sopenharmony_ci * to schedule free or call free_cmd 54928c2ecf20Sopenharmony_ci */ 54938c2ecf20Sopenharmony_ci qlt_free_cmd(cmd); 54948c2ecf20Sopenharmony_ci } 54958c2ecf20Sopenharmony_ci 54968c2ecf20Sopenharmony_ci if (!list_empty(&q_full_list)) { 54978c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); 54988c2ecf20Sopenharmony_ci list_splice(&q_full_list, &vha->hw->tgt.q_full_list); 54998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); 55008c2ecf20Sopenharmony_ci } 55018c2ecf20Sopenharmony_ci 55028c2ecf20Sopenharmony_ci return rc; 55038c2ecf20Sopenharmony_ci} 55048c2ecf20Sopenharmony_ci 55058c2ecf20Sopenharmony_cistatic void 55068c2ecf20Sopenharmony_ciqlt_send_busy(struct qla_qpair *qpair, struct atio_from_isp *atio, 55078c2ecf20Sopenharmony_ci uint16_t status) 55088c2ecf20Sopenharmony_ci{ 55098c2ecf20Sopenharmony_ci int rc = 0; 55108c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = qpair->vha; 55118c2ecf20Sopenharmony_ci 55128c2ecf20Sopenharmony_ci rc = __qlt_send_busy(qpair, atio, status); 55138c2ecf20Sopenharmony_ci if (rc == -ENOMEM) 55148c2ecf20Sopenharmony_ci qlt_alloc_qfull_cmd(vha, atio, status, 1); 55158c2ecf20Sopenharmony_ci} 55168c2ecf20Sopenharmony_ci 55178c2ecf20Sopenharmony_cistatic int 55188c2ecf20Sopenharmony_ciqlt_chk_qfull_thresh_hold(struct scsi_qla_host *vha, struct qla_qpair *qpair, 55198c2ecf20Sopenharmony_ci struct atio_from_isp *atio, uint8_t ha_locked) 55208c2ecf20Sopenharmony_ci{ 55218c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 55228c2ecf20Sopenharmony_ci unsigned long flags; 55238c2ecf20Sopenharmony_ci 55248c2ecf20Sopenharmony_ci if (ha->tgt.num_pend_cmds < Q_FULL_THRESH_HOLD(ha)) 55258c2ecf20Sopenharmony_ci return 0; 55268c2ecf20Sopenharmony_ci 55278c2ecf20Sopenharmony_ci if (!ha_locked) 55288c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 55298c2ecf20Sopenharmony_ci qlt_send_busy(qpair, atio, qla_sam_status); 55308c2ecf20Sopenharmony_ci if (!ha_locked) 55318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 55328c2ecf20Sopenharmony_ci 55338c2ecf20Sopenharmony_ci return 1; 55348c2ecf20Sopenharmony_ci} 55358c2ecf20Sopenharmony_ci 55368c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 55378c2ecf20Sopenharmony_ci/* called via callback from qla2xxx */ 55388c2ecf20Sopenharmony_cistatic void qlt_24xx_atio_pkt(struct scsi_qla_host *vha, 55398c2ecf20Sopenharmony_ci struct atio_from_isp *atio, uint8_t ha_locked) 55408c2ecf20Sopenharmony_ci{ 55418c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 55428c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 55438c2ecf20Sopenharmony_ci int rc; 55448c2ecf20Sopenharmony_ci unsigned long flags = 0; 55458c2ecf20Sopenharmony_ci 55468c2ecf20Sopenharmony_ci if (unlikely(tgt == NULL)) { 55478c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0x3064, 55488c2ecf20Sopenharmony_ci "ATIO pkt, but no tgt (ha %p)", ha); 55498c2ecf20Sopenharmony_ci return; 55508c2ecf20Sopenharmony_ci } 55518c2ecf20Sopenharmony_ci /* 55528c2ecf20Sopenharmony_ci * In tgt_stop mode we also should allow all requests to pass. 55538c2ecf20Sopenharmony_ci * Otherwise, some commands can stuck. 55548c2ecf20Sopenharmony_ci */ 55558c2ecf20Sopenharmony_ci 55568c2ecf20Sopenharmony_ci tgt->atio_irq_cmd_count++; 55578c2ecf20Sopenharmony_ci 55588c2ecf20Sopenharmony_ci switch (atio->u.raw.entry_type) { 55598c2ecf20Sopenharmony_ci case ATIO_TYPE7: 55608c2ecf20Sopenharmony_ci if (unlikely(atio->u.isp24.exchange_addr == 55618c2ecf20Sopenharmony_ci cpu_to_le32(ATIO_EXCHANGE_ADDRESS_UNKNOWN))) { 55628c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3065, 55638c2ecf20Sopenharmony_ci "qla_target(%d): ATIO_TYPE7 " 55648c2ecf20Sopenharmony_ci "received with UNKNOWN exchange address, " 55658c2ecf20Sopenharmony_ci "sending QUEUE_FULL\n", vha->vp_idx); 55668c2ecf20Sopenharmony_ci if (!ha_locked) 55678c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 55688c2ecf20Sopenharmony_ci qlt_send_busy(ha->base_qpair, atio, qla_sam_status); 55698c2ecf20Sopenharmony_ci if (!ha_locked) 55708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, 55718c2ecf20Sopenharmony_ci flags); 55728c2ecf20Sopenharmony_ci break; 55738c2ecf20Sopenharmony_ci } 55748c2ecf20Sopenharmony_ci 55758c2ecf20Sopenharmony_ci if (likely(atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0)) { 55768c2ecf20Sopenharmony_ci rc = qlt_chk_qfull_thresh_hold(vha, ha->base_qpair, 55778c2ecf20Sopenharmony_ci atio, ha_locked); 55788c2ecf20Sopenharmony_ci if (rc != 0) { 55798c2ecf20Sopenharmony_ci tgt->atio_irq_cmd_count--; 55808c2ecf20Sopenharmony_ci return; 55818c2ecf20Sopenharmony_ci } 55828c2ecf20Sopenharmony_ci rc = qlt_handle_cmd_for_atio(vha, atio); 55838c2ecf20Sopenharmony_ci } else { 55848c2ecf20Sopenharmony_ci rc = qlt_handle_task_mgmt(vha, atio); 55858c2ecf20Sopenharmony_ci } 55868c2ecf20Sopenharmony_ci if (unlikely(rc != 0)) { 55878c2ecf20Sopenharmony_ci if (!ha_locked) 55888c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 55898c2ecf20Sopenharmony_ci switch (rc) { 55908c2ecf20Sopenharmony_ci case -ENODEV: 55918c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe05f, 55928c2ecf20Sopenharmony_ci "qla_target: Unable to send command to target\n"); 55938c2ecf20Sopenharmony_ci break; 55948c2ecf20Sopenharmony_ci case -EBADF: 55958c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe05f, 55968c2ecf20Sopenharmony_ci "qla_target: Unable to send command to target, sending TERM EXCHANGE for rsp\n"); 55978c2ecf20Sopenharmony_ci qlt_send_term_exchange(ha->base_qpair, NULL, 55988c2ecf20Sopenharmony_ci atio, 1, 0); 55998c2ecf20Sopenharmony_ci break; 56008c2ecf20Sopenharmony_ci case -EBUSY: 56018c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe060, 56028c2ecf20Sopenharmony_ci "qla_target(%d): Unable to send command to target, sending BUSY status\n", 56038c2ecf20Sopenharmony_ci vha->vp_idx); 56048c2ecf20Sopenharmony_ci qlt_send_busy(ha->base_qpair, atio, 56058c2ecf20Sopenharmony_ci tc_sam_status); 56068c2ecf20Sopenharmony_ci break; 56078c2ecf20Sopenharmony_ci default: 56088c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe060, 56098c2ecf20Sopenharmony_ci "qla_target(%d): Unable to send command to target, sending BUSY status\n", 56108c2ecf20Sopenharmony_ci vha->vp_idx); 56118c2ecf20Sopenharmony_ci qlt_send_busy(ha->base_qpair, atio, 56128c2ecf20Sopenharmony_ci qla_sam_status); 56138c2ecf20Sopenharmony_ci break; 56148c2ecf20Sopenharmony_ci } 56158c2ecf20Sopenharmony_ci if (!ha_locked) 56168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, 56178c2ecf20Sopenharmony_ci flags); 56188c2ecf20Sopenharmony_ci } 56198c2ecf20Sopenharmony_ci break; 56208c2ecf20Sopenharmony_ci 56218c2ecf20Sopenharmony_ci case IMMED_NOTIFY_TYPE: 56228c2ecf20Sopenharmony_ci { 56238c2ecf20Sopenharmony_ci if (unlikely(atio->u.isp2x.entry_status != 0)) { 56248c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe05b, 56258c2ecf20Sopenharmony_ci "qla_target(%d): Received ATIO packet %x " 56268c2ecf20Sopenharmony_ci "with error status %x\n", vha->vp_idx, 56278c2ecf20Sopenharmony_ci atio->u.raw.entry_type, 56288c2ecf20Sopenharmony_ci atio->u.isp2x.entry_status); 56298c2ecf20Sopenharmony_ci break; 56308c2ecf20Sopenharmony_ci } 56318c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe02e, "%s", "IMMED_NOTIFY ATIO"); 56328c2ecf20Sopenharmony_ci 56338c2ecf20Sopenharmony_ci if (!ha_locked) 56348c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 56358c2ecf20Sopenharmony_ci qlt_handle_imm_notify(vha, (struct imm_ntfy_from_isp *)atio); 56368c2ecf20Sopenharmony_ci if (!ha_locked) 56378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 56388c2ecf20Sopenharmony_ci break; 56398c2ecf20Sopenharmony_ci } 56408c2ecf20Sopenharmony_ci 56418c2ecf20Sopenharmony_ci default: 56428c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe05c, 56438c2ecf20Sopenharmony_ci "qla_target(%d): Received unknown ATIO atio " 56448c2ecf20Sopenharmony_ci "type %x\n", vha->vp_idx, atio->u.raw.entry_type); 56458c2ecf20Sopenharmony_ci break; 56468c2ecf20Sopenharmony_ci } 56478c2ecf20Sopenharmony_ci 56488c2ecf20Sopenharmony_ci tgt->atio_irq_cmd_count--; 56498c2ecf20Sopenharmony_ci} 56508c2ecf20Sopenharmony_ci 56518c2ecf20Sopenharmony_ci/* 56528c2ecf20Sopenharmony_ci * qpair lock is assume to be held 56538c2ecf20Sopenharmony_ci * rc = 0 : send terminate & abts respond 56548c2ecf20Sopenharmony_ci * rc != 0: do not send term & abts respond 56558c2ecf20Sopenharmony_ci */ 56568c2ecf20Sopenharmony_cistatic int qlt_chk_unresolv_exchg(struct scsi_qla_host *vha, 56578c2ecf20Sopenharmony_ci struct qla_qpair *qpair, struct abts_resp_from_24xx_fw *entry) 56588c2ecf20Sopenharmony_ci{ 56598c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 56608c2ecf20Sopenharmony_ci int rc = 0; 56618c2ecf20Sopenharmony_ci 56628c2ecf20Sopenharmony_ci /* 56638c2ecf20Sopenharmony_ci * Detect unresolved exchange. If the same ABTS is unable 56648c2ecf20Sopenharmony_ci * to terminate an existing command and the same ABTS loops 56658c2ecf20Sopenharmony_ci * between FW & Driver, then force FW dump. Under 1 jiff, 56668c2ecf20Sopenharmony_ci * we should see multiple loops. 56678c2ecf20Sopenharmony_ci */ 56688c2ecf20Sopenharmony_ci if (qpair->retry_term_exchg_addr == entry->exchange_addr_to_abort && 56698c2ecf20Sopenharmony_ci qpair->retry_term_jiff == jiffies) { 56708c2ecf20Sopenharmony_ci /* found existing exchange */ 56718c2ecf20Sopenharmony_ci qpair->retry_term_cnt++; 56728c2ecf20Sopenharmony_ci if (qpair->retry_term_cnt >= 5) { 56738c2ecf20Sopenharmony_ci rc = -EIO; 56748c2ecf20Sopenharmony_ci qpair->retry_term_cnt = 0; 56758c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xffff, 56768c2ecf20Sopenharmony_ci "Unable to send ABTS Respond. Dumping firmware.\n"); 56778c2ecf20Sopenharmony_ci ql_dump_buffer(ql_dbg_tgt_mgt + ql_dbg_buffer, 56788c2ecf20Sopenharmony_ci vha, 0xffff, (uint8_t *)entry, sizeof(*entry)); 56798c2ecf20Sopenharmony_ci 56808c2ecf20Sopenharmony_ci if (qpair == ha->base_qpair) 56818c2ecf20Sopenharmony_ci ha->isp_ops->fw_dump(vha); 56828c2ecf20Sopenharmony_ci else 56838c2ecf20Sopenharmony_ci qla2xxx_dump_fw(vha); 56848c2ecf20Sopenharmony_ci 56858c2ecf20Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 56868c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(vha); 56878c2ecf20Sopenharmony_ci } 56888c2ecf20Sopenharmony_ci } else if (qpair->retry_term_jiff != jiffies) { 56898c2ecf20Sopenharmony_ci qpair->retry_term_exchg_addr = entry->exchange_addr_to_abort; 56908c2ecf20Sopenharmony_ci qpair->retry_term_cnt = 0; 56918c2ecf20Sopenharmony_ci qpair->retry_term_jiff = jiffies; 56928c2ecf20Sopenharmony_ci } 56938c2ecf20Sopenharmony_ci 56948c2ecf20Sopenharmony_ci return rc; 56958c2ecf20Sopenharmony_ci} 56968c2ecf20Sopenharmony_ci 56978c2ecf20Sopenharmony_ci 56988c2ecf20Sopenharmony_cistatic void qlt_handle_abts_completion(struct scsi_qla_host *vha, 56998c2ecf20Sopenharmony_ci struct rsp_que *rsp, response_t *pkt) 57008c2ecf20Sopenharmony_ci{ 57018c2ecf20Sopenharmony_ci struct abts_resp_from_24xx_fw *entry = 57028c2ecf20Sopenharmony_ci (struct abts_resp_from_24xx_fw *)pkt; 57038c2ecf20Sopenharmony_ci u32 h = pkt->handle & ~QLA_TGT_HANDLE_MASK; 57048c2ecf20Sopenharmony_ci struct qla_tgt_mgmt_cmd *mcmd; 57058c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 57068c2ecf20Sopenharmony_ci 57078c2ecf20Sopenharmony_ci mcmd = qlt_ctio_to_cmd(vha, rsp, pkt->handle, pkt); 57088c2ecf20Sopenharmony_ci if (mcmd == NULL && h != QLA_TGT_SKIP_HANDLE) { 57098c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0xe064, 57108c2ecf20Sopenharmony_ci "qla_target(%d): ABTS Comp without mcmd\n", 57118c2ecf20Sopenharmony_ci vha->vp_idx); 57128c2ecf20Sopenharmony_ci return; 57138c2ecf20Sopenharmony_ci } 57148c2ecf20Sopenharmony_ci 57158c2ecf20Sopenharmony_ci if (mcmd) 57168c2ecf20Sopenharmony_ci vha = mcmd->vha; 57178c2ecf20Sopenharmony_ci vha->vha_tgt.qla_tgt->abts_resp_expected--; 57188c2ecf20Sopenharmony_ci 57198c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe038, 57208c2ecf20Sopenharmony_ci "ABTS_RESP_24XX: compl_status %x\n", 57218c2ecf20Sopenharmony_ci entry->compl_status); 57228c2ecf20Sopenharmony_ci 57238c2ecf20Sopenharmony_ci if (le16_to_cpu(entry->compl_status) != ABTS_RESP_COMPL_SUCCESS) { 57248c2ecf20Sopenharmony_ci if (le32_to_cpu(entry->error_subcode1) == 0x1E && 57258c2ecf20Sopenharmony_ci le32_to_cpu(entry->error_subcode2) == 0) { 57268c2ecf20Sopenharmony_ci if (qlt_chk_unresolv_exchg(vha, rsp->qpair, entry)) { 57278c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->free_mcmd(mcmd); 57288c2ecf20Sopenharmony_ci return; 57298c2ecf20Sopenharmony_ci } 57308c2ecf20Sopenharmony_ci qlt_24xx_retry_term_exchange(vha, rsp->qpair, 57318c2ecf20Sopenharmony_ci pkt, mcmd); 57328c2ecf20Sopenharmony_ci } else { 57338c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe063, 57348c2ecf20Sopenharmony_ci "qla_target(%d): ABTS_RESP_24XX failed %x (subcode %x:%x)", 57358c2ecf20Sopenharmony_ci vha->vp_idx, entry->compl_status, 57368c2ecf20Sopenharmony_ci entry->error_subcode1, 57378c2ecf20Sopenharmony_ci entry->error_subcode2); 57388c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->free_mcmd(mcmd); 57398c2ecf20Sopenharmony_ci } 57408c2ecf20Sopenharmony_ci } else if (mcmd) { 57418c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->free_mcmd(mcmd); 57428c2ecf20Sopenharmony_ci } 57438c2ecf20Sopenharmony_ci} 57448c2ecf20Sopenharmony_ci 57458c2ecf20Sopenharmony_ci/* ha->hardware_lock supposed to be held on entry */ 57468c2ecf20Sopenharmony_ci/* called via callback from qla2xxx */ 57478c2ecf20Sopenharmony_cistatic void qlt_response_pkt(struct scsi_qla_host *vha, 57488c2ecf20Sopenharmony_ci struct rsp_que *rsp, response_t *pkt) 57498c2ecf20Sopenharmony_ci{ 57508c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 57518c2ecf20Sopenharmony_ci 57528c2ecf20Sopenharmony_ci if (unlikely(tgt == NULL)) { 57538c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe05d, 57548c2ecf20Sopenharmony_ci "qla_target(%d): Response pkt %x received, but no tgt (ha %p)\n", 57558c2ecf20Sopenharmony_ci vha->vp_idx, pkt->entry_type, vha->hw); 57568c2ecf20Sopenharmony_ci return; 57578c2ecf20Sopenharmony_ci } 57588c2ecf20Sopenharmony_ci 57598c2ecf20Sopenharmony_ci /* 57608c2ecf20Sopenharmony_ci * In tgt_stop mode we also should allow all requests to pass. 57618c2ecf20Sopenharmony_ci * Otherwise, some commands can stuck. 57628c2ecf20Sopenharmony_ci */ 57638c2ecf20Sopenharmony_ci 57648c2ecf20Sopenharmony_ci switch (pkt->entry_type) { 57658c2ecf20Sopenharmony_ci case CTIO_CRC2: 57668c2ecf20Sopenharmony_ci case CTIO_TYPE7: 57678c2ecf20Sopenharmony_ci { 57688c2ecf20Sopenharmony_ci struct ctio7_from_24xx *entry = (struct ctio7_from_24xx *)pkt; 57698c2ecf20Sopenharmony_ci 57708c2ecf20Sopenharmony_ci qlt_do_ctio_completion(vha, rsp, entry->handle, 57718c2ecf20Sopenharmony_ci le16_to_cpu(entry->status)|(pkt->entry_status << 16), 57728c2ecf20Sopenharmony_ci entry); 57738c2ecf20Sopenharmony_ci break; 57748c2ecf20Sopenharmony_ci } 57758c2ecf20Sopenharmony_ci 57768c2ecf20Sopenharmony_ci case ACCEPT_TGT_IO_TYPE: 57778c2ecf20Sopenharmony_ci { 57788c2ecf20Sopenharmony_ci struct atio_from_isp *atio = (struct atio_from_isp *)pkt; 57798c2ecf20Sopenharmony_ci int rc; 57808c2ecf20Sopenharmony_ci 57818c2ecf20Sopenharmony_ci if (atio->u.isp2x.status != 57828c2ecf20Sopenharmony_ci cpu_to_le16(ATIO_CDB_VALID)) { 57838c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe05e, 57848c2ecf20Sopenharmony_ci "qla_target(%d): ATIO with error " 57858c2ecf20Sopenharmony_ci "status %x received\n", vha->vp_idx, 57868c2ecf20Sopenharmony_ci le16_to_cpu(atio->u.isp2x.status)); 57878c2ecf20Sopenharmony_ci break; 57888c2ecf20Sopenharmony_ci } 57898c2ecf20Sopenharmony_ci 57908c2ecf20Sopenharmony_ci rc = qlt_chk_qfull_thresh_hold(vha, rsp->qpair, atio, 1); 57918c2ecf20Sopenharmony_ci if (rc != 0) 57928c2ecf20Sopenharmony_ci return; 57938c2ecf20Sopenharmony_ci 57948c2ecf20Sopenharmony_ci rc = qlt_handle_cmd_for_atio(vha, atio); 57958c2ecf20Sopenharmony_ci if (unlikely(rc != 0)) { 57968c2ecf20Sopenharmony_ci switch (rc) { 57978c2ecf20Sopenharmony_ci case -ENODEV: 57988c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe05f, 57998c2ecf20Sopenharmony_ci "qla_target: Unable to send command to target\n"); 58008c2ecf20Sopenharmony_ci break; 58018c2ecf20Sopenharmony_ci case -EBADF: 58028c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe05f, 58038c2ecf20Sopenharmony_ci "qla_target: Unable to send command to target, sending TERM EXCHANGE for rsp\n"); 58048c2ecf20Sopenharmony_ci qlt_send_term_exchange(rsp->qpair, NULL, 58058c2ecf20Sopenharmony_ci atio, 1, 0); 58068c2ecf20Sopenharmony_ci break; 58078c2ecf20Sopenharmony_ci case -EBUSY: 58088c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe060, 58098c2ecf20Sopenharmony_ci "qla_target(%d): Unable to send command to target, sending BUSY status\n", 58108c2ecf20Sopenharmony_ci vha->vp_idx); 58118c2ecf20Sopenharmony_ci qlt_send_busy(rsp->qpair, atio, 58128c2ecf20Sopenharmony_ci tc_sam_status); 58138c2ecf20Sopenharmony_ci break; 58148c2ecf20Sopenharmony_ci default: 58158c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe060, 58168c2ecf20Sopenharmony_ci "qla_target(%d): Unable to send command to target, sending BUSY status\n", 58178c2ecf20Sopenharmony_ci vha->vp_idx); 58188c2ecf20Sopenharmony_ci qlt_send_busy(rsp->qpair, atio, 58198c2ecf20Sopenharmony_ci qla_sam_status); 58208c2ecf20Sopenharmony_ci break; 58218c2ecf20Sopenharmony_ci } 58228c2ecf20Sopenharmony_ci } 58238c2ecf20Sopenharmony_ci } 58248c2ecf20Sopenharmony_ci break; 58258c2ecf20Sopenharmony_ci 58268c2ecf20Sopenharmony_ci case CONTINUE_TGT_IO_TYPE: 58278c2ecf20Sopenharmony_ci { 58288c2ecf20Sopenharmony_ci struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; 58298c2ecf20Sopenharmony_ci 58308c2ecf20Sopenharmony_ci qlt_do_ctio_completion(vha, rsp, entry->handle, 58318c2ecf20Sopenharmony_ci le16_to_cpu(entry->status)|(pkt->entry_status << 16), 58328c2ecf20Sopenharmony_ci entry); 58338c2ecf20Sopenharmony_ci break; 58348c2ecf20Sopenharmony_ci } 58358c2ecf20Sopenharmony_ci 58368c2ecf20Sopenharmony_ci case CTIO_A64_TYPE: 58378c2ecf20Sopenharmony_ci { 58388c2ecf20Sopenharmony_ci struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; 58398c2ecf20Sopenharmony_ci 58408c2ecf20Sopenharmony_ci qlt_do_ctio_completion(vha, rsp, entry->handle, 58418c2ecf20Sopenharmony_ci le16_to_cpu(entry->status)|(pkt->entry_status << 16), 58428c2ecf20Sopenharmony_ci entry); 58438c2ecf20Sopenharmony_ci break; 58448c2ecf20Sopenharmony_ci } 58458c2ecf20Sopenharmony_ci 58468c2ecf20Sopenharmony_ci case IMMED_NOTIFY_TYPE: 58478c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe035, "%s", "IMMED_NOTIFY\n"); 58488c2ecf20Sopenharmony_ci qlt_handle_imm_notify(vha, (struct imm_ntfy_from_isp *)pkt); 58498c2ecf20Sopenharmony_ci break; 58508c2ecf20Sopenharmony_ci 58518c2ecf20Sopenharmony_ci case NOTIFY_ACK_TYPE: 58528c2ecf20Sopenharmony_ci if (tgt->notify_ack_expected > 0) { 58538c2ecf20Sopenharmony_ci struct nack_to_isp *entry = (struct nack_to_isp *)pkt; 58548c2ecf20Sopenharmony_ci 58558c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe036, 58568c2ecf20Sopenharmony_ci "NOTIFY_ACK seq %08x status %x\n", 58578c2ecf20Sopenharmony_ci le16_to_cpu(entry->u.isp2x.seq_id), 58588c2ecf20Sopenharmony_ci le16_to_cpu(entry->u.isp2x.status)); 58598c2ecf20Sopenharmony_ci tgt->notify_ack_expected--; 58608c2ecf20Sopenharmony_ci if (entry->u.isp2x.status != 58618c2ecf20Sopenharmony_ci cpu_to_le16(NOTIFY_ACK_SUCCESS)) { 58628c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe061, 58638c2ecf20Sopenharmony_ci "qla_target(%d): NOTIFY_ACK " 58648c2ecf20Sopenharmony_ci "failed %x\n", vha->vp_idx, 58658c2ecf20Sopenharmony_ci le16_to_cpu(entry->u.isp2x.status)); 58668c2ecf20Sopenharmony_ci } 58678c2ecf20Sopenharmony_ci } else { 58688c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe062, 58698c2ecf20Sopenharmony_ci "qla_target(%d): Unexpected NOTIFY_ACK received\n", 58708c2ecf20Sopenharmony_ci vha->vp_idx); 58718c2ecf20Sopenharmony_ci } 58728c2ecf20Sopenharmony_ci break; 58738c2ecf20Sopenharmony_ci 58748c2ecf20Sopenharmony_ci case ABTS_RECV_24XX: 58758c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe037, 58768c2ecf20Sopenharmony_ci "ABTS_RECV_24XX: instance %d\n", vha->vp_idx); 58778c2ecf20Sopenharmony_ci qlt_24xx_handle_abts(vha, (struct abts_recv_from_24xx *)pkt); 58788c2ecf20Sopenharmony_ci break; 58798c2ecf20Sopenharmony_ci 58808c2ecf20Sopenharmony_ci case ABTS_RESP_24XX: 58818c2ecf20Sopenharmony_ci if (tgt->abts_resp_expected > 0) { 58828c2ecf20Sopenharmony_ci qlt_handle_abts_completion(vha, rsp, pkt); 58838c2ecf20Sopenharmony_ci } else { 58848c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe064, 58858c2ecf20Sopenharmony_ci "qla_target(%d): Unexpected ABTS_RESP_24XX " 58868c2ecf20Sopenharmony_ci "received\n", vha->vp_idx); 58878c2ecf20Sopenharmony_ci } 58888c2ecf20Sopenharmony_ci break; 58898c2ecf20Sopenharmony_ci 58908c2ecf20Sopenharmony_ci default: 58918c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe065, 58928c2ecf20Sopenharmony_ci "qla_target(%d): Received unknown response pkt " 58938c2ecf20Sopenharmony_ci "type %x\n", vha->vp_idx, pkt->entry_type); 58948c2ecf20Sopenharmony_ci break; 58958c2ecf20Sopenharmony_ci } 58968c2ecf20Sopenharmony_ci 58978c2ecf20Sopenharmony_ci} 58988c2ecf20Sopenharmony_ci 58998c2ecf20Sopenharmony_ci/* 59008c2ecf20Sopenharmony_ci * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire 59018c2ecf20Sopenharmony_ci */ 59028c2ecf20Sopenharmony_civoid qlt_async_event(uint16_t code, struct scsi_qla_host *vha, 59038c2ecf20Sopenharmony_ci uint16_t *mailbox) 59048c2ecf20Sopenharmony_ci{ 59058c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 59068c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 59078c2ecf20Sopenharmony_ci int login_code; 59088c2ecf20Sopenharmony_ci 59098c2ecf20Sopenharmony_ci if (!tgt || tgt->tgt_stop || tgt->tgt_stopped) 59108c2ecf20Sopenharmony_ci return; 59118c2ecf20Sopenharmony_ci 59128c2ecf20Sopenharmony_ci if (((code == MBA_POINT_TO_POINT) || (code == MBA_CHG_IN_CONNECTION)) && 59138c2ecf20Sopenharmony_ci IS_QLA2100(ha)) 59148c2ecf20Sopenharmony_ci return; 59158c2ecf20Sopenharmony_ci /* 59168c2ecf20Sopenharmony_ci * In tgt_stop mode we also should allow all requests to pass. 59178c2ecf20Sopenharmony_ci * Otherwise, some commands can stuck. 59188c2ecf20Sopenharmony_ci */ 59198c2ecf20Sopenharmony_ci 59208c2ecf20Sopenharmony_ci 59218c2ecf20Sopenharmony_ci switch (code) { 59228c2ecf20Sopenharmony_ci case MBA_RESET: /* Reset */ 59238c2ecf20Sopenharmony_ci case MBA_SYSTEM_ERR: /* System Error */ 59248c2ecf20Sopenharmony_ci case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */ 59258c2ecf20Sopenharmony_ci case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */ 59268c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03a, 59278c2ecf20Sopenharmony_ci "qla_target(%d): System error async event %#x " 59288c2ecf20Sopenharmony_ci "occurred", vha->vp_idx, code); 59298c2ecf20Sopenharmony_ci break; 59308c2ecf20Sopenharmony_ci case MBA_WAKEUP_THRES: /* Request Queue Wake-up. */ 59318c2ecf20Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 59328c2ecf20Sopenharmony_ci break; 59338c2ecf20Sopenharmony_ci 59348c2ecf20Sopenharmony_ci case MBA_LOOP_UP: 59358c2ecf20Sopenharmony_ci { 59368c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03b, 59378c2ecf20Sopenharmony_ci "qla_target(%d): Async LOOP_UP occurred " 59388c2ecf20Sopenharmony_ci "(m[0]=%x, m[1]=%x, m[2]=%x, m[3]=%x)", vha->vp_idx, 59398c2ecf20Sopenharmony_ci mailbox[0], mailbox[1], mailbox[2], mailbox[3]); 59408c2ecf20Sopenharmony_ci if (tgt->link_reinit_iocb_pending) { 59418c2ecf20Sopenharmony_ci qlt_send_notify_ack(ha->base_qpair, 59428c2ecf20Sopenharmony_ci &tgt->link_reinit_iocb, 59438c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0); 59448c2ecf20Sopenharmony_ci tgt->link_reinit_iocb_pending = 0; 59458c2ecf20Sopenharmony_ci } 59468c2ecf20Sopenharmony_ci break; 59478c2ecf20Sopenharmony_ci } 59488c2ecf20Sopenharmony_ci 59498c2ecf20Sopenharmony_ci case MBA_LIP_OCCURRED: 59508c2ecf20Sopenharmony_ci case MBA_LOOP_DOWN: 59518c2ecf20Sopenharmony_ci case MBA_LIP_RESET: 59528c2ecf20Sopenharmony_ci case MBA_RSCN_UPDATE: 59538c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03c, 59548c2ecf20Sopenharmony_ci "qla_target(%d): Async event %#x occurred " 59558c2ecf20Sopenharmony_ci "(m[0]=%x, m[1]=%x, m[2]=%x, m[3]=%x)", vha->vp_idx, code, 59568c2ecf20Sopenharmony_ci mailbox[0], mailbox[1], mailbox[2], mailbox[3]); 59578c2ecf20Sopenharmony_ci break; 59588c2ecf20Sopenharmony_ci 59598c2ecf20Sopenharmony_ci case MBA_REJECTED_FCP_CMD: 59608c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf017, 59618c2ecf20Sopenharmony_ci "qla_target(%d): Async event LS_REJECT occurred (m[0]=%x, m[1]=%x, m[2]=%x, m[3]=%x)", 59628c2ecf20Sopenharmony_ci vha->vp_idx, 59638c2ecf20Sopenharmony_ci mailbox[0], mailbox[1], mailbox[2], mailbox[3]); 59648c2ecf20Sopenharmony_ci 59658c2ecf20Sopenharmony_ci if (mailbox[3] == 1) { 59668c2ecf20Sopenharmony_ci /* exchange starvation. */ 59678c2ecf20Sopenharmony_ci vha->hw->exch_starvation++; 59688c2ecf20Sopenharmony_ci if (vha->hw->exch_starvation > 5) { 59698c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd03a, 59708c2ecf20Sopenharmony_ci "Exchange starvation-. Resetting RISC\n"); 59718c2ecf20Sopenharmony_ci 59728c2ecf20Sopenharmony_ci vha->hw->exch_starvation = 0; 59738c2ecf20Sopenharmony_ci if (IS_P3P_TYPE(vha->hw)) 59748c2ecf20Sopenharmony_ci set_bit(FCOE_CTX_RESET_NEEDED, 59758c2ecf20Sopenharmony_ci &vha->dpc_flags); 59768c2ecf20Sopenharmony_ci else 59778c2ecf20Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, 59788c2ecf20Sopenharmony_ci &vha->dpc_flags); 59798c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(vha); 59808c2ecf20Sopenharmony_ci } 59818c2ecf20Sopenharmony_ci } 59828c2ecf20Sopenharmony_ci break; 59838c2ecf20Sopenharmony_ci 59848c2ecf20Sopenharmony_ci case MBA_PORT_UPDATE: 59858c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03d, 59868c2ecf20Sopenharmony_ci "qla_target(%d): Port update async event %#x " 59878c2ecf20Sopenharmony_ci "occurred: updating the ports database (m[0]=%x, m[1]=%x, " 59888c2ecf20Sopenharmony_ci "m[2]=%x, m[3]=%x)", vha->vp_idx, code, 59898c2ecf20Sopenharmony_ci mailbox[0], mailbox[1], mailbox[2], mailbox[3]); 59908c2ecf20Sopenharmony_ci 59918c2ecf20Sopenharmony_ci login_code = mailbox[2]; 59928c2ecf20Sopenharmony_ci if (login_code == 0x4) { 59938c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03e, 59948c2ecf20Sopenharmony_ci "Async MB 2: Got PLOGI Complete\n"); 59958c2ecf20Sopenharmony_ci vha->hw->exch_starvation = 0; 59968c2ecf20Sopenharmony_ci } else if (login_code == 0x7) 59978c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03f, 59988c2ecf20Sopenharmony_ci "Async MB 2: Port Logged Out\n"); 59998c2ecf20Sopenharmony_ci break; 60008c2ecf20Sopenharmony_ci default: 60018c2ecf20Sopenharmony_ci break; 60028c2ecf20Sopenharmony_ci } 60038c2ecf20Sopenharmony_ci 60048c2ecf20Sopenharmony_ci} 60058c2ecf20Sopenharmony_ci 60068c2ecf20Sopenharmony_cistatic fc_port_t *qlt_get_port_database(struct scsi_qla_host *vha, 60078c2ecf20Sopenharmony_ci uint16_t loop_id) 60088c2ecf20Sopenharmony_ci{ 60098c2ecf20Sopenharmony_ci fc_port_t *fcport, *tfcp, *del; 60108c2ecf20Sopenharmony_ci int rc; 60118c2ecf20Sopenharmony_ci unsigned long flags; 60128c2ecf20Sopenharmony_ci u8 newfcport = 0; 60138c2ecf20Sopenharmony_ci 60148c2ecf20Sopenharmony_ci fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); 60158c2ecf20Sopenharmony_ci if (!fcport) { 60168c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06f, 60178c2ecf20Sopenharmony_ci "qla_target(%d): Allocation of tmp FC port failed", 60188c2ecf20Sopenharmony_ci vha->vp_idx); 60198c2ecf20Sopenharmony_ci return NULL; 60208c2ecf20Sopenharmony_ci } 60218c2ecf20Sopenharmony_ci 60228c2ecf20Sopenharmony_ci fcport->loop_id = loop_id; 60238c2ecf20Sopenharmony_ci 60248c2ecf20Sopenharmony_ci rc = qla24xx_gpdb_wait(vha, fcport, 0); 60258c2ecf20Sopenharmony_ci if (rc != QLA_SUCCESS) { 60268c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf070, 60278c2ecf20Sopenharmony_ci "qla_target(%d): Failed to retrieve fcport " 60288c2ecf20Sopenharmony_ci "information -- get_port_database() returned %x " 60298c2ecf20Sopenharmony_ci "(loop_id=0x%04x)", vha->vp_idx, rc, loop_id); 60308c2ecf20Sopenharmony_ci kfree(fcport); 60318c2ecf20Sopenharmony_ci return NULL; 60328c2ecf20Sopenharmony_ci } 60338c2ecf20Sopenharmony_ci 60348c2ecf20Sopenharmony_ci del = NULL; 60358c2ecf20Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 60368c2ecf20Sopenharmony_ci tfcp = qla2x00_find_fcport_by_wwpn(vha, fcport->port_name, 1); 60378c2ecf20Sopenharmony_ci 60388c2ecf20Sopenharmony_ci if (tfcp) { 60398c2ecf20Sopenharmony_ci tfcp->d_id = fcport->d_id; 60408c2ecf20Sopenharmony_ci tfcp->port_type = fcport->port_type; 60418c2ecf20Sopenharmony_ci tfcp->supported_classes = fcport->supported_classes; 60428c2ecf20Sopenharmony_ci tfcp->flags |= fcport->flags; 60438c2ecf20Sopenharmony_ci tfcp->scan_state = QLA_FCPORT_FOUND; 60448c2ecf20Sopenharmony_ci 60458c2ecf20Sopenharmony_ci del = fcport; 60468c2ecf20Sopenharmony_ci fcport = tfcp; 60478c2ecf20Sopenharmony_ci } else { 60488c2ecf20Sopenharmony_ci if (vha->hw->current_topology == ISP_CFG_F) 60498c2ecf20Sopenharmony_ci fcport->flags |= FCF_FABRIC_DEVICE; 60508c2ecf20Sopenharmony_ci 60518c2ecf20Sopenharmony_ci list_add_tail(&fcport->list, &vha->vp_fcports); 60528c2ecf20Sopenharmony_ci if (!IS_SW_RESV_ADDR(fcport->d_id)) 60538c2ecf20Sopenharmony_ci vha->fcport_count++; 60548c2ecf20Sopenharmony_ci fcport->login_gen++; 60558c2ecf20Sopenharmony_ci qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_COMPLETE); 60568c2ecf20Sopenharmony_ci fcport->login_succ = 1; 60578c2ecf20Sopenharmony_ci newfcport = 1; 60588c2ecf20Sopenharmony_ci } 60598c2ecf20Sopenharmony_ci 60608c2ecf20Sopenharmony_ci fcport->deleted = 0; 60618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 60628c2ecf20Sopenharmony_ci 60638c2ecf20Sopenharmony_ci switch (vha->host->active_mode) { 60648c2ecf20Sopenharmony_ci case MODE_INITIATOR: 60658c2ecf20Sopenharmony_ci case MODE_DUAL: 60668c2ecf20Sopenharmony_ci if (newfcport) { 60678c2ecf20Sopenharmony_ci if (!IS_IIDMA_CAPABLE(vha->hw) || !vha->hw->flags.gpsc_supported) { 60688c2ecf20Sopenharmony_ci qla24xx_sched_upd_fcport(fcport); 60698c2ecf20Sopenharmony_ci } else { 60708c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ff, 60718c2ecf20Sopenharmony_ci "%s %d %8phC post gpsc fcp_cnt %d\n", 60728c2ecf20Sopenharmony_ci __func__, __LINE__, fcport->port_name, vha->fcport_count); 60738c2ecf20Sopenharmony_ci qla24xx_post_gpsc_work(vha, fcport); 60748c2ecf20Sopenharmony_ci } 60758c2ecf20Sopenharmony_ci } 60768c2ecf20Sopenharmony_ci break; 60778c2ecf20Sopenharmony_ci 60788c2ecf20Sopenharmony_ci case MODE_TARGET: 60798c2ecf20Sopenharmony_ci default: 60808c2ecf20Sopenharmony_ci break; 60818c2ecf20Sopenharmony_ci } 60828c2ecf20Sopenharmony_ci if (del) 60838c2ecf20Sopenharmony_ci qla2x00_free_fcport(del); 60848c2ecf20Sopenharmony_ci 60858c2ecf20Sopenharmony_ci return fcport; 60868c2ecf20Sopenharmony_ci} 60878c2ecf20Sopenharmony_ci 60888c2ecf20Sopenharmony_ci/* Must be called under tgt_mutex */ 60898c2ecf20Sopenharmony_cistatic struct fc_port *qlt_make_local_sess(struct scsi_qla_host *vha, 60908c2ecf20Sopenharmony_ci be_id_t s_id) 60918c2ecf20Sopenharmony_ci{ 60928c2ecf20Sopenharmony_ci struct fc_port *sess = NULL; 60938c2ecf20Sopenharmony_ci fc_port_t *fcport = NULL; 60948c2ecf20Sopenharmony_ci int rc, global_resets; 60958c2ecf20Sopenharmony_ci uint16_t loop_id = 0; 60968c2ecf20Sopenharmony_ci 60978c2ecf20Sopenharmony_ci if (s_id.domain == 0xFF && s_id.area == 0xFC) { 60988c2ecf20Sopenharmony_ci /* 60998c2ecf20Sopenharmony_ci * This is Domain Controller, so it should be 61008c2ecf20Sopenharmony_ci * OK to drop SCSI commands from it. 61018c2ecf20Sopenharmony_ci */ 61028c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf042, 61038c2ecf20Sopenharmony_ci "Unable to find initiator with S_ID %x:%x:%x", 61048c2ecf20Sopenharmony_ci s_id.domain, s_id.area, s_id.al_pa); 61058c2ecf20Sopenharmony_ci return NULL; 61068c2ecf20Sopenharmony_ci } 61078c2ecf20Sopenharmony_ci 61088c2ecf20Sopenharmony_ci mutex_lock(&vha->vha_tgt.tgt_mutex); 61098c2ecf20Sopenharmony_ci 61108c2ecf20Sopenharmony_ciretry: 61118c2ecf20Sopenharmony_ci global_resets = 61128c2ecf20Sopenharmony_ci atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count); 61138c2ecf20Sopenharmony_ci 61148c2ecf20Sopenharmony_ci rc = qla24xx_get_loop_id(vha, s_id, &loop_id); 61158c2ecf20Sopenharmony_ci if (rc != 0) { 61168c2ecf20Sopenharmony_ci mutex_unlock(&vha->vha_tgt.tgt_mutex); 61178c2ecf20Sopenharmony_ci 61188c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xf071, 61198c2ecf20Sopenharmony_ci "qla_target(%d): Unable to find " 61208c2ecf20Sopenharmony_ci "initiator with S_ID %x:%x:%x", 61218c2ecf20Sopenharmony_ci vha->vp_idx, s_id.domain, s_id.area, s_id.al_pa); 61228c2ecf20Sopenharmony_ci 61238c2ecf20Sopenharmony_ci if (rc == -ENOENT) { 61248c2ecf20Sopenharmony_ci qlt_port_logo_t logo; 61258c2ecf20Sopenharmony_ci 61268c2ecf20Sopenharmony_ci logo.id = be_to_port_id(s_id); 61278c2ecf20Sopenharmony_ci logo.cmd_count = 1; 61288c2ecf20Sopenharmony_ci qlt_send_first_logo(vha, &logo); 61298c2ecf20Sopenharmony_ci } 61308c2ecf20Sopenharmony_ci 61318c2ecf20Sopenharmony_ci return NULL; 61328c2ecf20Sopenharmony_ci } 61338c2ecf20Sopenharmony_ci 61348c2ecf20Sopenharmony_ci fcport = qlt_get_port_database(vha, loop_id); 61358c2ecf20Sopenharmony_ci if (!fcport) { 61368c2ecf20Sopenharmony_ci mutex_unlock(&vha->vha_tgt.tgt_mutex); 61378c2ecf20Sopenharmony_ci return NULL; 61388c2ecf20Sopenharmony_ci } 61398c2ecf20Sopenharmony_ci 61408c2ecf20Sopenharmony_ci if (global_resets != 61418c2ecf20Sopenharmony_ci atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count)) { 61428c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf043, 61438c2ecf20Sopenharmony_ci "qla_target(%d): global reset during session discovery " 61448c2ecf20Sopenharmony_ci "(counter was %d, new %d), retrying", vha->vp_idx, 61458c2ecf20Sopenharmony_ci global_resets, 61468c2ecf20Sopenharmony_ci atomic_read(&vha->vha_tgt. 61478c2ecf20Sopenharmony_ci qla_tgt->tgt_global_resets_count)); 61488c2ecf20Sopenharmony_ci goto retry; 61498c2ecf20Sopenharmony_ci } 61508c2ecf20Sopenharmony_ci 61518c2ecf20Sopenharmony_ci sess = qlt_create_sess(vha, fcport, true); 61528c2ecf20Sopenharmony_ci 61538c2ecf20Sopenharmony_ci mutex_unlock(&vha->vha_tgt.tgt_mutex); 61548c2ecf20Sopenharmony_ci 61558c2ecf20Sopenharmony_ci return sess; 61568c2ecf20Sopenharmony_ci} 61578c2ecf20Sopenharmony_ci 61588c2ecf20Sopenharmony_cistatic void qlt_abort_work(struct qla_tgt *tgt, 61598c2ecf20Sopenharmony_ci struct qla_tgt_sess_work_param *prm) 61608c2ecf20Sopenharmony_ci{ 61618c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = tgt->vha; 61628c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 61638c2ecf20Sopenharmony_ci struct fc_port *sess = NULL; 61648c2ecf20Sopenharmony_ci unsigned long flags = 0, flags2 = 0; 61658c2ecf20Sopenharmony_ci be_id_t s_id; 61668c2ecf20Sopenharmony_ci int rc; 61678c2ecf20Sopenharmony_ci 61688c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags2); 61698c2ecf20Sopenharmony_ci 61708c2ecf20Sopenharmony_ci if (tgt->tgt_stop) 61718c2ecf20Sopenharmony_ci goto out_term2; 61728c2ecf20Sopenharmony_ci 61738c2ecf20Sopenharmony_ci s_id = le_id_to_be(prm->abts.fcp_hdr_le.s_id); 61748c2ecf20Sopenharmony_ci 61758c2ecf20Sopenharmony_ci sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); 61768c2ecf20Sopenharmony_ci if (!sess) { 61778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); 61788c2ecf20Sopenharmony_ci 61798c2ecf20Sopenharmony_ci sess = qlt_make_local_sess(vha, s_id); 61808c2ecf20Sopenharmony_ci /* sess has got an extra creation ref */ 61818c2ecf20Sopenharmony_ci 61828c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags2); 61838c2ecf20Sopenharmony_ci if (!sess) 61848c2ecf20Sopenharmony_ci goto out_term2; 61858c2ecf20Sopenharmony_ci } else { 61868c2ecf20Sopenharmony_ci if (sess->deleted) { 61878c2ecf20Sopenharmony_ci sess = NULL; 61888c2ecf20Sopenharmony_ci goto out_term2; 61898c2ecf20Sopenharmony_ci } 61908c2ecf20Sopenharmony_ci 61918c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&sess->sess_kref)) { 61928c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_tmr, vha, 0xf01c, 61938c2ecf20Sopenharmony_ci "%s: kref_get fail %8phC \n", 61948c2ecf20Sopenharmony_ci __func__, sess->port_name); 61958c2ecf20Sopenharmony_ci sess = NULL; 61968c2ecf20Sopenharmony_ci goto out_term2; 61978c2ecf20Sopenharmony_ci } 61988c2ecf20Sopenharmony_ci } 61998c2ecf20Sopenharmony_ci 62008c2ecf20Sopenharmony_ci rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess); 62018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); 62028c2ecf20Sopenharmony_ci 62038c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->put_sess(sess); 62048c2ecf20Sopenharmony_ci 62058c2ecf20Sopenharmony_ci if (rc != 0) 62068c2ecf20Sopenharmony_ci goto out_term; 62078c2ecf20Sopenharmony_ci return; 62088c2ecf20Sopenharmony_ci 62098c2ecf20Sopenharmony_ciout_term2: 62108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); 62118c2ecf20Sopenharmony_ci 62128c2ecf20Sopenharmony_ciout_term: 62138c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 62148c2ecf20Sopenharmony_ci qlt_24xx_send_abts_resp(ha->base_qpair, &prm->abts, 62158c2ecf20Sopenharmony_ci FCP_TMF_REJECTED, false); 62168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 62178c2ecf20Sopenharmony_ci} 62188c2ecf20Sopenharmony_ci 62198c2ecf20Sopenharmony_cistatic void qlt_tmr_work(struct qla_tgt *tgt, 62208c2ecf20Sopenharmony_ci struct qla_tgt_sess_work_param *prm) 62218c2ecf20Sopenharmony_ci{ 62228c2ecf20Sopenharmony_ci struct atio_from_isp *a = &prm->tm_iocb2; 62238c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = tgt->vha; 62248c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 62258c2ecf20Sopenharmony_ci struct fc_port *sess; 62268c2ecf20Sopenharmony_ci unsigned long flags; 62278c2ecf20Sopenharmony_ci be_id_t s_id; 62288c2ecf20Sopenharmony_ci int rc; 62298c2ecf20Sopenharmony_ci u64 unpacked_lun; 62308c2ecf20Sopenharmony_ci int fn; 62318c2ecf20Sopenharmony_ci void *iocb; 62328c2ecf20Sopenharmony_ci 62338c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 62348c2ecf20Sopenharmony_ci 62358c2ecf20Sopenharmony_ci if (tgt->tgt_stop) 62368c2ecf20Sopenharmony_ci goto out_term2; 62378c2ecf20Sopenharmony_ci 62388c2ecf20Sopenharmony_ci s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id; 62398c2ecf20Sopenharmony_ci sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); 62408c2ecf20Sopenharmony_ci if (!sess) { 62418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 62428c2ecf20Sopenharmony_ci 62438c2ecf20Sopenharmony_ci sess = qlt_make_local_sess(vha, s_id); 62448c2ecf20Sopenharmony_ci /* sess has got an extra creation ref */ 62458c2ecf20Sopenharmony_ci 62468c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 62478c2ecf20Sopenharmony_ci if (!sess) 62488c2ecf20Sopenharmony_ci goto out_term2; 62498c2ecf20Sopenharmony_ci } else { 62508c2ecf20Sopenharmony_ci if (sess->deleted) { 62518c2ecf20Sopenharmony_ci goto out_term2; 62528c2ecf20Sopenharmony_ci } 62538c2ecf20Sopenharmony_ci 62548c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&sess->sess_kref)) { 62558c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_tmr, vha, 0xf020, 62568c2ecf20Sopenharmony_ci "%s: kref_get fail %8phC\n", 62578c2ecf20Sopenharmony_ci __func__, sess->port_name); 62588c2ecf20Sopenharmony_ci goto out_term2; 62598c2ecf20Sopenharmony_ci } 62608c2ecf20Sopenharmony_ci } 62618c2ecf20Sopenharmony_ci 62628c2ecf20Sopenharmony_ci iocb = a; 62638c2ecf20Sopenharmony_ci fn = a->u.isp24.fcp_cmnd.task_mgmt_flags; 62648c2ecf20Sopenharmony_ci unpacked_lun = 62658c2ecf20Sopenharmony_ci scsilun_to_int((struct scsi_lun *)&a->u.isp24.fcp_cmnd.lun); 62668c2ecf20Sopenharmony_ci 62678c2ecf20Sopenharmony_ci rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); 62688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 62698c2ecf20Sopenharmony_ci 62708c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->put_sess(sess); 62718c2ecf20Sopenharmony_ci 62728c2ecf20Sopenharmony_ci if (rc != 0) 62738c2ecf20Sopenharmony_ci goto out_term; 62748c2ecf20Sopenharmony_ci return; 62758c2ecf20Sopenharmony_ci 62768c2ecf20Sopenharmony_ciout_term2: 62778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 62788c2ecf20Sopenharmony_ciout_term: 62798c2ecf20Sopenharmony_ci qlt_send_term_exchange(ha->base_qpair, NULL, &prm->tm_iocb2, 1, 0); 62808c2ecf20Sopenharmony_ci} 62818c2ecf20Sopenharmony_ci 62828c2ecf20Sopenharmony_cistatic void qlt_sess_work_fn(struct work_struct *work) 62838c2ecf20Sopenharmony_ci{ 62848c2ecf20Sopenharmony_ci struct qla_tgt *tgt = container_of(work, struct qla_tgt, sess_work); 62858c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = tgt->vha; 62868c2ecf20Sopenharmony_ci unsigned long flags; 62878c2ecf20Sopenharmony_ci 62888c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf000, "Sess work (tgt %p)", tgt); 62898c2ecf20Sopenharmony_ci 62908c2ecf20Sopenharmony_ci spin_lock_irqsave(&tgt->sess_work_lock, flags); 62918c2ecf20Sopenharmony_ci while (!list_empty(&tgt->sess_works_list)) { 62928c2ecf20Sopenharmony_ci struct qla_tgt_sess_work_param *prm = list_entry( 62938c2ecf20Sopenharmony_ci tgt->sess_works_list.next, typeof(*prm), 62948c2ecf20Sopenharmony_ci sess_works_list_entry); 62958c2ecf20Sopenharmony_ci 62968c2ecf20Sopenharmony_ci /* 62978c2ecf20Sopenharmony_ci * This work can be scheduled on several CPUs at time, so we 62988c2ecf20Sopenharmony_ci * must delete the entry to eliminate double processing 62998c2ecf20Sopenharmony_ci */ 63008c2ecf20Sopenharmony_ci list_del(&prm->sess_works_list_entry); 63018c2ecf20Sopenharmony_ci 63028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tgt->sess_work_lock, flags); 63038c2ecf20Sopenharmony_ci 63048c2ecf20Sopenharmony_ci switch (prm->type) { 63058c2ecf20Sopenharmony_ci case QLA_TGT_SESS_WORK_ABORT: 63068c2ecf20Sopenharmony_ci qlt_abort_work(tgt, prm); 63078c2ecf20Sopenharmony_ci break; 63088c2ecf20Sopenharmony_ci case QLA_TGT_SESS_WORK_TM: 63098c2ecf20Sopenharmony_ci qlt_tmr_work(tgt, prm); 63108c2ecf20Sopenharmony_ci break; 63118c2ecf20Sopenharmony_ci default: 63128c2ecf20Sopenharmony_ci BUG_ON(1); 63138c2ecf20Sopenharmony_ci break; 63148c2ecf20Sopenharmony_ci } 63158c2ecf20Sopenharmony_ci 63168c2ecf20Sopenharmony_ci spin_lock_irqsave(&tgt->sess_work_lock, flags); 63178c2ecf20Sopenharmony_ci 63188c2ecf20Sopenharmony_ci kfree(prm); 63198c2ecf20Sopenharmony_ci } 63208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tgt->sess_work_lock, flags); 63218c2ecf20Sopenharmony_ci} 63228c2ecf20Sopenharmony_ci 63238c2ecf20Sopenharmony_ci/* Must be called under tgt_host_action_mutex */ 63248c2ecf20Sopenharmony_ciint qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) 63258c2ecf20Sopenharmony_ci{ 63268c2ecf20Sopenharmony_ci struct qla_tgt *tgt; 63278c2ecf20Sopenharmony_ci int rc, i; 63288c2ecf20Sopenharmony_ci struct qla_qpair_hint *h; 63298c2ecf20Sopenharmony_ci 63308c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 63318c2ecf20Sopenharmony_ci return 0; 63328c2ecf20Sopenharmony_ci 63338c2ecf20Sopenharmony_ci if (!IS_TGT_MODE_CAPABLE(ha)) { 63348c2ecf20Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0xe070, 63358c2ecf20Sopenharmony_ci "This adapter does not support target mode.\n"); 63368c2ecf20Sopenharmony_ci return 0; 63378c2ecf20Sopenharmony_ci } 63388c2ecf20Sopenharmony_ci 63398c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, base_vha, 0xe03b, 63408c2ecf20Sopenharmony_ci "Registering target for host %ld(%p).\n", base_vha->host_no, ha); 63418c2ecf20Sopenharmony_ci 63428c2ecf20Sopenharmony_ci BUG_ON(base_vha->vha_tgt.qla_tgt != NULL); 63438c2ecf20Sopenharmony_ci 63448c2ecf20Sopenharmony_ci tgt = kzalloc(sizeof(struct qla_tgt), GFP_KERNEL); 63458c2ecf20Sopenharmony_ci if (!tgt) { 63468c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, base_vha, 0xe066, 63478c2ecf20Sopenharmony_ci "Unable to allocate struct qla_tgt\n"); 63488c2ecf20Sopenharmony_ci return -ENOMEM; 63498c2ecf20Sopenharmony_ci } 63508c2ecf20Sopenharmony_ci 63518c2ecf20Sopenharmony_ci tgt->qphints = kcalloc(ha->max_qpairs + 1, 63528c2ecf20Sopenharmony_ci sizeof(struct qla_qpair_hint), 63538c2ecf20Sopenharmony_ci GFP_KERNEL); 63548c2ecf20Sopenharmony_ci if (!tgt->qphints) { 63558c2ecf20Sopenharmony_ci kfree(tgt); 63568c2ecf20Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0x0197, 63578c2ecf20Sopenharmony_ci "Unable to allocate qpair hints.\n"); 63588c2ecf20Sopenharmony_ci return -ENOMEM; 63598c2ecf20Sopenharmony_ci } 63608c2ecf20Sopenharmony_ci 63618c2ecf20Sopenharmony_ci if (!(base_vha->host->hostt->supported_mode & MODE_TARGET)) 63628c2ecf20Sopenharmony_ci base_vha->host->hostt->supported_mode |= MODE_TARGET; 63638c2ecf20Sopenharmony_ci 63648c2ecf20Sopenharmony_ci rc = btree_init64(&tgt->lun_qpair_map); 63658c2ecf20Sopenharmony_ci if (rc) { 63668c2ecf20Sopenharmony_ci kfree(tgt->qphints); 63678c2ecf20Sopenharmony_ci kfree(tgt); 63688c2ecf20Sopenharmony_ci ql_log(ql_log_info, base_vha, 0x0198, 63698c2ecf20Sopenharmony_ci "Unable to initialize lun_qpair_map btree\n"); 63708c2ecf20Sopenharmony_ci return -EIO; 63718c2ecf20Sopenharmony_ci } 63728c2ecf20Sopenharmony_ci h = &tgt->qphints[0]; 63738c2ecf20Sopenharmony_ci h->qpair = ha->base_qpair; 63748c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&h->hint_elem); 63758c2ecf20Sopenharmony_ci h->cpuid = ha->base_qpair->cpuid; 63768c2ecf20Sopenharmony_ci list_add_tail(&h->hint_elem, &ha->base_qpair->hints_list); 63778c2ecf20Sopenharmony_ci 63788c2ecf20Sopenharmony_ci for (i = 0; i < ha->max_qpairs; i++) { 63798c2ecf20Sopenharmony_ci unsigned long flags; 63808c2ecf20Sopenharmony_ci 63818c2ecf20Sopenharmony_ci struct qla_qpair *qpair = ha->queue_pair_map[i]; 63828c2ecf20Sopenharmony_ci 63838c2ecf20Sopenharmony_ci h = &tgt->qphints[i + 1]; 63848c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&h->hint_elem); 63858c2ecf20Sopenharmony_ci if (qpair) { 63868c2ecf20Sopenharmony_ci h->qpair = qpair; 63878c2ecf20Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 63888c2ecf20Sopenharmony_ci list_add_tail(&h->hint_elem, &qpair->hints_list); 63898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 63908c2ecf20Sopenharmony_ci h->cpuid = qpair->cpuid; 63918c2ecf20Sopenharmony_ci } 63928c2ecf20Sopenharmony_ci } 63938c2ecf20Sopenharmony_ci 63948c2ecf20Sopenharmony_ci tgt->ha = ha; 63958c2ecf20Sopenharmony_ci tgt->vha = base_vha; 63968c2ecf20Sopenharmony_ci init_waitqueue_head(&tgt->waitQ); 63978c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tgt->del_sess_list); 63988c2ecf20Sopenharmony_ci spin_lock_init(&tgt->sess_work_lock); 63998c2ecf20Sopenharmony_ci INIT_WORK(&tgt->sess_work, qlt_sess_work_fn); 64008c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tgt->sess_works_list); 64018c2ecf20Sopenharmony_ci atomic_set(&tgt->tgt_global_resets_count, 0); 64028c2ecf20Sopenharmony_ci 64038c2ecf20Sopenharmony_ci base_vha->vha_tgt.qla_tgt = tgt; 64048c2ecf20Sopenharmony_ci 64058c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, base_vha, 0xe067, 64068c2ecf20Sopenharmony_ci "qla_target(%d): using 64 Bit PCI addressing", 64078c2ecf20Sopenharmony_ci base_vha->vp_idx); 64088c2ecf20Sopenharmony_ci /* 3 is reserved */ 64098c2ecf20Sopenharmony_ci tgt->sg_tablesize = QLA_TGT_MAX_SG_24XX(base_vha->req->length - 3); 64108c2ecf20Sopenharmony_ci 64118c2ecf20Sopenharmony_ci mutex_lock(&qla_tgt_mutex); 64128c2ecf20Sopenharmony_ci list_add_tail(&tgt->tgt_list_entry, &qla_tgt_glist); 64138c2ecf20Sopenharmony_ci mutex_unlock(&qla_tgt_mutex); 64148c2ecf20Sopenharmony_ci 64158c2ecf20Sopenharmony_ci if (ha->tgt.tgt_ops && ha->tgt.tgt_ops->add_target) 64168c2ecf20Sopenharmony_ci ha->tgt.tgt_ops->add_target(base_vha); 64178c2ecf20Sopenharmony_ci 64188c2ecf20Sopenharmony_ci return 0; 64198c2ecf20Sopenharmony_ci} 64208c2ecf20Sopenharmony_ci 64218c2ecf20Sopenharmony_ci/* Must be called under tgt_host_action_mutex */ 64228c2ecf20Sopenharmony_ciint qlt_remove_target(struct qla_hw_data *ha, struct scsi_qla_host *vha) 64238c2ecf20Sopenharmony_ci{ 64248c2ecf20Sopenharmony_ci if (!vha->vha_tgt.qla_tgt) 64258c2ecf20Sopenharmony_ci return 0; 64268c2ecf20Sopenharmony_ci 64278c2ecf20Sopenharmony_ci if (vha->fc_vport) { 64288c2ecf20Sopenharmony_ci qlt_release(vha->vha_tgt.qla_tgt); 64298c2ecf20Sopenharmony_ci return 0; 64308c2ecf20Sopenharmony_ci } 64318c2ecf20Sopenharmony_ci 64328c2ecf20Sopenharmony_ci /* free left over qfull cmds */ 64338c2ecf20Sopenharmony_ci qlt_init_term_exchange(vha); 64348c2ecf20Sopenharmony_ci 64358c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe03c, "Unregistering target for host %ld(%p)", 64368c2ecf20Sopenharmony_ci vha->host_no, ha); 64378c2ecf20Sopenharmony_ci qlt_release(vha->vha_tgt.qla_tgt); 64388c2ecf20Sopenharmony_ci 64398c2ecf20Sopenharmony_ci return 0; 64408c2ecf20Sopenharmony_ci} 64418c2ecf20Sopenharmony_ci 64428c2ecf20Sopenharmony_civoid qlt_remove_target_resources(struct qla_hw_data *ha) 64438c2ecf20Sopenharmony_ci{ 64448c2ecf20Sopenharmony_ci struct scsi_qla_host *node; 64458c2ecf20Sopenharmony_ci u32 key = 0; 64468c2ecf20Sopenharmony_ci 64478c2ecf20Sopenharmony_ci btree_for_each_safe32(&ha->tgt.host_map, key, node) 64488c2ecf20Sopenharmony_ci btree_remove32(&ha->tgt.host_map, key); 64498c2ecf20Sopenharmony_ci 64508c2ecf20Sopenharmony_ci btree_destroy32(&ha->tgt.host_map); 64518c2ecf20Sopenharmony_ci} 64528c2ecf20Sopenharmony_ci 64538c2ecf20Sopenharmony_cistatic void qlt_lport_dump(struct scsi_qla_host *vha, u64 wwpn, 64548c2ecf20Sopenharmony_ci unsigned char *b) 64558c2ecf20Sopenharmony_ci{ 64568c2ecf20Sopenharmony_ci pr_debug("qla2xxx HW vha->node_name: %8phC\n", vha->node_name); 64578c2ecf20Sopenharmony_ci pr_debug("qla2xxx HW vha->port_name: %8phC\n", vha->port_name); 64588c2ecf20Sopenharmony_ci put_unaligned_be64(wwpn, b); 64598c2ecf20Sopenharmony_ci pr_debug("qla2xxx passed configfs WWPN: %8phC\n", b); 64608c2ecf20Sopenharmony_ci} 64618c2ecf20Sopenharmony_ci 64628c2ecf20Sopenharmony_ci/** 64638c2ecf20Sopenharmony_ci * qla_tgt_lport_register - register lport with external module 64648c2ecf20Sopenharmony_ci * 64658c2ecf20Sopenharmony_ci * @target_lport_ptr: pointer for tcm_qla2xxx specific lport data 64668c2ecf20Sopenharmony_ci * @phys_wwpn: physical port WWPN 64678c2ecf20Sopenharmony_ci * @npiv_wwpn: NPIV WWPN 64688c2ecf20Sopenharmony_ci * @npiv_wwnn: NPIV WWNN 64698c2ecf20Sopenharmony_ci * @callback: lport initialization callback for tcm_qla2xxx code 64708c2ecf20Sopenharmony_ci */ 64718c2ecf20Sopenharmony_ciint qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn, 64728c2ecf20Sopenharmony_ci u64 npiv_wwpn, u64 npiv_wwnn, 64738c2ecf20Sopenharmony_ci int (*callback)(struct scsi_qla_host *, void *, u64, u64)) 64748c2ecf20Sopenharmony_ci{ 64758c2ecf20Sopenharmony_ci struct qla_tgt *tgt; 64768c2ecf20Sopenharmony_ci struct scsi_qla_host *vha; 64778c2ecf20Sopenharmony_ci struct qla_hw_data *ha; 64788c2ecf20Sopenharmony_ci struct Scsi_Host *host; 64798c2ecf20Sopenharmony_ci unsigned long flags; 64808c2ecf20Sopenharmony_ci int rc; 64818c2ecf20Sopenharmony_ci u8 b[WWN_SIZE]; 64828c2ecf20Sopenharmony_ci 64838c2ecf20Sopenharmony_ci mutex_lock(&qla_tgt_mutex); 64848c2ecf20Sopenharmony_ci list_for_each_entry(tgt, &qla_tgt_glist, tgt_list_entry) { 64858c2ecf20Sopenharmony_ci vha = tgt->vha; 64868c2ecf20Sopenharmony_ci ha = vha->hw; 64878c2ecf20Sopenharmony_ci 64888c2ecf20Sopenharmony_ci host = vha->host; 64898c2ecf20Sopenharmony_ci if (!host) 64908c2ecf20Sopenharmony_ci continue; 64918c2ecf20Sopenharmony_ci 64928c2ecf20Sopenharmony_ci if (!(host->hostt->supported_mode & MODE_TARGET)) 64938c2ecf20Sopenharmony_ci continue; 64948c2ecf20Sopenharmony_ci 64958c2ecf20Sopenharmony_ci if (vha->qlini_mode == QLA2XXX_INI_MODE_ENABLED) 64968c2ecf20Sopenharmony_ci continue; 64978c2ecf20Sopenharmony_ci 64988c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 64998c2ecf20Sopenharmony_ci if ((!npiv_wwpn || !npiv_wwnn) && host->active_mode & MODE_TARGET) { 65008c2ecf20Sopenharmony_ci pr_debug("MODE_TARGET already active on qla2xxx(%d)\n", 65018c2ecf20Sopenharmony_ci host->host_no); 65028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 65038c2ecf20Sopenharmony_ci continue; 65048c2ecf20Sopenharmony_ci } 65058c2ecf20Sopenharmony_ci if (tgt->tgt_stop) { 65068c2ecf20Sopenharmony_ci pr_debug("MODE_TARGET in shutdown on qla2xxx(%d)\n", 65078c2ecf20Sopenharmony_ci host->host_no); 65088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 65098c2ecf20Sopenharmony_ci continue; 65108c2ecf20Sopenharmony_ci } 65118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 65128c2ecf20Sopenharmony_ci 65138c2ecf20Sopenharmony_ci if (!scsi_host_get(host)) { 65148c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe068, 65158c2ecf20Sopenharmony_ci "Unable to scsi_host_get() for" 65168c2ecf20Sopenharmony_ci " qla2xxx scsi_host\n"); 65178c2ecf20Sopenharmony_ci continue; 65188c2ecf20Sopenharmony_ci } 65198c2ecf20Sopenharmony_ci qlt_lport_dump(vha, phys_wwpn, b); 65208c2ecf20Sopenharmony_ci 65218c2ecf20Sopenharmony_ci if (memcmp(vha->port_name, b, WWN_SIZE)) { 65228c2ecf20Sopenharmony_ci scsi_host_put(host); 65238c2ecf20Sopenharmony_ci continue; 65248c2ecf20Sopenharmony_ci } 65258c2ecf20Sopenharmony_ci rc = (*callback)(vha, target_lport_ptr, npiv_wwpn, npiv_wwnn); 65268c2ecf20Sopenharmony_ci if (rc != 0) 65278c2ecf20Sopenharmony_ci scsi_host_put(host); 65288c2ecf20Sopenharmony_ci 65298c2ecf20Sopenharmony_ci mutex_unlock(&qla_tgt_mutex); 65308c2ecf20Sopenharmony_ci return rc; 65318c2ecf20Sopenharmony_ci } 65328c2ecf20Sopenharmony_ci mutex_unlock(&qla_tgt_mutex); 65338c2ecf20Sopenharmony_ci 65348c2ecf20Sopenharmony_ci return -ENODEV; 65358c2ecf20Sopenharmony_ci} 65368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_lport_register); 65378c2ecf20Sopenharmony_ci 65388c2ecf20Sopenharmony_ci/** 65398c2ecf20Sopenharmony_ci * qla_tgt_lport_deregister - Degister lport 65408c2ecf20Sopenharmony_ci * 65418c2ecf20Sopenharmony_ci * @vha: Registered scsi_qla_host pointer 65428c2ecf20Sopenharmony_ci */ 65438c2ecf20Sopenharmony_civoid qlt_lport_deregister(struct scsi_qla_host *vha) 65448c2ecf20Sopenharmony_ci{ 65458c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 65468c2ecf20Sopenharmony_ci struct Scsi_Host *sh = vha->host; 65478c2ecf20Sopenharmony_ci /* 65488c2ecf20Sopenharmony_ci * Clear the target_lport_ptr qla_target_template pointer in qla_hw_data 65498c2ecf20Sopenharmony_ci */ 65508c2ecf20Sopenharmony_ci vha->vha_tgt.target_lport_ptr = NULL; 65518c2ecf20Sopenharmony_ci ha->tgt.tgt_ops = NULL; 65528c2ecf20Sopenharmony_ci /* 65538c2ecf20Sopenharmony_ci * Release the Scsi_Host reference for the underlying qla2xxx host 65548c2ecf20Sopenharmony_ci */ 65558c2ecf20Sopenharmony_ci scsi_host_put(sh); 65568c2ecf20Sopenharmony_ci} 65578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_lport_deregister); 65588c2ecf20Sopenharmony_ci 65598c2ecf20Sopenharmony_ci/* Must be called under HW lock */ 65608c2ecf20Sopenharmony_civoid qlt_set_mode(struct scsi_qla_host *vha) 65618c2ecf20Sopenharmony_ci{ 65628c2ecf20Sopenharmony_ci switch (vha->qlini_mode) { 65638c2ecf20Sopenharmony_ci case QLA2XXX_INI_MODE_DISABLED: 65648c2ecf20Sopenharmony_ci case QLA2XXX_INI_MODE_EXCLUSIVE: 65658c2ecf20Sopenharmony_ci vha->host->active_mode = MODE_TARGET; 65668c2ecf20Sopenharmony_ci break; 65678c2ecf20Sopenharmony_ci case QLA2XXX_INI_MODE_ENABLED: 65688c2ecf20Sopenharmony_ci vha->host->active_mode = MODE_INITIATOR; 65698c2ecf20Sopenharmony_ci break; 65708c2ecf20Sopenharmony_ci case QLA2XXX_INI_MODE_DUAL: 65718c2ecf20Sopenharmony_ci vha->host->active_mode = MODE_DUAL; 65728c2ecf20Sopenharmony_ci break; 65738c2ecf20Sopenharmony_ci default: 65748c2ecf20Sopenharmony_ci break; 65758c2ecf20Sopenharmony_ci } 65768c2ecf20Sopenharmony_ci} 65778c2ecf20Sopenharmony_ci 65788c2ecf20Sopenharmony_ci/* Must be called under HW lock */ 65798c2ecf20Sopenharmony_cistatic void qlt_clear_mode(struct scsi_qla_host *vha) 65808c2ecf20Sopenharmony_ci{ 65818c2ecf20Sopenharmony_ci switch (vha->qlini_mode) { 65828c2ecf20Sopenharmony_ci case QLA2XXX_INI_MODE_DISABLED: 65838c2ecf20Sopenharmony_ci vha->host->active_mode = MODE_UNKNOWN; 65848c2ecf20Sopenharmony_ci break; 65858c2ecf20Sopenharmony_ci case QLA2XXX_INI_MODE_EXCLUSIVE: 65868c2ecf20Sopenharmony_ci vha->host->active_mode = MODE_INITIATOR; 65878c2ecf20Sopenharmony_ci break; 65888c2ecf20Sopenharmony_ci case QLA2XXX_INI_MODE_ENABLED: 65898c2ecf20Sopenharmony_ci case QLA2XXX_INI_MODE_DUAL: 65908c2ecf20Sopenharmony_ci vha->host->active_mode = MODE_INITIATOR; 65918c2ecf20Sopenharmony_ci break; 65928c2ecf20Sopenharmony_ci default: 65938c2ecf20Sopenharmony_ci break; 65948c2ecf20Sopenharmony_ci } 65958c2ecf20Sopenharmony_ci} 65968c2ecf20Sopenharmony_ci 65978c2ecf20Sopenharmony_ci/* 65988c2ecf20Sopenharmony_ci * qla_tgt_enable_vha - NO LOCK HELD 65998c2ecf20Sopenharmony_ci * 66008c2ecf20Sopenharmony_ci * host_reset, bring up w/ Target Mode Enabled 66018c2ecf20Sopenharmony_ci */ 66028c2ecf20Sopenharmony_civoid 66038c2ecf20Sopenharmony_ciqlt_enable_vha(struct scsi_qla_host *vha) 66048c2ecf20Sopenharmony_ci{ 66058c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 66068c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 66078c2ecf20Sopenharmony_ci unsigned long flags; 66088c2ecf20Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 66098c2ecf20Sopenharmony_ci 66108c2ecf20Sopenharmony_ci if (!tgt) { 66118c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe069, 66128c2ecf20Sopenharmony_ci "Unable to locate qla_tgt pointer from" 66138c2ecf20Sopenharmony_ci " struct qla_hw_data\n"); 66148c2ecf20Sopenharmony_ci dump_stack(); 66158c2ecf20Sopenharmony_ci return; 66168c2ecf20Sopenharmony_ci } 66178c2ecf20Sopenharmony_ci if (vha->qlini_mode == QLA2XXX_INI_MODE_ENABLED) 66188c2ecf20Sopenharmony_ci return; 66198c2ecf20Sopenharmony_ci 66208c2ecf20Sopenharmony_ci if (ha->tgt.num_act_qpairs > ha->max_qpairs) 66218c2ecf20Sopenharmony_ci ha->tgt.num_act_qpairs = ha->max_qpairs; 66228c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 66238c2ecf20Sopenharmony_ci tgt->tgt_stopped = 0; 66248c2ecf20Sopenharmony_ci qlt_set_mode(vha); 66258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 66268c2ecf20Sopenharmony_ci 66278c2ecf20Sopenharmony_ci mutex_lock(&ha->optrom_mutex); 66288c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf021, 66298c2ecf20Sopenharmony_ci "%s.\n", __func__); 66308c2ecf20Sopenharmony_ci if (vha->vp_idx) { 66318c2ecf20Sopenharmony_ci qla24xx_disable_vp(vha); 66328c2ecf20Sopenharmony_ci qla24xx_enable_vp(vha); 66338c2ecf20Sopenharmony_ci } else { 66348c2ecf20Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); 66358c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(base_vha); 66368c2ecf20Sopenharmony_ci WARN_ON_ONCE(qla2x00_wait_for_hba_online(base_vha) != 66378c2ecf20Sopenharmony_ci QLA_SUCCESS); 66388c2ecf20Sopenharmony_ci } 66398c2ecf20Sopenharmony_ci mutex_unlock(&ha->optrom_mutex); 66408c2ecf20Sopenharmony_ci} 66418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qlt_enable_vha); 66428c2ecf20Sopenharmony_ci 66438c2ecf20Sopenharmony_ci/* 66448c2ecf20Sopenharmony_ci * qla_tgt_disable_vha - NO LOCK HELD 66458c2ecf20Sopenharmony_ci * 66468c2ecf20Sopenharmony_ci * Disable Target Mode and reset the adapter 66478c2ecf20Sopenharmony_ci */ 66488c2ecf20Sopenharmony_cistatic void qlt_disable_vha(struct scsi_qla_host *vha) 66498c2ecf20Sopenharmony_ci{ 66508c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 66518c2ecf20Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 66528c2ecf20Sopenharmony_ci unsigned long flags; 66538c2ecf20Sopenharmony_ci 66548c2ecf20Sopenharmony_ci if (!tgt) { 66558c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe06a, 66568c2ecf20Sopenharmony_ci "Unable to locate qla_tgt pointer from" 66578c2ecf20Sopenharmony_ci " struct qla_hw_data\n"); 66588c2ecf20Sopenharmony_ci dump_stack(); 66598c2ecf20Sopenharmony_ci return; 66608c2ecf20Sopenharmony_ci } 66618c2ecf20Sopenharmony_ci 66628c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 66638c2ecf20Sopenharmony_ci qlt_clear_mode(vha); 66648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 66658c2ecf20Sopenharmony_ci 66668c2ecf20Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 66678c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(vha); 66688c2ecf20Sopenharmony_ci 66698c2ecf20Sopenharmony_ci /* 66708c2ecf20Sopenharmony_ci * We are expecting the offline state. 66718c2ecf20Sopenharmony_ci * QLA_FUNCTION_FAILED means that adapter is offline. 66728c2ecf20Sopenharmony_ci */ 66738c2ecf20Sopenharmony_ci if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) 66748c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe081, 66758c2ecf20Sopenharmony_ci "adapter is offline\n"); 66768c2ecf20Sopenharmony_ci} 66778c2ecf20Sopenharmony_ci 66788c2ecf20Sopenharmony_ci/* 66798c2ecf20Sopenharmony_ci * Called from qla_init.c:qla24xx_vport_create() contex to setup 66808c2ecf20Sopenharmony_ci * the target mode specific struct scsi_qla_host and struct qla_hw_data 66818c2ecf20Sopenharmony_ci * members. 66828c2ecf20Sopenharmony_ci */ 66838c2ecf20Sopenharmony_civoid 66848c2ecf20Sopenharmony_ciqlt_vport_create(struct scsi_qla_host *vha, struct qla_hw_data *ha) 66858c2ecf20Sopenharmony_ci{ 66868c2ecf20Sopenharmony_ci vha->vha_tgt.qla_tgt = NULL; 66878c2ecf20Sopenharmony_ci 66888c2ecf20Sopenharmony_ci mutex_init(&vha->vha_tgt.tgt_mutex); 66898c2ecf20Sopenharmony_ci mutex_init(&vha->vha_tgt.tgt_host_action_mutex); 66908c2ecf20Sopenharmony_ci 66918c2ecf20Sopenharmony_ci qlt_clear_mode(vha); 66928c2ecf20Sopenharmony_ci 66938c2ecf20Sopenharmony_ci /* 66948c2ecf20Sopenharmony_ci * NOTE: Currently the value is kept the same for <24xx and 66958c2ecf20Sopenharmony_ci * >=24xx ISPs. If it is necessary to change it, 66968c2ecf20Sopenharmony_ci * the check should be added for specific ISPs, 66978c2ecf20Sopenharmony_ci * assigning the value appropriately. 66988c2ecf20Sopenharmony_ci */ 66998c2ecf20Sopenharmony_ci ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; 67008c2ecf20Sopenharmony_ci 67018c2ecf20Sopenharmony_ci qlt_add_target(ha, vha); 67028c2ecf20Sopenharmony_ci} 67038c2ecf20Sopenharmony_ci 67048c2ecf20Sopenharmony_ciu8 67058c2ecf20Sopenharmony_ciqlt_rff_id(struct scsi_qla_host *vha) 67068c2ecf20Sopenharmony_ci{ 67078c2ecf20Sopenharmony_ci u8 fc4_feature = 0; 67088c2ecf20Sopenharmony_ci /* 67098c2ecf20Sopenharmony_ci * FC-4 Feature bit 0 indicates target functionality to the name server. 67108c2ecf20Sopenharmony_ci */ 67118c2ecf20Sopenharmony_ci if (qla_tgt_mode_enabled(vha)) { 67128c2ecf20Sopenharmony_ci fc4_feature = BIT_0; 67138c2ecf20Sopenharmony_ci } else if (qla_ini_mode_enabled(vha)) { 67148c2ecf20Sopenharmony_ci fc4_feature = BIT_1; 67158c2ecf20Sopenharmony_ci } else if (qla_dual_mode_enabled(vha)) 67168c2ecf20Sopenharmony_ci fc4_feature = BIT_0 | BIT_1; 67178c2ecf20Sopenharmony_ci 67188c2ecf20Sopenharmony_ci return fc4_feature; 67198c2ecf20Sopenharmony_ci} 67208c2ecf20Sopenharmony_ci 67218c2ecf20Sopenharmony_ci/* 67228c2ecf20Sopenharmony_ci * qlt_init_atio_q_entries() - Initializes ATIO queue entries. 67238c2ecf20Sopenharmony_ci * @ha: HA context 67248c2ecf20Sopenharmony_ci * 67258c2ecf20Sopenharmony_ci * Beginning of ATIO ring has initialization control block already built 67268c2ecf20Sopenharmony_ci * by nvram config routine. 67278c2ecf20Sopenharmony_ci * 67288c2ecf20Sopenharmony_ci * Returns 0 on success. 67298c2ecf20Sopenharmony_ci */ 67308c2ecf20Sopenharmony_civoid 67318c2ecf20Sopenharmony_ciqlt_init_atio_q_entries(struct scsi_qla_host *vha) 67328c2ecf20Sopenharmony_ci{ 67338c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 67348c2ecf20Sopenharmony_ci uint16_t cnt; 67358c2ecf20Sopenharmony_ci struct atio_from_isp *pkt = (struct atio_from_isp *)ha->tgt.atio_ring; 67368c2ecf20Sopenharmony_ci 67378c2ecf20Sopenharmony_ci if (qla_ini_mode_enabled(vha)) 67388c2ecf20Sopenharmony_ci return; 67398c2ecf20Sopenharmony_ci 67408c2ecf20Sopenharmony_ci for (cnt = 0; cnt < ha->tgt.atio_q_length; cnt++) { 67418c2ecf20Sopenharmony_ci pkt->u.raw.signature = cpu_to_le32(ATIO_PROCESSED); 67428c2ecf20Sopenharmony_ci pkt++; 67438c2ecf20Sopenharmony_ci } 67448c2ecf20Sopenharmony_ci 67458c2ecf20Sopenharmony_ci} 67468c2ecf20Sopenharmony_ci 67478c2ecf20Sopenharmony_ci/* 67488c2ecf20Sopenharmony_ci * qlt_24xx_process_atio_queue() - Process ATIO queue entries. 67498c2ecf20Sopenharmony_ci * @ha: SCSI driver HA context 67508c2ecf20Sopenharmony_ci */ 67518c2ecf20Sopenharmony_civoid 67528c2ecf20Sopenharmony_ciqlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked) 67538c2ecf20Sopenharmony_ci{ 67548c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 67558c2ecf20Sopenharmony_ci struct atio_from_isp *pkt; 67568c2ecf20Sopenharmony_ci int cnt, i; 67578c2ecf20Sopenharmony_ci 67588c2ecf20Sopenharmony_ci if (!ha->flags.fw_started) 67598c2ecf20Sopenharmony_ci return; 67608c2ecf20Sopenharmony_ci 67618c2ecf20Sopenharmony_ci while ((ha->tgt.atio_ring_ptr->signature != ATIO_PROCESSED) || 67628c2ecf20Sopenharmony_ci fcpcmd_is_corrupted(ha->tgt.atio_ring_ptr)) { 67638c2ecf20Sopenharmony_ci pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr; 67648c2ecf20Sopenharmony_ci cnt = pkt->u.raw.entry_count; 67658c2ecf20Sopenharmony_ci 67668c2ecf20Sopenharmony_ci if (unlikely(fcpcmd_is_corrupted(ha->tgt.atio_ring_ptr))) { 67678c2ecf20Sopenharmony_ci /* 67688c2ecf20Sopenharmony_ci * This packet is corrupted. The header + payload 67698c2ecf20Sopenharmony_ci * can not be trusted. There is no point in passing 67708c2ecf20Sopenharmony_ci * it further up. 67718c2ecf20Sopenharmony_ci */ 67728c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd03c, 67738c2ecf20Sopenharmony_ci "corrupted fcp frame SID[%3phN] OXID[%04x] EXCG[%x] %64phN\n", 67748c2ecf20Sopenharmony_ci &pkt->u.isp24.fcp_hdr.s_id, 67758c2ecf20Sopenharmony_ci be16_to_cpu(pkt->u.isp24.fcp_hdr.ox_id), 67768c2ecf20Sopenharmony_ci pkt->u.isp24.exchange_addr, pkt); 67778c2ecf20Sopenharmony_ci 67788c2ecf20Sopenharmony_ci adjust_corrupted_atio(pkt); 67798c2ecf20Sopenharmony_ci qlt_send_term_exchange(ha->base_qpair, NULL, pkt, 67808c2ecf20Sopenharmony_ci ha_locked, 0); 67818c2ecf20Sopenharmony_ci } else { 67828c2ecf20Sopenharmony_ci qlt_24xx_atio_pkt_all_vps(vha, 67838c2ecf20Sopenharmony_ci (struct atio_from_isp *)pkt, ha_locked); 67848c2ecf20Sopenharmony_ci } 67858c2ecf20Sopenharmony_ci 67868c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) { 67878c2ecf20Sopenharmony_ci ha->tgt.atio_ring_index++; 67888c2ecf20Sopenharmony_ci if (ha->tgt.atio_ring_index == ha->tgt.atio_q_length) { 67898c2ecf20Sopenharmony_ci ha->tgt.atio_ring_index = 0; 67908c2ecf20Sopenharmony_ci ha->tgt.atio_ring_ptr = ha->tgt.atio_ring; 67918c2ecf20Sopenharmony_ci } else 67928c2ecf20Sopenharmony_ci ha->tgt.atio_ring_ptr++; 67938c2ecf20Sopenharmony_ci 67948c2ecf20Sopenharmony_ci pkt->u.raw.signature = cpu_to_le32(ATIO_PROCESSED); 67958c2ecf20Sopenharmony_ci pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr; 67968c2ecf20Sopenharmony_ci } 67978c2ecf20Sopenharmony_ci wmb(); 67988c2ecf20Sopenharmony_ci } 67998c2ecf20Sopenharmony_ci 68008c2ecf20Sopenharmony_ci /* Adjust ring index */ 68018c2ecf20Sopenharmony_ci wrt_reg_dword(ISP_ATIO_Q_OUT(vha), ha->tgt.atio_ring_index); 68028c2ecf20Sopenharmony_ci} 68038c2ecf20Sopenharmony_ci 68048c2ecf20Sopenharmony_civoid 68058c2ecf20Sopenharmony_ciqlt_24xx_config_rings(struct scsi_qla_host *vha) 68068c2ecf20Sopenharmony_ci{ 68078c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 68088c2ecf20Sopenharmony_ci struct qla_msix_entry *msix = &ha->msix_entries[2]; 68098c2ecf20Sopenharmony_ci struct init_cb_24xx *icb = (struct init_cb_24xx *)ha->init_cb; 68108c2ecf20Sopenharmony_ci 68118c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 68128c2ecf20Sopenharmony_ci return; 68138c2ecf20Sopenharmony_ci 68148c2ecf20Sopenharmony_ci wrt_reg_dword(ISP_ATIO_Q_IN(vha), 0); 68158c2ecf20Sopenharmony_ci wrt_reg_dword(ISP_ATIO_Q_OUT(vha), 0); 68168c2ecf20Sopenharmony_ci rd_reg_dword(ISP_ATIO_Q_OUT(vha)); 68178c2ecf20Sopenharmony_ci 68188c2ecf20Sopenharmony_ci if (ha->flags.msix_enabled) { 68198c2ecf20Sopenharmony_ci if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { 68208c2ecf20Sopenharmony_ci icb->msix_atio = cpu_to_le16(msix->entry); 68218c2ecf20Sopenharmony_ci icb->firmware_options_2 &= cpu_to_le32(~BIT_26); 68228c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0xf072, 68238c2ecf20Sopenharmony_ci "Registering ICB vector 0x%x for atio que.\n", 68248c2ecf20Sopenharmony_ci msix->entry); 68258c2ecf20Sopenharmony_ci } 68268c2ecf20Sopenharmony_ci } else { 68278c2ecf20Sopenharmony_ci /* INTx|MSI */ 68288c2ecf20Sopenharmony_ci if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { 68298c2ecf20Sopenharmony_ci icb->msix_atio = 0; 68308c2ecf20Sopenharmony_ci icb->firmware_options_2 |= cpu_to_le32(BIT_26); 68318c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0xf072, 68328c2ecf20Sopenharmony_ci "%s: Use INTx for ATIOQ.\n", __func__); 68338c2ecf20Sopenharmony_ci } 68348c2ecf20Sopenharmony_ci } 68358c2ecf20Sopenharmony_ci} 68368c2ecf20Sopenharmony_ci 68378c2ecf20Sopenharmony_civoid 68388c2ecf20Sopenharmony_ciqlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) 68398c2ecf20Sopenharmony_ci{ 68408c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 68418c2ecf20Sopenharmony_ci u32 tmp; 68428c2ecf20Sopenharmony_ci 68438c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 68448c2ecf20Sopenharmony_ci return; 68458c2ecf20Sopenharmony_ci 68468c2ecf20Sopenharmony_ci if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) { 68478c2ecf20Sopenharmony_ci if (!ha->tgt.saved_set) { 68488c2ecf20Sopenharmony_ci /* We save only once */ 68498c2ecf20Sopenharmony_ci ha->tgt.saved_exchange_count = nv->exchange_count; 68508c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_1 = 68518c2ecf20Sopenharmony_ci nv->firmware_options_1; 68528c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_2 = 68538c2ecf20Sopenharmony_ci nv->firmware_options_2; 68548c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_3 = 68558c2ecf20Sopenharmony_ci nv->firmware_options_3; 68568c2ecf20Sopenharmony_ci ha->tgt.saved_set = 1; 68578c2ecf20Sopenharmony_ci } 68588c2ecf20Sopenharmony_ci 68598c2ecf20Sopenharmony_ci if (qla_tgt_mode_enabled(vha)) 68608c2ecf20Sopenharmony_ci nv->exchange_count = cpu_to_le16(0xFFFF); 68618c2ecf20Sopenharmony_ci else /* dual */ 68628c2ecf20Sopenharmony_ci nv->exchange_count = cpu_to_le16(vha->ql2xexchoffld); 68638c2ecf20Sopenharmony_ci 68648c2ecf20Sopenharmony_ci /* Enable target mode */ 68658c2ecf20Sopenharmony_ci nv->firmware_options_1 |= cpu_to_le32(BIT_4); 68668c2ecf20Sopenharmony_ci 68678c2ecf20Sopenharmony_ci /* Disable ini mode, if requested */ 68688c2ecf20Sopenharmony_ci if (qla_tgt_mode_enabled(vha)) 68698c2ecf20Sopenharmony_ci nv->firmware_options_1 |= cpu_to_le32(BIT_5); 68708c2ecf20Sopenharmony_ci 68718c2ecf20Sopenharmony_ci /* Disable Full Login after LIP */ 68728c2ecf20Sopenharmony_ci nv->firmware_options_1 &= cpu_to_le32(~BIT_13); 68738c2ecf20Sopenharmony_ci /* Enable initial LIP */ 68748c2ecf20Sopenharmony_ci nv->firmware_options_1 &= cpu_to_le32(~BIT_9); 68758c2ecf20Sopenharmony_ci if (ql2xtgt_tape_enable) 68768c2ecf20Sopenharmony_ci /* Enable FC Tape support */ 68778c2ecf20Sopenharmony_ci nv->firmware_options_2 |= cpu_to_le32(BIT_12); 68788c2ecf20Sopenharmony_ci else 68798c2ecf20Sopenharmony_ci /* Disable FC Tape support */ 68808c2ecf20Sopenharmony_ci nv->firmware_options_2 &= cpu_to_le32(~BIT_12); 68818c2ecf20Sopenharmony_ci 68828c2ecf20Sopenharmony_ci /* Disable Full Login after LIP */ 68838c2ecf20Sopenharmony_ci nv->host_p &= cpu_to_le32(~BIT_10); 68848c2ecf20Sopenharmony_ci 68858c2ecf20Sopenharmony_ci /* 68868c2ecf20Sopenharmony_ci * clear BIT 15 explicitly as we have seen at least 68878c2ecf20Sopenharmony_ci * a couple of instances where this was set and this 68888c2ecf20Sopenharmony_ci * was causing the firmware to not be initialized. 68898c2ecf20Sopenharmony_ci */ 68908c2ecf20Sopenharmony_ci nv->firmware_options_1 &= cpu_to_le32(~BIT_15); 68918c2ecf20Sopenharmony_ci /* Enable target PRLI control */ 68928c2ecf20Sopenharmony_ci nv->firmware_options_2 |= cpu_to_le32(BIT_14); 68938c2ecf20Sopenharmony_ci 68948c2ecf20Sopenharmony_ci if (IS_QLA25XX(ha)) { 68958c2ecf20Sopenharmony_ci /* Change Loop-prefer to Pt-Pt */ 68968c2ecf20Sopenharmony_ci tmp = ~(BIT_4|BIT_5|BIT_6); 68978c2ecf20Sopenharmony_ci nv->firmware_options_2 &= cpu_to_le32(tmp); 68988c2ecf20Sopenharmony_ci tmp = P2P << 4; 68998c2ecf20Sopenharmony_ci nv->firmware_options_2 |= cpu_to_le32(tmp); 69008c2ecf20Sopenharmony_ci } 69018c2ecf20Sopenharmony_ci } else { 69028c2ecf20Sopenharmony_ci if (ha->tgt.saved_set) { 69038c2ecf20Sopenharmony_ci nv->exchange_count = ha->tgt.saved_exchange_count; 69048c2ecf20Sopenharmony_ci nv->firmware_options_1 = 69058c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_1; 69068c2ecf20Sopenharmony_ci nv->firmware_options_2 = 69078c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_2; 69088c2ecf20Sopenharmony_ci nv->firmware_options_3 = 69098c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_3; 69108c2ecf20Sopenharmony_ci } 69118c2ecf20Sopenharmony_ci return; 69128c2ecf20Sopenharmony_ci } 69138c2ecf20Sopenharmony_ci 69148c2ecf20Sopenharmony_ci if (ha->base_qpair->enable_class_2) { 69158c2ecf20Sopenharmony_ci if (vha->flags.init_done) 69168c2ecf20Sopenharmony_ci fc_host_supported_classes(vha->host) = 69178c2ecf20Sopenharmony_ci FC_COS_CLASS2 | FC_COS_CLASS3; 69188c2ecf20Sopenharmony_ci 69198c2ecf20Sopenharmony_ci nv->firmware_options_2 |= cpu_to_le32(BIT_8); 69208c2ecf20Sopenharmony_ci } else { 69218c2ecf20Sopenharmony_ci if (vha->flags.init_done) 69228c2ecf20Sopenharmony_ci fc_host_supported_classes(vha->host) = FC_COS_CLASS3; 69238c2ecf20Sopenharmony_ci 69248c2ecf20Sopenharmony_ci nv->firmware_options_2 &= ~cpu_to_le32(BIT_8); 69258c2ecf20Sopenharmony_ci } 69268c2ecf20Sopenharmony_ci} 69278c2ecf20Sopenharmony_ci 69288c2ecf20Sopenharmony_civoid 69298c2ecf20Sopenharmony_ciqlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha, 69308c2ecf20Sopenharmony_ci struct init_cb_24xx *icb) 69318c2ecf20Sopenharmony_ci{ 69328c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 69338c2ecf20Sopenharmony_ci 69348c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 69358c2ecf20Sopenharmony_ci return; 69368c2ecf20Sopenharmony_ci 69378c2ecf20Sopenharmony_ci if (ha->tgt.node_name_set) { 69388c2ecf20Sopenharmony_ci memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE); 69398c2ecf20Sopenharmony_ci icb->firmware_options_1 |= cpu_to_le32(BIT_14); 69408c2ecf20Sopenharmony_ci } 69418c2ecf20Sopenharmony_ci} 69428c2ecf20Sopenharmony_ci 69438c2ecf20Sopenharmony_civoid 69448c2ecf20Sopenharmony_ciqlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv) 69458c2ecf20Sopenharmony_ci{ 69468c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 69478c2ecf20Sopenharmony_ci u32 tmp; 69488c2ecf20Sopenharmony_ci 69498c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 69508c2ecf20Sopenharmony_ci return; 69518c2ecf20Sopenharmony_ci 69528c2ecf20Sopenharmony_ci if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) { 69538c2ecf20Sopenharmony_ci if (!ha->tgt.saved_set) { 69548c2ecf20Sopenharmony_ci /* We save only once */ 69558c2ecf20Sopenharmony_ci ha->tgt.saved_exchange_count = nv->exchange_count; 69568c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_1 = 69578c2ecf20Sopenharmony_ci nv->firmware_options_1; 69588c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_2 = 69598c2ecf20Sopenharmony_ci nv->firmware_options_2; 69608c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_3 = 69618c2ecf20Sopenharmony_ci nv->firmware_options_3; 69628c2ecf20Sopenharmony_ci ha->tgt.saved_set = 1; 69638c2ecf20Sopenharmony_ci } 69648c2ecf20Sopenharmony_ci 69658c2ecf20Sopenharmony_ci if (qla_tgt_mode_enabled(vha)) 69668c2ecf20Sopenharmony_ci nv->exchange_count = cpu_to_le16(0xFFFF); 69678c2ecf20Sopenharmony_ci else /* dual */ 69688c2ecf20Sopenharmony_ci nv->exchange_count = cpu_to_le16(vha->ql2xexchoffld); 69698c2ecf20Sopenharmony_ci 69708c2ecf20Sopenharmony_ci /* Enable target mode */ 69718c2ecf20Sopenharmony_ci nv->firmware_options_1 |= cpu_to_le32(BIT_4); 69728c2ecf20Sopenharmony_ci 69738c2ecf20Sopenharmony_ci /* Disable ini mode, if requested */ 69748c2ecf20Sopenharmony_ci if (qla_tgt_mode_enabled(vha)) 69758c2ecf20Sopenharmony_ci nv->firmware_options_1 |= cpu_to_le32(BIT_5); 69768c2ecf20Sopenharmony_ci /* Disable Full Login after LIP */ 69778c2ecf20Sopenharmony_ci nv->firmware_options_1 &= cpu_to_le32(~BIT_13); 69788c2ecf20Sopenharmony_ci /* Enable initial LIP */ 69798c2ecf20Sopenharmony_ci nv->firmware_options_1 &= cpu_to_le32(~BIT_9); 69808c2ecf20Sopenharmony_ci /* 69818c2ecf20Sopenharmony_ci * clear BIT 15 explicitly as we have seen at 69828c2ecf20Sopenharmony_ci * least a couple of instances where this was set 69838c2ecf20Sopenharmony_ci * and this was causing the firmware to not be 69848c2ecf20Sopenharmony_ci * initialized. 69858c2ecf20Sopenharmony_ci */ 69868c2ecf20Sopenharmony_ci nv->firmware_options_1 &= cpu_to_le32(~BIT_15); 69878c2ecf20Sopenharmony_ci if (ql2xtgt_tape_enable) 69888c2ecf20Sopenharmony_ci /* Enable FC tape support */ 69898c2ecf20Sopenharmony_ci nv->firmware_options_2 |= cpu_to_le32(BIT_12); 69908c2ecf20Sopenharmony_ci else 69918c2ecf20Sopenharmony_ci /* Disable FC tape support */ 69928c2ecf20Sopenharmony_ci nv->firmware_options_2 &= cpu_to_le32(~BIT_12); 69938c2ecf20Sopenharmony_ci 69948c2ecf20Sopenharmony_ci /* Disable Full Login after LIP */ 69958c2ecf20Sopenharmony_ci nv->host_p &= cpu_to_le32(~BIT_10); 69968c2ecf20Sopenharmony_ci /* Enable target PRLI control */ 69978c2ecf20Sopenharmony_ci nv->firmware_options_2 |= cpu_to_le32(BIT_14); 69988c2ecf20Sopenharmony_ci 69998c2ecf20Sopenharmony_ci /* Change Loop-prefer to Pt-Pt */ 70008c2ecf20Sopenharmony_ci tmp = ~(BIT_4|BIT_5|BIT_6); 70018c2ecf20Sopenharmony_ci nv->firmware_options_2 &= cpu_to_le32(tmp); 70028c2ecf20Sopenharmony_ci tmp = P2P << 4; 70038c2ecf20Sopenharmony_ci nv->firmware_options_2 |= cpu_to_le32(tmp); 70048c2ecf20Sopenharmony_ci } else { 70058c2ecf20Sopenharmony_ci if (ha->tgt.saved_set) { 70068c2ecf20Sopenharmony_ci nv->exchange_count = ha->tgt.saved_exchange_count; 70078c2ecf20Sopenharmony_ci nv->firmware_options_1 = 70088c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_1; 70098c2ecf20Sopenharmony_ci nv->firmware_options_2 = 70108c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_2; 70118c2ecf20Sopenharmony_ci nv->firmware_options_3 = 70128c2ecf20Sopenharmony_ci ha->tgt.saved_firmware_options_3; 70138c2ecf20Sopenharmony_ci } 70148c2ecf20Sopenharmony_ci return; 70158c2ecf20Sopenharmony_ci } 70168c2ecf20Sopenharmony_ci 70178c2ecf20Sopenharmony_ci if (ha->base_qpair->enable_class_2) { 70188c2ecf20Sopenharmony_ci if (vha->flags.init_done) 70198c2ecf20Sopenharmony_ci fc_host_supported_classes(vha->host) = 70208c2ecf20Sopenharmony_ci FC_COS_CLASS2 | FC_COS_CLASS3; 70218c2ecf20Sopenharmony_ci 70228c2ecf20Sopenharmony_ci nv->firmware_options_2 |= cpu_to_le32(BIT_8); 70238c2ecf20Sopenharmony_ci } else { 70248c2ecf20Sopenharmony_ci if (vha->flags.init_done) 70258c2ecf20Sopenharmony_ci fc_host_supported_classes(vha->host) = FC_COS_CLASS3; 70268c2ecf20Sopenharmony_ci 70278c2ecf20Sopenharmony_ci nv->firmware_options_2 &= ~cpu_to_le32(BIT_8); 70288c2ecf20Sopenharmony_ci } 70298c2ecf20Sopenharmony_ci} 70308c2ecf20Sopenharmony_ci 70318c2ecf20Sopenharmony_civoid 70328c2ecf20Sopenharmony_ciqlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha, 70338c2ecf20Sopenharmony_ci struct init_cb_81xx *icb) 70348c2ecf20Sopenharmony_ci{ 70358c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 70368c2ecf20Sopenharmony_ci 70378c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 70388c2ecf20Sopenharmony_ci return; 70398c2ecf20Sopenharmony_ci 70408c2ecf20Sopenharmony_ci if (ha->tgt.node_name_set) { 70418c2ecf20Sopenharmony_ci memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE); 70428c2ecf20Sopenharmony_ci icb->firmware_options_1 |= cpu_to_le32(BIT_14); 70438c2ecf20Sopenharmony_ci } 70448c2ecf20Sopenharmony_ci} 70458c2ecf20Sopenharmony_ci 70468c2ecf20Sopenharmony_civoid 70478c2ecf20Sopenharmony_ciqlt_83xx_iospace_config(struct qla_hw_data *ha) 70488c2ecf20Sopenharmony_ci{ 70498c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 70508c2ecf20Sopenharmony_ci return; 70518c2ecf20Sopenharmony_ci 70528c2ecf20Sopenharmony_ci ha->msix_count += 1; /* For ATIO Q */ 70538c2ecf20Sopenharmony_ci} 70548c2ecf20Sopenharmony_ci 70558c2ecf20Sopenharmony_ci 70568c2ecf20Sopenharmony_civoid 70578c2ecf20Sopenharmony_ciqlt_modify_vp_config(struct scsi_qla_host *vha, 70588c2ecf20Sopenharmony_ci struct vp_config_entry_24xx *vpmod) 70598c2ecf20Sopenharmony_ci{ 70608c2ecf20Sopenharmony_ci /* enable target mode. Bit5 = 1 => disable */ 70618c2ecf20Sopenharmony_ci if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) 70628c2ecf20Sopenharmony_ci vpmod->options_idx1 &= ~BIT_5; 70638c2ecf20Sopenharmony_ci 70648c2ecf20Sopenharmony_ci /* Disable ini mode, if requested. bit4 = 1 => disable */ 70658c2ecf20Sopenharmony_ci if (qla_tgt_mode_enabled(vha)) 70668c2ecf20Sopenharmony_ci vpmod->options_idx1 &= ~BIT_4; 70678c2ecf20Sopenharmony_ci} 70688c2ecf20Sopenharmony_ci 70698c2ecf20Sopenharmony_civoid 70708c2ecf20Sopenharmony_ciqlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha) 70718c2ecf20Sopenharmony_ci{ 70728c2ecf20Sopenharmony_ci int rc; 70738c2ecf20Sopenharmony_ci 70748c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 70758c2ecf20Sopenharmony_ci return; 70768c2ecf20Sopenharmony_ci 70778c2ecf20Sopenharmony_ci if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { 70788c2ecf20Sopenharmony_ci ISP_ATIO_Q_IN(base_vha) = &ha->mqiobase->isp25mq.atio_q_in; 70798c2ecf20Sopenharmony_ci ISP_ATIO_Q_OUT(base_vha) = &ha->mqiobase->isp25mq.atio_q_out; 70808c2ecf20Sopenharmony_ci } else { 70818c2ecf20Sopenharmony_ci ISP_ATIO_Q_IN(base_vha) = &ha->iobase->isp24.atio_q_in; 70828c2ecf20Sopenharmony_ci ISP_ATIO_Q_OUT(base_vha) = &ha->iobase->isp24.atio_q_out; 70838c2ecf20Sopenharmony_ci } 70848c2ecf20Sopenharmony_ci 70858c2ecf20Sopenharmony_ci mutex_init(&base_vha->vha_tgt.tgt_mutex); 70868c2ecf20Sopenharmony_ci mutex_init(&base_vha->vha_tgt.tgt_host_action_mutex); 70878c2ecf20Sopenharmony_ci 70888c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&base_vha->unknown_atio_list); 70898c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&base_vha->unknown_atio_work, 70908c2ecf20Sopenharmony_ci qlt_unknown_atio_work_fn); 70918c2ecf20Sopenharmony_ci 70928c2ecf20Sopenharmony_ci qlt_clear_mode(base_vha); 70938c2ecf20Sopenharmony_ci 70948c2ecf20Sopenharmony_ci rc = btree_init32(&ha->tgt.host_map); 70958c2ecf20Sopenharmony_ci if (rc) 70968c2ecf20Sopenharmony_ci ql_log(ql_log_info, base_vha, 0xd03d, 70978c2ecf20Sopenharmony_ci "Unable to initialize ha->host_map btree\n"); 70988c2ecf20Sopenharmony_ci 70998c2ecf20Sopenharmony_ci qlt_update_vp_map(base_vha, SET_VP_IDX); 71008c2ecf20Sopenharmony_ci} 71018c2ecf20Sopenharmony_ci 71028c2ecf20Sopenharmony_ciirqreturn_t 71038c2ecf20Sopenharmony_ciqla83xx_msix_atio_q(int irq, void *dev_id) 71048c2ecf20Sopenharmony_ci{ 71058c2ecf20Sopenharmony_ci struct rsp_que *rsp; 71068c2ecf20Sopenharmony_ci scsi_qla_host_t *vha; 71078c2ecf20Sopenharmony_ci struct qla_hw_data *ha; 71088c2ecf20Sopenharmony_ci unsigned long flags; 71098c2ecf20Sopenharmony_ci 71108c2ecf20Sopenharmony_ci rsp = (struct rsp_que *) dev_id; 71118c2ecf20Sopenharmony_ci ha = rsp->hw; 71128c2ecf20Sopenharmony_ci vha = pci_get_drvdata(ha->pdev); 71138c2ecf20Sopenharmony_ci 71148c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.atio_lock, flags); 71158c2ecf20Sopenharmony_ci 71168c2ecf20Sopenharmony_ci qlt_24xx_process_atio_queue(vha, 0); 71178c2ecf20Sopenharmony_ci 71188c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.atio_lock, flags); 71198c2ecf20Sopenharmony_ci 71208c2ecf20Sopenharmony_ci return IRQ_HANDLED; 71218c2ecf20Sopenharmony_ci} 71228c2ecf20Sopenharmony_ci 71238c2ecf20Sopenharmony_cistatic void 71248c2ecf20Sopenharmony_ciqlt_handle_abts_recv_work(struct work_struct *work) 71258c2ecf20Sopenharmony_ci{ 71268c2ecf20Sopenharmony_ci struct qla_tgt_sess_op *op = container_of(work, 71278c2ecf20Sopenharmony_ci struct qla_tgt_sess_op, work); 71288c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = op->vha; 71298c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 71308c2ecf20Sopenharmony_ci unsigned long flags; 71318c2ecf20Sopenharmony_ci 71328c2ecf20Sopenharmony_ci if (qla2x00_reset_active(vha) || 71338c2ecf20Sopenharmony_ci (op->chip_reset != ha->base_qpair->chip_reset)) 71348c2ecf20Sopenharmony_ci return; 71358c2ecf20Sopenharmony_ci 71368c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->tgt.atio_lock, flags); 71378c2ecf20Sopenharmony_ci qlt_24xx_process_atio_queue(vha, 0); 71388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.atio_lock, flags); 71398c2ecf20Sopenharmony_ci 71408c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 71418c2ecf20Sopenharmony_ci qlt_response_pkt_all_vps(vha, op->rsp, (response_t *)&op->atio); 71428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 71438c2ecf20Sopenharmony_ci 71448c2ecf20Sopenharmony_ci kfree(op); 71458c2ecf20Sopenharmony_ci} 71468c2ecf20Sopenharmony_ci 71478c2ecf20Sopenharmony_civoid 71488c2ecf20Sopenharmony_ciqlt_handle_abts_recv(struct scsi_qla_host *vha, struct rsp_que *rsp, 71498c2ecf20Sopenharmony_ci response_t *pkt) 71508c2ecf20Sopenharmony_ci{ 71518c2ecf20Sopenharmony_ci struct qla_tgt_sess_op *op; 71528c2ecf20Sopenharmony_ci 71538c2ecf20Sopenharmony_ci op = kzalloc(sizeof(*op), GFP_ATOMIC); 71548c2ecf20Sopenharmony_ci 71558c2ecf20Sopenharmony_ci if (!op) { 71568c2ecf20Sopenharmony_ci /* do not reach for ATIO queue here. This is best effort err 71578c2ecf20Sopenharmony_ci * recovery at this point. 71588c2ecf20Sopenharmony_ci */ 71598c2ecf20Sopenharmony_ci qlt_response_pkt_all_vps(vha, rsp, pkt); 71608c2ecf20Sopenharmony_ci return; 71618c2ecf20Sopenharmony_ci } 71628c2ecf20Sopenharmony_ci 71638c2ecf20Sopenharmony_ci memcpy(&op->atio, pkt, sizeof(*pkt)); 71648c2ecf20Sopenharmony_ci op->vha = vha; 71658c2ecf20Sopenharmony_ci op->chip_reset = vha->hw->base_qpair->chip_reset; 71668c2ecf20Sopenharmony_ci op->rsp = rsp; 71678c2ecf20Sopenharmony_ci INIT_WORK(&op->work, qlt_handle_abts_recv_work); 71688c2ecf20Sopenharmony_ci queue_work(qla_tgt_wq, &op->work); 71698c2ecf20Sopenharmony_ci return; 71708c2ecf20Sopenharmony_ci} 71718c2ecf20Sopenharmony_ci 71728c2ecf20Sopenharmony_ciint 71738c2ecf20Sopenharmony_ciqlt_mem_alloc(struct qla_hw_data *ha) 71748c2ecf20Sopenharmony_ci{ 71758c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 71768c2ecf20Sopenharmony_ci return 0; 71778c2ecf20Sopenharmony_ci 71788c2ecf20Sopenharmony_ci ha->tgt.tgt_vp_map = kcalloc(MAX_MULTI_ID_FABRIC, 71798c2ecf20Sopenharmony_ci sizeof(struct qla_tgt_vp_map), 71808c2ecf20Sopenharmony_ci GFP_KERNEL); 71818c2ecf20Sopenharmony_ci if (!ha->tgt.tgt_vp_map) 71828c2ecf20Sopenharmony_ci return -ENOMEM; 71838c2ecf20Sopenharmony_ci 71848c2ecf20Sopenharmony_ci ha->tgt.atio_ring = dma_alloc_coherent(&ha->pdev->dev, 71858c2ecf20Sopenharmony_ci (ha->tgt.atio_q_length + 1) * sizeof(struct atio_from_isp), 71868c2ecf20Sopenharmony_ci &ha->tgt.atio_dma, GFP_KERNEL); 71878c2ecf20Sopenharmony_ci if (!ha->tgt.atio_ring) { 71888c2ecf20Sopenharmony_ci kfree(ha->tgt.tgt_vp_map); 71898c2ecf20Sopenharmony_ci return -ENOMEM; 71908c2ecf20Sopenharmony_ci } 71918c2ecf20Sopenharmony_ci return 0; 71928c2ecf20Sopenharmony_ci} 71938c2ecf20Sopenharmony_ci 71948c2ecf20Sopenharmony_civoid 71958c2ecf20Sopenharmony_ciqlt_mem_free(struct qla_hw_data *ha) 71968c2ecf20Sopenharmony_ci{ 71978c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 71988c2ecf20Sopenharmony_ci return; 71998c2ecf20Sopenharmony_ci 72008c2ecf20Sopenharmony_ci if (ha->tgt.atio_ring) { 72018c2ecf20Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, (ha->tgt.atio_q_length + 1) * 72028c2ecf20Sopenharmony_ci sizeof(struct atio_from_isp), ha->tgt.atio_ring, 72038c2ecf20Sopenharmony_ci ha->tgt.atio_dma); 72048c2ecf20Sopenharmony_ci } 72058c2ecf20Sopenharmony_ci ha->tgt.atio_ring = NULL; 72068c2ecf20Sopenharmony_ci ha->tgt.atio_dma = 0; 72078c2ecf20Sopenharmony_ci kfree(ha->tgt.tgt_vp_map); 72088c2ecf20Sopenharmony_ci ha->tgt.tgt_vp_map = NULL; 72098c2ecf20Sopenharmony_ci} 72108c2ecf20Sopenharmony_ci 72118c2ecf20Sopenharmony_ci/* vport_slock to be held by the caller */ 72128c2ecf20Sopenharmony_civoid 72138c2ecf20Sopenharmony_ciqlt_update_vp_map(struct scsi_qla_host *vha, int cmd) 72148c2ecf20Sopenharmony_ci{ 72158c2ecf20Sopenharmony_ci void *slot; 72168c2ecf20Sopenharmony_ci u32 key; 72178c2ecf20Sopenharmony_ci int rc; 72188c2ecf20Sopenharmony_ci 72198c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 72208c2ecf20Sopenharmony_ci return; 72218c2ecf20Sopenharmony_ci 72228c2ecf20Sopenharmony_ci key = vha->d_id.b24; 72238c2ecf20Sopenharmony_ci 72248c2ecf20Sopenharmony_ci switch (cmd) { 72258c2ecf20Sopenharmony_ci case SET_VP_IDX: 72268c2ecf20Sopenharmony_ci vha->hw->tgt.tgt_vp_map[vha->vp_idx].vha = vha; 72278c2ecf20Sopenharmony_ci break; 72288c2ecf20Sopenharmony_ci case SET_AL_PA: 72298c2ecf20Sopenharmony_ci slot = btree_lookup32(&vha->hw->tgt.host_map, key); 72308c2ecf20Sopenharmony_ci if (!slot) { 72318c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf018, 72328c2ecf20Sopenharmony_ci "Save vha in host_map %p %06x\n", vha, key); 72338c2ecf20Sopenharmony_ci rc = btree_insert32(&vha->hw->tgt.host_map, 72348c2ecf20Sopenharmony_ci key, vha, GFP_ATOMIC); 72358c2ecf20Sopenharmony_ci if (rc) 72368c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xd03e, 72378c2ecf20Sopenharmony_ci "Unable to insert s_id into host_map: %06x\n", 72388c2ecf20Sopenharmony_ci key); 72398c2ecf20Sopenharmony_ci return; 72408c2ecf20Sopenharmony_ci } 72418c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf019, 72428c2ecf20Sopenharmony_ci "replace existing vha in host_map %p %06x\n", vha, key); 72438c2ecf20Sopenharmony_ci btree_update32(&vha->hw->tgt.host_map, key, vha); 72448c2ecf20Sopenharmony_ci break; 72458c2ecf20Sopenharmony_ci case RESET_VP_IDX: 72468c2ecf20Sopenharmony_ci vha->hw->tgt.tgt_vp_map[vha->vp_idx].vha = NULL; 72478c2ecf20Sopenharmony_ci break; 72488c2ecf20Sopenharmony_ci case RESET_AL_PA: 72498c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01a, 72508c2ecf20Sopenharmony_ci "clear vha in host_map %p %06x\n", vha, key); 72518c2ecf20Sopenharmony_ci slot = btree_lookup32(&vha->hw->tgt.host_map, key); 72528c2ecf20Sopenharmony_ci if (slot) 72538c2ecf20Sopenharmony_ci btree_remove32(&vha->hw->tgt.host_map, key); 72548c2ecf20Sopenharmony_ci vha->d_id.b24 = 0; 72558c2ecf20Sopenharmony_ci break; 72568c2ecf20Sopenharmony_ci } 72578c2ecf20Sopenharmony_ci} 72588c2ecf20Sopenharmony_ci 72598c2ecf20Sopenharmony_civoid qlt_update_host_map(struct scsi_qla_host *vha, port_id_t id) 72608c2ecf20Sopenharmony_ci{ 72618c2ecf20Sopenharmony_ci 72628c2ecf20Sopenharmony_ci if (!vha->d_id.b24) { 72638c2ecf20Sopenharmony_ci vha->d_id = id; 72648c2ecf20Sopenharmony_ci qlt_update_vp_map(vha, SET_AL_PA); 72658c2ecf20Sopenharmony_ci } else if (vha->d_id.b24 != id.b24) { 72668c2ecf20Sopenharmony_ci qlt_update_vp_map(vha, RESET_AL_PA); 72678c2ecf20Sopenharmony_ci vha->d_id = id; 72688c2ecf20Sopenharmony_ci qlt_update_vp_map(vha, SET_AL_PA); 72698c2ecf20Sopenharmony_ci } 72708c2ecf20Sopenharmony_ci} 72718c2ecf20Sopenharmony_ci 72728c2ecf20Sopenharmony_cistatic int __init qlt_parse_ini_mode(void) 72738c2ecf20Sopenharmony_ci{ 72748c2ecf20Sopenharmony_ci if (strcasecmp(qlini_mode, QLA2XXX_INI_MODE_STR_EXCLUSIVE) == 0) 72758c2ecf20Sopenharmony_ci ql2x_ini_mode = QLA2XXX_INI_MODE_EXCLUSIVE; 72768c2ecf20Sopenharmony_ci else if (strcasecmp(qlini_mode, QLA2XXX_INI_MODE_STR_DISABLED) == 0) 72778c2ecf20Sopenharmony_ci ql2x_ini_mode = QLA2XXX_INI_MODE_DISABLED; 72788c2ecf20Sopenharmony_ci else if (strcasecmp(qlini_mode, QLA2XXX_INI_MODE_STR_ENABLED) == 0) 72798c2ecf20Sopenharmony_ci ql2x_ini_mode = QLA2XXX_INI_MODE_ENABLED; 72808c2ecf20Sopenharmony_ci else if (strcasecmp(qlini_mode, QLA2XXX_INI_MODE_STR_DUAL) == 0) 72818c2ecf20Sopenharmony_ci ql2x_ini_mode = QLA2XXX_INI_MODE_DUAL; 72828c2ecf20Sopenharmony_ci else 72838c2ecf20Sopenharmony_ci return false; 72848c2ecf20Sopenharmony_ci 72858c2ecf20Sopenharmony_ci return true; 72868c2ecf20Sopenharmony_ci} 72878c2ecf20Sopenharmony_ci 72888c2ecf20Sopenharmony_ciint __init qlt_init(void) 72898c2ecf20Sopenharmony_ci{ 72908c2ecf20Sopenharmony_ci int ret; 72918c2ecf20Sopenharmony_ci 72928c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ctio7_to_24xx) != 64); 72938c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ctio_to_2xxx) != 64); 72948c2ecf20Sopenharmony_ci 72958c2ecf20Sopenharmony_ci if (!qlt_parse_ini_mode()) { 72968c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0xe06b, 72978c2ecf20Sopenharmony_ci "qlt_parse_ini_mode() failed\n"); 72988c2ecf20Sopenharmony_ci return -EINVAL; 72998c2ecf20Sopenharmony_ci } 73008c2ecf20Sopenharmony_ci 73018c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 73028c2ecf20Sopenharmony_ci return 0; 73038c2ecf20Sopenharmony_ci 73048c2ecf20Sopenharmony_ci qla_tgt_mgmt_cmd_cachep = kmem_cache_create("qla_tgt_mgmt_cmd_cachep", 73058c2ecf20Sopenharmony_ci sizeof(struct qla_tgt_mgmt_cmd), __alignof__(struct 73068c2ecf20Sopenharmony_ci qla_tgt_mgmt_cmd), 0, NULL); 73078c2ecf20Sopenharmony_ci if (!qla_tgt_mgmt_cmd_cachep) { 73088c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0xd04b, 73098c2ecf20Sopenharmony_ci "kmem_cache_create for qla_tgt_mgmt_cmd_cachep failed\n"); 73108c2ecf20Sopenharmony_ci return -ENOMEM; 73118c2ecf20Sopenharmony_ci } 73128c2ecf20Sopenharmony_ci 73138c2ecf20Sopenharmony_ci qla_tgt_plogi_cachep = kmem_cache_create("qla_tgt_plogi_cachep", 73148c2ecf20Sopenharmony_ci sizeof(struct qlt_plogi_ack_t), __alignof__(struct qlt_plogi_ack_t), 73158c2ecf20Sopenharmony_ci 0, NULL); 73168c2ecf20Sopenharmony_ci 73178c2ecf20Sopenharmony_ci if (!qla_tgt_plogi_cachep) { 73188c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0xe06d, 73198c2ecf20Sopenharmony_ci "kmem_cache_create for qla_tgt_plogi_cachep failed\n"); 73208c2ecf20Sopenharmony_ci ret = -ENOMEM; 73218c2ecf20Sopenharmony_ci goto out_mgmt_cmd_cachep; 73228c2ecf20Sopenharmony_ci } 73238c2ecf20Sopenharmony_ci 73248c2ecf20Sopenharmony_ci qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab, 73258c2ecf20Sopenharmony_ci mempool_free_slab, qla_tgt_mgmt_cmd_cachep); 73268c2ecf20Sopenharmony_ci if (!qla_tgt_mgmt_cmd_mempool) { 73278c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0xe06e, 73288c2ecf20Sopenharmony_ci "mempool_create for qla_tgt_mgmt_cmd_mempool failed\n"); 73298c2ecf20Sopenharmony_ci ret = -ENOMEM; 73308c2ecf20Sopenharmony_ci goto out_plogi_cachep; 73318c2ecf20Sopenharmony_ci } 73328c2ecf20Sopenharmony_ci 73338c2ecf20Sopenharmony_ci qla_tgt_wq = alloc_workqueue("qla_tgt_wq", 0, 0); 73348c2ecf20Sopenharmony_ci if (!qla_tgt_wq) { 73358c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0xe06f, 73368c2ecf20Sopenharmony_ci "alloc_workqueue for qla_tgt_wq failed\n"); 73378c2ecf20Sopenharmony_ci ret = -ENOMEM; 73388c2ecf20Sopenharmony_ci goto out_cmd_mempool; 73398c2ecf20Sopenharmony_ci } 73408c2ecf20Sopenharmony_ci /* 73418c2ecf20Sopenharmony_ci * Return 1 to signal that initiator-mode is being disabled 73428c2ecf20Sopenharmony_ci */ 73438c2ecf20Sopenharmony_ci return (ql2x_ini_mode == QLA2XXX_INI_MODE_DISABLED) ? 1 : 0; 73448c2ecf20Sopenharmony_ci 73458c2ecf20Sopenharmony_ciout_cmd_mempool: 73468c2ecf20Sopenharmony_ci mempool_destroy(qla_tgt_mgmt_cmd_mempool); 73478c2ecf20Sopenharmony_ciout_plogi_cachep: 73488c2ecf20Sopenharmony_ci kmem_cache_destroy(qla_tgt_plogi_cachep); 73498c2ecf20Sopenharmony_ciout_mgmt_cmd_cachep: 73508c2ecf20Sopenharmony_ci kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); 73518c2ecf20Sopenharmony_ci return ret; 73528c2ecf20Sopenharmony_ci} 73538c2ecf20Sopenharmony_ci 73548c2ecf20Sopenharmony_civoid qlt_exit(void) 73558c2ecf20Sopenharmony_ci{ 73568c2ecf20Sopenharmony_ci if (!QLA_TGT_MODE_ENABLED()) 73578c2ecf20Sopenharmony_ci return; 73588c2ecf20Sopenharmony_ci 73598c2ecf20Sopenharmony_ci destroy_workqueue(qla_tgt_wq); 73608c2ecf20Sopenharmony_ci mempool_destroy(qla_tgt_mgmt_cmd_mempool); 73618c2ecf20Sopenharmony_ci kmem_cache_destroy(qla_tgt_plogi_cachep); 73628c2ecf20Sopenharmony_ci kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); 73638c2ecf20Sopenharmony_ci} 7364