162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// Copyright 2014 Cisco Systems, Inc. All rights reserved. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/errno.h> 562306a36Sopenharmony_ci#include <linux/pci.h> 662306a36Sopenharmony_ci#include <linux/slab.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/interrupt.h> 962306a36Sopenharmony_ci#include <linux/workqueue.h> 1062306a36Sopenharmony_ci#include <linux/spinlock.h> 1162306a36Sopenharmony_ci#include <linux/mempool.h> 1262306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "snic_io.h" 1562306a36Sopenharmony_ci#include "snic.h" 1662306a36Sopenharmony_ci#include "cq_enet_desc.h" 1762306a36Sopenharmony_ci#include "snic_fwint.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic void 2062306a36Sopenharmony_cisnic_wq_cmpl_frame_send(struct vnic_wq *wq, 2162306a36Sopenharmony_ci struct cq_desc *cq_desc, 2262306a36Sopenharmony_ci struct vnic_wq_buf *buf, 2362306a36Sopenharmony_ci void *opaque) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct snic *snic = svnic_dev_priv(wq->vdev); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci SNIC_BUG_ON(buf->os_buf == NULL); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (snic_log_level & SNIC_DESC_LOGGING) 3062306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, 3162306a36Sopenharmony_ci "Ack received for snic_host_req %p.\n", 3262306a36Sopenharmony_ci buf->os_buf); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci SNIC_TRC(snic->shost->host_no, 0, 0, 3562306a36Sopenharmony_ci ((ulong)(buf->os_buf) - sizeof(struct snic_req_info)), 0, 0, 3662306a36Sopenharmony_ci 0); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci buf->os_buf = NULL; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int 4262306a36Sopenharmony_cisnic_wq_cmpl_handler_cont(struct vnic_dev *vdev, 4362306a36Sopenharmony_ci struct cq_desc *cq_desc, 4462306a36Sopenharmony_ci u8 type, 4562306a36Sopenharmony_ci u16 q_num, 4662306a36Sopenharmony_ci u16 cmpl_idx, 4762306a36Sopenharmony_ci void *opaque) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct snic *snic = svnic_dev_priv(vdev); 5062306a36Sopenharmony_ci unsigned long flags; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci SNIC_BUG_ON(q_num != 0); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci spin_lock_irqsave(&snic->wq_lock[q_num], flags); 5562306a36Sopenharmony_ci svnic_wq_service(&snic->wq[q_num], 5662306a36Sopenharmony_ci cq_desc, 5762306a36Sopenharmony_ci cmpl_idx, 5862306a36Sopenharmony_ci snic_wq_cmpl_frame_send, 5962306a36Sopenharmony_ci NULL); 6062306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->wq_lock[q_num], flags); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return 0; 6362306a36Sopenharmony_ci} /* end of snic_cmpl_handler_cont */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciint 6662306a36Sopenharmony_cisnic_wq_cmpl_handler(struct snic *snic, int work_to_do) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci unsigned int work_done = 0; 6962306a36Sopenharmony_ci unsigned int i; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci snic->s_stats.misc.last_ack_time = jiffies; 7262306a36Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) { 7362306a36Sopenharmony_ci work_done += svnic_cq_service(&snic->cq[i], 7462306a36Sopenharmony_ci work_to_do, 7562306a36Sopenharmony_ci snic_wq_cmpl_handler_cont, 7662306a36Sopenharmony_ci NULL); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return work_done; 8062306a36Sopenharmony_ci} /* end of snic_wq_cmpl_handler */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_civoid 8362306a36Sopenharmony_cisnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci struct snic_host_req *req = buf->os_buf; 8762306a36Sopenharmony_ci struct snic *snic = svnic_dev_priv(wq->vdev); 8862306a36Sopenharmony_ci struct snic_req_info *rqi = NULL; 8962306a36Sopenharmony_ci unsigned long flags; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, buf->dma_addr, buf->len, 9262306a36Sopenharmony_ci DMA_TO_DEVICE); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci rqi = req_to_rqi(req); 9562306a36Sopenharmony_ci spin_lock_irqsave(&snic->spl_cmd_lock, flags); 9662306a36Sopenharmony_ci if (list_empty(&rqi->list)) { 9762306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 9862306a36Sopenharmony_ci goto end; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci SNIC_BUG_ON(rqi->list.next == NULL); /* if not added to spl_cmd_list */ 10262306a36Sopenharmony_ci list_del_init(&rqi->list); 10362306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (rqi->sge_va) { 10662306a36Sopenharmony_ci snic_pci_unmap_rsp_buf(snic, rqi); 10762306a36Sopenharmony_ci kfree((void *)rqi->sge_va); 10862306a36Sopenharmony_ci rqi->sge_va = 0; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci snic_req_free(snic, rqi); 11162306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "snic_free_wq_buf .. freed.\n"); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciend: 11462306a36Sopenharmony_ci return; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* Criteria to select work queue in multi queue mode */ 11862306a36Sopenharmony_cistatic int 11962306a36Sopenharmony_cisnic_select_wq(struct snic *snic) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci /* No multi queue support for now */ 12262306a36Sopenharmony_ci BUILD_BUG_ON(SNIC_WQ_MAX > 1); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return 0; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int 12862306a36Sopenharmony_cisnic_wqdesc_avail(struct snic *snic, int q_num, int req_type) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci int nr_wqdesc = snic->config.wq_enet_desc_count; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (q_num > 0) { 13362306a36Sopenharmony_ci /* 13462306a36Sopenharmony_ci * Multi Queue case, additional care is required. 13562306a36Sopenharmony_ci * Per WQ active requests need to be maintained. 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "desc_avail: Multi Queue case.\n"); 13862306a36Sopenharmony_ci SNIC_BUG_ON(q_num > 0); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return -1; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci nr_wqdesc -= atomic64_read(&snic->s_stats.fw.actv_reqs); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return ((req_type == SNIC_REQ_HBA_RESET) ? nr_wqdesc : nr_wqdesc - 1); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ciint 14962306a36Sopenharmony_cisnic_queue_wq_desc(struct snic *snic, void *os_buf, u16 len) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci dma_addr_t pa = 0; 15262306a36Sopenharmony_ci unsigned long flags; 15362306a36Sopenharmony_ci struct snic_fw_stats *fwstats = &snic->s_stats.fw; 15462306a36Sopenharmony_ci struct snic_host_req *req = (struct snic_host_req *) os_buf; 15562306a36Sopenharmony_ci long act_reqs; 15662306a36Sopenharmony_ci long desc_avail = 0; 15762306a36Sopenharmony_ci int q_num = 0; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci snic_print_desc(__func__, os_buf, len); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Map request buffer */ 16262306a36Sopenharmony_ci pa = dma_map_single(&snic->pdev->dev, os_buf, len, DMA_TO_DEVICE); 16362306a36Sopenharmony_ci if (dma_mapping_error(&snic->pdev->dev, pa)) { 16462306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "qdesc: PCI DMA Mapping Fail.\n"); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return -ENOMEM; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci req->req_pa = (ulong)pa; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci q_num = snic_select_wq(snic); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci spin_lock_irqsave(&snic->wq_lock[q_num], flags); 17462306a36Sopenharmony_ci desc_avail = snic_wqdesc_avail(snic, q_num, req->hdr.type); 17562306a36Sopenharmony_ci if (desc_avail <= 0) { 17662306a36Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, pa, len, DMA_TO_DEVICE); 17762306a36Sopenharmony_ci req->req_pa = 0; 17862306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->wq_lock[q_num], flags); 17962306a36Sopenharmony_ci atomic64_inc(&snic->s_stats.misc.wq_alloc_fail); 18062306a36Sopenharmony_ci SNIC_DBG("host = %d, WQ is Full\n", snic->shost->host_no); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return -ENOMEM; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci snic_queue_wq_eth_desc(&snic->wq[q_num], os_buf, pa, len, 0, 0, 1); 18662306a36Sopenharmony_ci /* 18762306a36Sopenharmony_ci * Update stats 18862306a36Sopenharmony_ci * note: when multi queue enabled, fw actv_reqs should be per queue. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ci act_reqs = atomic64_inc_return(&fwstats->actv_reqs); 19162306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->wq_lock[q_num], flags); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (act_reqs > atomic64_read(&fwstats->max_actv_reqs)) 19462306a36Sopenharmony_ci atomic64_set(&fwstats->max_actv_reqs, act_reqs); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} /* end of snic_queue_wq_desc() */ 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* 20062306a36Sopenharmony_ci * snic_handle_untagged_req: Adds snic specific requests to spl_cmd_list. 20162306a36Sopenharmony_ci * Purpose : Used during driver unload to clean up the requests. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_civoid 20462306a36Sopenharmony_cisnic_handle_untagged_req(struct snic *snic, struct snic_req_info *rqi) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci unsigned long flags; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci INIT_LIST_HEAD(&rqi->list); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci spin_lock_irqsave(&snic->spl_cmd_lock, flags); 21162306a36Sopenharmony_ci list_add_tail(&rqi->list, &snic->spl_cmd_list); 21262306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci/* 21662306a36Sopenharmony_ci * snic_req_init: 21762306a36Sopenharmony_ci * Allocates snic_req_info + snic_host_req + sgl data, and initializes. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_cistruct snic_req_info * 22062306a36Sopenharmony_cisnic_req_init(struct snic *snic, int sg_cnt) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci u8 typ; 22362306a36Sopenharmony_ci struct snic_req_info *rqi = NULL; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci typ = (sg_cnt <= SNIC_REQ_CACHE_DFLT_SGL) ? 22662306a36Sopenharmony_ci SNIC_REQ_CACHE_DFLT_SGL : SNIC_REQ_CACHE_MAX_SGL; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci rqi = mempool_alloc(snic->req_pool[typ], GFP_ATOMIC); 22962306a36Sopenharmony_ci if (!rqi) { 23062306a36Sopenharmony_ci atomic64_inc(&snic->s_stats.io.alloc_fail); 23162306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 23262306a36Sopenharmony_ci "Failed to allocate memory from snic req pool id = %d\n", 23362306a36Sopenharmony_ci typ); 23462306a36Sopenharmony_ci return rqi; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci memset(rqi, 0, sizeof(*rqi)); 23862306a36Sopenharmony_ci rqi->rq_pool_type = typ; 23962306a36Sopenharmony_ci rqi->start_time = jiffies; 24062306a36Sopenharmony_ci rqi->req = (struct snic_host_req *) (rqi + 1); 24162306a36Sopenharmony_ci rqi->req_len = sizeof(struct snic_host_req); 24262306a36Sopenharmony_ci rqi->snic = snic; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci rqi->req = (struct snic_host_req *)(rqi + 1); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (sg_cnt == 0) 24762306a36Sopenharmony_ci goto end; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci rqi->req_len += (sg_cnt * sizeof(struct snic_sg_desc)); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (sg_cnt > atomic64_read(&snic->s_stats.io.max_sgl)) 25262306a36Sopenharmony_ci atomic64_set(&snic->s_stats.io.max_sgl, sg_cnt); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci SNIC_BUG_ON(sg_cnt > SNIC_MAX_SG_DESC_CNT); 25562306a36Sopenharmony_ci atomic64_inc(&snic->s_stats.io.sgl_cnt[sg_cnt - 1]); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ciend: 25862306a36Sopenharmony_ci memset(rqi->req, 0, rqi->req_len); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* pre initialization of init_ctx to support req_to_rqi */ 26162306a36Sopenharmony_ci rqi->req->hdr.init_ctx = (ulong) rqi; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "Req_alloc:rqi = %p allocatd.\n", rqi); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return rqi; 26662306a36Sopenharmony_ci} /* end of snic_req_init */ 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/* 26962306a36Sopenharmony_ci * snic_abort_req_init : Inits abort request. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_cistruct snic_host_req * 27262306a36Sopenharmony_cisnic_abort_req_init(struct snic *snic, struct snic_req_info *rqi) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct snic_host_req *req = NULL; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci SNIC_BUG_ON(!rqi); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* If abort to be issued second time, then reuse */ 27962306a36Sopenharmony_ci if (rqi->abort_req) 28062306a36Sopenharmony_ci return rqi->abort_req; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci req = mempool_alloc(snic->req_pool[SNIC_REQ_TM_CACHE], GFP_ATOMIC); 28462306a36Sopenharmony_ci if (!req) { 28562306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "abts:Failed to alloc tm req.\n"); 28662306a36Sopenharmony_ci WARN_ON_ONCE(1); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return NULL; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci rqi->abort_req = req; 29262306a36Sopenharmony_ci memset(req, 0, sizeof(struct snic_host_req)); 29362306a36Sopenharmony_ci /* pre initialization of init_ctx to support req_to_rqi */ 29462306a36Sopenharmony_ci req->hdr.init_ctx = (ulong) rqi; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return req; 29762306a36Sopenharmony_ci} /* end of snic_abort_req_init */ 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/* 30062306a36Sopenharmony_ci * snic_dr_req_init : Inits device reset req 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_cistruct snic_host_req * 30362306a36Sopenharmony_cisnic_dr_req_init(struct snic *snic, struct snic_req_info *rqi) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct snic_host_req *req = NULL; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci SNIC_BUG_ON(!rqi); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci req = mempool_alloc(snic->req_pool[SNIC_REQ_TM_CACHE], GFP_ATOMIC); 31062306a36Sopenharmony_ci if (!req) { 31162306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "dr:Failed to alloc tm req.\n"); 31262306a36Sopenharmony_ci WARN_ON_ONCE(1); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return NULL; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci SNIC_BUG_ON(rqi->dr_req != NULL); 31862306a36Sopenharmony_ci rqi->dr_req = req; 31962306a36Sopenharmony_ci memset(req, 0, sizeof(struct snic_host_req)); 32062306a36Sopenharmony_ci /* pre initialization of init_ctx to support req_to_rqi */ 32162306a36Sopenharmony_ci req->hdr.init_ctx = (ulong) rqi; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return req; 32462306a36Sopenharmony_ci} /* end of snic_dr_req_init */ 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/* frees snic_req_info and snic_host_req */ 32762306a36Sopenharmony_civoid 32862306a36Sopenharmony_cisnic_req_free(struct snic *snic, struct snic_req_info *rqi) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci SNIC_BUG_ON(rqi->req == rqi->abort_req); 33162306a36Sopenharmony_ci SNIC_BUG_ON(rqi->req == rqi->dr_req); 33262306a36Sopenharmony_ci SNIC_BUG_ON(rqi->sge_va != 0); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 33562306a36Sopenharmony_ci "Req_free:rqi %p:ioreq %p:abt %p:dr %p\n", 33662306a36Sopenharmony_ci rqi, rqi->req, rqi->abort_req, rqi->dr_req); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (rqi->abort_req) { 33962306a36Sopenharmony_ci if (rqi->abort_req->req_pa) 34062306a36Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, 34162306a36Sopenharmony_ci rqi->abort_req->req_pa, 34262306a36Sopenharmony_ci sizeof(struct snic_host_req), 34362306a36Sopenharmony_ci DMA_TO_DEVICE); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci mempool_free(rqi->abort_req, snic->req_pool[SNIC_REQ_TM_CACHE]); 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (rqi->dr_req) { 34962306a36Sopenharmony_ci if (rqi->dr_req->req_pa) 35062306a36Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, 35162306a36Sopenharmony_ci rqi->dr_req->req_pa, 35262306a36Sopenharmony_ci sizeof(struct snic_host_req), 35362306a36Sopenharmony_ci DMA_TO_DEVICE); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci mempool_free(rqi->dr_req, snic->req_pool[SNIC_REQ_TM_CACHE]); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (rqi->req->req_pa) 35962306a36Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, 36062306a36Sopenharmony_ci rqi->req->req_pa, 36162306a36Sopenharmony_ci rqi->req_len, 36262306a36Sopenharmony_ci DMA_TO_DEVICE); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci mempool_free(rqi, snic->req_pool[rqi->rq_pool_type]); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_civoid 36862306a36Sopenharmony_cisnic_pci_unmap_rsp_buf(struct snic *snic, struct snic_req_info *rqi) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct snic_sg_desc *sgd; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci sgd = req_to_sgl(rqi_to_req(rqi)); 37362306a36Sopenharmony_ci SNIC_BUG_ON(sgd[0].addr == 0); 37462306a36Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, 37562306a36Sopenharmony_ci le64_to_cpu(sgd[0].addr), 37662306a36Sopenharmony_ci le32_to_cpu(sgd[0].len), 37762306a36Sopenharmony_ci DMA_FROM_DEVICE); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci/* 38162306a36Sopenharmony_ci * snic_free_all_untagged_reqs: Walks through untagged reqs and frees them. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_civoid 38462306a36Sopenharmony_cisnic_free_all_untagged_reqs(struct snic *snic) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct snic_req_info *rqi; 38762306a36Sopenharmony_ci struct list_head *cur, *nxt; 38862306a36Sopenharmony_ci unsigned long flags; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci spin_lock_irqsave(&snic->spl_cmd_lock, flags); 39162306a36Sopenharmony_ci list_for_each_safe(cur, nxt, &snic->spl_cmd_list) { 39262306a36Sopenharmony_ci rqi = list_entry(cur, struct snic_req_info, list); 39362306a36Sopenharmony_ci list_del_init(&rqi->list); 39462306a36Sopenharmony_ci if (rqi->sge_va) { 39562306a36Sopenharmony_ci snic_pci_unmap_rsp_buf(snic, rqi); 39662306a36Sopenharmony_ci kfree((void *)rqi->sge_va); 39762306a36Sopenharmony_ci rqi->sge_va = 0; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci snic_req_free(snic, rqi); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/* 40662306a36Sopenharmony_ci * snic_release_untagged_req : Unlinks the untagged req and frees it. 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_civoid 40962306a36Sopenharmony_cisnic_release_untagged_req(struct snic *snic, struct snic_req_info *rqi) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci unsigned long flags; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci spin_lock_irqsave(&snic->snic_lock, flags); 41462306a36Sopenharmony_ci if (snic->in_remove) { 41562306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, flags); 41662306a36Sopenharmony_ci goto end; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, flags); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci spin_lock_irqsave(&snic->spl_cmd_lock, flags); 42162306a36Sopenharmony_ci if (list_empty(&rqi->list)) { 42262306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 42362306a36Sopenharmony_ci goto end; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci list_del_init(&rqi->list); 42662306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 42762306a36Sopenharmony_ci snic_req_free(snic, rqi); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ciend: 43062306a36Sopenharmony_ci return; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci/* dump buf in hex fmt */ 43462306a36Sopenharmony_civoid 43562306a36Sopenharmony_cisnic_hex_dump(char *pfx, char *data, int len) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci SNIC_INFO("%s Dumping Data of Len = %d\n", pfx, len); 43862306a36Sopenharmony_ci print_hex_dump_bytes(pfx, DUMP_PREFIX_NONE, data, len); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci#define LINE_BUFSZ 128 /* for snic_print_desc fn */ 44262306a36Sopenharmony_cistatic void 44362306a36Sopenharmony_cisnic_dump_desc(const char *fn, char *os_buf, int len) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct snic_host_req *req = (struct snic_host_req *) os_buf; 44662306a36Sopenharmony_ci struct snic_fw_req *fwreq = (struct snic_fw_req *) os_buf; 44762306a36Sopenharmony_ci struct snic_req_info *rqi = NULL; 44862306a36Sopenharmony_ci char line[LINE_BUFSZ] = { '\0' }; 44962306a36Sopenharmony_ci char *cmd_str = NULL; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (req->hdr.type >= SNIC_RSP_REPORT_TGTS_CMPL) 45262306a36Sopenharmony_ci rqi = (struct snic_req_info *) fwreq->hdr.init_ctx; 45362306a36Sopenharmony_ci else 45462306a36Sopenharmony_ci rqi = (struct snic_req_info *) req->hdr.init_ctx; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci SNIC_BUG_ON(rqi == NULL || rqi->req == NULL); 45762306a36Sopenharmony_ci switch (req->hdr.type) { 45862306a36Sopenharmony_ci case SNIC_REQ_REPORT_TGTS: 45962306a36Sopenharmony_ci cmd_str = "report-tgt : "; 46062306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_REQ_REPORT_TGTS :"); 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci case SNIC_REQ_ICMND: 46462306a36Sopenharmony_ci cmd_str = "icmnd : "; 46562306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_REQ_ICMND : 0x%x :", 46662306a36Sopenharmony_ci req->u.icmnd.cdb[0]); 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci case SNIC_REQ_ITMF: 47062306a36Sopenharmony_ci cmd_str = "itmf : "; 47162306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_REQ_ITMF :"); 47262306a36Sopenharmony_ci break; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci case SNIC_REQ_HBA_RESET: 47562306a36Sopenharmony_ci cmd_str = "hba reset :"; 47662306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_REQ_HBA_RESET :"); 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci case SNIC_REQ_EXCH_VER: 48062306a36Sopenharmony_ci cmd_str = "exch ver : "; 48162306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_REQ_EXCH_VER :"); 48262306a36Sopenharmony_ci break; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci case SNIC_REQ_TGT_INFO: 48562306a36Sopenharmony_ci cmd_str = "tgt info : "; 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci case SNIC_RSP_REPORT_TGTS_CMPL: 48962306a36Sopenharmony_ci cmd_str = "report tgt cmpl : "; 49062306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_RSP_REPORT_TGTS_CMPL :"); 49162306a36Sopenharmony_ci break; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci case SNIC_RSP_ICMND_CMPL: 49462306a36Sopenharmony_ci cmd_str = "icmnd_cmpl : "; 49562306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_RSP_ICMND_CMPL : 0x%x :", 49662306a36Sopenharmony_ci rqi->req->u.icmnd.cdb[0]); 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci case SNIC_RSP_ITMF_CMPL: 50062306a36Sopenharmony_ci cmd_str = "itmf_cmpl : "; 50162306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_RSP_ITMF_CMPL :"); 50262306a36Sopenharmony_ci break; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci case SNIC_RSP_HBA_RESET_CMPL: 50562306a36Sopenharmony_ci cmd_str = "hba_reset_cmpl : "; 50662306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_RSP_HBA_RESET_CMPL :"); 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci case SNIC_RSP_EXCH_VER_CMPL: 51062306a36Sopenharmony_ci cmd_str = "exch_ver_cmpl : "; 51162306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_RSP_EXCH_VER_CMPL :"); 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci case SNIC_MSG_ACK: 51562306a36Sopenharmony_ci cmd_str = "msg ack : "; 51662306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_MSG_ACK :"); 51762306a36Sopenharmony_ci break; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci case SNIC_MSG_ASYNC_EVNOTIFY: 52062306a36Sopenharmony_ci cmd_str = "async notify : "; 52162306a36Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_MSG_ASYNC_EVNOTIFY :"); 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci default: 52562306a36Sopenharmony_ci cmd_str = "unknown : "; 52662306a36Sopenharmony_ci SNIC_BUG_ON(1); 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci SNIC_INFO("%s:%s >>cmndid=%x:sg_cnt = %x:status = %x:ctx = %lx.\n", 53162306a36Sopenharmony_ci fn, line, req->hdr.cmnd_id, req->hdr.sg_cnt, req->hdr.status, 53262306a36Sopenharmony_ci req->hdr.init_ctx); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* Enable it, to dump byte stream */ 53562306a36Sopenharmony_ci if (snic_log_level & 0x20) 53662306a36Sopenharmony_ci snic_hex_dump(cmd_str, os_buf, len); 53762306a36Sopenharmony_ci} /* end of __snic_print_desc */ 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_civoid 54062306a36Sopenharmony_cisnic_print_desc(const char *fn, char *os_buf, int len) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci if (snic_log_level & SNIC_DESC_LOGGING) 54362306a36Sopenharmony_ci snic_dump_desc(fn, os_buf, len); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_civoid 54762306a36Sopenharmony_cisnic_calc_io_process_time(struct snic *snic, struct snic_req_info *rqi) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci u64 duration; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci duration = jiffies - rqi->start_time; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (duration > atomic64_read(&snic->s_stats.io.max_time)) 55462306a36Sopenharmony_ci atomic64_set(&snic->s_stats.io.max_time, duration); 55562306a36Sopenharmony_ci} 556