18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is part of the Chelsio FCoE driver for Linux. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/device.h> 368c2ecf20Sopenharmony_ci#include <linux/delay.h> 378c2ecf20Sopenharmony_ci#include <linux/ctype.h> 388c2ecf20Sopenharmony_ci#include <linux/kernel.h> 398c2ecf20Sopenharmony_ci#include <linux/slab.h> 408c2ecf20Sopenharmony_ci#include <linux/string.h> 418c2ecf20Sopenharmony_ci#include <linux/compiler.h> 428c2ecf20Sopenharmony_ci#include <linux/export.h> 438c2ecf20Sopenharmony_ci#include <linux/module.h> 448c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 458c2ecf20Sopenharmony_ci#include <asm/page.h> 468c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 478c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 488c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_fc.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include "csio_hw.h" 518c2ecf20Sopenharmony_ci#include "csio_lnode.h" 528c2ecf20Sopenharmony_ci#include "csio_rnode.h" 538c2ecf20Sopenharmony_ci#include "csio_scsi.h" 548c2ecf20Sopenharmony_ci#include "csio_init.h" 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciint csio_scsi_eqsize = 65536; 578c2ecf20Sopenharmony_ciint csio_scsi_iqlen = 128; 588c2ecf20Sopenharmony_ciint csio_scsi_ioreqs = 2048; 598c2ecf20Sopenharmony_ciuint32_t csio_max_scan_tmo; 608c2ecf20Sopenharmony_ciuint32_t csio_delta_scan_tmo = 5; 618c2ecf20Sopenharmony_ciint csio_lun_qdepth = 32; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int csio_ddp_descs = 128; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int csio_do_abrt_cls(struct csio_hw *, 668c2ecf20Sopenharmony_ci struct csio_ioreq *, bool); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void csio_scsis_uninit(struct csio_ioreq *, enum csio_scsi_ev); 698c2ecf20Sopenharmony_cistatic void csio_scsis_io_active(struct csio_ioreq *, enum csio_scsi_ev); 708c2ecf20Sopenharmony_cistatic void csio_scsis_tm_active(struct csio_ioreq *, enum csio_scsi_ev); 718c2ecf20Sopenharmony_cistatic void csio_scsis_aborting(struct csio_ioreq *, enum csio_scsi_ev); 728c2ecf20Sopenharmony_cistatic void csio_scsis_closing(struct csio_ioreq *, enum csio_scsi_ev); 738c2ecf20Sopenharmony_cistatic void csio_scsis_shost_cmpl_await(struct csio_ioreq *, enum csio_scsi_ev); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* 768c2ecf20Sopenharmony_ci * csio_scsi_match_io - Match an ioreq with the given SCSI level data. 778c2ecf20Sopenharmony_ci * @ioreq: The I/O request 788c2ecf20Sopenharmony_ci * @sld: Level information 798c2ecf20Sopenharmony_ci * 808c2ecf20Sopenharmony_ci * Should be called with lock held. 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_cistatic bool 848c2ecf20Sopenharmony_cicsio_scsi_match_io(struct csio_ioreq *ioreq, struct csio_scsi_level_data *sld) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct scsi_cmnd *scmnd = csio_scsi_cmnd(ioreq); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci switch (sld->level) { 898c2ecf20Sopenharmony_ci case CSIO_LEV_LUN: 908c2ecf20Sopenharmony_ci if (scmnd == NULL) 918c2ecf20Sopenharmony_ci return false; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return ((ioreq->lnode == sld->lnode) && 948c2ecf20Sopenharmony_ci (ioreq->rnode == sld->rnode) && 958c2ecf20Sopenharmony_ci ((uint64_t)scmnd->device->lun == sld->oslun)); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci case CSIO_LEV_RNODE: 988c2ecf20Sopenharmony_ci return ((ioreq->lnode == sld->lnode) && 998c2ecf20Sopenharmony_ci (ioreq->rnode == sld->rnode)); 1008c2ecf20Sopenharmony_ci case CSIO_LEV_LNODE: 1018c2ecf20Sopenharmony_ci return (ioreq->lnode == sld->lnode); 1028c2ecf20Sopenharmony_ci case CSIO_LEV_ALL: 1038c2ecf20Sopenharmony_ci return true; 1048c2ecf20Sopenharmony_ci default: 1058c2ecf20Sopenharmony_ci return false; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* 1108c2ecf20Sopenharmony_ci * csio_scsi_gather_active_ios - Gather active I/Os based on level 1118c2ecf20Sopenharmony_ci * @scm: SCSI module 1128c2ecf20Sopenharmony_ci * @sld: Level information 1138c2ecf20Sopenharmony_ci * @dest: The queue where these I/Os have to be gathered. 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * Should be called with lock held. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_cistatic void 1188c2ecf20Sopenharmony_cicsio_scsi_gather_active_ios(struct csio_scsim *scm, 1198c2ecf20Sopenharmony_ci struct csio_scsi_level_data *sld, 1208c2ecf20Sopenharmony_ci struct list_head *dest) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct list_head *tmp, *next; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (list_empty(&scm->active_q)) 1258c2ecf20Sopenharmony_ci return; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* Just splice the entire active_q into dest */ 1288c2ecf20Sopenharmony_ci if (sld->level == CSIO_LEV_ALL) { 1298c2ecf20Sopenharmony_ci list_splice_tail_init(&scm->active_q, dest); 1308c2ecf20Sopenharmony_ci return; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci list_for_each_safe(tmp, next, &scm->active_q) { 1348c2ecf20Sopenharmony_ci if (csio_scsi_match_io((struct csio_ioreq *)tmp, sld)) { 1358c2ecf20Sopenharmony_ci list_del_init(tmp); 1368c2ecf20Sopenharmony_ci list_add_tail(tmp, dest); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic inline bool 1428c2ecf20Sopenharmony_cicsio_scsi_itnexus_loss_error(uint16_t error) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci switch (error) { 1458c2ecf20Sopenharmony_ci case FW_ERR_LINK_DOWN: 1468c2ecf20Sopenharmony_ci case FW_RDEV_NOT_READY: 1478c2ecf20Sopenharmony_ci case FW_ERR_RDEV_LOST: 1488c2ecf20Sopenharmony_ci case FW_ERR_RDEV_LOGO: 1498c2ecf20Sopenharmony_ci case FW_ERR_RDEV_IMPL_LOGO: 1508c2ecf20Sopenharmony_ci return 1; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* 1568c2ecf20Sopenharmony_ci * csio_scsi_fcp_cmnd - Frame the SCSI FCP command paylod. 1578c2ecf20Sopenharmony_ci * @req: IO req structure. 1588c2ecf20Sopenharmony_ci * @addr: DMA location to place the payload. 1598c2ecf20Sopenharmony_ci * 1608c2ecf20Sopenharmony_ci * This routine is shared between FCP_WRITE, FCP_READ and FCP_CMD requests. 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_cistatic inline void 1638c2ecf20Sopenharmony_cicsio_scsi_fcp_cmnd(struct csio_ioreq *req, void *addr) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct fcp_cmnd *fcp_cmnd = (struct fcp_cmnd *)addr; 1668c2ecf20Sopenharmony_ci struct scsi_cmnd *scmnd = csio_scsi_cmnd(req); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Check for Task Management */ 1698c2ecf20Sopenharmony_ci if (likely(scmnd->SCp.Message == 0)) { 1708c2ecf20Sopenharmony_ci int_to_scsilun(scmnd->device->lun, &fcp_cmnd->fc_lun); 1718c2ecf20Sopenharmony_ci fcp_cmnd->fc_tm_flags = 0; 1728c2ecf20Sopenharmony_ci fcp_cmnd->fc_cmdref = 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci memcpy(fcp_cmnd->fc_cdb, scmnd->cmnd, 16); 1758c2ecf20Sopenharmony_ci fcp_cmnd->fc_pri_ta = FCP_PTA_SIMPLE; 1768c2ecf20Sopenharmony_ci fcp_cmnd->fc_dl = cpu_to_be32(scsi_bufflen(scmnd)); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (req->nsge) 1798c2ecf20Sopenharmony_ci if (req->datadir == DMA_TO_DEVICE) 1808c2ecf20Sopenharmony_ci fcp_cmnd->fc_flags = FCP_CFL_WRDATA; 1818c2ecf20Sopenharmony_ci else 1828c2ecf20Sopenharmony_ci fcp_cmnd->fc_flags = FCP_CFL_RDDATA; 1838c2ecf20Sopenharmony_ci else 1848c2ecf20Sopenharmony_ci fcp_cmnd->fc_flags = 0; 1858c2ecf20Sopenharmony_ci } else { 1868c2ecf20Sopenharmony_ci memset(fcp_cmnd, 0, sizeof(*fcp_cmnd)); 1878c2ecf20Sopenharmony_ci int_to_scsilun(scmnd->device->lun, &fcp_cmnd->fc_lun); 1888c2ecf20Sopenharmony_ci fcp_cmnd->fc_tm_flags = (uint8_t)scmnd->SCp.Message; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * csio_scsi_init_cmd_wr - Initialize the SCSI CMD WR. 1948c2ecf20Sopenharmony_ci * @req: IO req structure. 1958c2ecf20Sopenharmony_ci * @addr: DMA location to place the payload. 1968c2ecf20Sopenharmony_ci * @size: Size of WR (including FW WR + immed data + rsp SG entry 1978c2ecf20Sopenharmony_ci * 1988c2ecf20Sopenharmony_ci * Wrapper for populating fw_scsi_cmd_wr. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cistatic inline void 2018c2ecf20Sopenharmony_cicsio_scsi_init_cmd_wr(struct csio_ioreq *req, void *addr, uint32_t size) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 2048c2ecf20Sopenharmony_ci struct csio_rnode *rn = req->rnode; 2058c2ecf20Sopenharmony_ci struct fw_scsi_cmd_wr *wr = (struct fw_scsi_cmd_wr *)addr; 2068c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf; 2078c2ecf20Sopenharmony_ci uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_CMD_WR) | 2108c2ecf20Sopenharmony_ci FW_SCSI_CMD_WR_IMMDLEN(imm)); 2118c2ecf20Sopenharmony_ci wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) | 2128c2ecf20Sopenharmony_ci FW_WR_LEN16_V( 2138c2ecf20Sopenharmony_ci DIV_ROUND_UP(size, 16))); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci wr->cookie = (uintptr_t) req; 2168c2ecf20Sopenharmony_ci wr->iqid = cpu_to_be16(csio_q_physiqid(hw, req->iq_idx)); 2178c2ecf20Sopenharmony_ci wr->tmo_val = (uint8_t) req->tmo; 2188c2ecf20Sopenharmony_ci wr->r3 = 0; 2198c2ecf20Sopenharmony_ci memset(&wr->r5, 0, 8); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* Get RSP DMA buffer */ 2228c2ecf20Sopenharmony_ci dma_buf = &req->dma_buf; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* Prepare RSP SGL */ 2258c2ecf20Sopenharmony_ci wr->rsp_dmalen = cpu_to_be32(dma_buf->len); 2268c2ecf20Sopenharmony_ci wr->rsp_dmaaddr = cpu_to_be64(dma_buf->paddr); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci wr->r6 = 0; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci wr->u.fcoe.ctl_pri = 0; 2318c2ecf20Sopenharmony_ci wr->u.fcoe.cp_en_class = 0; 2328c2ecf20Sopenharmony_ci wr->u.fcoe.r4_lo[0] = 0; 2338c2ecf20Sopenharmony_ci wr->u.fcoe.r4_lo[1] = 0; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* Frame a FCP command */ 2368c2ecf20Sopenharmony_ci csio_scsi_fcp_cmnd(req, (void *)((uintptr_t)addr + 2378c2ecf20Sopenharmony_ci sizeof(struct fw_scsi_cmd_wr))); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#define CSIO_SCSI_CMD_WR_SZ(_imm) \ 2418c2ecf20Sopenharmony_ci (sizeof(struct fw_scsi_cmd_wr) + /* WR size */ \ 2428c2ecf20Sopenharmony_ci ALIGN((_imm), 16)) /* Immed data */ 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci#define CSIO_SCSI_CMD_WR_SZ_16(_imm) \ 2458c2ecf20Sopenharmony_ci (ALIGN(CSIO_SCSI_CMD_WR_SZ((_imm)), 16)) 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/* 2488c2ecf20Sopenharmony_ci * csio_scsi_cmd - Create a SCSI CMD WR. 2498c2ecf20Sopenharmony_ci * @req: IO req structure. 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * Gets a WR slot in the ingress queue and initializes it with SCSI CMD WR. 2528c2ecf20Sopenharmony_ci * 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_cistatic inline void 2558c2ecf20Sopenharmony_cicsio_scsi_cmd(struct csio_ioreq *req) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct csio_wr_pair wrp; 2588c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 2598c2ecf20Sopenharmony_ci struct csio_scsim *scsim = csio_hw_to_scsim(hw); 2608c2ecf20Sopenharmony_ci uint32_t size = CSIO_SCSI_CMD_WR_SZ_16(scsim->proto_cmd_len); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci req->drv_status = csio_wr_get(hw, req->eq_idx, size, &wrp); 2638c2ecf20Sopenharmony_ci if (unlikely(req->drv_status != 0)) 2648c2ecf20Sopenharmony_ci return; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (wrp.size1 >= size) { 2678c2ecf20Sopenharmony_ci /* Initialize WR in one shot */ 2688c2ecf20Sopenharmony_ci csio_scsi_init_cmd_wr(req, wrp.addr1, size); 2698c2ecf20Sopenharmony_ci } else { 2708c2ecf20Sopenharmony_ci uint8_t *tmpwr = csio_q_eq_wrap(hw, req->eq_idx); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* 2738c2ecf20Sopenharmony_ci * Make a temporary copy of the WR and write back 2748c2ecf20Sopenharmony_ci * the copy into the WR pair. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_ci csio_scsi_init_cmd_wr(req, (void *)tmpwr, size); 2778c2ecf20Sopenharmony_ci memcpy(wrp.addr1, tmpwr, wrp.size1); 2788c2ecf20Sopenharmony_ci memcpy(wrp.addr2, tmpwr + wrp.size1, size - wrp.size1); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* 2838c2ecf20Sopenharmony_ci * csio_scsi_init_ulptx_dsgl - Fill in a ULP_TX_SC_DSGL 2848c2ecf20Sopenharmony_ci * @hw: HW module 2858c2ecf20Sopenharmony_ci * @req: IO request 2868c2ecf20Sopenharmony_ci * @sgl: ULP TX SGL pointer. 2878c2ecf20Sopenharmony_ci * 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_cistatic inline void 2908c2ecf20Sopenharmony_cicsio_scsi_init_ultptx_dsgl(struct csio_hw *hw, struct csio_ioreq *req, 2918c2ecf20Sopenharmony_ci struct ulptx_sgl *sgl) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct ulptx_sge_pair *sge_pair = NULL; 2948c2ecf20Sopenharmony_ci struct scatterlist *sgel; 2958c2ecf20Sopenharmony_ci uint32_t i = 0; 2968c2ecf20Sopenharmony_ci uint32_t xfer_len; 2978c2ecf20Sopenharmony_ci struct list_head *tmp; 2988c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf; 2998c2ecf20Sopenharmony_ci struct scsi_cmnd *scmnd = csio_scsi_cmnd(req); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | ULPTX_MORE_F | 3028c2ecf20Sopenharmony_ci ULPTX_NSGE_V(req->nsge)); 3038c2ecf20Sopenharmony_ci /* Now add the data SGLs */ 3048c2ecf20Sopenharmony_ci if (likely(!req->dcopy)) { 3058c2ecf20Sopenharmony_ci scsi_for_each_sg(scmnd, sgel, req->nsge, i) { 3068c2ecf20Sopenharmony_ci if (i == 0) { 3078c2ecf20Sopenharmony_ci sgl->addr0 = cpu_to_be64(sg_dma_address(sgel)); 3088c2ecf20Sopenharmony_ci sgl->len0 = cpu_to_be32(sg_dma_len(sgel)); 3098c2ecf20Sopenharmony_ci sge_pair = (struct ulptx_sge_pair *)(sgl + 1); 3108c2ecf20Sopenharmony_ci continue; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci if ((i - 1) & 0x1) { 3138c2ecf20Sopenharmony_ci sge_pair->addr[1] = cpu_to_be64( 3148c2ecf20Sopenharmony_ci sg_dma_address(sgel)); 3158c2ecf20Sopenharmony_ci sge_pair->len[1] = cpu_to_be32( 3168c2ecf20Sopenharmony_ci sg_dma_len(sgel)); 3178c2ecf20Sopenharmony_ci sge_pair++; 3188c2ecf20Sopenharmony_ci } else { 3198c2ecf20Sopenharmony_ci sge_pair->addr[0] = cpu_to_be64( 3208c2ecf20Sopenharmony_ci sg_dma_address(sgel)); 3218c2ecf20Sopenharmony_ci sge_pair->len[0] = cpu_to_be32( 3228c2ecf20Sopenharmony_ci sg_dma_len(sgel)); 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci } else { 3268c2ecf20Sopenharmony_ci /* Program sg elements with driver's DDP buffer */ 3278c2ecf20Sopenharmony_ci xfer_len = scsi_bufflen(scmnd); 3288c2ecf20Sopenharmony_ci list_for_each(tmp, &req->gen_list) { 3298c2ecf20Sopenharmony_ci dma_buf = (struct csio_dma_buf *)tmp; 3308c2ecf20Sopenharmony_ci if (i == 0) { 3318c2ecf20Sopenharmony_ci sgl->addr0 = cpu_to_be64(dma_buf->paddr); 3328c2ecf20Sopenharmony_ci sgl->len0 = cpu_to_be32( 3338c2ecf20Sopenharmony_ci min(xfer_len, dma_buf->len)); 3348c2ecf20Sopenharmony_ci sge_pair = (struct ulptx_sge_pair *)(sgl + 1); 3358c2ecf20Sopenharmony_ci } else if ((i - 1) & 0x1) { 3368c2ecf20Sopenharmony_ci sge_pair->addr[1] = cpu_to_be64(dma_buf->paddr); 3378c2ecf20Sopenharmony_ci sge_pair->len[1] = cpu_to_be32( 3388c2ecf20Sopenharmony_ci min(xfer_len, dma_buf->len)); 3398c2ecf20Sopenharmony_ci sge_pair++; 3408c2ecf20Sopenharmony_ci } else { 3418c2ecf20Sopenharmony_ci sge_pair->addr[0] = cpu_to_be64(dma_buf->paddr); 3428c2ecf20Sopenharmony_ci sge_pair->len[0] = cpu_to_be32( 3438c2ecf20Sopenharmony_ci min(xfer_len, dma_buf->len)); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci xfer_len -= min(xfer_len, dma_buf->len); 3468c2ecf20Sopenharmony_ci i++; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/* 3528c2ecf20Sopenharmony_ci * csio_scsi_init_read_wr - Initialize the READ SCSI WR. 3538c2ecf20Sopenharmony_ci * @req: IO req structure. 3548c2ecf20Sopenharmony_ci * @wrp: DMA location to place the payload. 3558c2ecf20Sopenharmony_ci * @size: Size of WR (including FW WR + immed data + rsp SG entry + data SGL 3568c2ecf20Sopenharmony_ci * 3578c2ecf20Sopenharmony_ci * Wrapper for populating fw_scsi_read_wr. 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_cistatic inline void 3608c2ecf20Sopenharmony_cicsio_scsi_init_read_wr(struct csio_ioreq *req, void *wrp, uint32_t size) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 3638c2ecf20Sopenharmony_ci struct csio_rnode *rn = req->rnode; 3648c2ecf20Sopenharmony_ci struct fw_scsi_read_wr *wr = (struct fw_scsi_read_wr *)wrp; 3658c2ecf20Sopenharmony_ci struct ulptx_sgl *sgl; 3668c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf; 3678c2ecf20Sopenharmony_ci uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len; 3688c2ecf20Sopenharmony_ci struct scsi_cmnd *scmnd = csio_scsi_cmnd(req); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_READ_WR) | 3718c2ecf20Sopenharmony_ci FW_SCSI_READ_WR_IMMDLEN(imm)); 3728c2ecf20Sopenharmony_ci wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) | 3738c2ecf20Sopenharmony_ci FW_WR_LEN16_V(DIV_ROUND_UP(size, 16))); 3748c2ecf20Sopenharmony_ci wr->cookie = (uintptr_t)req; 3758c2ecf20Sopenharmony_ci wr->iqid = cpu_to_be16(csio_q_physiqid(hw, req->iq_idx)); 3768c2ecf20Sopenharmony_ci wr->tmo_val = (uint8_t)(req->tmo); 3778c2ecf20Sopenharmony_ci wr->use_xfer_cnt = 1; 3788c2ecf20Sopenharmony_ci wr->xfer_cnt = cpu_to_be32(scsi_bufflen(scmnd)); 3798c2ecf20Sopenharmony_ci wr->ini_xfer_cnt = cpu_to_be32(scsi_bufflen(scmnd)); 3808c2ecf20Sopenharmony_ci /* Get RSP DMA buffer */ 3818c2ecf20Sopenharmony_ci dma_buf = &req->dma_buf; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Prepare RSP SGL */ 3848c2ecf20Sopenharmony_ci wr->rsp_dmalen = cpu_to_be32(dma_buf->len); 3858c2ecf20Sopenharmony_ci wr->rsp_dmaaddr = cpu_to_be64(dma_buf->paddr); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci wr->r4 = 0; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci wr->u.fcoe.ctl_pri = 0; 3908c2ecf20Sopenharmony_ci wr->u.fcoe.cp_en_class = 0; 3918c2ecf20Sopenharmony_ci wr->u.fcoe.r3_lo[0] = 0; 3928c2ecf20Sopenharmony_ci wr->u.fcoe.r3_lo[1] = 0; 3938c2ecf20Sopenharmony_ci csio_scsi_fcp_cmnd(req, (void *)((uintptr_t)wrp + 3948c2ecf20Sopenharmony_ci sizeof(struct fw_scsi_read_wr))); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* Move WR pointer past command and immediate data */ 3978c2ecf20Sopenharmony_ci sgl = (struct ulptx_sgl *)((uintptr_t)wrp + 3988c2ecf20Sopenharmony_ci sizeof(struct fw_scsi_read_wr) + ALIGN(imm, 16)); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* Fill in the DSGL */ 4018c2ecf20Sopenharmony_ci csio_scsi_init_ultptx_dsgl(hw, req, sgl); 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci/* 4058c2ecf20Sopenharmony_ci * csio_scsi_init_write_wr - Initialize the WRITE SCSI WR. 4068c2ecf20Sopenharmony_ci * @req: IO req structure. 4078c2ecf20Sopenharmony_ci * @wrp: DMA location to place the payload. 4088c2ecf20Sopenharmony_ci * @size: Size of WR (including FW WR + immed data + rsp SG entry + data SGL 4098c2ecf20Sopenharmony_ci * 4108c2ecf20Sopenharmony_ci * Wrapper for populating fw_scsi_write_wr. 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_cistatic inline void 4138c2ecf20Sopenharmony_cicsio_scsi_init_write_wr(struct csio_ioreq *req, void *wrp, uint32_t size) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 4168c2ecf20Sopenharmony_ci struct csio_rnode *rn = req->rnode; 4178c2ecf20Sopenharmony_ci struct fw_scsi_write_wr *wr = (struct fw_scsi_write_wr *)wrp; 4188c2ecf20Sopenharmony_ci struct ulptx_sgl *sgl; 4198c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf; 4208c2ecf20Sopenharmony_ci uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len; 4218c2ecf20Sopenharmony_ci struct scsi_cmnd *scmnd = csio_scsi_cmnd(req); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_WRITE_WR) | 4248c2ecf20Sopenharmony_ci FW_SCSI_WRITE_WR_IMMDLEN(imm)); 4258c2ecf20Sopenharmony_ci wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) | 4268c2ecf20Sopenharmony_ci FW_WR_LEN16_V(DIV_ROUND_UP(size, 16))); 4278c2ecf20Sopenharmony_ci wr->cookie = (uintptr_t)req; 4288c2ecf20Sopenharmony_ci wr->iqid = cpu_to_be16(csio_q_physiqid(hw, req->iq_idx)); 4298c2ecf20Sopenharmony_ci wr->tmo_val = (uint8_t)(req->tmo); 4308c2ecf20Sopenharmony_ci wr->use_xfer_cnt = 1; 4318c2ecf20Sopenharmony_ci wr->xfer_cnt = cpu_to_be32(scsi_bufflen(scmnd)); 4328c2ecf20Sopenharmony_ci wr->ini_xfer_cnt = cpu_to_be32(scsi_bufflen(scmnd)); 4338c2ecf20Sopenharmony_ci /* Get RSP DMA buffer */ 4348c2ecf20Sopenharmony_ci dma_buf = &req->dma_buf; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Prepare RSP SGL */ 4378c2ecf20Sopenharmony_ci wr->rsp_dmalen = cpu_to_be32(dma_buf->len); 4388c2ecf20Sopenharmony_ci wr->rsp_dmaaddr = cpu_to_be64(dma_buf->paddr); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci wr->r4 = 0; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci wr->u.fcoe.ctl_pri = 0; 4438c2ecf20Sopenharmony_ci wr->u.fcoe.cp_en_class = 0; 4448c2ecf20Sopenharmony_ci wr->u.fcoe.r3_lo[0] = 0; 4458c2ecf20Sopenharmony_ci wr->u.fcoe.r3_lo[1] = 0; 4468c2ecf20Sopenharmony_ci csio_scsi_fcp_cmnd(req, (void *)((uintptr_t)wrp + 4478c2ecf20Sopenharmony_ci sizeof(struct fw_scsi_write_wr))); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* Move WR pointer past command and immediate data */ 4508c2ecf20Sopenharmony_ci sgl = (struct ulptx_sgl *)((uintptr_t)wrp + 4518c2ecf20Sopenharmony_ci sizeof(struct fw_scsi_write_wr) + ALIGN(imm, 16)); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* Fill in the DSGL */ 4548c2ecf20Sopenharmony_ci csio_scsi_init_ultptx_dsgl(hw, req, sgl); 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci/* Calculate WR size needed for fw_scsi_read_wr/fw_scsi_write_wr */ 4588c2ecf20Sopenharmony_ci#define CSIO_SCSI_DATA_WRSZ(req, oper, sz, imm) \ 4598c2ecf20Sopenharmony_cido { \ 4608c2ecf20Sopenharmony_ci (sz) = sizeof(struct fw_scsi_##oper##_wr) + /* WR size */ \ 4618c2ecf20Sopenharmony_ci ALIGN((imm), 16) + /* Immed data */ \ 4628c2ecf20Sopenharmony_ci sizeof(struct ulptx_sgl); /* ulptx_sgl */ \ 4638c2ecf20Sopenharmony_ci \ 4648c2ecf20Sopenharmony_ci if (unlikely((req)->nsge > 1)) \ 4658c2ecf20Sopenharmony_ci (sz) += (sizeof(struct ulptx_sge_pair) * \ 4668c2ecf20Sopenharmony_ci (ALIGN(((req)->nsge - 1), 2) / 2)); \ 4678c2ecf20Sopenharmony_ci /* Data SGE */ \ 4688c2ecf20Sopenharmony_ci} while (0) 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci/* 4718c2ecf20Sopenharmony_ci * csio_scsi_read - Create a SCSI READ WR. 4728c2ecf20Sopenharmony_ci * @req: IO req structure. 4738c2ecf20Sopenharmony_ci * 4748c2ecf20Sopenharmony_ci * Gets a WR slot in the ingress queue and initializes it with 4758c2ecf20Sopenharmony_ci * SCSI READ WR. 4768c2ecf20Sopenharmony_ci * 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_cistatic inline void 4798c2ecf20Sopenharmony_cicsio_scsi_read(struct csio_ioreq *req) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct csio_wr_pair wrp; 4828c2ecf20Sopenharmony_ci uint32_t size; 4838c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 4848c2ecf20Sopenharmony_ci struct csio_scsim *scsim = csio_hw_to_scsim(hw); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci CSIO_SCSI_DATA_WRSZ(req, read, size, scsim->proto_cmd_len); 4878c2ecf20Sopenharmony_ci size = ALIGN(size, 16); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci req->drv_status = csio_wr_get(hw, req->eq_idx, size, &wrp); 4908c2ecf20Sopenharmony_ci if (likely(req->drv_status == 0)) { 4918c2ecf20Sopenharmony_ci if (likely(wrp.size1 >= size)) { 4928c2ecf20Sopenharmony_ci /* Initialize WR in one shot */ 4938c2ecf20Sopenharmony_ci csio_scsi_init_read_wr(req, wrp.addr1, size); 4948c2ecf20Sopenharmony_ci } else { 4958c2ecf20Sopenharmony_ci uint8_t *tmpwr = csio_q_eq_wrap(hw, req->eq_idx); 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * Make a temporary copy of the WR and write back 4988c2ecf20Sopenharmony_ci * the copy into the WR pair. 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_ci csio_scsi_init_read_wr(req, (void *)tmpwr, size); 5018c2ecf20Sopenharmony_ci memcpy(wrp.addr1, tmpwr, wrp.size1); 5028c2ecf20Sopenharmony_ci memcpy(wrp.addr2, tmpwr + wrp.size1, size - wrp.size1); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/* 5088c2ecf20Sopenharmony_ci * csio_scsi_write - Create a SCSI WRITE WR. 5098c2ecf20Sopenharmony_ci * @req: IO req structure. 5108c2ecf20Sopenharmony_ci * 5118c2ecf20Sopenharmony_ci * Gets a WR slot in the ingress queue and initializes it with 5128c2ecf20Sopenharmony_ci * SCSI WRITE WR. 5138c2ecf20Sopenharmony_ci * 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_cistatic inline void 5168c2ecf20Sopenharmony_cicsio_scsi_write(struct csio_ioreq *req) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct csio_wr_pair wrp; 5198c2ecf20Sopenharmony_ci uint32_t size; 5208c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 5218c2ecf20Sopenharmony_ci struct csio_scsim *scsim = csio_hw_to_scsim(hw); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci CSIO_SCSI_DATA_WRSZ(req, write, size, scsim->proto_cmd_len); 5248c2ecf20Sopenharmony_ci size = ALIGN(size, 16); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci req->drv_status = csio_wr_get(hw, req->eq_idx, size, &wrp); 5278c2ecf20Sopenharmony_ci if (likely(req->drv_status == 0)) { 5288c2ecf20Sopenharmony_ci if (likely(wrp.size1 >= size)) { 5298c2ecf20Sopenharmony_ci /* Initialize WR in one shot */ 5308c2ecf20Sopenharmony_ci csio_scsi_init_write_wr(req, wrp.addr1, size); 5318c2ecf20Sopenharmony_ci } else { 5328c2ecf20Sopenharmony_ci uint8_t *tmpwr = csio_q_eq_wrap(hw, req->eq_idx); 5338c2ecf20Sopenharmony_ci /* 5348c2ecf20Sopenharmony_ci * Make a temporary copy of the WR and write back 5358c2ecf20Sopenharmony_ci * the copy into the WR pair. 5368c2ecf20Sopenharmony_ci */ 5378c2ecf20Sopenharmony_ci csio_scsi_init_write_wr(req, (void *)tmpwr, size); 5388c2ecf20Sopenharmony_ci memcpy(wrp.addr1, tmpwr, wrp.size1); 5398c2ecf20Sopenharmony_ci memcpy(wrp.addr2, tmpwr + wrp.size1, size - wrp.size1); 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci/* 5458c2ecf20Sopenharmony_ci * csio_setup_ddp - Setup DDP buffers for Read request. 5468c2ecf20Sopenharmony_ci * @req: IO req structure. 5478c2ecf20Sopenharmony_ci * 5488c2ecf20Sopenharmony_ci * Checks SGLs/Data buffers are virtually contiguous required for DDP. 5498c2ecf20Sopenharmony_ci * If contiguous,driver posts SGLs in the WR otherwise post internal 5508c2ecf20Sopenharmony_ci * buffers for such request for DDP. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_cistatic inline void 5538c2ecf20Sopenharmony_cicsio_setup_ddp(struct csio_scsim *scsim, struct csio_ioreq *req) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci#ifdef __CSIO_DEBUG__ 5568c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 5578c2ecf20Sopenharmony_ci#endif 5588c2ecf20Sopenharmony_ci struct scatterlist *sgel = NULL; 5598c2ecf20Sopenharmony_ci struct scsi_cmnd *scmnd = csio_scsi_cmnd(req); 5608c2ecf20Sopenharmony_ci uint64_t sg_addr = 0; 5618c2ecf20Sopenharmony_ci uint32_t ddp_pagesz = 4096; 5628c2ecf20Sopenharmony_ci uint32_t buf_off; 5638c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf = NULL; 5648c2ecf20Sopenharmony_ci uint32_t alloc_len = 0; 5658c2ecf20Sopenharmony_ci uint32_t xfer_len = 0; 5668c2ecf20Sopenharmony_ci uint32_t sg_len = 0; 5678c2ecf20Sopenharmony_ci uint32_t i; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci scsi_for_each_sg(scmnd, sgel, req->nsge, i) { 5708c2ecf20Sopenharmony_ci sg_addr = sg_dma_address(sgel); 5718c2ecf20Sopenharmony_ci sg_len = sg_dma_len(sgel); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci buf_off = sg_addr & (ddp_pagesz - 1); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* Except 1st buffer,all buffer addr have to be Page aligned */ 5768c2ecf20Sopenharmony_ci if (i != 0 && buf_off) { 5778c2ecf20Sopenharmony_ci csio_dbg(hw, "SGL addr not DDP aligned (%llx:%d)\n", 5788c2ecf20Sopenharmony_ci sg_addr, sg_len); 5798c2ecf20Sopenharmony_ci goto unaligned; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* Except last buffer,all buffer must end on page boundary */ 5838c2ecf20Sopenharmony_ci if ((i != (req->nsge - 1)) && 5848c2ecf20Sopenharmony_ci ((buf_off + sg_len) & (ddp_pagesz - 1))) { 5858c2ecf20Sopenharmony_ci csio_dbg(hw, 5868c2ecf20Sopenharmony_ci "SGL addr not ending on page boundary" 5878c2ecf20Sopenharmony_ci "(%llx:%d)\n", sg_addr, sg_len); 5888c2ecf20Sopenharmony_ci goto unaligned; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* SGL's are virtually contiguous. HW will DDP to SGLs */ 5938c2ecf20Sopenharmony_ci req->dcopy = 0; 5948c2ecf20Sopenharmony_ci csio_scsi_read(req); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci return; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ciunaligned: 5998c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_unaligned); 6008c2ecf20Sopenharmony_ci /* 6018c2ecf20Sopenharmony_ci * For unaligned SGLs, driver will allocate internal DDP buffer. 6028c2ecf20Sopenharmony_ci * Once command is completed data from DDP buffer copied to SGLs 6038c2ecf20Sopenharmony_ci */ 6048c2ecf20Sopenharmony_ci req->dcopy = 1; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* Use gen_list to store the DDP buffers */ 6078c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&req->gen_list); 6088c2ecf20Sopenharmony_ci xfer_len = scsi_bufflen(scmnd); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci i = 0; 6118c2ecf20Sopenharmony_ci /* Allocate ddp buffers for this request */ 6128c2ecf20Sopenharmony_ci while (alloc_len < xfer_len) { 6138c2ecf20Sopenharmony_ci dma_buf = csio_get_scsi_ddp(scsim); 6148c2ecf20Sopenharmony_ci if (dma_buf == NULL || i > scsim->max_sge) { 6158c2ecf20Sopenharmony_ci req->drv_status = -EBUSY; 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci alloc_len += dma_buf->len; 6198c2ecf20Sopenharmony_ci /* Added to IO req */ 6208c2ecf20Sopenharmony_ci list_add_tail(&dma_buf->list, &req->gen_list); 6218c2ecf20Sopenharmony_ci i++; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (!req->drv_status) { 6258c2ecf20Sopenharmony_ci /* set number of ddp bufs used */ 6268c2ecf20Sopenharmony_ci req->nsge = i; 6278c2ecf20Sopenharmony_ci csio_scsi_read(req); 6288c2ecf20Sopenharmony_ci return; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* release dma descs */ 6328c2ecf20Sopenharmony_ci if (i > 0) 6338c2ecf20Sopenharmony_ci csio_put_scsi_ddp_list(scsim, &req->gen_list, i); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci/* 6378c2ecf20Sopenharmony_ci * csio_scsi_init_abrt_cls_wr - Initialize an ABORT/CLOSE WR. 6388c2ecf20Sopenharmony_ci * @req: IO req structure. 6398c2ecf20Sopenharmony_ci * @addr: DMA location to place the payload. 6408c2ecf20Sopenharmony_ci * @size: Size of WR 6418c2ecf20Sopenharmony_ci * @abort: abort OR close 6428c2ecf20Sopenharmony_ci * 6438c2ecf20Sopenharmony_ci * Wrapper for populating fw_scsi_cmd_wr. 6448c2ecf20Sopenharmony_ci */ 6458c2ecf20Sopenharmony_cistatic inline void 6468c2ecf20Sopenharmony_cicsio_scsi_init_abrt_cls_wr(struct csio_ioreq *req, void *addr, uint32_t size, 6478c2ecf20Sopenharmony_ci bool abort) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 6508c2ecf20Sopenharmony_ci struct csio_rnode *rn = req->rnode; 6518c2ecf20Sopenharmony_ci struct fw_scsi_abrt_cls_wr *wr = (struct fw_scsi_abrt_cls_wr *)addr; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_ABRT_CLS_WR)); 6548c2ecf20Sopenharmony_ci wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) | 6558c2ecf20Sopenharmony_ci FW_WR_LEN16_V( 6568c2ecf20Sopenharmony_ci DIV_ROUND_UP(size, 16))); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci wr->cookie = (uintptr_t) req; 6598c2ecf20Sopenharmony_ci wr->iqid = cpu_to_be16(csio_q_physiqid(hw, req->iq_idx)); 6608c2ecf20Sopenharmony_ci wr->tmo_val = (uint8_t) req->tmo; 6618c2ecf20Sopenharmony_ci /* 0 for CHK_ALL_IO tells FW to look up t_cookie */ 6628c2ecf20Sopenharmony_ci wr->sub_opcode_to_chk_all_io = 6638c2ecf20Sopenharmony_ci (FW_SCSI_ABRT_CLS_WR_SUB_OPCODE(abort) | 6648c2ecf20Sopenharmony_ci FW_SCSI_ABRT_CLS_WR_CHK_ALL_IO(0)); 6658c2ecf20Sopenharmony_ci wr->r3[0] = 0; 6668c2ecf20Sopenharmony_ci wr->r3[1] = 0; 6678c2ecf20Sopenharmony_ci wr->r3[2] = 0; 6688c2ecf20Sopenharmony_ci wr->r3[3] = 0; 6698c2ecf20Sopenharmony_ci /* Since we re-use the same ioreq for abort as well */ 6708c2ecf20Sopenharmony_ci wr->t_cookie = (uintptr_t) req; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic inline void 6748c2ecf20Sopenharmony_cicsio_scsi_abrt_cls(struct csio_ioreq *req, bool abort) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci struct csio_wr_pair wrp; 6778c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 6788c2ecf20Sopenharmony_ci uint32_t size = ALIGN(sizeof(struct fw_scsi_abrt_cls_wr), 16); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci req->drv_status = csio_wr_get(hw, req->eq_idx, size, &wrp); 6818c2ecf20Sopenharmony_ci if (req->drv_status != 0) 6828c2ecf20Sopenharmony_ci return; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (wrp.size1 >= size) { 6858c2ecf20Sopenharmony_ci /* Initialize WR in one shot */ 6868c2ecf20Sopenharmony_ci csio_scsi_init_abrt_cls_wr(req, wrp.addr1, size, abort); 6878c2ecf20Sopenharmony_ci } else { 6888c2ecf20Sopenharmony_ci uint8_t *tmpwr = csio_q_eq_wrap(hw, req->eq_idx); 6898c2ecf20Sopenharmony_ci /* 6908c2ecf20Sopenharmony_ci * Make a temporary copy of the WR and write back 6918c2ecf20Sopenharmony_ci * the copy into the WR pair. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci csio_scsi_init_abrt_cls_wr(req, (void *)tmpwr, size, abort); 6948c2ecf20Sopenharmony_ci memcpy(wrp.addr1, tmpwr, wrp.size1); 6958c2ecf20Sopenharmony_ci memcpy(wrp.addr2, tmpwr + wrp.size1, size - wrp.size1); 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci/*****************************************************************************/ 7008c2ecf20Sopenharmony_ci/* START: SCSI SM */ 7018c2ecf20Sopenharmony_ci/*****************************************************************************/ 7028c2ecf20Sopenharmony_cistatic void 7038c2ecf20Sopenharmony_cicsio_scsis_uninit(struct csio_ioreq *req, enum csio_scsi_ev evt) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 7068c2ecf20Sopenharmony_ci struct csio_scsim *scsim = csio_hw_to_scsim(hw); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci switch (evt) { 7098c2ecf20Sopenharmony_ci case CSIO_SCSIE_START_IO: 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (req->nsge) { 7128c2ecf20Sopenharmony_ci if (req->datadir == DMA_TO_DEVICE) { 7138c2ecf20Sopenharmony_ci req->dcopy = 0; 7148c2ecf20Sopenharmony_ci csio_scsi_write(req); 7158c2ecf20Sopenharmony_ci } else 7168c2ecf20Sopenharmony_ci csio_setup_ddp(scsim, req); 7178c2ecf20Sopenharmony_ci } else { 7188c2ecf20Sopenharmony_ci csio_scsi_cmd(req); 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (likely(req->drv_status == 0)) { 7228c2ecf20Sopenharmony_ci /* change state and enqueue on active_q */ 7238c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_io_active); 7248c2ecf20Sopenharmony_ci list_add_tail(&req->sm.sm_list, &scsim->active_q); 7258c2ecf20Sopenharmony_ci csio_wr_issue(hw, req->eq_idx, false); 7268c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_active); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci return; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci break; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci case CSIO_SCSIE_START_TM: 7338c2ecf20Sopenharmony_ci csio_scsi_cmd(req); 7348c2ecf20Sopenharmony_ci if (req->drv_status == 0) { 7358c2ecf20Sopenharmony_ci /* 7368c2ecf20Sopenharmony_ci * NOTE: We collect the affected I/Os prior to issuing 7378c2ecf20Sopenharmony_ci * LUN reset, and not after it. This is to prevent 7388c2ecf20Sopenharmony_ci * aborting I/Os that get issued after the LUN reset, 7398c2ecf20Sopenharmony_ci * but prior to LUN reset completion (in the event that 7408c2ecf20Sopenharmony_ci * the host stack has not blocked I/Os to a LUN that is 7418c2ecf20Sopenharmony_ci * being reset. 7428c2ecf20Sopenharmony_ci */ 7438c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_tm_active); 7448c2ecf20Sopenharmony_ci list_add_tail(&req->sm.sm_list, &scsim->active_q); 7458c2ecf20Sopenharmony_ci csio_wr_issue(hw, req->eq_idx, false); 7468c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_tm_active); 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci return; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci case CSIO_SCSIE_ABORT: 7518c2ecf20Sopenharmony_ci case CSIO_SCSIE_CLOSE: 7528c2ecf20Sopenharmony_ci /* 7538c2ecf20Sopenharmony_ci * NOTE: 7548c2ecf20Sopenharmony_ci * We could get here due to : 7558c2ecf20Sopenharmony_ci * - a window in the cleanup path of the SCSI module 7568c2ecf20Sopenharmony_ci * (csio_scsi_abort_io()). Please see NOTE in this function. 7578c2ecf20Sopenharmony_ci * - a window in the time we tried to issue an abort/close 7588c2ecf20Sopenharmony_ci * of a request to FW, and the FW completed the request 7598c2ecf20Sopenharmony_ci * itself. 7608c2ecf20Sopenharmony_ci * Print a message for now, and return INVAL either way. 7618c2ecf20Sopenharmony_ci */ 7628c2ecf20Sopenharmony_ci req->drv_status = -EINVAL; 7638c2ecf20Sopenharmony_ci csio_warn(hw, "Trying to abort/close completed IO:%p!\n", req); 7648c2ecf20Sopenharmony_ci break; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci default: 7678c2ecf20Sopenharmony_ci csio_dbg(hw, "Unhandled event:%d sent to req:%p\n", evt, req); 7688c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic void 7738c2ecf20Sopenharmony_cicsio_scsis_io_active(struct csio_ioreq *req, enum csio_scsi_ev evt) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 7768c2ecf20Sopenharmony_ci struct csio_scsim *scm = csio_hw_to_scsim(hw); 7778c2ecf20Sopenharmony_ci struct csio_rnode *rn; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci switch (evt) { 7808c2ecf20Sopenharmony_ci case CSIO_SCSIE_COMPLETED: 7818c2ecf20Sopenharmony_ci CSIO_DEC_STATS(scm, n_active); 7828c2ecf20Sopenharmony_ci list_del_init(&req->sm.sm_list); 7838c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_uninit); 7848c2ecf20Sopenharmony_ci /* 7858c2ecf20Sopenharmony_ci * In MSIX mode, with multiple queues, the SCSI compeltions 7868c2ecf20Sopenharmony_ci * could reach us sooner than the FW events sent to indicate 7878c2ecf20Sopenharmony_ci * I-T nexus loss (link down, remote device logo etc). We 7888c2ecf20Sopenharmony_ci * dont want to be returning such I/Os to the upper layer 7898c2ecf20Sopenharmony_ci * immediately, since we wouldnt have reported the I-T nexus 7908c2ecf20Sopenharmony_ci * loss itself. This forces us to serialize such completions 7918c2ecf20Sopenharmony_ci * with the reporting of the I-T nexus loss. Therefore, we 7928c2ecf20Sopenharmony_ci * internally queue up such up such completions in the rnode. 7938c2ecf20Sopenharmony_ci * The reporting of I-T nexus loss to the upper layer is then 7948c2ecf20Sopenharmony_ci * followed by the returning of I/Os in this internal queue. 7958c2ecf20Sopenharmony_ci * Having another state alongwith another queue helps us take 7968c2ecf20Sopenharmony_ci * actions for events such as ABORT received while we are 7978c2ecf20Sopenharmony_ci * in this rnode queue. 7988c2ecf20Sopenharmony_ci */ 7998c2ecf20Sopenharmony_ci if (unlikely(req->wr_status != FW_SUCCESS)) { 8008c2ecf20Sopenharmony_ci rn = req->rnode; 8018c2ecf20Sopenharmony_ci /* 8028c2ecf20Sopenharmony_ci * FW says remote device is lost, but rnode 8038c2ecf20Sopenharmony_ci * doesnt reflect it. 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_ci if (csio_scsi_itnexus_loss_error(req->wr_status) && 8068c2ecf20Sopenharmony_ci csio_is_rnode_ready(rn)) { 8078c2ecf20Sopenharmony_ci csio_set_state(&req->sm, 8088c2ecf20Sopenharmony_ci csio_scsis_shost_cmpl_await); 8098c2ecf20Sopenharmony_ci list_add_tail(&req->sm.sm_list, 8108c2ecf20Sopenharmony_ci &rn->host_cmpl_q); 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci break; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci case CSIO_SCSIE_ABORT: 8178c2ecf20Sopenharmony_ci csio_scsi_abrt_cls(req, SCSI_ABORT); 8188c2ecf20Sopenharmony_ci if (req->drv_status == 0) { 8198c2ecf20Sopenharmony_ci csio_wr_issue(hw, req->eq_idx, false); 8208c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_aborting); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci break; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci case CSIO_SCSIE_CLOSE: 8258c2ecf20Sopenharmony_ci csio_scsi_abrt_cls(req, SCSI_CLOSE); 8268c2ecf20Sopenharmony_ci if (req->drv_status == 0) { 8278c2ecf20Sopenharmony_ci csio_wr_issue(hw, req->eq_idx, false); 8288c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_closing); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci break; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci case CSIO_SCSIE_DRVCLEANUP: 8338c2ecf20Sopenharmony_ci req->wr_status = FW_HOSTERROR; 8348c2ecf20Sopenharmony_ci CSIO_DEC_STATS(scm, n_active); 8358c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_uninit); 8368c2ecf20Sopenharmony_ci break; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci default: 8398c2ecf20Sopenharmony_ci csio_dbg(hw, "Unhandled event:%d sent to req:%p\n", evt, req); 8408c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic void 8458c2ecf20Sopenharmony_cicsio_scsis_tm_active(struct csio_ioreq *req, enum csio_scsi_ev evt) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 8488c2ecf20Sopenharmony_ci struct csio_scsim *scm = csio_hw_to_scsim(hw); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci switch (evt) { 8518c2ecf20Sopenharmony_ci case CSIO_SCSIE_COMPLETED: 8528c2ecf20Sopenharmony_ci CSIO_DEC_STATS(scm, n_tm_active); 8538c2ecf20Sopenharmony_ci list_del_init(&req->sm.sm_list); 8548c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_uninit); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci break; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci case CSIO_SCSIE_ABORT: 8598c2ecf20Sopenharmony_ci csio_scsi_abrt_cls(req, SCSI_ABORT); 8608c2ecf20Sopenharmony_ci if (req->drv_status == 0) { 8618c2ecf20Sopenharmony_ci csio_wr_issue(hw, req->eq_idx, false); 8628c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_aborting); 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci break; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci case CSIO_SCSIE_CLOSE: 8688c2ecf20Sopenharmony_ci csio_scsi_abrt_cls(req, SCSI_CLOSE); 8698c2ecf20Sopenharmony_ci if (req->drv_status == 0) { 8708c2ecf20Sopenharmony_ci csio_wr_issue(hw, req->eq_idx, false); 8718c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_closing); 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci break; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci case CSIO_SCSIE_DRVCLEANUP: 8768c2ecf20Sopenharmony_ci req->wr_status = FW_HOSTERROR; 8778c2ecf20Sopenharmony_ci CSIO_DEC_STATS(scm, n_tm_active); 8788c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_uninit); 8798c2ecf20Sopenharmony_ci break; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci default: 8828c2ecf20Sopenharmony_ci csio_dbg(hw, "Unhandled event:%d sent to req:%p\n", evt, req); 8838c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic void 8888c2ecf20Sopenharmony_cicsio_scsis_aborting(struct csio_ioreq *req, enum csio_scsi_ev evt) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 8918c2ecf20Sopenharmony_ci struct csio_scsim *scm = csio_hw_to_scsim(hw); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci switch (evt) { 8948c2ecf20Sopenharmony_ci case CSIO_SCSIE_COMPLETED: 8958c2ecf20Sopenharmony_ci csio_dbg(hw, 8968c2ecf20Sopenharmony_ci "ioreq %p recvd cmpltd (wr_status:%d) " 8978c2ecf20Sopenharmony_ci "in aborting st\n", req, req->wr_status); 8988c2ecf20Sopenharmony_ci /* 8998c2ecf20Sopenharmony_ci * Use -ECANCELED to explicitly tell the ABORTED event that 9008c2ecf20Sopenharmony_ci * the original I/O was returned to driver by FW. 9018c2ecf20Sopenharmony_ci * We dont really care if the I/O was returned with success by 9028c2ecf20Sopenharmony_ci * FW (because the ABORT and completion of the I/O crossed each 9038c2ecf20Sopenharmony_ci * other), or any other return value. Once we are in aborting 9048c2ecf20Sopenharmony_ci * state, the success or failure of the I/O is unimportant to 9058c2ecf20Sopenharmony_ci * us. 9068c2ecf20Sopenharmony_ci */ 9078c2ecf20Sopenharmony_ci req->drv_status = -ECANCELED; 9088c2ecf20Sopenharmony_ci break; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci case CSIO_SCSIE_ABORT: 9118c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_abrt_dups); 9128c2ecf20Sopenharmony_ci break; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci case CSIO_SCSIE_ABORTED: 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci csio_dbg(hw, "abort of %p return status:0x%x drv_status:%x\n", 9178c2ecf20Sopenharmony_ci req, req->wr_status, req->drv_status); 9188c2ecf20Sopenharmony_ci /* 9198c2ecf20Sopenharmony_ci * Check if original I/O WR completed before the Abort 9208c2ecf20Sopenharmony_ci * completion. 9218c2ecf20Sopenharmony_ci */ 9228c2ecf20Sopenharmony_ci if (req->drv_status != -ECANCELED) { 9238c2ecf20Sopenharmony_ci csio_warn(hw, 9248c2ecf20Sopenharmony_ci "Abort completed before original I/O," 9258c2ecf20Sopenharmony_ci " req:%p\n", req); 9268c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* 9308c2ecf20Sopenharmony_ci * There are the following possible scenarios: 9318c2ecf20Sopenharmony_ci * 1. The abort completed successfully, FW returned FW_SUCCESS. 9328c2ecf20Sopenharmony_ci * 2. The completion of an I/O and the receipt of 9338c2ecf20Sopenharmony_ci * abort for that I/O by the FW crossed each other. 9348c2ecf20Sopenharmony_ci * The FW returned FW_EINVAL. The original I/O would have 9358c2ecf20Sopenharmony_ci * returned with FW_SUCCESS or any other SCSI error. 9368c2ecf20Sopenharmony_ci * 3. The FW couldn't sent the abort out on the wire, as there 9378c2ecf20Sopenharmony_ci * was an I-T nexus loss (link down, remote device logged 9388c2ecf20Sopenharmony_ci * out etc). FW sent back an appropriate IT nexus loss status 9398c2ecf20Sopenharmony_ci * for the abort. 9408c2ecf20Sopenharmony_ci * 4. FW sent an abort, but abort timed out (remote device 9418c2ecf20Sopenharmony_ci * didnt respond). FW replied back with 9428c2ecf20Sopenharmony_ci * FW_SCSI_ABORT_TIMEDOUT. 9438c2ecf20Sopenharmony_ci * 5. FW couldn't genuinely abort the request for some reason, 9448c2ecf20Sopenharmony_ci * and sent us an error. 9458c2ecf20Sopenharmony_ci * 9468c2ecf20Sopenharmony_ci * The first 3 scenarios are treated as succesful abort 9478c2ecf20Sopenharmony_ci * operations by the host, while the last 2 are failed attempts 9488c2ecf20Sopenharmony_ci * to abort. Manipulate the return value of the request 9498c2ecf20Sopenharmony_ci * appropriately, so that host can convey these results 9508c2ecf20Sopenharmony_ci * back to the upper layer. 9518c2ecf20Sopenharmony_ci */ 9528c2ecf20Sopenharmony_ci if ((req->wr_status == FW_SUCCESS) || 9538c2ecf20Sopenharmony_ci (req->wr_status == FW_EINVAL) || 9548c2ecf20Sopenharmony_ci csio_scsi_itnexus_loss_error(req->wr_status)) 9558c2ecf20Sopenharmony_ci req->wr_status = FW_SCSI_ABORT_REQUESTED; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci CSIO_DEC_STATS(scm, n_active); 9588c2ecf20Sopenharmony_ci list_del_init(&req->sm.sm_list); 9598c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_uninit); 9608c2ecf20Sopenharmony_ci break; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci case CSIO_SCSIE_DRVCLEANUP: 9638c2ecf20Sopenharmony_ci req->wr_status = FW_HOSTERROR; 9648c2ecf20Sopenharmony_ci CSIO_DEC_STATS(scm, n_active); 9658c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_uninit); 9668c2ecf20Sopenharmony_ci break; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci case CSIO_SCSIE_CLOSE: 9698c2ecf20Sopenharmony_ci /* 9708c2ecf20Sopenharmony_ci * We can receive this event from the module 9718c2ecf20Sopenharmony_ci * cleanup paths, if the FW forgot to reply to the ABORT WR 9728c2ecf20Sopenharmony_ci * and left this ioreq in this state. For now, just ignore 9738c2ecf20Sopenharmony_ci * the event. The CLOSE event is sent to this state, as 9748c2ecf20Sopenharmony_ci * the LINK may have already gone down. 9758c2ecf20Sopenharmony_ci */ 9768c2ecf20Sopenharmony_ci break; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci default: 9798c2ecf20Sopenharmony_ci csio_dbg(hw, "Unhandled event:%d sent to req:%p\n", evt, req); 9808c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic void 9858c2ecf20Sopenharmony_cicsio_scsis_closing(struct csio_ioreq *req, enum csio_scsi_ev evt) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct csio_hw *hw = req->lnode->hwp; 9888c2ecf20Sopenharmony_ci struct csio_scsim *scm = csio_hw_to_scsim(hw); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci switch (evt) { 9918c2ecf20Sopenharmony_ci case CSIO_SCSIE_COMPLETED: 9928c2ecf20Sopenharmony_ci csio_dbg(hw, 9938c2ecf20Sopenharmony_ci "ioreq %p recvd cmpltd (wr_status:%d) " 9948c2ecf20Sopenharmony_ci "in closing st\n", req, req->wr_status); 9958c2ecf20Sopenharmony_ci /* 9968c2ecf20Sopenharmony_ci * Use -ECANCELED to explicitly tell the CLOSED event that 9978c2ecf20Sopenharmony_ci * the original I/O was returned to driver by FW. 9988c2ecf20Sopenharmony_ci * We dont really care if the I/O was returned with success by 9998c2ecf20Sopenharmony_ci * FW (because the CLOSE and completion of the I/O crossed each 10008c2ecf20Sopenharmony_ci * other), or any other return value. Once we are in aborting 10018c2ecf20Sopenharmony_ci * state, the success or failure of the I/O is unimportant to 10028c2ecf20Sopenharmony_ci * us. 10038c2ecf20Sopenharmony_ci */ 10048c2ecf20Sopenharmony_ci req->drv_status = -ECANCELED; 10058c2ecf20Sopenharmony_ci break; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci case CSIO_SCSIE_CLOSED: 10088c2ecf20Sopenharmony_ci /* 10098c2ecf20Sopenharmony_ci * Check if original I/O WR completed before the Close 10108c2ecf20Sopenharmony_ci * completion. 10118c2ecf20Sopenharmony_ci */ 10128c2ecf20Sopenharmony_ci if (req->drv_status != -ECANCELED) { 10138c2ecf20Sopenharmony_ci csio_fatal(hw, 10148c2ecf20Sopenharmony_ci "Close completed before original I/O," 10158c2ecf20Sopenharmony_ci " req:%p\n", req); 10168c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci /* 10208c2ecf20Sopenharmony_ci * Either close succeeded, or we issued close to FW at the 10218c2ecf20Sopenharmony_ci * same time FW compelted it to us. Either way, the I/O 10228c2ecf20Sopenharmony_ci * is closed. 10238c2ecf20Sopenharmony_ci */ 10248c2ecf20Sopenharmony_ci CSIO_DB_ASSERT((req->wr_status == FW_SUCCESS) || 10258c2ecf20Sopenharmony_ci (req->wr_status == FW_EINVAL)); 10268c2ecf20Sopenharmony_ci req->wr_status = FW_SCSI_CLOSE_REQUESTED; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci CSIO_DEC_STATS(scm, n_active); 10298c2ecf20Sopenharmony_ci list_del_init(&req->sm.sm_list); 10308c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_uninit); 10318c2ecf20Sopenharmony_ci break; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci case CSIO_SCSIE_CLOSE: 10348c2ecf20Sopenharmony_ci break; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci case CSIO_SCSIE_DRVCLEANUP: 10378c2ecf20Sopenharmony_ci req->wr_status = FW_HOSTERROR; 10388c2ecf20Sopenharmony_ci CSIO_DEC_STATS(scm, n_active); 10398c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_uninit); 10408c2ecf20Sopenharmony_ci break; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci default: 10438c2ecf20Sopenharmony_ci csio_dbg(hw, "Unhandled event:%d sent to req:%p\n", evt, req); 10448c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_cistatic void 10498c2ecf20Sopenharmony_cicsio_scsis_shost_cmpl_await(struct csio_ioreq *req, enum csio_scsi_ev evt) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci switch (evt) { 10528c2ecf20Sopenharmony_ci case CSIO_SCSIE_ABORT: 10538c2ecf20Sopenharmony_ci case CSIO_SCSIE_CLOSE: 10548c2ecf20Sopenharmony_ci /* 10558c2ecf20Sopenharmony_ci * Just succeed the abort request, and hope that 10568c2ecf20Sopenharmony_ci * the remote device unregister path will cleanup 10578c2ecf20Sopenharmony_ci * this I/O to the upper layer within a sane 10588c2ecf20Sopenharmony_ci * amount of time. 10598c2ecf20Sopenharmony_ci */ 10608c2ecf20Sopenharmony_ci /* 10618c2ecf20Sopenharmony_ci * A close can come in during a LINK DOWN. The FW would have 10628c2ecf20Sopenharmony_ci * returned us the I/O back, but not the remote device lost 10638c2ecf20Sopenharmony_ci * FW event. In this interval, if the I/O times out at the upper 10648c2ecf20Sopenharmony_ci * layer, a close can come in. Take the same action as abort: 10658c2ecf20Sopenharmony_ci * return success, and hope that the remote device unregister 10668c2ecf20Sopenharmony_ci * path will cleanup this I/O. If the FW still doesnt send 10678c2ecf20Sopenharmony_ci * the msg, the close times out, and the upper layer resorts 10688c2ecf20Sopenharmony_ci * to the next level of error recovery. 10698c2ecf20Sopenharmony_ci */ 10708c2ecf20Sopenharmony_ci req->drv_status = 0; 10718c2ecf20Sopenharmony_ci break; 10728c2ecf20Sopenharmony_ci case CSIO_SCSIE_DRVCLEANUP: 10738c2ecf20Sopenharmony_ci csio_set_state(&req->sm, csio_scsis_uninit); 10748c2ecf20Sopenharmony_ci break; 10758c2ecf20Sopenharmony_ci default: 10768c2ecf20Sopenharmony_ci csio_dbg(req->lnode->hwp, "Unhandled event:%d sent to req:%p\n", 10778c2ecf20Sopenharmony_ci evt, req); 10788c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci/* 10838c2ecf20Sopenharmony_ci * csio_scsi_cmpl_handler - WR completion handler for SCSI. 10848c2ecf20Sopenharmony_ci * @hw: HW module. 10858c2ecf20Sopenharmony_ci * @wr: The completed WR from the ingress queue. 10868c2ecf20Sopenharmony_ci * @len: Length of the WR. 10878c2ecf20Sopenharmony_ci * @flb: Freelist buffer array. 10888c2ecf20Sopenharmony_ci * @priv: Private object 10898c2ecf20Sopenharmony_ci * @scsiwr: Pointer to SCSI WR. 10908c2ecf20Sopenharmony_ci * 10918c2ecf20Sopenharmony_ci * This is the WR completion handler called per completion from the 10928c2ecf20Sopenharmony_ci * ISR. It is called with lock held. It walks past the RSS and CPL message 10938c2ecf20Sopenharmony_ci * header where the actual WR is present. 10948c2ecf20Sopenharmony_ci * It then gets the status, WR handle (ioreq pointer) and the len of 10958c2ecf20Sopenharmony_ci * the WR, based on WR opcode. Only on a non-good status is the entire 10968c2ecf20Sopenharmony_ci * WR copied into the WR cache (ioreq->fw_wr). 10978c2ecf20Sopenharmony_ci * The ioreq corresponding to the WR is returned to the caller. 10988c2ecf20Sopenharmony_ci * NOTE: The SCSI queue doesnt allocate a freelist today, hence 10998c2ecf20Sopenharmony_ci * no freelist buffer is expected. 11008c2ecf20Sopenharmony_ci */ 11018c2ecf20Sopenharmony_cistruct csio_ioreq * 11028c2ecf20Sopenharmony_cicsio_scsi_cmpl_handler(struct csio_hw *hw, void *wr, uint32_t len, 11038c2ecf20Sopenharmony_ci struct csio_fl_dma_buf *flb, void *priv, uint8_t **scsiwr) 11048c2ecf20Sopenharmony_ci{ 11058c2ecf20Sopenharmony_ci struct csio_ioreq *ioreq = NULL; 11068c2ecf20Sopenharmony_ci struct cpl_fw6_msg *cpl; 11078c2ecf20Sopenharmony_ci uint8_t *tempwr; 11088c2ecf20Sopenharmony_ci uint8_t status; 11098c2ecf20Sopenharmony_ci struct csio_scsim *scm = csio_hw_to_scsim(hw); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* skip RSS header */ 11128c2ecf20Sopenharmony_ci cpl = (struct cpl_fw6_msg *)((uintptr_t)wr + sizeof(__be64)); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (unlikely(cpl->opcode != CPL_FW6_MSG)) { 11158c2ecf20Sopenharmony_ci csio_warn(hw, "Error: Invalid CPL msg %x recvd on SCSI q\n", 11168c2ecf20Sopenharmony_ci cpl->opcode); 11178c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_inval_cplop); 11188c2ecf20Sopenharmony_ci return NULL; 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci tempwr = (uint8_t *)(cpl->data); 11228c2ecf20Sopenharmony_ci status = csio_wr_status(tempwr); 11238c2ecf20Sopenharmony_ci *scsiwr = tempwr; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (likely((*tempwr == FW_SCSI_READ_WR) || 11268c2ecf20Sopenharmony_ci (*tempwr == FW_SCSI_WRITE_WR) || 11278c2ecf20Sopenharmony_ci (*tempwr == FW_SCSI_CMD_WR))) { 11288c2ecf20Sopenharmony_ci ioreq = (struct csio_ioreq *)((uintptr_t) 11298c2ecf20Sopenharmony_ci (((struct fw_scsi_read_wr *)tempwr)->cookie)); 11308c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(virt_addr_valid(ioreq)); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci ioreq->wr_status = status; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci return ioreq; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (*tempwr == FW_SCSI_ABRT_CLS_WR) { 11388c2ecf20Sopenharmony_ci ioreq = (struct csio_ioreq *)((uintptr_t) 11398c2ecf20Sopenharmony_ci (((struct fw_scsi_abrt_cls_wr *)tempwr)->cookie)); 11408c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(virt_addr_valid(ioreq)); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci ioreq->wr_status = status; 11438c2ecf20Sopenharmony_ci return ioreq; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci csio_warn(hw, "WR with invalid opcode in SCSI IQ: %x\n", *tempwr); 11478c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_inval_scsiop); 11488c2ecf20Sopenharmony_ci return NULL; 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci/* 11528c2ecf20Sopenharmony_ci * csio_scsi_cleanup_io_q - Cleanup the given queue. 11538c2ecf20Sopenharmony_ci * @scm: SCSI module. 11548c2ecf20Sopenharmony_ci * @q: Queue to be cleaned up. 11558c2ecf20Sopenharmony_ci * 11568c2ecf20Sopenharmony_ci * Called with lock held. Has to exit with lock held. 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_civoid 11598c2ecf20Sopenharmony_cicsio_scsi_cleanup_io_q(struct csio_scsim *scm, struct list_head *q) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci struct csio_hw *hw = scm->hw; 11628c2ecf20Sopenharmony_ci struct csio_ioreq *ioreq; 11638c2ecf20Sopenharmony_ci struct list_head *tmp, *next; 11648c2ecf20Sopenharmony_ci struct scsi_cmnd *scmnd; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci /* Call back the completion routines of the active_q */ 11678c2ecf20Sopenharmony_ci list_for_each_safe(tmp, next, q) { 11688c2ecf20Sopenharmony_ci ioreq = (struct csio_ioreq *)tmp; 11698c2ecf20Sopenharmony_ci csio_scsi_drvcleanup(ioreq); 11708c2ecf20Sopenharmony_ci list_del_init(&ioreq->sm.sm_list); 11718c2ecf20Sopenharmony_ci scmnd = csio_scsi_cmnd(ioreq); 11728c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci /* 11758c2ecf20Sopenharmony_ci * Upper layers may have cleared this command, hence this 11768c2ecf20Sopenharmony_ci * check to avoid accessing stale references. 11778c2ecf20Sopenharmony_ci */ 11788c2ecf20Sopenharmony_ci if (scmnd != NULL) 11798c2ecf20Sopenharmony_ci ioreq->io_cbfn(hw, ioreq); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci spin_lock_irq(&scm->freelist_lock); 11828c2ecf20Sopenharmony_ci csio_put_scsi_ioreq(scm, ioreq); 11838c2ecf20Sopenharmony_ci spin_unlock_irq(&scm->freelist_lock); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci#define CSIO_SCSI_ABORT_Q_POLL_MS 2000 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_cistatic void 11928c2ecf20Sopenharmony_cicsio_abrt_cls(struct csio_ioreq *ioreq, struct scsi_cmnd *scmnd) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci struct csio_lnode *ln = ioreq->lnode; 11958c2ecf20Sopenharmony_ci struct csio_hw *hw = ln->hwp; 11968c2ecf20Sopenharmony_ci int ready = 0; 11978c2ecf20Sopenharmony_ci struct csio_scsim *scsim = csio_hw_to_scsim(hw); 11988c2ecf20Sopenharmony_ci int rv; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci if (csio_scsi_cmnd(ioreq) != scmnd) { 12018c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_abrt_race_comp); 12028c2ecf20Sopenharmony_ci return; 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci ready = csio_is_lnode_ready(ln); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci rv = csio_do_abrt_cls(hw, ioreq, (ready ? SCSI_ABORT : SCSI_CLOSE)); 12088c2ecf20Sopenharmony_ci if (rv != 0) { 12098c2ecf20Sopenharmony_ci if (ready) 12108c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_abrt_busy_error); 12118c2ecf20Sopenharmony_ci else 12128c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_cls_busy_error); 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci/* 12178c2ecf20Sopenharmony_ci * csio_scsi_abort_io_q - Abort all I/Os on given queue 12188c2ecf20Sopenharmony_ci * @scm: SCSI module. 12198c2ecf20Sopenharmony_ci * @q: Queue to abort. 12208c2ecf20Sopenharmony_ci * @tmo: Timeout in ms 12218c2ecf20Sopenharmony_ci * 12228c2ecf20Sopenharmony_ci * Attempt to abort all I/Os on given queue, and wait for a max 12238c2ecf20Sopenharmony_ci * of tmo milliseconds for them to complete. Returns success 12248c2ecf20Sopenharmony_ci * if all I/Os are aborted. Else returns -ETIMEDOUT. 12258c2ecf20Sopenharmony_ci * Should be entered with lock held. Exits with lock held. 12268c2ecf20Sopenharmony_ci * NOTE: 12278c2ecf20Sopenharmony_ci * Lock has to be held across the loop that aborts I/Os, since dropping the lock 12288c2ecf20Sopenharmony_ci * in between can cause the list to be corrupted. As a result, the caller 12298c2ecf20Sopenharmony_ci * of this function has to ensure that the number of I/os to be aborted 12308c2ecf20Sopenharmony_ci * is finite enough to not cause lock-held-for-too-long issues. 12318c2ecf20Sopenharmony_ci */ 12328c2ecf20Sopenharmony_cistatic int 12338c2ecf20Sopenharmony_cicsio_scsi_abort_io_q(struct csio_scsim *scm, struct list_head *q, uint32_t tmo) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci struct csio_hw *hw = scm->hw; 12368c2ecf20Sopenharmony_ci struct list_head *tmp, *next; 12378c2ecf20Sopenharmony_ci int count = DIV_ROUND_UP(tmo, CSIO_SCSI_ABORT_Q_POLL_MS); 12388c2ecf20Sopenharmony_ci struct scsi_cmnd *scmnd; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (list_empty(q)) 12418c2ecf20Sopenharmony_ci return 0; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci csio_dbg(hw, "Aborting SCSI I/Os\n"); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci /* Now abort/close I/Os in the queue passed */ 12468c2ecf20Sopenharmony_ci list_for_each_safe(tmp, next, q) { 12478c2ecf20Sopenharmony_ci scmnd = csio_scsi_cmnd((struct csio_ioreq *)tmp); 12488c2ecf20Sopenharmony_ci csio_abrt_cls((struct csio_ioreq *)tmp, scmnd); 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci /* Wait till all active I/Os are completed/aborted/closed */ 12528c2ecf20Sopenharmony_ci while (!list_empty(q) && count--) { 12538c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 12548c2ecf20Sopenharmony_ci msleep(CSIO_SCSI_ABORT_Q_POLL_MS); 12558c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci /* all aborts completed */ 12598c2ecf20Sopenharmony_ci if (list_empty(q)) 12608c2ecf20Sopenharmony_ci return 0; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci return -ETIMEDOUT; 12638c2ecf20Sopenharmony_ci} 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci/* 12668c2ecf20Sopenharmony_ci * csio_scsim_cleanup_io - Cleanup all I/Os in SCSI module. 12678c2ecf20Sopenharmony_ci * @scm: SCSI module. 12688c2ecf20Sopenharmony_ci * @abort: abort required. 12698c2ecf20Sopenharmony_ci * Called with lock held, should exit with lock held. 12708c2ecf20Sopenharmony_ci * Can sleep when waiting for I/Os to complete. 12718c2ecf20Sopenharmony_ci */ 12728c2ecf20Sopenharmony_ciint 12738c2ecf20Sopenharmony_cicsio_scsim_cleanup_io(struct csio_scsim *scm, bool abort) 12748c2ecf20Sopenharmony_ci{ 12758c2ecf20Sopenharmony_ci struct csio_hw *hw = scm->hw; 12768c2ecf20Sopenharmony_ci int rv = 0; 12778c2ecf20Sopenharmony_ci int count = DIV_ROUND_UP(60 * 1000, CSIO_SCSI_ABORT_Q_POLL_MS); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci /* No I/Os pending */ 12808c2ecf20Sopenharmony_ci if (list_empty(&scm->active_q)) 12818c2ecf20Sopenharmony_ci return 0; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* Wait until all active I/Os are completed */ 12848c2ecf20Sopenharmony_ci while (!list_empty(&scm->active_q) && count--) { 12858c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 12868c2ecf20Sopenharmony_ci msleep(CSIO_SCSI_ABORT_Q_POLL_MS); 12878c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci /* all I/Os completed */ 12918c2ecf20Sopenharmony_ci if (list_empty(&scm->active_q)) 12928c2ecf20Sopenharmony_ci return 0; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* Else abort */ 12958c2ecf20Sopenharmony_ci if (abort) { 12968c2ecf20Sopenharmony_ci rv = csio_scsi_abort_io_q(scm, &scm->active_q, 30000); 12978c2ecf20Sopenharmony_ci if (rv == 0) 12988c2ecf20Sopenharmony_ci return rv; 12998c2ecf20Sopenharmony_ci csio_dbg(hw, "Some I/O aborts timed out, cleaning up..\n"); 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci csio_scsi_cleanup_io_q(scm, &scm->active_q); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(list_empty(&scm->active_q)); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci return rv; 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci/* 13108c2ecf20Sopenharmony_ci * csio_scsim_cleanup_io_lnode - Cleanup all I/Os of given lnode. 13118c2ecf20Sopenharmony_ci * @scm: SCSI module. 13128c2ecf20Sopenharmony_ci * @lnode: lnode 13138c2ecf20Sopenharmony_ci * 13148c2ecf20Sopenharmony_ci * Called with lock held, should exit with lock held. 13158c2ecf20Sopenharmony_ci * Can sleep (with dropped lock) when waiting for I/Os to complete. 13168c2ecf20Sopenharmony_ci */ 13178c2ecf20Sopenharmony_ciint 13188c2ecf20Sopenharmony_cicsio_scsim_cleanup_io_lnode(struct csio_scsim *scm, struct csio_lnode *ln) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct csio_hw *hw = scm->hw; 13218c2ecf20Sopenharmony_ci struct csio_scsi_level_data sld; 13228c2ecf20Sopenharmony_ci int rv; 13238c2ecf20Sopenharmony_ci int count = DIV_ROUND_UP(60 * 1000, CSIO_SCSI_ABORT_Q_POLL_MS); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci csio_dbg(hw, "Gathering all SCSI I/Os on lnode %p\n", ln); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci sld.level = CSIO_LEV_LNODE; 13288c2ecf20Sopenharmony_ci sld.lnode = ln; 13298c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ln->cmpl_q); 13308c2ecf20Sopenharmony_ci csio_scsi_gather_active_ios(scm, &sld, &ln->cmpl_q); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* No I/Os pending on this lnode */ 13338c2ecf20Sopenharmony_ci if (list_empty(&ln->cmpl_q)) 13348c2ecf20Sopenharmony_ci return 0; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci /* Wait until all active I/Os on this lnode are completed */ 13378c2ecf20Sopenharmony_ci while (!list_empty(&ln->cmpl_q) && count--) { 13388c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 13398c2ecf20Sopenharmony_ci msleep(CSIO_SCSI_ABORT_Q_POLL_MS); 13408c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 13418c2ecf20Sopenharmony_ci } 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci /* all I/Os completed */ 13448c2ecf20Sopenharmony_ci if (list_empty(&ln->cmpl_q)) 13458c2ecf20Sopenharmony_ci return 0; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci csio_dbg(hw, "Some I/Os pending on ln:%p, aborting them..\n", ln); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci /* I/Os are pending, abort them */ 13508c2ecf20Sopenharmony_ci rv = csio_scsi_abort_io_q(scm, &ln->cmpl_q, 30000); 13518c2ecf20Sopenharmony_ci if (rv != 0) { 13528c2ecf20Sopenharmony_ci csio_dbg(hw, "Some I/O aborts timed out, cleaning up..\n"); 13538c2ecf20Sopenharmony_ci csio_scsi_cleanup_io_q(scm, &ln->cmpl_q); 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(list_empty(&ln->cmpl_q)); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci return rv; 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_cistatic ssize_t 13628c2ecf20Sopenharmony_cicsio_show_hw_state(struct device *dev, 13638c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci struct csio_lnode *ln = shost_priv(class_to_shost(dev)); 13668c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (csio_is_hw_ready(hw)) 13698c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "ready\n"); 13708c2ecf20Sopenharmony_ci else 13718c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "not ready\n"); 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci/* Device reset */ 13758c2ecf20Sopenharmony_cistatic ssize_t 13768c2ecf20Sopenharmony_cicsio_device_reset(struct device *dev, 13778c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci struct csio_lnode *ln = shost_priv(class_to_shost(dev)); 13808c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (*buf != '1') 13838c2ecf20Sopenharmony_ci return -EINVAL; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci /* Delete NPIV lnodes */ 13868c2ecf20Sopenharmony_ci csio_lnodes_exit(hw, 1); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci /* Block upper IOs */ 13898c2ecf20Sopenharmony_ci csio_lnodes_block_request(hw); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 13928c2ecf20Sopenharmony_ci csio_hw_reset(hw); 13938c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci /* Unblock upper IOs */ 13968c2ecf20Sopenharmony_ci csio_lnodes_unblock_request(hw); 13978c2ecf20Sopenharmony_ci return count; 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci/* disable port */ 14018c2ecf20Sopenharmony_cistatic ssize_t 14028c2ecf20Sopenharmony_cicsio_disable_port(struct device *dev, 14038c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci struct csio_lnode *ln = shost_priv(class_to_shost(dev)); 14068c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 14078c2ecf20Sopenharmony_ci bool disable; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (*buf == '1' || *buf == '0') 14108c2ecf20Sopenharmony_ci disable = (*buf == '1') ? true : false; 14118c2ecf20Sopenharmony_ci else 14128c2ecf20Sopenharmony_ci return -EINVAL; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci /* Block upper IOs */ 14158c2ecf20Sopenharmony_ci csio_lnodes_block_by_port(hw, ln->portid); 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 14188c2ecf20Sopenharmony_ci csio_disable_lnodes(hw, ln->portid, disable); 14198c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci /* Unblock upper IOs */ 14228c2ecf20Sopenharmony_ci csio_lnodes_unblock_by_port(hw, ln->portid); 14238c2ecf20Sopenharmony_ci return count; 14248c2ecf20Sopenharmony_ci} 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci/* Show debug level */ 14278c2ecf20Sopenharmony_cistatic ssize_t 14288c2ecf20Sopenharmony_cicsio_show_dbg_level(struct device *dev, 14298c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 14308c2ecf20Sopenharmony_ci{ 14318c2ecf20Sopenharmony_ci struct csio_lnode *ln = shost_priv(class_to_shost(dev)); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%x\n", ln->params.log_level); 14348c2ecf20Sopenharmony_ci} 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci/* Store debug level */ 14378c2ecf20Sopenharmony_cistatic ssize_t 14388c2ecf20Sopenharmony_cicsio_store_dbg_level(struct device *dev, 14398c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci struct csio_lnode *ln = shost_priv(class_to_shost(dev)); 14428c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 14438c2ecf20Sopenharmony_ci uint32_t dbg_level = 0; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci if (!isdigit(buf[0])) 14468c2ecf20Sopenharmony_ci return -EINVAL; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if (sscanf(buf, "%i", &dbg_level)) 14498c2ecf20Sopenharmony_ci return -EINVAL; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci ln->params.log_level = dbg_level; 14528c2ecf20Sopenharmony_ci hw->params.log_level = dbg_level; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci return 0; 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_cistatic DEVICE_ATTR(hw_state, S_IRUGO, csio_show_hw_state, NULL); 14588c2ecf20Sopenharmony_cistatic DEVICE_ATTR(device_reset, S_IWUSR, NULL, csio_device_reset); 14598c2ecf20Sopenharmony_cistatic DEVICE_ATTR(disable_port, S_IWUSR, NULL, csio_disable_port); 14608c2ecf20Sopenharmony_cistatic DEVICE_ATTR(dbg_level, S_IRUGO | S_IWUSR, csio_show_dbg_level, 14618c2ecf20Sopenharmony_ci csio_store_dbg_level); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic struct device_attribute *csio_fcoe_lport_attrs[] = { 14648c2ecf20Sopenharmony_ci &dev_attr_hw_state, 14658c2ecf20Sopenharmony_ci &dev_attr_device_reset, 14668c2ecf20Sopenharmony_ci &dev_attr_disable_port, 14678c2ecf20Sopenharmony_ci &dev_attr_dbg_level, 14688c2ecf20Sopenharmony_ci NULL, 14698c2ecf20Sopenharmony_ci}; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_cistatic ssize_t 14728c2ecf20Sopenharmony_cicsio_show_num_reg_rnodes(struct device *dev, 14738c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci struct csio_lnode *ln = shost_priv(class_to_shost(dev)); 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", ln->num_reg_rnodes); 14788c2ecf20Sopenharmony_ci} 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_cistatic DEVICE_ATTR(num_reg_rnodes, S_IRUGO, csio_show_num_reg_rnodes, NULL); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic struct device_attribute *csio_fcoe_vport_attrs[] = { 14838c2ecf20Sopenharmony_ci &dev_attr_num_reg_rnodes, 14848c2ecf20Sopenharmony_ci &dev_attr_dbg_level, 14858c2ecf20Sopenharmony_ci NULL, 14868c2ecf20Sopenharmony_ci}; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_cistatic inline uint32_t 14898c2ecf20Sopenharmony_cicsio_scsi_copy_to_sgl(struct csio_hw *hw, struct csio_ioreq *req) 14908c2ecf20Sopenharmony_ci{ 14918c2ecf20Sopenharmony_ci struct scsi_cmnd *scmnd = (struct scsi_cmnd *)csio_scsi_cmnd(req); 14928c2ecf20Sopenharmony_ci struct scatterlist *sg; 14938c2ecf20Sopenharmony_ci uint32_t bytes_left; 14948c2ecf20Sopenharmony_ci uint32_t bytes_copy; 14958c2ecf20Sopenharmony_ci uint32_t buf_off = 0; 14968c2ecf20Sopenharmony_ci uint32_t start_off = 0; 14978c2ecf20Sopenharmony_ci uint32_t sg_off = 0; 14988c2ecf20Sopenharmony_ci void *sg_addr; 14998c2ecf20Sopenharmony_ci void *buf_addr; 15008c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci bytes_left = scsi_bufflen(scmnd); 15038c2ecf20Sopenharmony_ci sg = scsi_sglist(scmnd); 15048c2ecf20Sopenharmony_ci dma_buf = (struct csio_dma_buf *)csio_list_next(&req->gen_list); 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci /* Copy data from driver buffer to SGs of SCSI CMD */ 15078c2ecf20Sopenharmony_ci while (bytes_left > 0 && sg && dma_buf) { 15088c2ecf20Sopenharmony_ci if (buf_off >= dma_buf->len) { 15098c2ecf20Sopenharmony_ci buf_off = 0; 15108c2ecf20Sopenharmony_ci dma_buf = (struct csio_dma_buf *) 15118c2ecf20Sopenharmony_ci csio_list_next(dma_buf); 15128c2ecf20Sopenharmony_ci continue; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci if (start_off >= sg->length) { 15168c2ecf20Sopenharmony_ci start_off -= sg->length; 15178c2ecf20Sopenharmony_ci sg = sg_next(sg); 15188c2ecf20Sopenharmony_ci continue; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci buf_addr = dma_buf->vaddr + buf_off; 15228c2ecf20Sopenharmony_ci sg_off = sg->offset + start_off; 15238c2ecf20Sopenharmony_ci bytes_copy = min((dma_buf->len - buf_off), 15248c2ecf20Sopenharmony_ci sg->length - start_off); 15258c2ecf20Sopenharmony_ci bytes_copy = min((uint32_t)(PAGE_SIZE - (sg_off & ~PAGE_MASK)), 15268c2ecf20Sopenharmony_ci bytes_copy); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci sg_addr = kmap_atomic(sg_page(sg) + (sg_off >> PAGE_SHIFT)); 15298c2ecf20Sopenharmony_ci if (!sg_addr) { 15308c2ecf20Sopenharmony_ci csio_err(hw, "failed to kmap sg:%p of ioreq:%p\n", 15318c2ecf20Sopenharmony_ci sg, req); 15328c2ecf20Sopenharmony_ci break; 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci csio_dbg(hw, "copy_to_sgl:sg_addr %p sg_off %d buf %p len %d\n", 15368c2ecf20Sopenharmony_ci sg_addr, sg_off, buf_addr, bytes_copy); 15378c2ecf20Sopenharmony_ci memcpy(sg_addr + (sg_off & ~PAGE_MASK), buf_addr, bytes_copy); 15388c2ecf20Sopenharmony_ci kunmap_atomic(sg_addr); 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci start_off += bytes_copy; 15418c2ecf20Sopenharmony_ci buf_off += bytes_copy; 15428c2ecf20Sopenharmony_ci bytes_left -= bytes_copy; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci if (bytes_left > 0) 15468c2ecf20Sopenharmony_ci return DID_ERROR; 15478c2ecf20Sopenharmony_ci else 15488c2ecf20Sopenharmony_ci return DID_OK; 15498c2ecf20Sopenharmony_ci} 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci/* 15528c2ecf20Sopenharmony_ci * csio_scsi_err_handler - SCSI error handler. 15538c2ecf20Sopenharmony_ci * @hw: HW module. 15548c2ecf20Sopenharmony_ci * @req: IO request. 15558c2ecf20Sopenharmony_ci * 15568c2ecf20Sopenharmony_ci */ 15578c2ecf20Sopenharmony_cistatic inline void 15588c2ecf20Sopenharmony_cicsio_scsi_err_handler(struct csio_hw *hw, struct csio_ioreq *req) 15598c2ecf20Sopenharmony_ci{ 15608c2ecf20Sopenharmony_ci struct scsi_cmnd *cmnd = (struct scsi_cmnd *)csio_scsi_cmnd(req); 15618c2ecf20Sopenharmony_ci struct csio_scsim *scm = csio_hw_to_scsim(hw); 15628c2ecf20Sopenharmony_ci struct fcp_resp_with_ext *fcp_resp; 15638c2ecf20Sopenharmony_ci struct fcp_resp_rsp_info *rsp_info; 15648c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf; 15658c2ecf20Sopenharmony_ci uint8_t flags, scsi_status = 0; 15668c2ecf20Sopenharmony_ci uint32_t host_status = DID_OK; 15678c2ecf20Sopenharmony_ci uint32_t rsp_len = 0, sns_len = 0; 15688c2ecf20Sopenharmony_ci struct csio_rnode *rn = (struct csio_rnode *)(cmnd->device->hostdata); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci switch (req->wr_status) { 15728c2ecf20Sopenharmony_ci case FW_HOSTERROR: 15738c2ecf20Sopenharmony_ci if (unlikely(!csio_is_hw_ready(hw))) 15748c2ecf20Sopenharmony_ci return; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci host_status = DID_ERROR; 15778c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_hosterror); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci break; 15808c2ecf20Sopenharmony_ci case FW_SCSI_RSP_ERR: 15818c2ecf20Sopenharmony_ci dma_buf = &req->dma_buf; 15828c2ecf20Sopenharmony_ci fcp_resp = (struct fcp_resp_with_ext *)dma_buf->vaddr; 15838c2ecf20Sopenharmony_ci rsp_info = (struct fcp_resp_rsp_info *)(fcp_resp + 1); 15848c2ecf20Sopenharmony_ci flags = fcp_resp->resp.fr_flags; 15858c2ecf20Sopenharmony_ci scsi_status = fcp_resp->resp.fr_status; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci if (flags & FCP_RSP_LEN_VAL) { 15888c2ecf20Sopenharmony_ci rsp_len = be32_to_cpu(fcp_resp->ext.fr_rsp_len); 15898c2ecf20Sopenharmony_ci if ((rsp_len != 0 && rsp_len != 4 && rsp_len != 8) || 15908c2ecf20Sopenharmony_ci (rsp_info->rsp_code != FCP_TMF_CMPL)) { 15918c2ecf20Sopenharmony_ci host_status = DID_ERROR; 15928c2ecf20Sopenharmony_ci goto out; 15938c2ecf20Sopenharmony_ci } 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if ((flags & FCP_SNS_LEN_VAL) && fcp_resp->ext.fr_sns_len) { 15978c2ecf20Sopenharmony_ci sns_len = be32_to_cpu(fcp_resp->ext.fr_sns_len); 15988c2ecf20Sopenharmony_ci if (sns_len > SCSI_SENSE_BUFFERSIZE) 15998c2ecf20Sopenharmony_ci sns_len = SCSI_SENSE_BUFFERSIZE; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci memcpy(cmnd->sense_buffer, 16028c2ecf20Sopenharmony_ci &rsp_info->_fr_resvd[0] + rsp_len, sns_len); 16038c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_autosense); 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci scsi_set_resid(cmnd, 0); 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci /* Under run */ 16098c2ecf20Sopenharmony_ci if (flags & FCP_RESID_UNDER) { 16108c2ecf20Sopenharmony_ci scsi_set_resid(cmnd, 16118c2ecf20Sopenharmony_ci be32_to_cpu(fcp_resp->ext.fr_resid)); 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci if (!(flags & FCP_SNS_LEN_VAL) && 16148c2ecf20Sopenharmony_ci (scsi_status == SAM_STAT_GOOD) && 16158c2ecf20Sopenharmony_ci ((scsi_bufflen(cmnd) - scsi_get_resid(cmnd)) 16168c2ecf20Sopenharmony_ci < cmnd->underflow)) 16178c2ecf20Sopenharmony_ci host_status = DID_ERROR; 16188c2ecf20Sopenharmony_ci } else if (flags & FCP_RESID_OVER) 16198c2ecf20Sopenharmony_ci host_status = DID_ERROR; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_rsperror); 16228c2ecf20Sopenharmony_ci break; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci case FW_SCSI_OVER_FLOW_ERR: 16258c2ecf20Sopenharmony_ci csio_warn(hw, 16268c2ecf20Sopenharmony_ci "Over-flow error,cmnd:0x%x expected len:0x%x" 16278c2ecf20Sopenharmony_ci " resid:0x%x\n", cmnd->cmnd[0], 16288c2ecf20Sopenharmony_ci scsi_bufflen(cmnd), scsi_get_resid(cmnd)); 16298c2ecf20Sopenharmony_ci host_status = DID_ERROR; 16308c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_ovflerror); 16318c2ecf20Sopenharmony_ci break; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci case FW_SCSI_UNDER_FLOW_ERR: 16348c2ecf20Sopenharmony_ci csio_warn(hw, 16358c2ecf20Sopenharmony_ci "Under-flow error,cmnd:0x%x expected" 16368c2ecf20Sopenharmony_ci " len:0x%x resid:0x%x lun:0x%llx ssn:0x%x\n", 16378c2ecf20Sopenharmony_ci cmnd->cmnd[0], scsi_bufflen(cmnd), 16388c2ecf20Sopenharmony_ci scsi_get_resid(cmnd), cmnd->device->lun, 16398c2ecf20Sopenharmony_ci rn->flowid); 16408c2ecf20Sopenharmony_ci host_status = DID_ERROR; 16418c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_unflerror); 16428c2ecf20Sopenharmony_ci break; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci case FW_SCSI_ABORT_REQUESTED: 16458c2ecf20Sopenharmony_ci case FW_SCSI_ABORTED: 16468c2ecf20Sopenharmony_ci case FW_SCSI_CLOSE_REQUESTED: 16478c2ecf20Sopenharmony_ci csio_dbg(hw, "Req %p cmd:%p op:%x %s\n", req, cmnd, 16488c2ecf20Sopenharmony_ci cmnd->cmnd[0], 16498c2ecf20Sopenharmony_ci (req->wr_status == FW_SCSI_CLOSE_REQUESTED) ? 16508c2ecf20Sopenharmony_ci "closed" : "aborted"); 16518c2ecf20Sopenharmony_ci /* 16528c2ecf20Sopenharmony_ci * csio_eh_abort_handler checks this value to 16538c2ecf20Sopenharmony_ci * succeed or fail the abort request. 16548c2ecf20Sopenharmony_ci */ 16558c2ecf20Sopenharmony_ci host_status = DID_REQUEUE; 16568c2ecf20Sopenharmony_ci if (req->wr_status == FW_SCSI_CLOSE_REQUESTED) 16578c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_closed); 16588c2ecf20Sopenharmony_ci else 16598c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_aborted); 16608c2ecf20Sopenharmony_ci break; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci case FW_SCSI_ABORT_TIMEDOUT: 16638c2ecf20Sopenharmony_ci /* FW timed out the abort itself */ 16648c2ecf20Sopenharmony_ci csio_dbg(hw, "FW timed out abort req:%p cmnd:%p status:%x\n", 16658c2ecf20Sopenharmony_ci req, cmnd, req->wr_status); 16668c2ecf20Sopenharmony_ci host_status = DID_ERROR; 16678c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_abrt_timedout); 16688c2ecf20Sopenharmony_ci break; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci case FW_RDEV_NOT_READY: 16718c2ecf20Sopenharmony_ci /* 16728c2ecf20Sopenharmony_ci * In firmware, a RDEV can get into this state 16738c2ecf20Sopenharmony_ci * temporarily, before moving into dissapeared/lost 16748c2ecf20Sopenharmony_ci * state. So, the driver should complete the request equivalent 16758c2ecf20Sopenharmony_ci * to device-disappeared! 16768c2ecf20Sopenharmony_ci */ 16778c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_rdev_nr_error); 16788c2ecf20Sopenharmony_ci host_status = DID_ERROR; 16798c2ecf20Sopenharmony_ci break; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci case FW_ERR_RDEV_LOST: 16828c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_rdev_lost_error); 16838c2ecf20Sopenharmony_ci host_status = DID_ERROR; 16848c2ecf20Sopenharmony_ci break; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci case FW_ERR_RDEV_LOGO: 16878c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_rdev_logo_error); 16888c2ecf20Sopenharmony_ci host_status = DID_ERROR; 16898c2ecf20Sopenharmony_ci break; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci case FW_ERR_RDEV_IMPL_LOGO: 16928c2ecf20Sopenharmony_ci host_status = DID_ERROR; 16938c2ecf20Sopenharmony_ci break; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci case FW_ERR_LINK_DOWN: 16968c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_link_down_error); 16978c2ecf20Sopenharmony_ci host_status = DID_ERROR; 16988c2ecf20Sopenharmony_ci break; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci case FW_FCOE_NO_XCHG: 17018c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_no_xchg_error); 17028c2ecf20Sopenharmony_ci host_status = DID_ERROR; 17038c2ecf20Sopenharmony_ci break; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci default: 17068c2ecf20Sopenharmony_ci csio_err(hw, "Unknown SCSI FW WR status:%d req:%p cmnd:%p\n", 17078c2ecf20Sopenharmony_ci req->wr_status, req, cmnd); 17088c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_unknown_error); 17118c2ecf20Sopenharmony_ci host_status = DID_ERROR; 17128c2ecf20Sopenharmony_ci break; 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ciout: 17168c2ecf20Sopenharmony_ci if (req->nsge > 0) { 17178c2ecf20Sopenharmony_ci scsi_dma_unmap(cmnd); 17188c2ecf20Sopenharmony_ci if (req->dcopy && (host_status == DID_OK)) 17198c2ecf20Sopenharmony_ci host_status = csio_scsi_copy_to_sgl(hw, req); 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci cmnd->result = (((host_status) << 16) | scsi_status); 17238c2ecf20Sopenharmony_ci cmnd->scsi_done(cmnd); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci /* Wake up waiting threads */ 17268c2ecf20Sopenharmony_ci csio_scsi_cmnd(req) = NULL; 17278c2ecf20Sopenharmony_ci complete(&req->cmplobj); 17288c2ecf20Sopenharmony_ci} 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci/* 17318c2ecf20Sopenharmony_ci * csio_scsi_cbfn - SCSI callback function. 17328c2ecf20Sopenharmony_ci * @hw: HW module. 17338c2ecf20Sopenharmony_ci * @req: IO request. 17348c2ecf20Sopenharmony_ci * 17358c2ecf20Sopenharmony_ci */ 17368c2ecf20Sopenharmony_cistatic void 17378c2ecf20Sopenharmony_cicsio_scsi_cbfn(struct csio_hw *hw, struct csio_ioreq *req) 17388c2ecf20Sopenharmony_ci{ 17398c2ecf20Sopenharmony_ci struct scsi_cmnd *cmnd = (struct scsi_cmnd *)csio_scsi_cmnd(req); 17408c2ecf20Sopenharmony_ci uint8_t scsi_status = SAM_STAT_GOOD; 17418c2ecf20Sopenharmony_ci uint32_t host_status = DID_OK; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci if (likely(req->wr_status == FW_SUCCESS)) { 17448c2ecf20Sopenharmony_ci if (req->nsge > 0) { 17458c2ecf20Sopenharmony_ci scsi_dma_unmap(cmnd); 17468c2ecf20Sopenharmony_ci if (req->dcopy) 17478c2ecf20Sopenharmony_ci host_status = csio_scsi_copy_to_sgl(hw, req); 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci cmnd->result = (((host_status) << 16) | scsi_status); 17518c2ecf20Sopenharmony_ci cmnd->scsi_done(cmnd); 17528c2ecf20Sopenharmony_ci csio_scsi_cmnd(req) = NULL; 17538c2ecf20Sopenharmony_ci CSIO_INC_STATS(csio_hw_to_scsim(hw), n_tot_success); 17548c2ecf20Sopenharmony_ci } else { 17558c2ecf20Sopenharmony_ci /* Error handling */ 17568c2ecf20Sopenharmony_ci csio_scsi_err_handler(hw, req); 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci} 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci/** 17618c2ecf20Sopenharmony_ci * csio_queuecommand - Entry point to kickstart an I/O request. 17628c2ecf20Sopenharmony_ci * @host: The scsi_host pointer. 17638c2ecf20Sopenharmony_ci * @cmnd: The I/O request from ML. 17648c2ecf20Sopenharmony_ci * 17658c2ecf20Sopenharmony_ci * This routine does the following: 17668c2ecf20Sopenharmony_ci * - Checks for HW and Rnode module readiness. 17678c2ecf20Sopenharmony_ci * - Gets a free ioreq structure (which is already initialized 17688c2ecf20Sopenharmony_ci * to uninit during its allocation). 17698c2ecf20Sopenharmony_ci * - Maps SG elements. 17708c2ecf20Sopenharmony_ci * - Initializes ioreq members. 17718c2ecf20Sopenharmony_ci * - Kicks off the SCSI state machine for this IO. 17728c2ecf20Sopenharmony_ci * - Returns busy status on error. 17738c2ecf20Sopenharmony_ci */ 17748c2ecf20Sopenharmony_cistatic int 17758c2ecf20Sopenharmony_cicsio_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmnd) 17768c2ecf20Sopenharmony_ci{ 17778c2ecf20Sopenharmony_ci struct csio_lnode *ln = shost_priv(host); 17788c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 17798c2ecf20Sopenharmony_ci struct csio_scsim *scsim = csio_hw_to_scsim(hw); 17808c2ecf20Sopenharmony_ci struct csio_rnode *rn = (struct csio_rnode *)(cmnd->device->hostdata); 17818c2ecf20Sopenharmony_ci struct csio_ioreq *ioreq = NULL; 17828c2ecf20Sopenharmony_ci unsigned long flags; 17838c2ecf20Sopenharmony_ci int nsge = 0; 17848c2ecf20Sopenharmony_ci int rv = SCSI_MLQUEUE_HOST_BUSY, nr; 17858c2ecf20Sopenharmony_ci int retval; 17868c2ecf20Sopenharmony_ci struct csio_scsi_qset *sqset; 17878c2ecf20Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci sqset = &hw->sqset[ln->portid][blk_mq_rq_cpu(cmnd->request)]; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci nr = fc_remote_port_chkready(rport); 17928c2ecf20Sopenharmony_ci if (nr) { 17938c2ecf20Sopenharmony_ci cmnd->result = nr; 17948c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_rn_nr_error); 17958c2ecf20Sopenharmony_ci goto err_done; 17968c2ecf20Sopenharmony_ci } 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci if (unlikely(!csio_is_hw_ready(hw))) { 17998c2ecf20Sopenharmony_ci cmnd->result = (DID_REQUEUE << 16); 18008c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_hw_nr_error); 18018c2ecf20Sopenharmony_ci goto err_done; 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci /* Get req->nsge, if there are SG elements to be mapped */ 18058c2ecf20Sopenharmony_ci nsge = scsi_dma_map(cmnd); 18068c2ecf20Sopenharmony_ci if (unlikely(nsge < 0)) { 18078c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_dmamap_error); 18088c2ecf20Sopenharmony_ci goto err; 18098c2ecf20Sopenharmony_ci } 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci /* Do we support so many mappings? */ 18128c2ecf20Sopenharmony_ci if (unlikely(nsge > scsim->max_sge)) { 18138c2ecf20Sopenharmony_ci csio_warn(hw, 18148c2ecf20Sopenharmony_ci "More SGEs than can be supported." 18158c2ecf20Sopenharmony_ci " SGEs: %d, Max SGEs: %d\n", nsge, scsim->max_sge); 18168c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_unsupp_sge_error); 18178c2ecf20Sopenharmony_ci goto err_dma_unmap; 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci /* Get a free ioreq structure - SM is already set to uninit */ 18218c2ecf20Sopenharmony_ci ioreq = csio_get_scsi_ioreq_lock(hw, scsim); 18228c2ecf20Sopenharmony_ci if (!ioreq) { 18238c2ecf20Sopenharmony_ci csio_err(hw, "Out of I/O request elements. Active #:%d\n", 18248c2ecf20Sopenharmony_ci scsim->stats.n_active); 18258c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_no_req_error); 18268c2ecf20Sopenharmony_ci goto err_dma_unmap; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci ioreq->nsge = nsge; 18308c2ecf20Sopenharmony_ci ioreq->lnode = ln; 18318c2ecf20Sopenharmony_ci ioreq->rnode = rn; 18328c2ecf20Sopenharmony_ci ioreq->iq_idx = sqset->iq_idx; 18338c2ecf20Sopenharmony_ci ioreq->eq_idx = sqset->eq_idx; 18348c2ecf20Sopenharmony_ci ioreq->wr_status = 0; 18358c2ecf20Sopenharmony_ci ioreq->drv_status = 0; 18368c2ecf20Sopenharmony_ci csio_scsi_cmnd(ioreq) = (void *)cmnd; 18378c2ecf20Sopenharmony_ci ioreq->tmo = 0; 18388c2ecf20Sopenharmony_ci ioreq->datadir = cmnd->sc_data_direction; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if (cmnd->sc_data_direction == DMA_TO_DEVICE) { 18418c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_output_requests); 18428c2ecf20Sopenharmony_ci ln->stats.n_output_bytes += scsi_bufflen(cmnd); 18438c2ecf20Sopenharmony_ci } else if (cmnd->sc_data_direction == DMA_FROM_DEVICE) { 18448c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_input_requests); 18458c2ecf20Sopenharmony_ci ln->stats.n_input_bytes += scsi_bufflen(cmnd); 18468c2ecf20Sopenharmony_ci } else 18478c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_control_requests); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci /* Set cbfn */ 18508c2ecf20Sopenharmony_ci ioreq->io_cbfn = csio_scsi_cbfn; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci /* Needed during abort */ 18538c2ecf20Sopenharmony_ci cmnd->host_scribble = (unsigned char *)ioreq; 18548c2ecf20Sopenharmony_ci cmnd->SCp.Message = 0; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci /* Kick off SCSI IO SM on the ioreq */ 18578c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 18588c2ecf20Sopenharmony_ci retval = csio_scsi_start_io(ioreq); 18598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci if (retval != 0) { 18628c2ecf20Sopenharmony_ci csio_err(hw, "ioreq: %p couldn't be started, status:%d\n", 18638c2ecf20Sopenharmony_ci ioreq, retval); 18648c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_busy_error); 18658c2ecf20Sopenharmony_ci goto err_put_req; 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci return 0; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_cierr_put_req: 18718c2ecf20Sopenharmony_ci csio_put_scsi_ioreq_lock(hw, scsim, ioreq); 18728c2ecf20Sopenharmony_cierr_dma_unmap: 18738c2ecf20Sopenharmony_ci if (nsge > 0) 18748c2ecf20Sopenharmony_ci scsi_dma_unmap(cmnd); 18758c2ecf20Sopenharmony_cierr: 18768c2ecf20Sopenharmony_ci return rv; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_cierr_done: 18798c2ecf20Sopenharmony_ci cmnd->scsi_done(cmnd); 18808c2ecf20Sopenharmony_ci return 0; 18818c2ecf20Sopenharmony_ci} 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_cistatic int 18848c2ecf20Sopenharmony_cicsio_do_abrt_cls(struct csio_hw *hw, struct csio_ioreq *ioreq, bool abort) 18858c2ecf20Sopenharmony_ci{ 18868c2ecf20Sopenharmony_ci int rv; 18878c2ecf20Sopenharmony_ci int cpu = smp_processor_id(); 18888c2ecf20Sopenharmony_ci struct csio_lnode *ln = ioreq->lnode; 18898c2ecf20Sopenharmony_ci struct csio_scsi_qset *sqset = &hw->sqset[ln->portid][cpu]; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci ioreq->tmo = CSIO_SCSI_ABRT_TMO_MS; 18928c2ecf20Sopenharmony_ci /* 18938c2ecf20Sopenharmony_ci * Use current processor queue for posting the abort/close, but retain 18948c2ecf20Sopenharmony_ci * the ingress queue ID of the original I/O being aborted/closed - we 18958c2ecf20Sopenharmony_ci * need the abort/close completion to be received on the same queue 18968c2ecf20Sopenharmony_ci * as the original I/O. 18978c2ecf20Sopenharmony_ci */ 18988c2ecf20Sopenharmony_ci ioreq->eq_idx = sqset->eq_idx; 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci if (abort == SCSI_ABORT) 19018c2ecf20Sopenharmony_ci rv = csio_scsi_abort(ioreq); 19028c2ecf20Sopenharmony_ci else 19038c2ecf20Sopenharmony_ci rv = csio_scsi_close(ioreq); 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci return rv; 19068c2ecf20Sopenharmony_ci} 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_cistatic int 19098c2ecf20Sopenharmony_cicsio_eh_abort_handler(struct scsi_cmnd *cmnd) 19108c2ecf20Sopenharmony_ci{ 19118c2ecf20Sopenharmony_ci struct csio_ioreq *ioreq; 19128c2ecf20Sopenharmony_ci struct csio_lnode *ln = shost_priv(cmnd->device->host); 19138c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 19148c2ecf20Sopenharmony_ci struct csio_scsim *scsim = csio_hw_to_scsim(hw); 19158c2ecf20Sopenharmony_ci int ready = 0, ret; 19168c2ecf20Sopenharmony_ci unsigned long tmo = 0; 19178c2ecf20Sopenharmony_ci int rv; 19188c2ecf20Sopenharmony_ci struct csio_rnode *rn = (struct csio_rnode *)(cmnd->device->hostdata); 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci ret = fc_block_scsi_eh(cmnd); 19218c2ecf20Sopenharmony_ci if (ret) 19228c2ecf20Sopenharmony_ci return ret; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci ioreq = (struct csio_ioreq *)cmnd->host_scribble; 19258c2ecf20Sopenharmony_ci if (!ioreq) 19268c2ecf20Sopenharmony_ci return SUCCESS; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci if (!rn) 19298c2ecf20Sopenharmony_ci return FAILED; 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci csio_dbg(hw, 19328c2ecf20Sopenharmony_ci "Request to abort ioreq:%p cmd:%p cdb:%08llx" 19338c2ecf20Sopenharmony_ci " ssni:0x%x lun:%llu iq:0x%x\n", 19348c2ecf20Sopenharmony_ci ioreq, cmnd, *((uint64_t *)cmnd->cmnd), rn->flowid, 19358c2ecf20Sopenharmony_ci cmnd->device->lun, csio_q_physiqid(hw, ioreq->iq_idx)); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci if (((struct scsi_cmnd *)csio_scsi_cmnd(ioreq)) != cmnd) { 19388c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_abrt_race_comp); 19398c2ecf20Sopenharmony_ci return SUCCESS; 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci ready = csio_is_lnode_ready(ln); 19438c2ecf20Sopenharmony_ci tmo = CSIO_SCSI_ABRT_TMO_MS; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci reinit_completion(&ioreq->cmplobj); 19468c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 19478c2ecf20Sopenharmony_ci rv = csio_do_abrt_cls(hw, ioreq, (ready ? SCSI_ABORT : SCSI_CLOSE)); 19488c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci if (rv != 0) { 19518c2ecf20Sopenharmony_ci if (rv == -EINVAL) { 19528c2ecf20Sopenharmony_ci /* Return success, if abort/close request issued on 19538c2ecf20Sopenharmony_ci * already completed IO 19548c2ecf20Sopenharmony_ci */ 19558c2ecf20Sopenharmony_ci return SUCCESS; 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci if (ready) 19588c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_abrt_busy_error); 19598c2ecf20Sopenharmony_ci else 19608c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_cls_busy_error); 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci goto inval_scmnd; 19638c2ecf20Sopenharmony_ci } 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci wait_for_completion_timeout(&ioreq->cmplobj, msecs_to_jiffies(tmo)); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci /* FW didnt respond to abort within our timeout */ 19688c2ecf20Sopenharmony_ci if (((struct scsi_cmnd *)csio_scsi_cmnd(ioreq)) == cmnd) { 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci csio_err(hw, "Abort timed out -- req: %p\n", ioreq); 19718c2ecf20Sopenharmony_ci CSIO_INC_STATS(scsim, n_abrt_timedout); 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ciinval_scmnd: 19748c2ecf20Sopenharmony_ci if (ioreq->nsge > 0) 19758c2ecf20Sopenharmony_ci scsi_dma_unmap(cmnd); 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 19788c2ecf20Sopenharmony_ci csio_scsi_cmnd(ioreq) = NULL; 19798c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci cmnd->result = (DID_ERROR << 16); 19828c2ecf20Sopenharmony_ci cmnd->scsi_done(cmnd); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci return FAILED; 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci /* FW successfully aborted the request */ 19888c2ecf20Sopenharmony_ci if (host_byte(cmnd->result) == DID_REQUEUE) { 19898c2ecf20Sopenharmony_ci csio_info(hw, 19908c2ecf20Sopenharmony_ci "Aborted SCSI command to (%d:%llu) tag %u\n", 19918c2ecf20Sopenharmony_ci cmnd->device->id, cmnd->device->lun, 19928c2ecf20Sopenharmony_ci cmnd->request->tag); 19938c2ecf20Sopenharmony_ci return SUCCESS; 19948c2ecf20Sopenharmony_ci } else { 19958c2ecf20Sopenharmony_ci csio_info(hw, 19968c2ecf20Sopenharmony_ci "Failed to abort SCSI command, (%d:%llu) tag %u\n", 19978c2ecf20Sopenharmony_ci cmnd->device->id, cmnd->device->lun, 19988c2ecf20Sopenharmony_ci cmnd->request->tag); 19998c2ecf20Sopenharmony_ci return FAILED; 20008c2ecf20Sopenharmony_ci } 20018c2ecf20Sopenharmony_ci} 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci/* 20048c2ecf20Sopenharmony_ci * csio_tm_cbfn - TM callback function. 20058c2ecf20Sopenharmony_ci * @hw: HW module. 20068c2ecf20Sopenharmony_ci * @req: IO request. 20078c2ecf20Sopenharmony_ci * 20088c2ecf20Sopenharmony_ci * Cache the result in 'cmnd', since ioreq will be freed soon 20098c2ecf20Sopenharmony_ci * after we return from here, and the waiting thread shouldnt trust 20108c2ecf20Sopenharmony_ci * the ioreq contents. 20118c2ecf20Sopenharmony_ci */ 20128c2ecf20Sopenharmony_cistatic void 20138c2ecf20Sopenharmony_cicsio_tm_cbfn(struct csio_hw *hw, struct csio_ioreq *req) 20148c2ecf20Sopenharmony_ci{ 20158c2ecf20Sopenharmony_ci struct scsi_cmnd *cmnd = (struct scsi_cmnd *)csio_scsi_cmnd(req); 20168c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf; 20178c2ecf20Sopenharmony_ci uint8_t flags = 0; 20188c2ecf20Sopenharmony_ci struct fcp_resp_with_ext *fcp_resp; 20198c2ecf20Sopenharmony_ci struct fcp_resp_rsp_info *rsp_info; 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci csio_dbg(hw, "req: %p in csio_tm_cbfn status: %d\n", 20228c2ecf20Sopenharmony_ci req, req->wr_status); 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci /* Cache FW return status */ 20258c2ecf20Sopenharmony_ci cmnd->SCp.Status = req->wr_status; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci /* Special handling based on FCP response */ 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci /* 20308c2ecf20Sopenharmony_ci * FW returns us this error, if flags were set. FCP4 says 20318c2ecf20Sopenharmony_ci * FCP_RSP_LEN_VAL in flags shall be set for TM completions. 20328c2ecf20Sopenharmony_ci * So if a target were to set this bit, we expect that the 20338c2ecf20Sopenharmony_ci * rsp_code is set to FCP_TMF_CMPL for a successful TM 20348c2ecf20Sopenharmony_ci * completion. Any other rsp_code means TM operation failed. 20358c2ecf20Sopenharmony_ci * If a target were to just ignore setting flags, we treat 20368c2ecf20Sopenharmony_ci * the TM operation as success, and FW returns FW_SUCCESS. 20378c2ecf20Sopenharmony_ci */ 20388c2ecf20Sopenharmony_ci if (req->wr_status == FW_SCSI_RSP_ERR) { 20398c2ecf20Sopenharmony_ci dma_buf = &req->dma_buf; 20408c2ecf20Sopenharmony_ci fcp_resp = (struct fcp_resp_with_ext *)dma_buf->vaddr; 20418c2ecf20Sopenharmony_ci rsp_info = (struct fcp_resp_rsp_info *)(fcp_resp + 1); 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci flags = fcp_resp->resp.fr_flags; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci /* Modify return status if flags indicate success */ 20468c2ecf20Sopenharmony_ci if (flags & FCP_RSP_LEN_VAL) 20478c2ecf20Sopenharmony_ci if (rsp_info->rsp_code == FCP_TMF_CMPL) 20488c2ecf20Sopenharmony_ci cmnd->SCp.Status = FW_SUCCESS; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci csio_dbg(hw, "TM FCP rsp code: %d\n", rsp_info->rsp_code); 20518c2ecf20Sopenharmony_ci } 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci /* Wake up the TM handler thread */ 20548c2ecf20Sopenharmony_ci csio_scsi_cmnd(req) = NULL; 20558c2ecf20Sopenharmony_ci} 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_cistatic int 20588c2ecf20Sopenharmony_cicsio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) 20598c2ecf20Sopenharmony_ci{ 20608c2ecf20Sopenharmony_ci struct csio_lnode *ln = shost_priv(cmnd->device->host); 20618c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 20628c2ecf20Sopenharmony_ci struct csio_scsim *scsim = csio_hw_to_scsim(hw); 20638c2ecf20Sopenharmony_ci struct csio_rnode *rn = (struct csio_rnode *)(cmnd->device->hostdata); 20648c2ecf20Sopenharmony_ci struct csio_ioreq *ioreq = NULL; 20658c2ecf20Sopenharmony_ci struct csio_scsi_qset *sqset; 20668c2ecf20Sopenharmony_ci unsigned long flags; 20678c2ecf20Sopenharmony_ci int retval; 20688c2ecf20Sopenharmony_ci int count, ret; 20698c2ecf20Sopenharmony_ci LIST_HEAD(local_q); 20708c2ecf20Sopenharmony_ci struct csio_scsi_level_data sld; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci if (!rn) 20738c2ecf20Sopenharmony_ci goto fail; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci csio_dbg(hw, "Request to reset LUN:%llu (ssni:0x%x tgtid:%d)\n", 20768c2ecf20Sopenharmony_ci cmnd->device->lun, rn->flowid, rn->scsi_id); 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci if (!csio_is_lnode_ready(ln)) { 20798c2ecf20Sopenharmony_ci csio_err(hw, 20808c2ecf20Sopenharmony_ci "LUN reset cannot be issued on non-ready" 20818c2ecf20Sopenharmony_ci " local node vnpi:0x%x (LUN:%llu)\n", 20828c2ecf20Sopenharmony_ci ln->vnp_flowid, cmnd->device->lun); 20838c2ecf20Sopenharmony_ci goto fail; 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci /* Lnode is ready, now wait on rport node readiness */ 20878c2ecf20Sopenharmony_ci ret = fc_block_scsi_eh(cmnd); 20888c2ecf20Sopenharmony_ci if (ret) 20898c2ecf20Sopenharmony_ci return ret; 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci /* 20928c2ecf20Sopenharmony_ci * If we have blocked in the previous call, at this point, either the 20938c2ecf20Sopenharmony_ci * remote node has come back online, or device loss timer has fired 20948c2ecf20Sopenharmony_ci * and the remote node is destroyed. Allow the LUN reset only for 20958c2ecf20Sopenharmony_ci * the former case, since LUN reset is a TMF I/O on the wire, and we 20968c2ecf20Sopenharmony_ci * need a valid session to issue it. 20978c2ecf20Sopenharmony_ci */ 20988c2ecf20Sopenharmony_ci if (fc_remote_port_chkready(rn->rport)) { 20998c2ecf20Sopenharmony_ci csio_err(hw, 21008c2ecf20Sopenharmony_ci "LUN reset cannot be issued on non-ready" 21018c2ecf20Sopenharmony_ci " remote node ssni:0x%x (LUN:%llu)\n", 21028c2ecf20Sopenharmony_ci rn->flowid, cmnd->device->lun); 21038c2ecf20Sopenharmony_ci goto fail; 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci /* Get a free ioreq structure - SM is already set to uninit */ 21078c2ecf20Sopenharmony_ci ioreq = csio_get_scsi_ioreq_lock(hw, scsim); 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci if (!ioreq) { 21108c2ecf20Sopenharmony_ci csio_err(hw, "Out of IO request elements. Active # :%d\n", 21118c2ecf20Sopenharmony_ci scsim->stats.n_active); 21128c2ecf20Sopenharmony_ci goto fail; 21138c2ecf20Sopenharmony_ci } 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci sqset = &hw->sqset[ln->portid][smp_processor_id()]; 21168c2ecf20Sopenharmony_ci ioreq->nsge = 0; 21178c2ecf20Sopenharmony_ci ioreq->lnode = ln; 21188c2ecf20Sopenharmony_ci ioreq->rnode = rn; 21198c2ecf20Sopenharmony_ci ioreq->iq_idx = sqset->iq_idx; 21208c2ecf20Sopenharmony_ci ioreq->eq_idx = sqset->eq_idx; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci csio_scsi_cmnd(ioreq) = cmnd; 21238c2ecf20Sopenharmony_ci cmnd->host_scribble = (unsigned char *)ioreq; 21248c2ecf20Sopenharmony_ci cmnd->SCp.Status = 0; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci cmnd->SCp.Message = FCP_TMF_LUN_RESET; 21278c2ecf20Sopenharmony_ci ioreq->tmo = CSIO_SCSI_LUNRST_TMO_MS / 1000; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci /* 21308c2ecf20Sopenharmony_ci * FW times the LUN reset for ioreq->tmo, so we got to wait a little 21318c2ecf20Sopenharmony_ci * longer (10s for now) than that to allow FW to return the timed 21328c2ecf20Sopenharmony_ci * out command. 21338c2ecf20Sopenharmony_ci */ 21348c2ecf20Sopenharmony_ci count = DIV_ROUND_UP((ioreq->tmo + 10) * 1000, CSIO_SCSI_TM_POLL_MS); 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci /* Set cbfn */ 21378c2ecf20Sopenharmony_ci ioreq->io_cbfn = csio_tm_cbfn; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci /* Save of the ioreq info for later use */ 21408c2ecf20Sopenharmony_ci sld.level = CSIO_LEV_LUN; 21418c2ecf20Sopenharmony_ci sld.lnode = ioreq->lnode; 21428c2ecf20Sopenharmony_ci sld.rnode = ioreq->rnode; 21438c2ecf20Sopenharmony_ci sld.oslun = cmnd->device->lun; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 21468c2ecf20Sopenharmony_ci /* Kick off TM SM on the ioreq */ 21478c2ecf20Sopenharmony_ci retval = csio_scsi_start_tm(ioreq); 21488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci if (retval != 0) { 21518c2ecf20Sopenharmony_ci csio_err(hw, "Failed to issue LUN reset, req:%p, status:%d\n", 21528c2ecf20Sopenharmony_ci ioreq, retval); 21538c2ecf20Sopenharmony_ci goto fail_ret_ioreq; 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci csio_dbg(hw, "Waiting max %d secs for LUN reset completion\n", 21578c2ecf20Sopenharmony_ci count * (CSIO_SCSI_TM_POLL_MS / 1000)); 21588c2ecf20Sopenharmony_ci /* Wait for completion */ 21598c2ecf20Sopenharmony_ci while ((((struct scsi_cmnd *)csio_scsi_cmnd(ioreq)) == cmnd) 21608c2ecf20Sopenharmony_ci && count--) 21618c2ecf20Sopenharmony_ci msleep(CSIO_SCSI_TM_POLL_MS); 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci /* LUN reset timed-out */ 21648c2ecf20Sopenharmony_ci if (((struct scsi_cmnd *)csio_scsi_cmnd(ioreq)) == cmnd) { 21658c2ecf20Sopenharmony_ci csio_err(hw, "LUN reset (%d:%llu) timed out\n", 21668c2ecf20Sopenharmony_ci cmnd->device->id, cmnd->device->lun); 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 21698c2ecf20Sopenharmony_ci csio_scsi_drvcleanup(ioreq); 21708c2ecf20Sopenharmony_ci list_del_init(&ioreq->sm.sm_list); 21718c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci goto fail_ret_ioreq; 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci /* LUN reset returned, check cached status */ 21778c2ecf20Sopenharmony_ci if (cmnd->SCp.Status != FW_SUCCESS) { 21788c2ecf20Sopenharmony_ci csio_err(hw, "LUN reset failed (%d:%llu), status: %d\n", 21798c2ecf20Sopenharmony_ci cmnd->device->id, cmnd->device->lun, cmnd->SCp.Status); 21808c2ecf20Sopenharmony_ci goto fail; 21818c2ecf20Sopenharmony_ci } 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci /* LUN reset succeeded, Start aborting affected I/Os */ 21848c2ecf20Sopenharmony_ci /* 21858c2ecf20Sopenharmony_ci * Since the host guarantees during LUN reset that there 21868c2ecf20Sopenharmony_ci * will not be any more I/Os to that LUN, until the LUN reset 21878c2ecf20Sopenharmony_ci * completes, we gather pending I/Os after the LUN reset. 21888c2ecf20Sopenharmony_ci */ 21898c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 21908c2ecf20Sopenharmony_ci csio_scsi_gather_active_ios(scsim, &sld, &local_q); 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci retval = csio_scsi_abort_io_q(scsim, &local_q, 30000); 21938c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci /* Aborts may have timed out */ 21968c2ecf20Sopenharmony_ci if (retval != 0) { 21978c2ecf20Sopenharmony_ci csio_err(hw, 21988c2ecf20Sopenharmony_ci "Attempt to abort I/Os during LUN reset of %llu" 21998c2ecf20Sopenharmony_ci " returned %d\n", cmnd->device->lun, retval); 22008c2ecf20Sopenharmony_ci /* Return I/Os back to active_q */ 22018c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 22028c2ecf20Sopenharmony_ci list_splice_tail_init(&local_q, &scsim->active_q); 22038c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 22048c2ecf20Sopenharmony_ci goto fail; 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_lun_rst); 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci csio_info(hw, "LUN reset occurred (%d:%llu)\n", 22108c2ecf20Sopenharmony_ci cmnd->device->id, cmnd->device->lun); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci return SUCCESS; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_cifail_ret_ioreq: 22158c2ecf20Sopenharmony_ci csio_put_scsi_ioreq_lock(hw, scsim, ioreq); 22168c2ecf20Sopenharmony_cifail: 22178c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_lun_rst_fail); 22188c2ecf20Sopenharmony_ci return FAILED; 22198c2ecf20Sopenharmony_ci} 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_cistatic int 22228c2ecf20Sopenharmony_cicsio_slave_alloc(struct scsi_device *sdev) 22238c2ecf20Sopenharmony_ci{ 22248c2ecf20Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci if (!rport || fc_remote_port_chkready(rport)) 22278c2ecf20Sopenharmony_ci return -ENXIO; 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci sdev->hostdata = *((struct csio_lnode **)(rport->dd_data)); 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci return 0; 22328c2ecf20Sopenharmony_ci} 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_cistatic int 22358c2ecf20Sopenharmony_cicsio_slave_configure(struct scsi_device *sdev) 22368c2ecf20Sopenharmony_ci{ 22378c2ecf20Sopenharmony_ci scsi_change_queue_depth(sdev, csio_lun_qdepth); 22388c2ecf20Sopenharmony_ci return 0; 22398c2ecf20Sopenharmony_ci} 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_cistatic void 22428c2ecf20Sopenharmony_cicsio_slave_destroy(struct scsi_device *sdev) 22438c2ecf20Sopenharmony_ci{ 22448c2ecf20Sopenharmony_ci sdev->hostdata = NULL; 22458c2ecf20Sopenharmony_ci} 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_cistatic int 22488c2ecf20Sopenharmony_cicsio_scan_finished(struct Scsi_Host *shost, unsigned long time) 22498c2ecf20Sopenharmony_ci{ 22508c2ecf20Sopenharmony_ci struct csio_lnode *ln = shost_priv(shost); 22518c2ecf20Sopenharmony_ci int rv = 1; 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci spin_lock_irq(shost->host_lock); 22548c2ecf20Sopenharmony_ci if (!ln->hwp || csio_list_deleted(&ln->sm.sm_list)) 22558c2ecf20Sopenharmony_ci goto out; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci rv = csio_scan_done(ln, jiffies, time, csio_max_scan_tmo * HZ, 22588c2ecf20Sopenharmony_ci csio_delta_scan_tmo * HZ); 22598c2ecf20Sopenharmony_ciout: 22608c2ecf20Sopenharmony_ci spin_unlock_irq(shost->host_lock); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci return rv; 22638c2ecf20Sopenharmony_ci} 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_cistruct scsi_host_template csio_fcoe_shost_template = { 22668c2ecf20Sopenharmony_ci .module = THIS_MODULE, 22678c2ecf20Sopenharmony_ci .name = CSIO_DRV_DESC, 22688c2ecf20Sopenharmony_ci .proc_name = KBUILD_MODNAME, 22698c2ecf20Sopenharmony_ci .queuecommand = csio_queuecommand, 22708c2ecf20Sopenharmony_ci .eh_timed_out = fc_eh_timed_out, 22718c2ecf20Sopenharmony_ci .eh_abort_handler = csio_eh_abort_handler, 22728c2ecf20Sopenharmony_ci .eh_device_reset_handler = csio_eh_lun_reset_handler, 22738c2ecf20Sopenharmony_ci .slave_alloc = csio_slave_alloc, 22748c2ecf20Sopenharmony_ci .slave_configure = csio_slave_configure, 22758c2ecf20Sopenharmony_ci .slave_destroy = csio_slave_destroy, 22768c2ecf20Sopenharmony_ci .scan_finished = csio_scan_finished, 22778c2ecf20Sopenharmony_ci .this_id = -1, 22788c2ecf20Sopenharmony_ci .sg_tablesize = CSIO_SCSI_MAX_SGE, 22798c2ecf20Sopenharmony_ci .cmd_per_lun = CSIO_MAX_CMD_PER_LUN, 22808c2ecf20Sopenharmony_ci .shost_attrs = csio_fcoe_lport_attrs, 22818c2ecf20Sopenharmony_ci .max_sectors = CSIO_MAX_SECTOR_SIZE, 22828c2ecf20Sopenharmony_ci}; 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_cistruct scsi_host_template csio_fcoe_shost_vport_template = { 22858c2ecf20Sopenharmony_ci .module = THIS_MODULE, 22868c2ecf20Sopenharmony_ci .name = CSIO_DRV_DESC, 22878c2ecf20Sopenharmony_ci .proc_name = KBUILD_MODNAME, 22888c2ecf20Sopenharmony_ci .queuecommand = csio_queuecommand, 22898c2ecf20Sopenharmony_ci .eh_timed_out = fc_eh_timed_out, 22908c2ecf20Sopenharmony_ci .eh_abort_handler = csio_eh_abort_handler, 22918c2ecf20Sopenharmony_ci .eh_device_reset_handler = csio_eh_lun_reset_handler, 22928c2ecf20Sopenharmony_ci .slave_alloc = csio_slave_alloc, 22938c2ecf20Sopenharmony_ci .slave_configure = csio_slave_configure, 22948c2ecf20Sopenharmony_ci .slave_destroy = csio_slave_destroy, 22958c2ecf20Sopenharmony_ci .scan_finished = csio_scan_finished, 22968c2ecf20Sopenharmony_ci .this_id = -1, 22978c2ecf20Sopenharmony_ci .sg_tablesize = CSIO_SCSI_MAX_SGE, 22988c2ecf20Sopenharmony_ci .cmd_per_lun = CSIO_MAX_CMD_PER_LUN, 22998c2ecf20Sopenharmony_ci .shost_attrs = csio_fcoe_vport_attrs, 23008c2ecf20Sopenharmony_ci .max_sectors = CSIO_MAX_SECTOR_SIZE, 23018c2ecf20Sopenharmony_ci}; 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci/* 23048c2ecf20Sopenharmony_ci * csio_scsi_alloc_ddp_bufs - Allocate buffers for DDP of unaligned SGLs. 23058c2ecf20Sopenharmony_ci * @scm: SCSI Module 23068c2ecf20Sopenharmony_ci * @hw: HW device. 23078c2ecf20Sopenharmony_ci * @buf_size: buffer size 23088c2ecf20Sopenharmony_ci * @num_buf : Number of buffers. 23098c2ecf20Sopenharmony_ci * 23108c2ecf20Sopenharmony_ci * This routine allocates DMA buffers required for SCSI Data xfer, if 23118c2ecf20Sopenharmony_ci * each SGL buffer for a SCSI Read request posted by SCSI midlayer are 23128c2ecf20Sopenharmony_ci * not virtually contiguous. 23138c2ecf20Sopenharmony_ci */ 23148c2ecf20Sopenharmony_cistatic int 23158c2ecf20Sopenharmony_cicsio_scsi_alloc_ddp_bufs(struct csio_scsim *scm, struct csio_hw *hw, 23168c2ecf20Sopenharmony_ci int buf_size, int num_buf) 23178c2ecf20Sopenharmony_ci{ 23188c2ecf20Sopenharmony_ci int n = 0; 23198c2ecf20Sopenharmony_ci struct list_head *tmp; 23208c2ecf20Sopenharmony_ci struct csio_dma_buf *ddp_desc = NULL; 23218c2ecf20Sopenharmony_ci uint32_t unit_size = 0; 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci if (!num_buf) 23248c2ecf20Sopenharmony_ci return 0; 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci if (!buf_size) 23278c2ecf20Sopenharmony_ci return -EINVAL; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&scm->ddp_freelist); 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci /* Align buf size to page size */ 23328c2ecf20Sopenharmony_ci buf_size = (buf_size + PAGE_SIZE - 1) & PAGE_MASK; 23338c2ecf20Sopenharmony_ci /* Initialize dma descriptors */ 23348c2ecf20Sopenharmony_ci for (n = 0; n < num_buf; n++) { 23358c2ecf20Sopenharmony_ci /* Set unit size to request size */ 23368c2ecf20Sopenharmony_ci unit_size = buf_size; 23378c2ecf20Sopenharmony_ci ddp_desc = kzalloc(sizeof(struct csio_dma_buf), GFP_KERNEL); 23388c2ecf20Sopenharmony_ci if (!ddp_desc) { 23398c2ecf20Sopenharmony_ci csio_err(hw, 23408c2ecf20Sopenharmony_ci "Failed to allocate ddp descriptors," 23418c2ecf20Sopenharmony_ci " Num allocated = %d.\n", 23428c2ecf20Sopenharmony_ci scm->stats.n_free_ddp); 23438c2ecf20Sopenharmony_ci goto no_mem; 23448c2ecf20Sopenharmony_ci } 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci /* Allocate Dma buffers for DDP */ 23478c2ecf20Sopenharmony_ci ddp_desc->vaddr = dma_alloc_coherent(&hw->pdev->dev, unit_size, 23488c2ecf20Sopenharmony_ci &ddp_desc->paddr, GFP_KERNEL); 23498c2ecf20Sopenharmony_ci if (!ddp_desc->vaddr) { 23508c2ecf20Sopenharmony_ci csio_err(hw, 23518c2ecf20Sopenharmony_ci "SCSI response DMA buffer (ddp) allocation" 23528c2ecf20Sopenharmony_ci " failed!\n"); 23538c2ecf20Sopenharmony_ci kfree(ddp_desc); 23548c2ecf20Sopenharmony_ci goto no_mem; 23558c2ecf20Sopenharmony_ci } 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci ddp_desc->len = unit_size; 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci /* Added it to scsi ddp freelist */ 23608c2ecf20Sopenharmony_ci list_add_tail(&ddp_desc->list, &scm->ddp_freelist); 23618c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_free_ddp); 23628c2ecf20Sopenharmony_ci } 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci return 0; 23658c2ecf20Sopenharmony_cino_mem: 23668c2ecf20Sopenharmony_ci /* release dma descs back to freelist and free dma memory */ 23678c2ecf20Sopenharmony_ci list_for_each(tmp, &scm->ddp_freelist) { 23688c2ecf20Sopenharmony_ci ddp_desc = (struct csio_dma_buf *) tmp; 23698c2ecf20Sopenharmony_ci tmp = csio_list_prev(tmp); 23708c2ecf20Sopenharmony_ci dma_free_coherent(&hw->pdev->dev, ddp_desc->len, 23718c2ecf20Sopenharmony_ci ddp_desc->vaddr, ddp_desc->paddr); 23728c2ecf20Sopenharmony_ci list_del_init(&ddp_desc->list); 23738c2ecf20Sopenharmony_ci kfree(ddp_desc); 23748c2ecf20Sopenharmony_ci } 23758c2ecf20Sopenharmony_ci scm->stats.n_free_ddp = 0; 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci return -ENOMEM; 23788c2ecf20Sopenharmony_ci} 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci/* 23818c2ecf20Sopenharmony_ci * csio_scsi_free_ddp_bufs - free DDP buffers of unaligned SGLs. 23828c2ecf20Sopenharmony_ci * @scm: SCSI Module 23838c2ecf20Sopenharmony_ci * @hw: HW device. 23848c2ecf20Sopenharmony_ci * 23858c2ecf20Sopenharmony_ci * This routine frees ddp buffers. 23868c2ecf20Sopenharmony_ci */ 23878c2ecf20Sopenharmony_cistatic void 23888c2ecf20Sopenharmony_cicsio_scsi_free_ddp_bufs(struct csio_scsim *scm, struct csio_hw *hw) 23898c2ecf20Sopenharmony_ci{ 23908c2ecf20Sopenharmony_ci struct list_head *tmp; 23918c2ecf20Sopenharmony_ci struct csio_dma_buf *ddp_desc; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci /* release dma descs back to freelist and free dma memory */ 23948c2ecf20Sopenharmony_ci list_for_each(tmp, &scm->ddp_freelist) { 23958c2ecf20Sopenharmony_ci ddp_desc = (struct csio_dma_buf *) tmp; 23968c2ecf20Sopenharmony_ci tmp = csio_list_prev(tmp); 23978c2ecf20Sopenharmony_ci dma_free_coherent(&hw->pdev->dev, ddp_desc->len, 23988c2ecf20Sopenharmony_ci ddp_desc->vaddr, ddp_desc->paddr); 23998c2ecf20Sopenharmony_ci list_del_init(&ddp_desc->list); 24008c2ecf20Sopenharmony_ci kfree(ddp_desc); 24018c2ecf20Sopenharmony_ci } 24028c2ecf20Sopenharmony_ci scm->stats.n_free_ddp = 0; 24038c2ecf20Sopenharmony_ci} 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci/** 24068c2ecf20Sopenharmony_ci * csio_scsim_init - Initialize SCSI Module 24078c2ecf20Sopenharmony_ci * @scm: SCSI Module 24088c2ecf20Sopenharmony_ci * @hw: HW module 24098c2ecf20Sopenharmony_ci * 24108c2ecf20Sopenharmony_ci */ 24118c2ecf20Sopenharmony_ciint 24128c2ecf20Sopenharmony_cicsio_scsim_init(struct csio_scsim *scm, struct csio_hw *hw) 24138c2ecf20Sopenharmony_ci{ 24148c2ecf20Sopenharmony_ci int i; 24158c2ecf20Sopenharmony_ci struct csio_ioreq *ioreq; 24168c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&scm->active_q); 24198c2ecf20Sopenharmony_ci scm->hw = hw; 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci scm->proto_cmd_len = sizeof(struct fcp_cmnd); 24228c2ecf20Sopenharmony_ci scm->proto_rsp_len = CSIO_SCSI_RSP_LEN; 24238c2ecf20Sopenharmony_ci scm->max_sge = CSIO_SCSI_MAX_SGE; 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci spin_lock_init(&scm->freelist_lock); 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci /* Pre-allocate ioreqs and initialize them */ 24288c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&scm->ioreq_freelist); 24298c2ecf20Sopenharmony_ci for (i = 0; i < csio_scsi_ioreqs; i++) { 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci ioreq = kzalloc(sizeof(struct csio_ioreq), GFP_KERNEL); 24328c2ecf20Sopenharmony_ci if (!ioreq) { 24338c2ecf20Sopenharmony_ci csio_err(hw, 24348c2ecf20Sopenharmony_ci "I/O request element allocation failed, " 24358c2ecf20Sopenharmony_ci " Num allocated = %d.\n", 24368c2ecf20Sopenharmony_ci scm->stats.n_free_ioreq); 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci goto free_ioreq; 24398c2ecf20Sopenharmony_ci } 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci /* Allocate Dma buffers for Response Payload */ 24428c2ecf20Sopenharmony_ci dma_buf = &ioreq->dma_buf; 24438c2ecf20Sopenharmony_ci dma_buf->vaddr = dma_pool_alloc(hw->scsi_dma_pool, GFP_KERNEL, 24448c2ecf20Sopenharmony_ci &dma_buf->paddr); 24458c2ecf20Sopenharmony_ci if (!dma_buf->vaddr) { 24468c2ecf20Sopenharmony_ci csio_err(hw, 24478c2ecf20Sopenharmony_ci "SCSI response DMA buffer allocation" 24488c2ecf20Sopenharmony_ci " failed!\n"); 24498c2ecf20Sopenharmony_ci kfree(ioreq); 24508c2ecf20Sopenharmony_ci goto free_ioreq; 24518c2ecf20Sopenharmony_ci } 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci dma_buf->len = scm->proto_rsp_len; 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ci /* Set state to uninit */ 24568c2ecf20Sopenharmony_ci csio_init_state(&ioreq->sm, csio_scsis_uninit); 24578c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ioreq->gen_list); 24588c2ecf20Sopenharmony_ci init_completion(&ioreq->cmplobj); 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci list_add_tail(&ioreq->sm.sm_list, &scm->ioreq_freelist); 24618c2ecf20Sopenharmony_ci CSIO_INC_STATS(scm, n_free_ioreq); 24628c2ecf20Sopenharmony_ci } 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci if (csio_scsi_alloc_ddp_bufs(scm, hw, PAGE_SIZE, csio_ddp_descs)) 24658c2ecf20Sopenharmony_ci goto free_ioreq; 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci return 0; 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_cifree_ioreq: 24708c2ecf20Sopenharmony_ci /* 24718c2ecf20Sopenharmony_ci * Free up existing allocations, since an error 24728c2ecf20Sopenharmony_ci * from here means we are returning for good 24738c2ecf20Sopenharmony_ci */ 24748c2ecf20Sopenharmony_ci while (!list_empty(&scm->ioreq_freelist)) { 24758c2ecf20Sopenharmony_ci struct csio_sm *tmp; 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci tmp = list_first_entry(&scm->ioreq_freelist, 24788c2ecf20Sopenharmony_ci struct csio_sm, sm_list); 24798c2ecf20Sopenharmony_ci list_del_init(&tmp->sm_list); 24808c2ecf20Sopenharmony_ci ioreq = (struct csio_ioreq *)tmp; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci dma_buf = &ioreq->dma_buf; 24838c2ecf20Sopenharmony_ci dma_pool_free(hw->scsi_dma_pool, dma_buf->vaddr, 24848c2ecf20Sopenharmony_ci dma_buf->paddr); 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci kfree(ioreq); 24878c2ecf20Sopenharmony_ci } 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci scm->stats.n_free_ioreq = 0; 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci return -ENOMEM; 24928c2ecf20Sopenharmony_ci} 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci/** 24958c2ecf20Sopenharmony_ci * csio_scsim_exit: Uninitialize SCSI Module 24968c2ecf20Sopenharmony_ci * @scm: SCSI Module 24978c2ecf20Sopenharmony_ci * 24988c2ecf20Sopenharmony_ci */ 24998c2ecf20Sopenharmony_civoid 25008c2ecf20Sopenharmony_cicsio_scsim_exit(struct csio_scsim *scm) 25018c2ecf20Sopenharmony_ci{ 25028c2ecf20Sopenharmony_ci struct csio_ioreq *ioreq; 25038c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf; 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci while (!list_empty(&scm->ioreq_freelist)) { 25068c2ecf20Sopenharmony_ci struct csio_sm *tmp; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci tmp = list_first_entry(&scm->ioreq_freelist, 25098c2ecf20Sopenharmony_ci struct csio_sm, sm_list); 25108c2ecf20Sopenharmony_ci list_del_init(&tmp->sm_list); 25118c2ecf20Sopenharmony_ci ioreq = (struct csio_ioreq *)tmp; 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci dma_buf = &ioreq->dma_buf; 25148c2ecf20Sopenharmony_ci dma_pool_free(scm->hw->scsi_dma_pool, dma_buf->vaddr, 25158c2ecf20Sopenharmony_ci dma_buf->paddr); 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci kfree(ioreq); 25188c2ecf20Sopenharmony_ci } 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci scm->stats.n_free_ioreq = 0; 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci csio_scsi_free_ddp_bufs(scm, scm->hw); 25238c2ecf20Sopenharmony_ci} 2524