18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2014 Cisco Systems, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This program is free software; you may redistribute it and/or modify 58c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 68c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 98c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 118c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 128c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 148c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 158c2ecf20Sopenharmony_ci * SOFTWARE. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/errno.h> 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 238c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 248c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 258c2ecf20Sopenharmony_ci#include <linux/mempool.h> 268c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "snic_io.h" 298c2ecf20Sopenharmony_ci#include "snic.h" 308c2ecf20Sopenharmony_ci#include "cq_enet_desc.h" 318c2ecf20Sopenharmony_ci#include "snic_fwint.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic void 348c2ecf20Sopenharmony_cisnic_wq_cmpl_frame_send(struct vnic_wq *wq, 358c2ecf20Sopenharmony_ci struct cq_desc *cq_desc, 368c2ecf20Sopenharmony_ci struct vnic_wq_buf *buf, 378c2ecf20Sopenharmony_ci void *opaque) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct snic *snic = svnic_dev_priv(wq->vdev); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci SNIC_BUG_ON(buf->os_buf == NULL); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (snic_log_level & SNIC_DESC_LOGGING) 448c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, 458c2ecf20Sopenharmony_ci "Ack received for snic_host_req %p.\n", 468c2ecf20Sopenharmony_ci buf->os_buf); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, 0, 0, 498c2ecf20Sopenharmony_ci ((ulong)(buf->os_buf) - sizeof(struct snic_req_info)), 0, 0, 508c2ecf20Sopenharmony_ci 0); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci buf->os_buf = NULL; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int 568c2ecf20Sopenharmony_cisnic_wq_cmpl_handler_cont(struct vnic_dev *vdev, 578c2ecf20Sopenharmony_ci struct cq_desc *cq_desc, 588c2ecf20Sopenharmony_ci u8 type, 598c2ecf20Sopenharmony_ci u16 q_num, 608c2ecf20Sopenharmony_ci u16 cmpl_idx, 618c2ecf20Sopenharmony_ci void *opaque) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct snic *snic = svnic_dev_priv(vdev); 648c2ecf20Sopenharmony_ci unsigned long flags; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci SNIC_BUG_ON(q_num != 0); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci spin_lock_irqsave(&snic->wq_lock[q_num], flags); 698c2ecf20Sopenharmony_ci svnic_wq_service(&snic->wq[q_num], 708c2ecf20Sopenharmony_ci cq_desc, 718c2ecf20Sopenharmony_ci cmpl_idx, 728c2ecf20Sopenharmony_ci snic_wq_cmpl_frame_send, 738c2ecf20Sopenharmony_ci NULL); 748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->wq_lock[q_num], flags); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci} /* end of snic_cmpl_handler_cont */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciint 808c2ecf20Sopenharmony_cisnic_wq_cmpl_handler(struct snic *snic, int work_to_do) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci unsigned int work_done = 0; 838c2ecf20Sopenharmony_ci unsigned int i; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci snic->s_stats.misc.last_ack_time = jiffies; 868c2ecf20Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) { 878c2ecf20Sopenharmony_ci work_done += svnic_cq_service(&snic->cq[i], 888c2ecf20Sopenharmony_ci work_to_do, 898c2ecf20Sopenharmony_ci snic_wq_cmpl_handler_cont, 908c2ecf20Sopenharmony_ci NULL); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return work_done; 948c2ecf20Sopenharmony_ci} /* end of snic_wq_cmpl_handler */ 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_civoid 978c2ecf20Sopenharmony_cisnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci struct snic_host_req *req = buf->os_buf; 1018c2ecf20Sopenharmony_ci struct snic *snic = svnic_dev_priv(wq->vdev); 1028c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 1038c2ecf20Sopenharmony_ci unsigned long flags; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, buf->dma_addr, buf->len, 1068c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci rqi = req_to_rqi(req); 1098c2ecf20Sopenharmony_ci spin_lock_irqsave(&snic->spl_cmd_lock, flags); 1108c2ecf20Sopenharmony_ci if (list_empty(&rqi->list)) { 1118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 1128c2ecf20Sopenharmony_ci goto end; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci SNIC_BUG_ON(rqi->list.next == NULL); /* if not added to spl_cmd_list */ 1168c2ecf20Sopenharmony_ci list_del_init(&rqi->list); 1178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (rqi->sge_va) { 1208c2ecf20Sopenharmony_ci snic_pci_unmap_rsp_buf(snic, rqi); 1218c2ecf20Sopenharmony_ci kfree((void *)rqi->sge_va); 1228c2ecf20Sopenharmony_ci rqi->sge_va = 0; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci snic_req_free(snic, rqi); 1258c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "snic_free_wq_buf .. freed.\n"); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ciend: 1288c2ecf20Sopenharmony_ci return; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* Criteria to select work queue in multi queue mode */ 1328c2ecf20Sopenharmony_cistatic int 1338c2ecf20Sopenharmony_cisnic_select_wq(struct snic *snic) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci /* No multi queue support for now */ 1368c2ecf20Sopenharmony_ci BUILD_BUG_ON(SNIC_WQ_MAX > 1); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int 1428c2ecf20Sopenharmony_cisnic_wqdesc_avail(struct snic *snic, int q_num, int req_type) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci int nr_wqdesc = snic->config.wq_enet_desc_count; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (q_num > 0) { 1478c2ecf20Sopenharmony_ci /* 1488c2ecf20Sopenharmony_ci * Multi Queue case, additional care is required. 1498c2ecf20Sopenharmony_ci * Per WQ active requests need to be maintained. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "desc_avail: Multi Queue case.\n"); 1528c2ecf20Sopenharmony_ci SNIC_BUG_ON(q_num > 0); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return -1; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci nr_wqdesc -= atomic64_read(&snic->s_stats.fw.actv_reqs); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return ((req_type == SNIC_REQ_HBA_RESET) ? nr_wqdesc : nr_wqdesc - 1); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ciint 1638c2ecf20Sopenharmony_cisnic_queue_wq_desc(struct snic *snic, void *os_buf, u16 len) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci dma_addr_t pa = 0; 1668c2ecf20Sopenharmony_ci unsigned long flags; 1678c2ecf20Sopenharmony_ci struct snic_fw_stats *fwstats = &snic->s_stats.fw; 1688c2ecf20Sopenharmony_ci struct snic_host_req *req = (struct snic_host_req *) os_buf; 1698c2ecf20Sopenharmony_ci long act_reqs; 1708c2ecf20Sopenharmony_ci long desc_avail = 0; 1718c2ecf20Sopenharmony_ci int q_num = 0; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci snic_print_desc(__func__, os_buf, len); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Map request buffer */ 1768c2ecf20Sopenharmony_ci pa = dma_map_single(&snic->pdev->dev, os_buf, len, DMA_TO_DEVICE); 1778c2ecf20Sopenharmony_ci if (dma_mapping_error(&snic->pdev->dev, pa)) { 1788c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "qdesc: PCI DMA Mapping Fail.\n"); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return -ENOMEM; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci req->req_pa = (ulong)pa; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci q_num = snic_select_wq(snic); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci spin_lock_irqsave(&snic->wq_lock[q_num], flags); 1888c2ecf20Sopenharmony_ci desc_avail = snic_wqdesc_avail(snic, q_num, req->hdr.type); 1898c2ecf20Sopenharmony_ci if (desc_avail <= 0) { 1908c2ecf20Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, pa, len, DMA_TO_DEVICE); 1918c2ecf20Sopenharmony_ci req->req_pa = 0; 1928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->wq_lock[q_num], flags); 1938c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.misc.wq_alloc_fail); 1948c2ecf20Sopenharmony_ci SNIC_DBG("host = %d, WQ is Full\n", snic->shost->host_no); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return -ENOMEM; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci snic_queue_wq_eth_desc(&snic->wq[q_num], os_buf, pa, len, 0, 0, 1); 2008c2ecf20Sopenharmony_ci /* 2018c2ecf20Sopenharmony_ci * Update stats 2028c2ecf20Sopenharmony_ci * note: when multi queue enabled, fw actv_reqs should be per queue. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci act_reqs = atomic64_inc_return(&fwstats->actv_reqs); 2058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->wq_lock[q_num], flags); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (act_reqs > atomic64_read(&fwstats->max_actv_reqs)) 2088c2ecf20Sopenharmony_ci atomic64_set(&fwstats->max_actv_reqs, act_reqs); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci} /* end of snic_queue_wq_desc() */ 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* 2148c2ecf20Sopenharmony_ci * snic_handle_untagged_req: Adds snic specific requests to spl_cmd_list. 2158c2ecf20Sopenharmony_ci * Purpose : Used during driver unload to clean up the requests. 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_civoid 2188c2ecf20Sopenharmony_cisnic_handle_untagged_req(struct snic *snic, struct snic_req_info *rqi) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci unsigned long flags; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rqi->list); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci spin_lock_irqsave(&snic->spl_cmd_lock, flags); 2258c2ecf20Sopenharmony_ci list_add_tail(&rqi->list, &snic->spl_cmd_list); 2268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/* 2308c2ecf20Sopenharmony_ci * snic_req_init: 2318c2ecf20Sopenharmony_ci * Allocates snic_req_info + snic_host_req + sgl data, and initializes. 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_cistruct snic_req_info * 2348c2ecf20Sopenharmony_cisnic_req_init(struct snic *snic, int sg_cnt) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci u8 typ; 2378c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci typ = (sg_cnt <= SNIC_REQ_CACHE_DFLT_SGL) ? 2408c2ecf20Sopenharmony_ci SNIC_REQ_CACHE_DFLT_SGL : SNIC_REQ_CACHE_MAX_SGL; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci rqi = mempool_alloc(snic->req_pool[typ], GFP_ATOMIC); 2438c2ecf20Sopenharmony_ci if (!rqi) { 2448c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.alloc_fail); 2458c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 2468c2ecf20Sopenharmony_ci "Failed to allocate memory from snic req pool id = %d\n", 2478c2ecf20Sopenharmony_ci typ); 2488c2ecf20Sopenharmony_ci return rqi; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci memset(rqi, 0, sizeof(*rqi)); 2528c2ecf20Sopenharmony_ci rqi->rq_pool_type = typ; 2538c2ecf20Sopenharmony_ci rqi->start_time = jiffies; 2548c2ecf20Sopenharmony_ci rqi->req = (struct snic_host_req *) (rqi + 1); 2558c2ecf20Sopenharmony_ci rqi->req_len = sizeof(struct snic_host_req); 2568c2ecf20Sopenharmony_ci rqi->snic = snic; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci rqi->req = (struct snic_host_req *)(rqi + 1); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (sg_cnt == 0) 2618c2ecf20Sopenharmony_ci goto end; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci rqi->req_len += (sg_cnt * sizeof(struct snic_sg_desc)); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (sg_cnt > atomic64_read(&snic->s_stats.io.max_sgl)) 2668c2ecf20Sopenharmony_ci atomic64_set(&snic->s_stats.io.max_sgl, sg_cnt); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci SNIC_BUG_ON(sg_cnt > SNIC_MAX_SG_DESC_CNT); 2698c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.sgl_cnt[sg_cnt - 1]); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ciend: 2728c2ecf20Sopenharmony_ci memset(rqi->req, 0, rqi->req_len); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* pre initialization of init_ctx to support req_to_rqi */ 2758c2ecf20Sopenharmony_ci rqi->req->hdr.init_ctx = (ulong) rqi; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "Req_alloc:rqi = %p allocatd.\n", rqi); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return rqi; 2808c2ecf20Sopenharmony_ci} /* end of snic_req_init */ 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* 2838c2ecf20Sopenharmony_ci * snic_abort_req_init : Inits abort request. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistruct snic_host_req * 2868c2ecf20Sopenharmony_cisnic_abort_req_init(struct snic *snic, struct snic_req_info *rqi) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct snic_host_req *req = NULL; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci SNIC_BUG_ON(!rqi); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* If abort to be issued second time, then reuse */ 2938c2ecf20Sopenharmony_ci if (rqi->abort_req) 2948c2ecf20Sopenharmony_ci return rqi->abort_req; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci req = mempool_alloc(snic->req_pool[SNIC_REQ_TM_CACHE], GFP_ATOMIC); 2988c2ecf20Sopenharmony_ci if (!req) { 2998c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "abts:Failed to alloc tm req.\n"); 3008c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return NULL; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci rqi->abort_req = req; 3068c2ecf20Sopenharmony_ci memset(req, 0, sizeof(struct snic_host_req)); 3078c2ecf20Sopenharmony_ci /* pre initialization of init_ctx to support req_to_rqi */ 3088c2ecf20Sopenharmony_ci req->hdr.init_ctx = (ulong) rqi; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci return req; 3118c2ecf20Sopenharmony_ci} /* end of snic_abort_req_init */ 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* 3148c2ecf20Sopenharmony_ci * snic_dr_req_init : Inits device reset req 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_cistruct snic_host_req * 3178c2ecf20Sopenharmony_cisnic_dr_req_init(struct snic *snic, struct snic_req_info *rqi) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct snic_host_req *req = NULL; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci SNIC_BUG_ON(!rqi); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci req = mempool_alloc(snic->req_pool[SNIC_REQ_TM_CACHE], GFP_ATOMIC); 3248c2ecf20Sopenharmony_ci if (!req) { 3258c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "dr:Failed to alloc tm req.\n"); 3268c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return NULL; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci SNIC_BUG_ON(rqi->dr_req != NULL); 3328c2ecf20Sopenharmony_ci rqi->dr_req = req; 3338c2ecf20Sopenharmony_ci memset(req, 0, sizeof(struct snic_host_req)); 3348c2ecf20Sopenharmony_ci /* pre initialization of init_ctx to support req_to_rqi */ 3358c2ecf20Sopenharmony_ci req->hdr.init_ctx = (ulong) rqi; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return req; 3388c2ecf20Sopenharmony_ci} /* end of snic_dr_req_init */ 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/* frees snic_req_info and snic_host_req */ 3418c2ecf20Sopenharmony_civoid 3428c2ecf20Sopenharmony_cisnic_req_free(struct snic *snic, struct snic_req_info *rqi) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci SNIC_BUG_ON(rqi->req == rqi->abort_req); 3458c2ecf20Sopenharmony_ci SNIC_BUG_ON(rqi->req == rqi->dr_req); 3468c2ecf20Sopenharmony_ci SNIC_BUG_ON(rqi->sge_va != 0); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 3498c2ecf20Sopenharmony_ci "Req_free:rqi %p:ioreq %p:abt %p:dr %p\n", 3508c2ecf20Sopenharmony_ci rqi, rqi->req, rqi->abort_req, rqi->dr_req); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (rqi->abort_req) { 3538c2ecf20Sopenharmony_ci if (rqi->abort_req->req_pa) 3548c2ecf20Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, 3558c2ecf20Sopenharmony_ci rqi->abort_req->req_pa, 3568c2ecf20Sopenharmony_ci sizeof(struct snic_host_req), 3578c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci mempool_free(rqi->abort_req, snic->req_pool[SNIC_REQ_TM_CACHE]); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (rqi->dr_req) { 3638c2ecf20Sopenharmony_ci if (rqi->dr_req->req_pa) 3648c2ecf20Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, 3658c2ecf20Sopenharmony_ci rqi->dr_req->req_pa, 3668c2ecf20Sopenharmony_ci sizeof(struct snic_host_req), 3678c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci mempool_free(rqi->dr_req, snic->req_pool[SNIC_REQ_TM_CACHE]); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (rqi->req->req_pa) 3738c2ecf20Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, 3748c2ecf20Sopenharmony_ci rqi->req->req_pa, 3758c2ecf20Sopenharmony_ci rqi->req_len, 3768c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci mempool_free(rqi, snic->req_pool[rqi->rq_pool_type]); 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_civoid 3828c2ecf20Sopenharmony_cisnic_pci_unmap_rsp_buf(struct snic *snic, struct snic_req_info *rqi) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct snic_sg_desc *sgd; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci sgd = req_to_sgl(rqi_to_req(rqi)); 3878c2ecf20Sopenharmony_ci SNIC_BUG_ON(sgd[0].addr == 0); 3888c2ecf20Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, 3898c2ecf20Sopenharmony_ci le64_to_cpu(sgd[0].addr), 3908c2ecf20Sopenharmony_ci le32_to_cpu(sgd[0].len), 3918c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/* 3958c2ecf20Sopenharmony_ci * snic_free_all_untagged_reqs: Walks through untagged reqs and frees them. 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_civoid 3988c2ecf20Sopenharmony_cisnic_free_all_untagged_reqs(struct snic *snic) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct snic_req_info *rqi; 4018c2ecf20Sopenharmony_ci struct list_head *cur, *nxt; 4028c2ecf20Sopenharmony_ci unsigned long flags; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci spin_lock_irqsave(&snic->spl_cmd_lock, flags); 4058c2ecf20Sopenharmony_ci list_for_each_safe(cur, nxt, &snic->spl_cmd_list) { 4068c2ecf20Sopenharmony_ci rqi = list_entry(cur, struct snic_req_info, list); 4078c2ecf20Sopenharmony_ci list_del_init(&rqi->list); 4088c2ecf20Sopenharmony_ci if (rqi->sge_va) { 4098c2ecf20Sopenharmony_ci snic_pci_unmap_rsp_buf(snic, rqi); 4108c2ecf20Sopenharmony_ci kfree((void *)rqi->sge_va); 4118c2ecf20Sopenharmony_ci rqi->sge_va = 0; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci snic_req_free(snic, rqi); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/* 4208c2ecf20Sopenharmony_ci * snic_release_untagged_req : Unlinks the untagged req and frees it. 4218c2ecf20Sopenharmony_ci */ 4228c2ecf20Sopenharmony_civoid 4238c2ecf20Sopenharmony_cisnic_release_untagged_req(struct snic *snic, struct snic_req_info *rqi) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci unsigned long flags; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci spin_lock_irqsave(&snic->snic_lock, flags); 4288c2ecf20Sopenharmony_ci if (snic->in_remove) { 4298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, flags); 4308c2ecf20Sopenharmony_ci goto end; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, flags); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci spin_lock_irqsave(&snic->spl_cmd_lock, flags); 4358c2ecf20Sopenharmony_ci if (list_empty(&rqi->list)) { 4368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 4378c2ecf20Sopenharmony_ci goto end; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci list_del_init(&rqi->list); 4408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->spl_cmd_lock, flags); 4418c2ecf20Sopenharmony_ci snic_req_free(snic, rqi); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ciend: 4448c2ecf20Sopenharmony_ci return; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci/* dump buf in hex fmt */ 4488c2ecf20Sopenharmony_civoid 4498c2ecf20Sopenharmony_cisnic_hex_dump(char *pfx, char *data, int len) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci SNIC_INFO("%s Dumping Data of Len = %d\n", pfx, len); 4528c2ecf20Sopenharmony_ci print_hex_dump_bytes(pfx, DUMP_PREFIX_NONE, data, len); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci#define LINE_BUFSZ 128 /* for snic_print_desc fn */ 4568c2ecf20Sopenharmony_cistatic void 4578c2ecf20Sopenharmony_cisnic_dump_desc(const char *fn, char *os_buf, int len) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct snic_host_req *req = (struct snic_host_req *) os_buf; 4608c2ecf20Sopenharmony_ci struct snic_fw_req *fwreq = (struct snic_fw_req *) os_buf; 4618c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 4628c2ecf20Sopenharmony_ci char line[LINE_BUFSZ] = { '\0' }; 4638c2ecf20Sopenharmony_ci char *cmd_str = NULL; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (req->hdr.type >= SNIC_RSP_REPORT_TGTS_CMPL) 4668c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) fwreq->hdr.init_ctx; 4678c2ecf20Sopenharmony_ci else 4688c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) req->hdr.init_ctx; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci SNIC_BUG_ON(rqi == NULL || rqi->req == NULL); 4718c2ecf20Sopenharmony_ci switch (req->hdr.type) { 4728c2ecf20Sopenharmony_ci case SNIC_REQ_REPORT_TGTS: 4738c2ecf20Sopenharmony_ci cmd_str = "report-tgt : "; 4748c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_REQ_REPORT_TGTS :"); 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci case SNIC_REQ_ICMND: 4788c2ecf20Sopenharmony_ci cmd_str = "icmnd : "; 4798c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_REQ_ICMND : 0x%x :", 4808c2ecf20Sopenharmony_ci req->u.icmnd.cdb[0]); 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci case SNIC_REQ_ITMF: 4848c2ecf20Sopenharmony_ci cmd_str = "itmf : "; 4858c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_REQ_ITMF :"); 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci case SNIC_REQ_HBA_RESET: 4898c2ecf20Sopenharmony_ci cmd_str = "hba reset :"; 4908c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_REQ_HBA_RESET :"); 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci case SNIC_REQ_EXCH_VER: 4948c2ecf20Sopenharmony_ci cmd_str = "exch ver : "; 4958c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_REQ_EXCH_VER :"); 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci case SNIC_REQ_TGT_INFO: 4998c2ecf20Sopenharmony_ci cmd_str = "tgt info : "; 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci case SNIC_RSP_REPORT_TGTS_CMPL: 5038c2ecf20Sopenharmony_ci cmd_str = "report tgt cmpl : "; 5048c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_RSP_REPORT_TGTS_CMPL :"); 5058c2ecf20Sopenharmony_ci break; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci case SNIC_RSP_ICMND_CMPL: 5088c2ecf20Sopenharmony_ci cmd_str = "icmnd_cmpl : "; 5098c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_RSP_ICMND_CMPL : 0x%x :", 5108c2ecf20Sopenharmony_ci rqi->req->u.icmnd.cdb[0]); 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci case SNIC_RSP_ITMF_CMPL: 5148c2ecf20Sopenharmony_ci cmd_str = "itmf_cmpl : "; 5158c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_RSP_ITMF_CMPL :"); 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci case SNIC_RSP_HBA_RESET_CMPL: 5198c2ecf20Sopenharmony_ci cmd_str = "hba_reset_cmpl : "; 5208c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_RSP_HBA_RESET_CMPL :"); 5218c2ecf20Sopenharmony_ci break; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci case SNIC_RSP_EXCH_VER_CMPL: 5248c2ecf20Sopenharmony_ci cmd_str = "exch_ver_cmpl : "; 5258c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_RSP_EXCH_VER_CMPL :"); 5268c2ecf20Sopenharmony_ci break; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci case SNIC_MSG_ACK: 5298c2ecf20Sopenharmony_ci cmd_str = "msg ack : "; 5308c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_MSG_ACK :"); 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci case SNIC_MSG_ASYNC_EVNOTIFY: 5348c2ecf20Sopenharmony_ci cmd_str = "async notify : "; 5358c2ecf20Sopenharmony_ci snprintf(line, LINE_BUFSZ, "SNIC_MSG_ASYNC_EVNOTIFY :"); 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci default: 5398c2ecf20Sopenharmony_ci cmd_str = "unknown : "; 5408c2ecf20Sopenharmony_ci SNIC_BUG_ON(1); 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci SNIC_INFO("%s:%s >>cmndid=%x:sg_cnt = %x:status = %x:ctx = %lx.\n", 5458c2ecf20Sopenharmony_ci fn, line, req->hdr.cmnd_id, req->hdr.sg_cnt, req->hdr.status, 5468c2ecf20Sopenharmony_ci req->hdr.init_ctx); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* Enable it, to dump byte stream */ 5498c2ecf20Sopenharmony_ci if (snic_log_level & 0x20) 5508c2ecf20Sopenharmony_ci snic_hex_dump(cmd_str, os_buf, len); 5518c2ecf20Sopenharmony_ci} /* end of __snic_print_desc */ 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_civoid 5548c2ecf20Sopenharmony_cisnic_print_desc(const char *fn, char *os_buf, int len) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci if (snic_log_level & SNIC_DESC_LOGGING) 5578c2ecf20Sopenharmony_ci snic_dump_desc(fn, os_buf, len); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_civoid 5618c2ecf20Sopenharmony_cisnic_calc_io_process_time(struct snic *snic, struct snic_req_info *rqi) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci u64 duration; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci duration = jiffies - rqi->start_time; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (duration > atomic64_read(&snic->s_stats.io.max_time)) 5688c2ecf20Sopenharmony_ci atomic64_set(&snic->s_stats.io.max_time, duration); 5698c2ecf20Sopenharmony_ci} 570