18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2014 Cisco Systems, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This program is free software; you may redistribute it and/or modify 58c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 68c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 98c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 118c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 128c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 148c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 158c2ecf20Sopenharmony_ci * SOFTWARE. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/mempool.h> 198c2ecf20Sopenharmony_ci#include <linux/errno.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 228c2ecf20Sopenharmony_ci#include <linux/pci.h> 238c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 248c2ecf20Sopenharmony_ci#include <linux/delay.h> 258c2ecf20Sopenharmony_ci#include <linux/gfp.h> 268c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 278c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 288c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 298c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 308c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 318c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "snic_io.h" 348c2ecf20Sopenharmony_ci#include "snic.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define snic_cmd_tag(sc) (((struct scsi_cmnd *) sc)->request->tag) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciconst char *snic_state_str[] = { 398c2ecf20Sopenharmony_ci [SNIC_INIT] = "SNIC_INIT", 408c2ecf20Sopenharmony_ci [SNIC_ERROR] = "SNIC_ERROR", 418c2ecf20Sopenharmony_ci [SNIC_ONLINE] = "SNIC_ONLINE", 428c2ecf20Sopenharmony_ci [SNIC_OFFLINE] = "SNIC_OFFLINE", 438c2ecf20Sopenharmony_ci [SNIC_FWRESET] = "SNIC_FWRESET", 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic const char * const snic_req_state_str[] = { 478c2ecf20Sopenharmony_ci [SNIC_IOREQ_NOT_INITED] = "SNIC_IOREQ_NOT_INITED", 488c2ecf20Sopenharmony_ci [SNIC_IOREQ_PENDING] = "SNIC_IOREQ_PENDING", 498c2ecf20Sopenharmony_ci [SNIC_IOREQ_ABTS_PENDING] = "SNIC_IOREQ_ABTS_PENDING", 508c2ecf20Sopenharmony_ci [SNIC_IOREQ_ABTS_COMPLETE] = "SNIC_IOREQ_ABTS_COMPLETE", 518c2ecf20Sopenharmony_ci [SNIC_IOREQ_LR_PENDING] = "SNIC_IOREQ_LR_PENDING", 528c2ecf20Sopenharmony_ci [SNIC_IOREQ_LR_COMPLETE] = "SNIC_IOREQ_LR_COMPLETE", 538c2ecf20Sopenharmony_ci [SNIC_IOREQ_COMPLETE] = "SNIC_IOREQ_CMD_COMPLETE", 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* snic cmd status strings */ 578c2ecf20Sopenharmony_cistatic const char * const snic_io_status_str[] = { 588c2ecf20Sopenharmony_ci [SNIC_STAT_IO_SUCCESS] = "SNIC_STAT_IO_SUCCESS", /* 0x0 */ 598c2ecf20Sopenharmony_ci [SNIC_STAT_INVALID_HDR] = "SNIC_STAT_INVALID_HDR", 608c2ecf20Sopenharmony_ci [SNIC_STAT_OUT_OF_RES] = "SNIC_STAT_OUT_OF_RES", 618c2ecf20Sopenharmony_ci [SNIC_STAT_INVALID_PARM] = "SNIC_STAT_INVALID_PARM", 628c2ecf20Sopenharmony_ci [SNIC_STAT_REQ_NOT_SUP] = "SNIC_STAT_REQ_NOT_SUP", 638c2ecf20Sopenharmony_ci [SNIC_STAT_IO_NOT_FOUND] = "SNIC_STAT_IO_NOT_FOUND", 648c2ecf20Sopenharmony_ci [SNIC_STAT_ABORTED] = "SNIC_STAT_ABORTED", 658c2ecf20Sopenharmony_ci [SNIC_STAT_TIMEOUT] = "SNIC_STAT_TIMEOUT", 668c2ecf20Sopenharmony_ci [SNIC_STAT_SGL_INVALID] = "SNIC_STAT_SGL_INVALID", 678c2ecf20Sopenharmony_ci [SNIC_STAT_DATA_CNT_MISMATCH] = "SNIC_STAT_DATA_CNT_MISMATCH", 688c2ecf20Sopenharmony_ci [SNIC_STAT_FW_ERR] = "SNIC_STAT_FW_ERR", 698c2ecf20Sopenharmony_ci [SNIC_STAT_ITMF_REJECT] = "SNIC_STAT_ITMF_REJECT", 708c2ecf20Sopenharmony_ci [SNIC_STAT_ITMF_FAIL] = "SNIC_STAT_ITMF_FAIL", 718c2ecf20Sopenharmony_ci [SNIC_STAT_ITMF_INCORRECT_LUN] = "SNIC_STAT_ITMF_INCORRECT_LUN", 728c2ecf20Sopenharmony_ci [SNIC_STAT_CMND_REJECT] = "SNIC_STAT_CMND_REJECT", 738c2ecf20Sopenharmony_ci [SNIC_STAT_DEV_OFFLINE] = "SNIC_STAT_DEV_OFFLINE", 748c2ecf20Sopenharmony_ci [SNIC_STAT_NO_BOOTLUN] = "SNIC_STAT_NO_BOOTLUN", 758c2ecf20Sopenharmony_ci [SNIC_STAT_SCSI_ERR] = "SNIC_STAT_SCSI_ERR", 768c2ecf20Sopenharmony_ci [SNIC_STAT_NOT_READY] = "SNIC_STAT_NOT_READY", 778c2ecf20Sopenharmony_ci [SNIC_STAT_FATAL_ERROR] = "SNIC_STAT_FATAL_ERROR", 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void snic_scsi_cleanup(struct snic *, int); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciconst char * 838c2ecf20Sopenharmony_cisnic_state_to_str(unsigned int state) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci if (state >= ARRAY_SIZE(snic_state_str) || !snic_state_str[state]) 868c2ecf20Sopenharmony_ci return "Unknown"; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return snic_state_str[state]; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic const char * 928c2ecf20Sopenharmony_cisnic_io_status_to_str(unsigned int state) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci if ((state >= ARRAY_SIZE(snic_io_status_str)) || 958c2ecf20Sopenharmony_ci (!snic_io_status_str[state])) 968c2ecf20Sopenharmony_ci return "Unknown"; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return snic_io_status_str[state]; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic const char * 1028c2ecf20Sopenharmony_cisnic_ioreq_state_to_str(unsigned int state) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci if (state >= ARRAY_SIZE(snic_req_state_str) || 1058c2ecf20Sopenharmony_ci !snic_req_state_str[state]) 1068c2ecf20Sopenharmony_ci return "Unknown"; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return snic_req_state_str[state]; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic inline spinlock_t * 1128c2ecf20Sopenharmony_cisnic_io_lock_hash(struct snic *snic, struct scsi_cmnd *sc) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci u32 hash = snic_cmd_tag(sc) & (SNIC_IO_LOCKS - 1); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return &snic->io_req_lock[hash]; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic inline spinlock_t * 1208c2ecf20Sopenharmony_cisnic_io_lock_tag(struct snic *snic, int tag) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci return &snic->io_req_lock[tag & (SNIC_IO_LOCKS - 1)]; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* snic_release_req_buf : Releases snic_req_info */ 1268c2ecf20Sopenharmony_cistatic void 1278c2ecf20Sopenharmony_cisnic_release_req_buf(struct snic *snic, 1288c2ecf20Sopenharmony_ci struct snic_req_info *rqi, 1298c2ecf20Sopenharmony_ci struct scsi_cmnd *sc) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct snic_host_req *req = rqi_to_req(rqi); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Freeing cmd without marking completion, not okay */ 1348c2ecf20Sopenharmony_ci SNIC_BUG_ON(!((CMD_STATE(sc) == SNIC_IOREQ_COMPLETE) || 1358c2ecf20Sopenharmony_ci (CMD_STATE(sc) == SNIC_IOREQ_ABTS_COMPLETE) || 1368c2ecf20Sopenharmony_ci (CMD_FLAGS(sc) & SNIC_DEV_RST_NOTSUP) || 1378c2ecf20Sopenharmony_ci (CMD_FLAGS(sc) & SNIC_IO_INTERNAL_TERM_ISSUED) || 1388c2ecf20Sopenharmony_ci (CMD_FLAGS(sc) & SNIC_DEV_RST_TERM_ISSUED) || 1398c2ecf20Sopenharmony_ci (CMD_FLAGS(sc) & SNIC_SCSI_CLEANUP) || 1408c2ecf20Sopenharmony_ci (CMD_STATE(sc) == SNIC_IOREQ_LR_COMPLETE))); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 1438c2ecf20Sopenharmony_ci "Rel_req:sc %p:tag %x:rqi %p:ioreq %p:abt %p:dr %p: state %s:flags 0x%llx\n", 1448c2ecf20Sopenharmony_ci sc, snic_cmd_tag(sc), rqi, rqi->req, rqi->abort_req, 1458c2ecf20Sopenharmony_ci rqi->dr_req, snic_ioreq_state_to_str(CMD_STATE(sc)), 1468c2ecf20Sopenharmony_ci CMD_FLAGS(sc)); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (req->u.icmnd.sense_addr) 1498c2ecf20Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, 1508c2ecf20Sopenharmony_ci le64_to_cpu(req->u.icmnd.sense_addr), 1518c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 1528c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci scsi_dma_unmap(sc); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci snic_req_free(snic, rqi); 1578c2ecf20Sopenharmony_ci} /* end of snic_release_req_buf */ 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* 1608c2ecf20Sopenharmony_ci * snic_queue_icmnd_req : Queues snic_icmnd request 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_cistatic int 1638c2ecf20Sopenharmony_cisnic_queue_icmnd_req(struct snic *snic, 1648c2ecf20Sopenharmony_ci struct snic_req_info *rqi, 1658c2ecf20Sopenharmony_ci struct scsi_cmnd *sc, 1668c2ecf20Sopenharmony_ci int sg_cnt) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct scatterlist *sg; 1698c2ecf20Sopenharmony_ci struct snic_sg_desc *sgd; 1708c2ecf20Sopenharmony_ci dma_addr_t pa = 0; 1718c2ecf20Sopenharmony_ci struct scsi_lun lun; 1728c2ecf20Sopenharmony_ci u16 flags = 0; 1738c2ecf20Sopenharmony_ci int ret = 0; 1748c2ecf20Sopenharmony_ci unsigned int i; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (sg_cnt) { 1778c2ecf20Sopenharmony_ci flags = SNIC_ICMND_ESGL; 1788c2ecf20Sopenharmony_ci sgd = (struct snic_sg_desc *) req_to_sgl(rqi->req); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci for_each_sg(scsi_sglist(sc), sg, sg_cnt, i) { 1818c2ecf20Sopenharmony_ci sgd->addr = cpu_to_le64(sg_dma_address(sg)); 1828c2ecf20Sopenharmony_ci sgd->len = cpu_to_le32(sg_dma_len(sg)); 1838c2ecf20Sopenharmony_ci sgd->_resvd = 0; 1848c2ecf20Sopenharmony_ci sgd++; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci pa = dma_map_single(&snic->pdev->dev, 1898c2ecf20Sopenharmony_ci sc->sense_buffer, 1908c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 1918c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 1928c2ecf20Sopenharmony_ci if (dma_mapping_error(&snic->pdev->dev, pa)) { 1938c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 1948c2ecf20Sopenharmony_ci "QIcmnd:PCI Map Failed for sns buf %p tag %x\n", 1958c2ecf20Sopenharmony_ci sc->sense_buffer, snic_cmd_tag(sc)); 1968c2ecf20Sopenharmony_ci ret = -ENOMEM; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return ret; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci int_to_scsilun(sc->device->lun, &lun); 2028c2ecf20Sopenharmony_ci if (sc->sc_data_direction == DMA_FROM_DEVICE) 2038c2ecf20Sopenharmony_ci flags |= SNIC_ICMND_RD; 2048c2ecf20Sopenharmony_ci if (sc->sc_data_direction == DMA_TO_DEVICE) 2058c2ecf20Sopenharmony_ci flags |= SNIC_ICMND_WR; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* Initialize icmnd */ 2088c2ecf20Sopenharmony_ci snic_icmnd_init(rqi->req, 2098c2ecf20Sopenharmony_ci snic_cmd_tag(sc), 2108c2ecf20Sopenharmony_ci snic->config.hid, /* hid */ 2118c2ecf20Sopenharmony_ci (ulong) rqi, 2128c2ecf20Sopenharmony_ci flags, /* command flags */ 2138c2ecf20Sopenharmony_ci rqi->tgt_id, 2148c2ecf20Sopenharmony_ci lun.scsi_lun, 2158c2ecf20Sopenharmony_ci sc->cmnd, 2168c2ecf20Sopenharmony_ci sc->cmd_len, 2178c2ecf20Sopenharmony_ci scsi_bufflen(sc), 2188c2ecf20Sopenharmony_ci sg_cnt, 2198c2ecf20Sopenharmony_ci (ulong) req_to_sgl(rqi->req), 2208c2ecf20Sopenharmony_ci pa, /* sense buffer pa */ 2218c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.active); 2248c2ecf20Sopenharmony_ci ret = snic_queue_wq_desc(snic, rqi->req, rqi->req_len); 2258c2ecf20Sopenharmony_ci if (ret) { 2268c2ecf20Sopenharmony_ci atomic64_dec(&snic->s_stats.io.active); 2278c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 2288c2ecf20Sopenharmony_ci "QIcmnd: Queuing Icmnd Failed. ret = %d\n", 2298c2ecf20Sopenharmony_ci ret); 2308c2ecf20Sopenharmony_ci } else 2318c2ecf20Sopenharmony_ci snic_stats_update_active_ios(&snic->s_stats); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return ret; 2348c2ecf20Sopenharmony_ci} /* end of snic_queue_icmnd_req */ 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/* 2378c2ecf20Sopenharmony_ci * snic_issue_scsi_req : Prepares IO request and Issues to FW. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_cistatic int 2408c2ecf20Sopenharmony_cisnic_issue_scsi_req(struct snic *snic, 2418c2ecf20Sopenharmony_ci struct snic_tgt *tgt, 2428c2ecf20Sopenharmony_ci struct scsi_cmnd *sc) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 2458c2ecf20Sopenharmony_ci int sg_cnt = 0; 2468c2ecf20Sopenharmony_ci int ret = 0; 2478c2ecf20Sopenharmony_ci u32 tag = snic_cmd_tag(sc); 2488c2ecf20Sopenharmony_ci u64 cmd_trc = 0, cmd_st_flags = 0; 2498c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 2508c2ecf20Sopenharmony_ci unsigned long flags; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_NOT_INITED; 2538c2ecf20Sopenharmony_ci CMD_FLAGS(sc) = SNIC_NO_FLAGS; 2548c2ecf20Sopenharmony_ci sg_cnt = scsi_dma_map(sc); 2558c2ecf20Sopenharmony_ci if (sg_cnt < 0) { 2568c2ecf20Sopenharmony_ci SNIC_TRC((u16)snic->shost->host_no, tag, (ulong) sc, 0, 2578c2ecf20Sopenharmony_ci sc->cmnd[0], sg_cnt, CMD_STATE(sc)); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "issue_sc:Failed to map SG List.\n"); 2608c2ecf20Sopenharmony_ci ret = -ENOMEM; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci goto issue_sc_end; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci rqi = snic_req_init(snic, sg_cnt); 2668c2ecf20Sopenharmony_ci if (!rqi) { 2678c2ecf20Sopenharmony_ci scsi_dma_unmap(sc); 2688c2ecf20Sopenharmony_ci ret = -ENOMEM; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci goto issue_sc_end; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci rqi->tgt_id = tgt->id; 2748c2ecf20Sopenharmony_ci rqi->sc = sc; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_PENDING; 2778c2ecf20Sopenharmony_ci CMD_SP(sc) = (char *) rqi; 2788c2ecf20Sopenharmony_ci cmd_trc = SNIC_TRC_CMD(sc); 2798c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= (SNIC_IO_INITIALIZED | SNIC_IO_ISSUED); 2808c2ecf20Sopenharmony_ci cmd_st_flags = SNIC_TRC_CMD_STATE_FLAGS(sc); 2818c2ecf20Sopenharmony_ci io_lock = snic_io_lock_hash(snic, sc); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* create wq desc and enqueue it */ 2848c2ecf20Sopenharmony_ci ret = snic_queue_icmnd_req(snic, rqi, sc, sg_cnt); 2858c2ecf20Sopenharmony_ci if (ret) { 2868c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 2878c2ecf20Sopenharmony_ci "issue_sc: icmnd qing Failed for sc %p, err %d\n", 2888c2ecf20Sopenharmony_ci sc, ret); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 2918c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 2928c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 2938c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_COMPLETE; 2948c2ecf20Sopenharmony_ci CMD_FLAGS(sc) &= ~SNIC_IO_ISSUED; /* turn off the flag */ 2958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (rqi) 2988c2ecf20Sopenharmony_ci snic_release_req_buf(snic, rqi, sc); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, tag, (ulong) sc, 0, 0, 0, 3018c2ecf20Sopenharmony_ci SNIC_TRC_CMD_STATE_FLAGS(sc)); 3028c2ecf20Sopenharmony_ci } else { 3038c2ecf20Sopenharmony_ci u32 io_sz = scsi_bufflen(sc) >> 9; 3048c2ecf20Sopenharmony_ci u32 qtime = jiffies - rqi->start_time; 3058c2ecf20Sopenharmony_ci struct snic_io_stats *iostats = &snic->s_stats.io; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (io_sz > atomic64_read(&iostats->max_io_sz)) 3088c2ecf20Sopenharmony_ci atomic64_set(&iostats->max_io_sz, io_sz); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (qtime > atomic64_read(&iostats->max_qtime)) 3118c2ecf20Sopenharmony_ci atomic64_set(&iostats->max_qtime, qtime); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 3148c2ecf20Sopenharmony_ci "issue_sc:sc %p, tag %d queued to WQ.\n", 3158c2ecf20Sopenharmony_ci sc, tag); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, tag, (ulong) sc, (ulong) rqi, 3188c2ecf20Sopenharmony_ci sg_cnt, cmd_trc, cmd_st_flags); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ciissue_sc_end: 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return ret; 3248c2ecf20Sopenharmony_ci} /* end of snic_issue_scsi_req */ 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci/* 3288c2ecf20Sopenharmony_ci * snic_queuecommand 3298c2ecf20Sopenharmony_ci * Routine to send a scsi cdb to LLD 3308c2ecf20Sopenharmony_ci * Called with host_lock held and interrupts disabled 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ciint 3338c2ecf20Sopenharmony_cisnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct snic_tgt *tgt = NULL; 3368c2ecf20Sopenharmony_ci struct snic *snic = shost_priv(shost); 3378c2ecf20Sopenharmony_ci int ret; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci tgt = starget_to_tgt(scsi_target(sc->device)); 3408c2ecf20Sopenharmony_ci ret = snic_tgt_chkready(tgt); 3418c2ecf20Sopenharmony_ci if (ret) { 3428c2ecf20Sopenharmony_ci SNIC_HOST_ERR(shost, "Tgt %p id %d Not Ready.\n", tgt, tgt->id); 3438c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.misc.tgt_not_rdy); 3448c2ecf20Sopenharmony_ci sc->result = ret; 3458c2ecf20Sopenharmony_ci sc->scsi_done(sc); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return 0; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (snic_get_state(snic) != SNIC_ONLINE) { 3518c2ecf20Sopenharmony_ci SNIC_HOST_ERR(shost, "snic state is %s\n", 3528c2ecf20Sopenharmony_ci snic_state_str[snic_get_state(snic)]); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci atomic_inc(&snic->ios_inflight); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(shost, "sc %p Tag %d (sc %0x) lun %lld in snic_qcmd\n", 3598c2ecf20Sopenharmony_ci sc, snic_cmd_tag(sc), sc->cmnd[0], sc->device->lun); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ret = snic_issue_scsi_req(snic, tgt, sc); 3628c2ecf20Sopenharmony_ci if (ret) { 3638c2ecf20Sopenharmony_ci SNIC_HOST_ERR(shost, "Failed to Q, Scsi Req w/ err %d.\n", ret); 3648c2ecf20Sopenharmony_ci ret = SCSI_MLQUEUE_HOST_BUSY; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci atomic_dec(&snic->ios_inflight); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return ret; 3708c2ecf20Sopenharmony_ci} /* end of snic_queuecommand */ 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* 3738c2ecf20Sopenharmony_ci * snic_process_abts_pending_state: 3748c2ecf20Sopenharmony_ci * caller should hold IO lock 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_cistatic void 3778c2ecf20Sopenharmony_cisnic_proc_tmreq_pending_state(struct snic *snic, 3788c2ecf20Sopenharmony_ci struct scsi_cmnd *sc, 3798c2ecf20Sopenharmony_ci u8 cmpl_status) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci int state = CMD_STATE(sc); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (state == SNIC_IOREQ_ABTS_PENDING) 3848c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_ABTS_PENDING; 3858c2ecf20Sopenharmony_ci else if (state == SNIC_IOREQ_LR_PENDING) 3868c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_DEV_RST_PENDING; 3878c2ecf20Sopenharmony_ci else 3888c2ecf20Sopenharmony_ci SNIC_BUG_ON(1); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci switch (cmpl_status) { 3918c2ecf20Sopenharmony_ci case SNIC_STAT_IO_SUCCESS: 3928c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_DONE; 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci case SNIC_STAT_ABORTED: 3968c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_ABORTED; 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci default: 4008c2ecf20Sopenharmony_ci SNIC_BUG_ON(1); 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci/* 4058c2ecf20Sopenharmony_ci * snic_process_io_failed_state: 4068c2ecf20Sopenharmony_ci * Processes IO's error states 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_cistatic void 4098c2ecf20Sopenharmony_cisnic_process_io_failed_state(struct snic *snic, 4108c2ecf20Sopenharmony_ci struct snic_icmnd_cmpl *icmnd_cmpl, 4118c2ecf20Sopenharmony_ci struct scsi_cmnd *sc, 4128c2ecf20Sopenharmony_ci u8 cmpl_stat) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci int res = 0; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci switch (cmpl_stat) { 4178c2ecf20Sopenharmony_ci case SNIC_STAT_TIMEOUT: /* Req was timedout */ 4188c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.misc.io_tmo); 4198c2ecf20Sopenharmony_ci res = DID_TIME_OUT; 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci case SNIC_STAT_ABORTED: /* Req was aborted */ 4238c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.misc.io_aborted); 4248c2ecf20Sopenharmony_ci res = DID_ABORT; 4258c2ecf20Sopenharmony_ci break; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci case SNIC_STAT_DATA_CNT_MISMATCH:/* Recv/Sent more/less data than exp */ 4288c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.misc.data_cnt_mismat); 4298c2ecf20Sopenharmony_ci scsi_set_resid(sc, le32_to_cpu(icmnd_cmpl->resid)); 4308c2ecf20Sopenharmony_ci res = DID_ERROR; 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci case SNIC_STAT_OUT_OF_RES: /* Out of resources to complete request */ 4348c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.fw.out_of_res); 4358c2ecf20Sopenharmony_ci res = DID_REQUEUE; 4368c2ecf20Sopenharmony_ci break; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci case SNIC_STAT_IO_NOT_FOUND: /* Requested I/O was not found */ 4398c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.io_not_found); 4408c2ecf20Sopenharmony_ci res = DID_ERROR; 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci case SNIC_STAT_SGL_INVALID: /* Req was aborted to due to sgl error*/ 4448c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.misc.sgl_inval); 4458c2ecf20Sopenharmony_ci res = DID_ERROR; 4468c2ecf20Sopenharmony_ci break; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci case SNIC_STAT_FW_ERR: /* Req terminated due to FW Error */ 4498c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.fw.io_errs); 4508c2ecf20Sopenharmony_ci res = DID_ERROR; 4518c2ecf20Sopenharmony_ci break; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci case SNIC_STAT_SCSI_ERR: /* FW hits SCSI Error */ 4548c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.fw.scsi_errs); 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci case SNIC_STAT_NOT_READY: /* XPT yet to initialize */ 4588c2ecf20Sopenharmony_ci case SNIC_STAT_DEV_OFFLINE: /* Device offline */ 4598c2ecf20Sopenharmony_ci res = DID_NO_CONNECT; 4608c2ecf20Sopenharmony_ci break; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci case SNIC_STAT_INVALID_HDR: /* Hdr contains invalid data */ 4638c2ecf20Sopenharmony_ci case SNIC_STAT_INVALID_PARM: /* Some param in req is invalid */ 4648c2ecf20Sopenharmony_ci case SNIC_STAT_REQ_NOT_SUP: /* Req type is not supported */ 4658c2ecf20Sopenharmony_ci case SNIC_STAT_CMND_REJECT: /* Req rejected */ 4668c2ecf20Sopenharmony_ci case SNIC_STAT_FATAL_ERROR: /* XPT Error */ 4678c2ecf20Sopenharmony_ci default: 4688c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 4698c2ecf20Sopenharmony_ci "Invalid Hdr/Param or Req Not Supported or Cmnd Rejected or Device Offline. or Unknown\n"); 4708c2ecf20Sopenharmony_ci res = DID_ERROR; 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "fw returns failed status %s flags 0x%llx\n", 4758c2ecf20Sopenharmony_ci snic_io_status_to_str(cmpl_stat), CMD_FLAGS(sc)); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* Set sc->result */ 4788c2ecf20Sopenharmony_ci sc->result = (res << 16) | icmnd_cmpl->scsi_status; 4798c2ecf20Sopenharmony_ci} /* end of snic_process_io_failed_state */ 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci/* 4828c2ecf20Sopenharmony_ci * snic_tmreq_pending : is task management in progress. 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_cistatic int 4858c2ecf20Sopenharmony_cisnic_tmreq_pending(struct scsi_cmnd *sc) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci int state = CMD_STATE(sc); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return ((state == SNIC_IOREQ_ABTS_PENDING) || 4908c2ecf20Sopenharmony_ci (state == SNIC_IOREQ_LR_PENDING)); 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci/* 4948c2ecf20Sopenharmony_ci * snic_process_icmnd_cmpl_status: 4958c2ecf20Sopenharmony_ci * Caller should hold io_lock 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_cistatic int 4988c2ecf20Sopenharmony_cisnic_process_icmnd_cmpl_status(struct snic *snic, 4998c2ecf20Sopenharmony_ci struct snic_icmnd_cmpl *icmnd_cmpl, 5008c2ecf20Sopenharmony_ci u8 cmpl_stat, 5018c2ecf20Sopenharmony_ci struct scsi_cmnd *sc) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci u8 scsi_stat = icmnd_cmpl->scsi_status; 5048c2ecf20Sopenharmony_ci u64 xfer_len = 0; 5058c2ecf20Sopenharmony_ci int ret = 0; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* Mark the IO as complete */ 5088c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_COMPLETE; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (likely(cmpl_stat == SNIC_STAT_IO_SUCCESS)) { 5118c2ecf20Sopenharmony_ci sc->result = (DID_OK << 16) | scsi_stat; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci xfer_len = scsi_bufflen(sc); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* Update SCSI Cmd with resid value */ 5168c2ecf20Sopenharmony_ci scsi_set_resid(sc, le32_to_cpu(icmnd_cmpl->resid)); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (icmnd_cmpl->flags & SNIC_ICMND_CMPL_UNDR_RUN) { 5198c2ecf20Sopenharmony_ci xfer_len -= le32_to_cpu(icmnd_cmpl->resid); 5208c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.misc.io_under_run); 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (icmnd_cmpl->scsi_status == SAM_STAT_TASK_SET_FULL) 5248c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.misc.qfull); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci ret = 0; 5278c2ecf20Sopenharmony_ci } else { 5288c2ecf20Sopenharmony_ci snic_process_io_failed_state(snic, icmnd_cmpl, sc, cmpl_stat); 5298c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.fail); 5308c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 5318c2ecf20Sopenharmony_ci "icmnd_cmpl: IO Failed : Hdr Status %s flags 0x%llx\n", 5328c2ecf20Sopenharmony_ci snic_io_status_to_str(cmpl_stat), CMD_FLAGS(sc)); 5338c2ecf20Sopenharmony_ci ret = 1; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return ret; 5378c2ecf20Sopenharmony_ci} /* end of snic_process_icmnd_cmpl_status */ 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/* 5418c2ecf20Sopenharmony_ci * snic_icmnd_cmpl_handler 5428c2ecf20Sopenharmony_ci * Routine to handle icmnd completions 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_cistatic void 5458c2ecf20Sopenharmony_cisnic_icmnd_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci u8 typ, hdr_stat; 5488c2ecf20Sopenharmony_ci u32 cmnd_id, hid; 5498c2ecf20Sopenharmony_ci ulong ctx; 5508c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = NULL; 5518c2ecf20Sopenharmony_ci struct snic_icmnd_cmpl *icmnd_cmpl = NULL; 5528c2ecf20Sopenharmony_ci struct snic_host_req *req = NULL; 5538c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 5548c2ecf20Sopenharmony_ci unsigned long flags, start_time; 5558c2ecf20Sopenharmony_ci spinlock_t *io_lock; 5568c2ecf20Sopenharmony_ci u8 sc_stat = 0; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci snic_io_hdr_dec(&fwreq->hdr, &typ, &hdr_stat, &cmnd_id, &hid, &ctx); 5598c2ecf20Sopenharmony_ci icmnd_cmpl = &fwreq->u.icmnd_cmpl; 5608c2ecf20Sopenharmony_ci sc_stat = icmnd_cmpl->scsi_status; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 5638c2ecf20Sopenharmony_ci "Icmnd_cmpl: type = %x, hdr_stat = %x, cmnd_id = %x, hid = %x,i ctx = %lx\n", 5648c2ecf20Sopenharmony_ci typ, hdr_stat, cmnd_id, hid, ctx); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (cmnd_id >= snic->max_tag_id) { 5678c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 5688c2ecf20Sopenharmony_ci "Icmnd_cmpl:Tag Error:Out of Range Tag %d, hdr status = %s\n", 5698c2ecf20Sopenharmony_ci cmnd_id, snic_io_status_to_str(hdr_stat)); 5708c2ecf20Sopenharmony_ci return; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(snic->shost, cmnd_id); 5748c2ecf20Sopenharmony_ci WARN_ON_ONCE(!sc); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (!sc) { 5778c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.sc_null); 5788c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 5798c2ecf20Sopenharmony_ci "Icmnd_cmpl: Scsi Cmnd Not found, sc = NULL Hdr Status = %s tag = 0x%x fwreq = 0x%p\n", 5808c2ecf20Sopenharmony_ci snic_io_status_to_str(hdr_stat), 5818c2ecf20Sopenharmony_ci cmnd_id, 5828c2ecf20Sopenharmony_ci fwreq); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, cmnd_id, 0, 5858c2ecf20Sopenharmony_ci ((u64)hdr_stat << 16 | 5868c2ecf20Sopenharmony_ci (u64)sc_stat << 8 | (u64)icmnd_cmpl->flags), 5878c2ecf20Sopenharmony_ci (ulong) fwreq, le32_to_cpu(icmnd_cmpl->resid), ctx); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci return; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci io_lock = snic_io_lock_hash(snic, sc); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 5958c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 5968c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 5978c2ecf20Sopenharmony_ci "Icmnd_cmpl:lun %lld sc %p cmd %xtag %d flags 0x%llx rqi %p\n", 5988c2ecf20Sopenharmony_ci sc->device->lun, sc, sc->cmnd[0], snic_cmd_tag(sc), 5998c2ecf20Sopenharmony_ci CMD_FLAGS(sc), rqi); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & SNIC_HOST_RESET_CMD_TERM) { 6028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci SNIC_BUG_ON(rqi != (struct snic_req_info *)ctx); 6088c2ecf20Sopenharmony_ci WARN_ON_ONCE(req); 6098c2ecf20Sopenharmony_ci if (!rqi) { 6108c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.req_null); 6118c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_REQ_NULL; 6128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 6158c2ecf20Sopenharmony_ci "Icmnd_cmpl:Host Req Not Found(null), Hdr Status %s, Tag 0x%x, sc 0x%p flags 0x%llx\n", 6168c2ecf20Sopenharmony_ci snic_io_status_to_str(hdr_stat), 6178c2ecf20Sopenharmony_ci cmnd_id, sc, CMD_FLAGS(sc)); 6188c2ecf20Sopenharmony_ci return; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) ctx; 6228c2ecf20Sopenharmony_ci start_time = rqi->start_time; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* firmware completed the io */ 6258c2ecf20Sopenharmony_ci rqi->io_cmpl = 1; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* 6288c2ecf20Sopenharmony_ci * if SCSI-ML has already issued abort on this command, 6298c2ecf20Sopenharmony_ci * ignore completion of the IO. The abts path will clean it up 6308c2ecf20Sopenharmony_ci */ 6318c2ecf20Sopenharmony_ci if (unlikely(snic_tmreq_pending(sc))) { 6328c2ecf20Sopenharmony_ci snic_proc_tmreq_pending_state(snic, sc, hdr_stat); 6338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci snic_stats_update_io_cmpl(&snic->s_stats); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* Expected value is SNIC_STAT_ABORTED */ 6388c2ecf20Sopenharmony_ci if (likely(hdr_stat == SNIC_STAT_ABORTED)) 6398c2ecf20Sopenharmony_ci return; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 6428c2ecf20Sopenharmony_ci "icmnd_cmpl:TM Req Pending(%s), Hdr Status %s sc 0x%p scsi status %x resid %d flags 0x%llx\n", 6438c2ecf20Sopenharmony_ci snic_ioreq_state_to_str(CMD_STATE(sc)), 6448c2ecf20Sopenharmony_ci snic_io_status_to_str(hdr_stat), 6458c2ecf20Sopenharmony_ci sc, sc_stat, le32_to_cpu(icmnd_cmpl->resid), 6468c2ecf20Sopenharmony_ci CMD_FLAGS(sc)); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, cmnd_id, (ulong) sc, 6498c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), (ulong) fwreq, 6508c2ecf20Sopenharmony_ci SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc)); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci return; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (snic_process_icmnd_cmpl_status(snic, icmnd_cmpl, hdr_stat, sc)) { 6568c2ecf20Sopenharmony_ci scsi_print_command(sc); 6578c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 6588c2ecf20Sopenharmony_ci "icmnd_cmpl:IO Failed, sc 0x%p Tag %d Cmd %x Hdr Status %s flags 0x%llx\n", 6598c2ecf20Sopenharmony_ci sc, sc->cmnd[0], cmnd_id, 6608c2ecf20Sopenharmony_ci snic_io_status_to_str(hdr_stat), CMD_FLAGS(sc)); 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* Break link with the SCSI Command */ 6648c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 6658c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_DONE; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* For now, consider only successful IO. */ 6708c2ecf20Sopenharmony_ci snic_calc_io_process_time(snic, rqi); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci snic_release_req_buf(snic, rqi, sc); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, cmnd_id, (ulong) sc, 6758c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), (ulong) fwreq, 6768c2ecf20Sopenharmony_ci SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc)); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (sc->scsi_done) 6808c2ecf20Sopenharmony_ci sc->scsi_done(sc); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci snic_stats_update_io_cmpl(&snic->s_stats); 6838c2ecf20Sopenharmony_ci} /* end of snic_icmnd_cmpl_handler */ 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cistatic void 6868c2ecf20Sopenharmony_cisnic_proc_dr_cmpl_locked(struct snic *snic, 6878c2ecf20Sopenharmony_ci struct snic_fw_req *fwreq, 6888c2ecf20Sopenharmony_ci u8 cmpl_stat, 6898c2ecf20Sopenharmony_ci u32 cmnd_id, 6908c2ecf20Sopenharmony_ci struct scsi_cmnd *sc) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci struct snic_req_info *rqi = (struct snic_req_info *) CMD_SP(sc); 6938c2ecf20Sopenharmony_ci u32 start_time = rqi->start_time; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci CMD_LR_STATUS(sc) = cmpl_stat; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "itmf_cmpl: Cmd State = %s\n", 6988c2ecf20Sopenharmony_ci snic_ioreq_state_to_str(CMD_STATE(sc))); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING) { 7018c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_DEV_RST_ABTS_PENDING; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, cmnd_id, (ulong) sc, 7048c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 7058c2ecf20Sopenharmony_ci (ulong) fwreq, 0, SNIC_TRC_CMD_STATE_FLAGS(sc)); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 7088c2ecf20Sopenharmony_ci "itmf_cmpl: Terminate Pending Dev Reset Cmpl Recvd.id %x, status %s flags 0x%llx\n", 7098c2ecf20Sopenharmony_ci (int)(cmnd_id & SNIC_TAG_MASK), 7108c2ecf20Sopenharmony_ci snic_io_status_to_str(cmpl_stat), 7118c2ecf20Sopenharmony_ci CMD_FLAGS(sc)); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci return; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & SNIC_DEV_RST_TIMEDOUT) { 7188c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, cmnd_id, (ulong) sc, 7198c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 7208c2ecf20Sopenharmony_ci (ulong) fwreq, 0, SNIC_TRC_CMD_STATE_FLAGS(sc)); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 7238c2ecf20Sopenharmony_ci "itmf_cmpl:Dev Reset Completion Received after timeout. id %d cmpl status %s flags 0x%llx\n", 7248c2ecf20Sopenharmony_ci (int)(cmnd_id & SNIC_TAG_MASK), 7258c2ecf20Sopenharmony_ci snic_io_status_to_str(cmpl_stat), 7268c2ecf20Sopenharmony_ci CMD_FLAGS(sc)); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci return; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_LR_COMPLETE; 7328c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_DEV_RST_DONE; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 7358c2ecf20Sopenharmony_ci "itmf_cmpl:Dev Reset Cmpl Recvd id %d cmpl status %s flags 0x%llx\n", 7368c2ecf20Sopenharmony_ci (int)(cmnd_id & SNIC_TAG_MASK), 7378c2ecf20Sopenharmony_ci snic_io_status_to_str(cmpl_stat), 7388c2ecf20Sopenharmony_ci CMD_FLAGS(sc)); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (rqi->dr_done) 7418c2ecf20Sopenharmony_ci complete(rqi->dr_done); 7428c2ecf20Sopenharmony_ci} /* end of snic_proc_dr_cmpl_locked */ 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci/* 7458c2ecf20Sopenharmony_ci * snic_update_abort_stats : Updates abort stats based on completion status. 7468c2ecf20Sopenharmony_ci */ 7478c2ecf20Sopenharmony_cistatic void 7488c2ecf20Sopenharmony_cisnic_update_abort_stats(struct snic *snic, u8 cmpl_stat) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci struct snic_abort_stats *abt_stats = &snic->s_stats.abts; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "Updating Abort stats.\n"); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci switch (cmpl_stat) { 7558c2ecf20Sopenharmony_ci case SNIC_STAT_IO_SUCCESS: 7568c2ecf20Sopenharmony_ci break; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci case SNIC_STAT_TIMEOUT: 7598c2ecf20Sopenharmony_ci atomic64_inc(&abt_stats->fw_tmo); 7608c2ecf20Sopenharmony_ci break; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci case SNIC_STAT_IO_NOT_FOUND: 7638c2ecf20Sopenharmony_ci atomic64_inc(&abt_stats->io_not_found); 7648c2ecf20Sopenharmony_ci break; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci default: 7678c2ecf20Sopenharmony_ci atomic64_inc(&abt_stats->fail); 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic int 7738c2ecf20Sopenharmony_cisnic_process_itmf_cmpl(struct snic *snic, 7748c2ecf20Sopenharmony_ci struct snic_fw_req *fwreq, 7758c2ecf20Sopenharmony_ci u32 cmnd_id, 7768c2ecf20Sopenharmony_ci u8 cmpl_stat, 7778c2ecf20Sopenharmony_ci struct scsi_cmnd *sc) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 7808c2ecf20Sopenharmony_ci u32 tm_tags = 0; 7818c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 7828c2ecf20Sopenharmony_ci unsigned long flags; 7838c2ecf20Sopenharmony_ci u32 start_time = 0; 7848c2ecf20Sopenharmony_ci int ret = 0; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci io_lock = snic_io_lock_hash(snic, sc); 7878c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 7888c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & SNIC_HOST_RESET_CMD_TERM) { 7898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci return ret; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 7948c2ecf20Sopenharmony_ci WARN_ON_ONCE(!rqi); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (!rqi) { 7978c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.req_null); 7988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 7998c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_REQ_NULL; 8008c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 8018c2ecf20Sopenharmony_ci "itmf_cmpl: rqi is null,Hdr stat = %s Tag = 0x%x sc = 0x%p flags 0x%llx\n", 8028c2ecf20Sopenharmony_ci snic_io_status_to_str(cmpl_stat), cmnd_id, sc, 8038c2ecf20Sopenharmony_ci CMD_FLAGS(sc)); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return ret; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Extract task management flags */ 8098c2ecf20Sopenharmony_ci tm_tags = cmnd_id & ~(SNIC_TAG_MASK); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci start_time = rqi->start_time; 8128c2ecf20Sopenharmony_ci cmnd_id &= (SNIC_TAG_MASK); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci switch (tm_tags) { 8158c2ecf20Sopenharmony_ci case SNIC_TAG_ABORT: 8168c2ecf20Sopenharmony_ci /* Abort only issued on cmd */ 8178c2ecf20Sopenharmony_ci snic_update_abort_stats(snic, cmpl_stat); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (CMD_STATE(sc) != SNIC_IOREQ_ABTS_PENDING) { 8208c2ecf20Sopenharmony_ci /* This is a late completion. Ignore it. */ 8218c2ecf20Sopenharmony_ci ret = -1; 8228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 8238c2ecf20Sopenharmony_ci break; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_ABTS_COMPLETE; 8278c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = cmpl_stat; 8288c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_DONE; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 8318c2ecf20Sopenharmony_ci "itmf_cmpl:Abort Cmpl Recvd.Tag 0x%x Status %s flags 0x%llx\n", 8328c2ecf20Sopenharmony_ci cmnd_id, 8338c2ecf20Sopenharmony_ci snic_io_status_to_str(cmpl_stat), 8348c2ecf20Sopenharmony_ci CMD_FLAGS(sc)); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci /* 8378c2ecf20Sopenharmony_ci * If scsi_eh thread is blocked waiting for abts complete, 8388c2ecf20Sopenharmony_ci * signal completion to it. IO will be cleaned in the thread, 8398c2ecf20Sopenharmony_ci * else clean it in this context. 8408c2ecf20Sopenharmony_ci */ 8418c2ecf20Sopenharmony_ci if (rqi->abts_done) { 8428c2ecf20Sopenharmony_ci complete(rqi->abts_done); 8438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci break; /* jump out */ 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 8498c2ecf20Sopenharmony_ci sc->result = (DID_ERROR << 16); 8508c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 8518c2ecf20Sopenharmony_ci "itmf_cmpl: Completing IO. sc %p flags 0x%llx\n", 8528c2ecf20Sopenharmony_ci sc, CMD_FLAGS(sc)); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci snic_release_req_buf(snic, rqi, sc); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci if (sc->scsi_done) { 8598c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, cmnd_id, (ulong) sc, 8608c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 8618c2ecf20Sopenharmony_ci (ulong) fwreq, SNIC_TRC_CMD(sc), 8628c2ecf20Sopenharmony_ci SNIC_TRC_CMD_STATE_FLAGS(sc)); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci sc->scsi_done(sc); 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci break; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci case SNIC_TAG_DEV_RST: 8708c2ecf20Sopenharmony_ci case SNIC_TAG_DEV_RST | SNIC_TAG_IOCTL_DEV_RST: 8718c2ecf20Sopenharmony_ci snic_proc_dr_cmpl_locked(snic, fwreq, cmpl_stat, cmnd_id, sc); 8728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 8738c2ecf20Sopenharmony_ci ret = 0; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci break; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci case SNIC_TAG_ABORT | SNIC_TAG_DEV_RST: 8788c2ecf20Sopenharmony_ci /* Abort and terminate completion of device reset req */ 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_ABTS_COMPLETE; 8818c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = cmpl_stat; 8828c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_DEV_RST_DONE; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 8858c2ecf20Sopenharmony_ci "itmf_cmpl:dev reset abts cmpl recvd. id %d status %s flags 0x%llx\n", 8868c2ecf20Sopenharmony_ci cmnd_id, snic_io_status_to_str(cmpl_stat), 8878c2ecf20Sopenharmony_ci CMD_FLAGS(sc)); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (rqi->abts_done) 8908c2ecf20Sopenharmony_ci complete(rqi->abts_done); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci break; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci default: 8978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 8988c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 8998c2ecf20Sopenharmony_ci "itmf_cmpl: Unknown TM tag bit 0x%x\n", tm_tags); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 9028c2ecf20Sopenharmony_ci "itmf_cmpl:Unexpected itmf io stat %s Tag = 0x%x flags 0x%llx\n", 9038c2ecf20Sopenharmony_ci snic_ioreq_state_to_str(CMD_STATE(sc)), 9048c2ecf20Sopenharmony_ci cmnd_id, 9058c2ecf20Sopenharmony_ci CMD_FLAGS(sc)); 9068c2ecf20Sopenharmony_ci ret = -1; 9078c2ecf20Sopenharmony_ci SNIC_BUG_ON(1); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci break; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci return ret; 9138c2ecf20Sopenharmony_ci} /* end of snic_process_itmf_cmpl_status */ 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci/* 9168c2ecf20Sopenharmony_ci * snic_itmf_cmpl_handler. 9178c2ecf20Sopenharmony_ci * Routine to handle itmf completions. 9188c2ecf20Sopenharmony_ci */ 9198c2ecf20Sopenharmony_cistatic void 9208c2ecf20Sopenharmony_cisnic_itmf_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = NULL; 9238c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 9248c2ecf20Sopenharmony_ci struct snic_itmf_cmpl *itmf_cmpl = NULL; 9258c2ecf20Sopenharmony_ci ulong ctx; 9268c2ecf20Sopenharmony_ci u32 cmnd_id; 9278c2ecf20Sopenharmony_ci u32 hid; 9288c2ecf20Sopenharmony_ci u8 typ; 9298c2ecf20Sopenharmony_ci u8 hdr_stat; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci snic_io_hdr_dec(&fwreq->hdr, &typ, &hdr_stat, &cmnd_id, &hid, &ctx); 9328c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 9338c2ecf20Sopenharmony_ci "Itmf_cmpl: %s: type = %x, hdr_stat = %x, cmnd_id = %x, hid = %x,ctx = %lx\n", 9348c2ecf20Sopenharmony_ci __func__, typ, hdr_stat, cmnd_id, hid, ctx); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci itmf_cmpl = &fwreq->u.itmf_cmpl; 9378c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 9388c2ecf20Sopenharmony_ci "Itmf_cmpl: nterm %u , flags 0x%x\n", 9398c2ecf20Sopenharmony_ci le32_to_cpu(itmf_cmpl->nterminated), itmf_cmpl->flags); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* spl case, dev reset issued through ioctl */ 9428c2ecf20Sopenharmony_ci if (cmnd_id & SNIC_TAG_IOCTL_DEV_RST) { 9438c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) ctx; 9448c2ecf20Sopenharmony_ci sc = rqi->sc; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci goto ioctl_dev_rst; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if ((cmnd_id & SNIC_TAG_MASK) >= snic->max_tag_id) { 9508c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 9518c2ecf20Sopenharmony_ci "Itmf_cmpl: Tag 0x%x out of Range,HdrStat %s\n", 9528c2ecf20Sopenharmony_ci cmnd_id, snic_io_status_to_str(hdr_stat)); 9538c2ecf20Sopenharmony_ci SNIC_BUG_ON(1); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci return; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(snic->shost, cmnd_id & SNIC_TAG_MASK); 9598c2ecf20Sopenharmony_ci WARN_ON_ONCE(!sc); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ciioctl_dev_rst: 9628c2ecf20Sopenharmony_ci if (!sc) { 9638c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.sc_null); 9648c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 9658c2ecf20Sopenharmony_ci "Itmf_cmpl: sc is NULL - Hdr Stat %s Tag 0x%x\n", 9668c2ecf20Sopenharmony_ci snic_io_status_to_str(hdr_stat), cmnd_id); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci return; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci snic_process_itmf_cmpl(snic, fwreq, cmnd_id, hdr_stat, sc); 9728c2ecf20Sopenharmony_ci} /* end of snic_itmf_cmpl_handler */ 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic void 9778c2ecf20Sopenharmony_cisnic_hba_reset_scsi_cleanup(struct snic *snic, struct scsi_cmnd *sc) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci struct snic_stats *st = &snic->s_stats; 9808c2ecf20Sopenharmony_ci long act_ios = 0, act_fwreqs = 0; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "HBA Reset scsi cleanup.\n"); 9838c2ecf20Sopenharmony_ci snic_scsi_cleanup(snic, snic_cmd_tag(sc)); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci /* Update stats on pending IOs */ 9868c2ecf20Sopenharmony_ci act_ios = atomic64_read(&st->io.active); 9878c2ecf20Sopenharmony_ci atomic64_add(act_ios, &st->io.compl); 9888c2ecf20Sopenharmony_ci atomic64_sub(act_ios, &st->io.active); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci act_fwreqs = atomic64_read(&st->fw.actv_reqs); 9918c2ecf20Sopenharmony_ci atomic64_sub(act_fwreqs, &st->fw.actv_reqs); 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci/* 9958c2ecf20Sopenharmony_ci * snic_hba_reset_cmpl_handler : 9968c2ecf20Sopenharmony_ci * 9978c2ecf20Sopenharmony_ci * Notes : 9988c2ecf20Sopenharmony_ci * 1. Cleanup all the scsi cmds, release all snic specific cmds 9998c2ecf20Sopenharmony_ci * 2. Issue Report Targets in case of SAN targets 10008c2ecf20Sopenharmony_ci */ 10018c2ecf20Sopenharmony_cistatic int 10028c2ecf20Sopenharmony_cisnic_hba_reset_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci ulong ctx; 10058c2ecf20Sopenharmony_ci u32 cmnd_id; 10068c2ecf20Sopenharmony_ci u32 hid; 10078c2ecf20Sopenharmony_ci u8 typ; 10088c2ecf20Sopenharmony_ci u8 hdr_stat; 10098c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = NULL; 10108c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 10118c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 10128c2ecf20Sopenharmony_ci unsigned long flags, gflags; 10138c2ecf20Sopenharmony_ci int ret = 0; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci snic_io_hdr_dec(&fwreq->hdr, &typ, &hdr_stat, &cmnd_id, &hid, &ctx); 10168c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, 10178c2ecf20Sopenharmony_ci "reset_cmpl:Tag %d ctx %lx cmpl status %s HBA Reset Completion received.\n", 10188c2ecf20Sopenharmony_ci cmnd_id, ctx, snic_io_status_to_str(hdr_stat)); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 10218c2ecf20Sopenharmony_ci "reset_cmpl: type = %x, hdr_stat = %x, cmnd_id = %x, hid = %x, ctx = %lx\n", 10228c2ecf20Sopenharmony_ci typ, hdr_stat, cmnd_id, hid, ctx); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* spl case, host reset issued through ioctl */ 10258c2ecf20Sopenharmony_ci if (cmnd_id == SCSI_NO_TAG) { 10268c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) ctx; 10278c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, 10288c2ecf20Sopenharmony_ci "reset_cmpl:Tag %d ctx %lx cmpl stat %s\n", 10298c2ecf20Sopenharmony_ci cmnd_id, ctx, snic_io_status_to_str(hdr_stat)); 10308c2ecf20Sopenharmony_ci sc = rqi->sc; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci goto ioctl_hba_rst; 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (cmnd_id >= snic->max_tag_id) { 10368c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 10378c2ecf20Sopenharmony_ci "reset_cmpl: Tag 0x%x out of Range,HdrStat %s\n", 10388c2ecf20Sopenharmony_ci cmnd_id, snic_io_status_to_str(hdr_stat)); 10398c2ecf20Sopenharmony_ci SNIC_BUG_ON(1); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci return 1; 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(snic->shost, cmnd_id); 10458c2ecf20Sopenharmony_ciioctl_hba_rst: 10468c2ecf20Sopenharmony_ci if (!sc) { 10478c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.sc_null); 10488c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 10498c2ecf20Sopenharmony_ci "reset_cmpl: sc is NULL - Hdr Stat %s Tag 0x%x\n", 10508c2ecf20Sopenharmony_ci snic_io_status_to_str(hdr_stat), cmnd_id); 10518c2ecf20Sopenharmony_ci ret = 1; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci return ret; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, 10578c2ecf20Sopenharmony_ci "reset_cmpl: sc %p rqi %p Tag %d flags 0x%llx\n", 10588c2ecf20Sopenharmony_ci sc, rqi, cmnd_id, CMD_FLAGS(sc)); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci io_lock = snic_io_lock_hash(snic, sc); 10618c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (!snic->remove_wait) { 10648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 10658c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 10668c2ecf20Sopenharmony_ci "reset_cmpl:host reset completed after timeout\n"); 10678c2ecf20Sopenharmony_ci ret = 1; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci return ret; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 10738c2ecf20Sopenharmony_ci WARN_ON_ONCE(!rqi); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (!rqi) { 10768c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.req_null); 10778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 10788c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_REQ_NULL; 10798c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 10808c2ecf20Sopenharmony_ci "reset_cmpl: rqi is null,Hdr stat %s Tag 0x%x sc 0x%p flags 0x%llx\n", 10818c2ecf20Sopenharmony_ci snic_io_status_to_str(hdr_stat), cmnd_id, sc, 10828c2ecf20Sopenharmony_ci CMD_FLAGS(sc)); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci ret = 1; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci return ret; 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci /* stats */ 10898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci /* scsi cleanup */ 10928c2ecf20Sopenharmony_ci snic_hba_reset_scsi_cleanup(snic, sc); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci SNIC_BUG_ON(snic_get_state(snic) != SNIC_OFFLINE && 10958c2ecf20Sopenharmony_ci snic_get_state(snic) != SNIC_FWRESET); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* Careful locking between snic_lock and io lock */ 10988c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 10998c2ecf20Sopenharmony_ci spin_lock_irqsave(&snic->snic_lock, gflags); 11008c2ecf20Sopenharmony_ci if (snic_get_state(snic) == SNIC_FWRESET) 11018c2ecf20Sopenharmony_ci snic_set_state(snic, SNIC_ONLINE); 11028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, gflags); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci if (snic->remove_wait) 11058c2ecf20Sopenharmony_ci complete(snic->remove_wait); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 11088c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.reset.hba_reset_cmpl); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci ret = 0; 11118c2ecf20Sopenharmony_ci /* Rediscovery is for SAN */ 11128c2ecf20Sopenharmony_ci if (snic->config.xpt_type == SNIC_DAS) 11138c2ecf20Sopenharmony_ci return ret; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "reset_cmpl: Queuing discovery work.\n"); 11168c2ecf20Sopenharmony_ci queue_work(snic_glob->event_q, &snic->disc_work); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci return ret; 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic void 11228c2ecf20Sopenharmony_cisnic_msg_ack_handler(struct snic *snic, struct snic_fw_req *fwreq) 11238c2ecf20Sopenharmony_ci{ 11248c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "Message Ack Received.\n"); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci SNIC_ASSERT_NOT_IMPL(1); 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic void 11308c2ecf20Sopenharmony_cisnic_aen_handler(struct snic *snic, struct snic_fw_req *fwreq) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci u8 typ, hdr_stat; 11338c2ecf20Sopenharmony_ci u32 cmnd_id, hid; 11348c2ecf20Sopenharmony_ci ulong ctx; 11358c2ecf20Sopenharmony_ci struct snic_async_evnotify *aen = &fwreq->u.async_ev; 11368c2ecf20Sopenharmony_ci u32 event_id = 0; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci snic_io_hdr_dec(&fwreq->hdr, &typ, &hdr_stat, &cmnd_id, &hid, &ctx); 11398c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 11408c2ecf20Sopenharmony_ci "aen: type = %x, hdr_stat = %x, cmnd_id = %x, hid = %x, ctx = %lx\n", 11418c2ecf20Sopenharmony_ci typ, hdr_stat, cmnd_id, hid, ctx); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci event_id = le32_to_cpu(aen->ev_id); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci switch (event_id) { 11468c2ecf20Sopenharmony_ci case SNIC_EV_TGT_OFFLINE: 11478c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "aen:TGT_OFFLINE Event Recvd.\n"); 11488c2ecf20Sopenharmony_ci break; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci case SNIC_EV_TGT_ONLINE: 11518c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "aen:TGT_ONLINE Event Recvd.\n"); 11528c2ecf20Sopenharmony_ci break; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci case SNIC_EV_LUN_OFFLINE: 11558c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "aen:LUN_OFFLINE Event Recvd.\n"); 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci case SNIC_EV_LUN_ONLINE: 11598c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "aen:LUN_ONLINE Event Recvd.\n"); 11608c2ecf20Sopenharmony_ci break; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci case SNIC_EV_CONF_CHG: 11638c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "aen:Config Change Event Recvd.\n"); 11648c2ecf20Sopenharmony_ci break; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci case SNIC_EV_TGT_ADDED: 11678c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "aen:TGT_ADD Event Recvd.\n"); 11688c2ecf20Sopenharmony_ci break; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci case SNIC_EV_TGT_DELTD: 11718c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "aen:TGT_DEL Event Recvd.\n"); 11728c2ecf20Sopenharmony_ci break; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci case SNIC_EV_LUN_ADDED: 11758c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "aen:LUN_ADD Event Recvd.\n"); 11768c2ecf20Sopenharmony_ci break; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci case SNIC_EV_LUN_DELTD: 11798c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "aen:LUN_DEL Event Recvd.\n"); 11808c2ecf20Sopenharmony_ci break; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci case SNIC_EV_DISC_CMPL: 11838c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "aen:DISC_CMPL Event Recvd.\n"); 11848c2ecf20Sopenharmony_ci break; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci default: 11878c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "aen:Unknown Event Recvd.\n"); 11888c2ecf20Sopenharmony_ci SNIC_BUG_ON(1); 11898c2ecf20Sopenharmony_ci break; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci SNIC_ASSERT_NOT_IMPL(1); 11938c2ecf20Sopenharmony_ci} /* end of snic_aen_handler */ 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci/* 11968c2ecf20Sopenharmony_ci * snic_io_cmpl_handler 11978c2ecf20Sopenharmony_ci * Routine to process CQ entries(IO Completions) posted by fw. 11988c2ecf20Sopenharmony_ci */ 11998c2ecf20Sopenharmony_cistatic int 12008c2ecf20Sopenharmony_cisnic_io_cmpl_handler(struct vnic_dev *vdev, 12018c2ecf20Sopenharmony_ci unsigned int cq_idx, 12028c2ecf20Sopenharmony_ci struct snic_fw_req *fwreq) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci struct snic *snic = svnic_dev_priv(vdev); 12058c2ecf20Sopenharmony_ci u64 start = jiffies, cmpl_time; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci snic_print_desc(__func__, (char *)fwreq, sizeof(*fwreq)); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci /* Update FW Stats */ 12108c2ecf20Sopenharmony_ci if ((fwreq->hdr.type >= SNIC_RSP_REPORT_TGTS_CMPL) && 12118c2ecf20Sopenharmony_ci (fwreq->hdr.type <= SNIC_RSP_BOOT_LUNS_CMPL)) 12128c2ecf20Sopenharmony_ci atomic64_dec(&snic->s_stats.fw.actv_reqs); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci SNIC_BUG_ON((fwreq->hdr.type > SNIC_RSP_BOOT_LUNS_CMPL) && 12158c2ecf20Sopenharmony_ci (fwreq->hdr.type < SNIC_MSG_ASYNC_EVNOTIFY)); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci /* Check for snic subsys errors */ 12188c2ecf20Sopenharmony_ci switch (fwreq->hdr.status) { 12198c2ecf20Sopenharmony_ci case SNIC_STAT_NOT_READY: /* XPT yet to initialize */ 12208c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 12218c2ecf20Sopenharmony_ci "sNIC SubSystem is NOT Ready.\n"); 12228c2ecf20Sopenharmony_ci break; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci case SNIC_STAT_FATAL_ERROR: /* XPT Error */ 12258c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 12268c2ecf20Sopenharmony_ci "sNIC SubSystem in Unrecoverable State.\n"); 12278c2ecf20Sopenharmony_ci break; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci switch (fwreq->hdr.type) { 12318c2ecf20Sopenharmony_ci case SNIC_RSP_EXCH_VER_CMPL: 12328c2ecf20Sopenharmony_ci snic_io_exch_ver_cmpl_handler(snic, fwreq); 12338c2ecf20Sopenharmony_ci break; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci case SNIC_RSP_REPORT_TGTS_CMPL: 12368c2ecf20Sopenharmony_ci snic_report_tgt_cmpl_handler(snic, fwreq); 12378c2ecf20Sopenharmony_ci break; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci case SNIC_RSP_ICMND_CMPL: 12408c2ecf20Sopenharmony_ci snic_icmnd_cmpl_handler(snic, fwreq); 12418c2ecf20Sopenharmony_ci break; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci case SNIC_RSP_ITMF_CMPL: 12448c2ecf20Sopenharmony_ci snic_itmf_cmpl_handler(snic, fwreq); 12458c2ecf20Sopenharmony_ci break; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci case SNIC_RSP_HBA_RESET_CMPL: 12488c2ecf20Sopenharmony_ci snic_hba_reset_cmpl_handler(snic, fwreq); 12498c2ecf20Sopenharmony_ci break; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci case SNIC_MSG_ACK: 12528c2ecf20Sopenharmony_ci snic_msg_ack_handler(snic, fwreq); 12538c2ecf20Sopenharmony_ci break; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci case SNIC_MSG_ASYNC_EVNOTIFY: 12568c2ecf20Sopenharmony_ci snic_aen_handler(snic, fwreq); 12578c2ecf20Sopenharmony_ci break; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci default: 12608c2ecf20Sopenharmony_ci SNIC_BUG_ON(1); 12618c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 12628c2ecf20Sopenharmony_ci "Unknown Firmware completion request type %d\n", 12638c2ecf20Sopenharmony_ci fwreq->hdr.type); 12648c2ecf20Sopenharmony_ci break; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci /* Update Stats */ 12688c2ecf20Sopenharmony_ci cmpl_time = jiffies - start; 12698c2ecf20Sopenharmony_ci if (cmpl_time > atomic64_read(&snic->s_stats.io.max_cmpl_time)) 12708c2ecf20Sopenharmony_ci atomic64_set(&snic->s_stats.io.max_cmpl_time, cmpl_time); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci return 0; 12738c2ecf20Sopenharmony_ci} /* end of snic_io_cmpl_handler */ 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci/* 12768c2ecf20Sopenharmony_ci * snic_fwcq_cmpl_handler 12778c2ecf20Sopenharmony_ci * Routine to process fwCQ 12788c2ecf20Sopenharmony_ci * This CQ is independent, and not associated with wq/rq/wq_copy queues 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_ciint 12818c2ecf20Sopenharmony_cisnic_fwcq_cmpl_handler(struct snic *snic, int io_cmpl_work) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci unsigned int num_ent = 0; /* number cq entries processed */ 12848c2ecf20Sopenharmony_ci unsigned int cq_idx; 12858c2ecf20Sopenharmony_ci unsigned int nent_per_cq; 12868c2ecf20Sopenharmony_ci struct snic_misc_stats *misc_stats = &snic->s_stats.misc; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci for (cq_idx = snic->wq_count; cq_idx < snic->cq_count; cq_idx++) { 12898c2ecf20Sopenharmony_ci nent_per_cq = vnic_cq_fw_service(&snic->cq[cq_idx], 12908c2ecf20Sopenharmony_ci snic_io_cmpl_handler, 12918c2ecf20Sopenharmony_ci io_cmpl_work); 12928c2ecf20Sopenharmony_ci num_ent += nent_per_cq; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (nent_per_cq > atomic64_read(&misc_stats->max_cq_ents)) 12958c2ecf20Sopenharmony_ci atomic64_set(&misc_stats->max_cq_ents, nent_per_cq); 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci return num_ent; 12998c2ecf20Sopenharmony_ci} /* end of snic_fwcq_cmpl_handler */ 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci/* 13028c2ecf20Sopenharmony_ci * snic_queue_itmf_req: Common API to queue Task Management requests. 13038c2ecf20Sopenharmony_ci * Use rqi->tm_tag for passing special tags. 13048c2ecf20Sopenharmony_ci * @req_id : aborted request's tag, -1 for lun reset. 13058c2ecf20Sopenharmony_ci */ 13068c2ecf20Sopenharmony_cistatic int 13078c2ecf20Sopenharmony_cisnic_queue_itmf_req(struct snic *snic, 13088c2ecf20Sopenharmony_ci struct snic_host_req *tmreq, 13098c2ecf20Sopenharmony_ci struct scsi_cmnd *sc, 13108c2ecf20Sopenharmony_ci u32 tmf, 13118c2ecf20Sopenharmony_ci u32 req_id) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci struct snic_req_info *rqi = req_to_rqi(tmreq); 13148c2ecf20Sopenharmony_ci struct scsi_lun lun; 13158c2ecf20Sopenharmony_ci int tm_tag = snic_cmd_tag(sc) | rqi->tm_tag; 13168c2ecf20Sopenharmony_ci int ret = 0; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci SNIC_BUG_ON(!rqi); 13198c2ecf20Sopenharmony_ci SNIC_BUG_ON(!rqi->tm_tag); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci /* fill in lun info */ 13228c2ecf20Sopenharmony_ci int_to_scsilun(sc->device->lun, &lun); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci /* Initialize snic_host_req: itmf */ 13258c2ecf20Sopenharmony_ci snic_itmf_init(tmreq, 13268c2ecf20Sopenharmony_ci tm_tag, 13278c2ecf20Sopenharmony_ci snic->config.hid, 13288c2ecf20Sopenharmony_ci (ulong) rqi, 13298c2ecf20Sopenharmony_ci 0 /* flags */, 13308c2ecf20Sopenharmony_ci req_id, /* Command to be aborted. */ 13318c2ecf20Sopenharmony_ci rqi->tgt_id, 13328c2ecf20Sopenharmony_ci lun.scsi_lun, 13338c2ecf20Sopenharmony_ci tmf); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci /* 13368c2ecf20Sopenharmony_ci * In case of multiple aborts on same cmd, 13378c2ecf20Sopenharmony_ci * use try_wait_for_completion and completion_done() to check 13388c2ecf20Sopenharmony_ci * whether it queues aborts even after completion of abort issued 13398c2ecf20Sopenharmony_ci * prior.SNIC_BUG_ON(completion_done(&rqi->done)); 13408c2ecf20Sopenharmony_ci */ 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci ret = snic_queue_wq_desc(snic, tmreq, sizeof(*tmreq)); 13438c2ecf20Sopenharmony_ci if (ret) 13448c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 13458c2ecf20Sopenharmony_ci "qitmf:Queuing ITMF(%d) Req sc %p, rqi %p, req_id %d tag %d Failed, ret = %d\n", 13468c2ecf20Sopenharmony_ci tmf, sc, rqi, req_id, snic_cmd_tag(sc), ret); 13478c2ecf20Sopenharmony_ci else 13488c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 13498c2ecf20Sopenharmony_ci "qitmf:Queuing ITMF(%d) Req sc %p, rqi %p, req_id %d, tag %d (req_id)- Success.", 13508c2ecf20Sopenharmony_ci tmf, sc, rqi, req_id, snic_cmd_tag(sc)); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci return ret; 13538c2ecf20Sopenharmony_ci} /* end of snic_queue_itmf_req */ 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_cistatic int 13568c2ecf20Sopenharmony_cisnic_issue_tm_req(struct snic *snic, 13578c2ecf20Sopenharmony_ci struct snic_req_info *rqi, 13588c2ecf20Sopenharmony_ci struct scsi_cmnd *sc, 13598c2ecf20Sopenharmony_ci int tmf) 13608c2ecf20Sopenharmony_ci{ 13618c2ecf20Sopenharmony_ci struct snic_host_req *tmreq = NULL; 13628c2ecf20Sopenharmony_ci int req_id = 0, tag = snic_cmd_tag(sc); 13638c2ecf20Sopenharmony_ci int ret = 0; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if (snic_get_state(snic) == SNIC_FWRESET) 13668c2ecf20Sopenharmony_ci return -EBUSY; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci atomic_inc(&snic->ios_inflight); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 13718c2ecf20Sopenharmony_ci "issu_tmreq: Task mgmt req %d. rqi %p w/ tag %x\n", 13728c2ecf20Sopenharmony_ci tmf, rqi, tag); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci if (tmf == SNIC_ITMF_LUN_RESET) { 13768c2ecf20Sopenharmony_ci tmreq = snic_dr_req_init(snic, rqi); 13778c2ecf20Sopenharmony_ci req_id = SCSI_NO_TAG; 13788c2ecf20Sopenharmony_ci } else { 13798c2ecf20Sopenharmony_ci tmreq = snic_abort_req_init(snic, rqi); 13808c2ecf20Sopenharmony_ci req_id = tag; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (!tmreq) { 13848c2ecf20Sopenharmony_ci ret = -ENOMEM; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci goto tmreq_err; 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci ret = snic_queue_itmf_req(snic, tmreq, sc, tmf, req_id); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_citmreq_err: 13928c2ecf20Sopenharmony_ci if (ret) { 13938c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 13948c2ecf20Sopenharmony_ci "issu_tmreq: Queueing ITMF(%d) Req, sc %p rqi %p req_id %d tag %x fails err = %d\n", 13958c2ecf20Sopenharmony_ci tmf, sc, rqi, req_id, tag, ret); 13968c2ecf20Sopenharmony_ci } else { 13978c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 13988c2ecf20Sopenharmony_ci "issu_tmreq: Queueing ITMF(%d) Req, sc %p, rqi %p, req_id %d tag %x - Success.\n", 13998c2ecf20Sopenharmony_ci tmf, sc, rqi, req_id, tag); 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci atomic_dec(&snic->ios_inflight); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci return ret; 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci/* 14088c2ecf20Sopenharmony_ci * snic_queue_abort_req : Queues abort req to WQ 14098c2ecf20Sopenharmony_ci */ 14108c2ecf20Sopenharmony_cistatic int 14118c2ecf20Sopenharmony_cisnic_queue_abort_req(struct snic *snic, 14128c2ecf20Sopenharmony_ci struct snic_req_info *rqi, 14138c2ecf20Sopenharmony_ci struct scsi_cmnd *sc, 14148c2ecf20Sopenharmony_ci int tmf) 14158c2ecf20Sopenharmony_ci{ 14168c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "q_abtreq: sc %p, rqi %p, tag %x, tmf %d\n", 14178c2ecf20Sopenharmony_ci sc, rqi, snic_cmd_tag(sc), tmf); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci /* Add special tag for abort */ 14208c2ecf20Sopenharmony_ci rqi->tm_tag |= SNIC_TAG_ABORT; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci return snic_issue_tm_req(snic, rqi, sc, tmf); 14238c2ecf20Sopenharmony_ci} 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci/* 14268c2ecf20Sopenharmony_ci * snic_abort_finish : called by snic_abort_cmd on queuing abort successfully. 14278c2ecf20Sopenharmony_ci */ 14288c2ecf20Sopenharmony_cistatic int 14298c2ecf20Sopenharmony_cisnic_abort_finish(struct snic *snic, struct scsi_cmnd *sc) 14308c2ecf20Sopenharmony_ci{ 14318c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 14328c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 14338c2ecf20Sopenharmony_ci unsigned long flags; 14348c2ecf20Sopenharmony_ci int ret = 0, tag = snic_cmd_tag(sc); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci io_lock = snic_io_lock_hash(snic, sc); 14378c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 14388c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 14398c2ecf20Sopenharmony_ci if (!rqi) { 14408c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.io.req_null); 14418c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_REQ_NULL; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 14448c2ecf20Sopenharmony_ci "abt_fini:req info is null tag 0x%x, sc 0x%p flags 0x%llx\n", 14458c2ecf20Sopenharmony_ci tag, sc, CMD_FLAGS(sc)); 14468c2ecf20Sopenharmony_ci ret = FAILED; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci goto abort_fail; 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci rqi->abts_done = NULL; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci ret = FAILED; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci /* Check the abort status. */ 14568c2ecf20Sopenharmony_ci switch (CMD_ABTS_STATUS(sc)) { 14578c2ecf20Sopenharmony_ci case SNIC_INVALID_CODE: 14588c2ecf20Sopenharmony_ci /* Firmware didn't complete abort req, timedout */ 14598c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_ABTS_TIMEDOUT; 14608c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.abts.drv_tmo); 14618c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 14628c2ecf20Sopenharmony_ci "abt_fini:sc %p Tag %x Driver Timeout.flags 0x%llx\n", 14638c2ecf20Sopenharmony_ci sc, snic_cmd_tag(sc), CMD_FLAGS(sc)); 14648c2ecf20Sopenharmony_ci /* do not release snic request in timedout case */ 14658c2ecf20Sopenharmony_ci rqi = NULL; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci goto abort_fail; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci case SNIC_STAT_IO_SUCCESS: 14708c2ecf20Sopenharmony_ci case SNIC_STAT_IO_NOT_FOUND: 14718c2ecf20Sopenharmony_ci ret = SUCCESS; 14728c2ecf20Sopenharmony_ci /* 14738c2ecf20Sopenharmony_ci * If abort path doesn't call scsi_done(), 14748c2ecf20Sopenharmony_ci * the # IO timeouts == 2, will cause the LUN offline. 14758c2ecf20Sopenharmony_ci * Call scsi_done to complete the IO. 14768c2ecf20Sopenharmony_ci */ 14778c2ecf20Sopenharmony_ci sc->result = (DID_ERROR << 16); 14788c2ecf20Sopenharmony_ci sc->scsi_done(sc); 14798c2ecf20Sopenharmony_ci break; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci default: 14828c2ecf20Sopenharmony_ci /* Firmware completed abort with error */ 14838c2ecf20Sopenharmony_ci ret = FAILED; 14848c2ecf20Sopenharmony_ci rqi = NULL; 14858c2ecf20Sopenharmony_ci break; 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 14898c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, 14908c2ecf20Sopenharmony_ci "abt_fini: Tag %x, Cmpl Status %s flags 0x%llx\n", 14918c2ecf20Sopenharmony_ci tag, snic_io_status_to_str(CMD_ABTS_STATUS(sc)), 14928c2ecf20Sopenharmony_ci CMD_FLAGS(sc)); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ciabort_fail: 14958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 14968c2ecf20Sopenharmony_ci if (rqi) 14978c2ecf20Sopenharmony_ci snic_release_req_buf(snic, rqi, sc); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci return ret; 15008c2ecf20Sopenharmony_ci} /* end of snic_abort_finish */ 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci/* 15038c2ecf20Sopenharmony_ci * snic_send_abort_and_wait : Issues Abort, and Waits 15048c2ecf20Sopenharmony_ci */ 15058c2ecf20Sopenharmony_cistatic int 15068c2ecf20Sopenharmony_cisnic_send_abort_and_wait(struct snic *snic, struct scsi_cmnd *sc) 15078c2ecf20Sopenharmony_ci{ 15088c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 15098c2ecf20Sopenharmony_ci enum snic_ioreq_state sv_state; 15108c2ecf20Sopenharmony_ci struct snic_tgt *tgt = NULL; 15118c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 15128c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(tm_done); 15138c2ecf20Sopenharmony_ci unsigned long flags; 15148c2ecf20Sopenharmony_ci int ret = 0, tmf = 0, tag = snic_cmd_tag(sc); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci tgt = starget_to_tgt(scsi_target(sc->device)); 15178c2ecf20Sopenharmony_ci if ((snic_tgt_chkready(tgt) != 0) && (tgt->tdata.typ == SNIC_TGT_SAN)) 15188c2ecf20Sopenharmony_ci tmf = SNIC_ITMF_ABTS_TASK_TERM; 15198c2ecf20Sopenharmony_ci else 15208c2ecf20Sopenharmony_ci tmf = SNIC_ITMF_ABTS_TASK; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci /* stats */ 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci io_lock = snic_io_lock_hash(snic, sc); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* 15278c2ecf20Sopenharmony_ci * Avoid a race between SCSI issuing the abort and the device 15288c2ecf20Sopenharmony_ci * completing the command. 15298c2ecf20Sopenharmony_ci * 15308c2ecf20Sopenharmony_ci * If the command is already completed by fw_cmpl code, 15318c2ecf20Sopenharmony_ci * we just return SUCCESS from here. This means that the abort 15328c2ecf20Sopenharmony_ci * succeeded. In the SCSI ML, since the timeout for command has 15338c2ecf20Sopenharmony_ci * happend, the completion wont actually complete the command 15348c2ecf20Sopenharmony_ci * and it will be considered as an aborted command 15358c2ecf20Sopenharmony_ci * 15368c2ecf20Sopenharmony_ci * The CMD_SP will not be cleared except while holding io_lock 15378c2ecf20Sopenharmony_ci */ 15388c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 15398c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 15408c2ecf20Sopenharmony_ci if (!rqi) { 15418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 15448c2ecf20Sopenharmony_ci "abt_cmd: rqi is null. Tag %d flags 0x%llx\n", 15458c2ecf20Sopenharmony_ci tag, CMD_FLAGS(sc)); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci ret = SUCCESS; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci goto send_abts_end; 15508c2ecf20Sopenharmony_ci } 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci rqi->abts_done = &tm_done; 15538c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING) { 15548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci ret = 0; 15578c2ecf20Sopenharmony_ci goto abts_pending; 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci SNIC_BUG_ON(!rqi->abts_done); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci /* Save Command State, should be restored on failed to Queue. */ 15628c2ecf20Sopenharmony_ci sv_state = CMD_STATE(sc); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci /* 15658c2ecf20Sopenharmony_ci * Command is still pending, need to abort it 15668c2ecf20Sopenharmony_ci * If the fw completes the command after this point, 15678c2ecf20Sopenharmony_ci * the completion won't be done till mid-layer, since abot 15688c2ecf20Sopenharmony_ci * has already started. 15698c2ecf20Sopenharmony_ci */ 15708c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_ABTS_PENDING; 15718c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = SNIC_INVALID_CODE; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "send_abt_cmd: TAG 0x%x\n", tag); 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci /* Now Queue the abort command to firmware */ 15788c2ecf20Sopenharmony_ci ret = snic_queue_abort_req(snic, rqi, sc, tmf); 15798c2ecf20Sopenharmony_ci if (ret) { 15808c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.abts.q_fail); 15818c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 15828c2ecf20Sopenharmony_ci "send_abt_cmd: IO w/ Tag 0x%x fail w/ err %d flags 0x%llx\n", 15838c2ecf20Sopenharmony_ci tag, ret, CMD_FLAGS(sc)); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 15868c2ecf20Sopenharmony_ci /* Restore Command's previous state */ 15878c2ecf20Sopenharmony_ci CMD_STATE(sc) = sv_state; 15888c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 15898c2ecf20Sopenharmony_ci if (rqi) 15908c2ecf20Sopenharmony_ci rqi->abts_done = NULL; 15918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 15928c2ecf20Sopenharmony_ci ret = FAILED; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci goto send_abts_end; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 15988c2ecf20Sopenharmony_ci if (tmf == SNIC_ITMF_ABTS_TASK) { 15998c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_ABTS_ISSUED; 16008c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.abts.num); 16018c2ecf20Sopenharmony_ci } else { 16028c2ecf20Sopenharmony_ci /* term stats */ 16038c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_TERM_ISSUED; 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 16088c2ecf20Sopenharmony_ci "send_abt_cmd: sc %p Tag %x flags 0x%llx\n", 16098c2ecf20Sopenharmony_ci sc, tag, CMD_FLAGS(sc)); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci ret = 0; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ciabts_pending: 16158c2ecf20Sopenharmony_ci /* 16168c2ecf20Sopenharmony_ci * Queued an abort IO, wait for its completion. 16178c2ecf20Sopenharmony_ci * Once the fw completes the abort command, it will 16188c2ecf20Sopenharmony_ci * wakeup this thread. 16198c2ecf20Sopenharmony_ci */ 16208c2ecf20Sopenharmony_ci wait_for_completion_timeout(&tm_done, SNIC_ABTS_TIMEOUT); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cisend_abts_end: 16238c2ecf20Sopenharmony_ci return ret; 16248c2ecf20Sopenharmony_ci} /* end of snic_send_abort_and_wait */ 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci/* 16278c2ecf20Sopenharmony_ci * This function is exported to SCSI for sending abort cmnds. 16288c2ecf20Sopenharmony_ci * A SCSI IO is represent by snic_ioreq in the driver. 16298c2ecf20Sopenharmony_ci * The snic_ioreq is linked to the SCSI Cmd, thus a link with the ULP'S IO 16308c2ecf20Sopenharmony_ci */ 16318c2ecf20Sopenharmony_ciint 16328c2ecf20Sopenharmony_cisnic_abort_cmd(struct scsi_cmnd *sc) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci struct snic *snic = shost_priv(sc->device->host); 16358c2ecf20Sopenharmony_ci int ret = SUCCESS, tag = snic_cmd_tag(sc); 16368c2ecf20Sopenharmony_ci u32 start_time = jiffies; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "abt_cmd:sc %p :0x%x :req = %p :tag = %d\n", 16398c2ecf20Sopenharmony_ci sc, sc->cmnd[0], sc->request, tag); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if (unlikely(snic_get_state(snic) != SNIC_ONLINE)) { 16428c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 16438c2ecf20Sopenharmony_ci "abt_cmd: tag %x Parent Devs are not rdy\n", 16448c2ecf20Sopenharmony_ci tag); 16458c2ecf20Sopenharmony_ci ret = FAST_IO_FAIL; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci goto abort_end; 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci ret = snic_send_abort_and_wait(snic, sc); 16528c2ecf20Sopenharmony_ci if (ret) 16538c2ecf20Sopenharmony_ci goto abort_end; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci ret = snic_abort_finish(snic, sc); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ciabort_end: 16588c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, tag, (ulong) sc, 16598c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 0, 16608c2ecf20Sopenharmony_ci SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc)); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 16638c2ecf20Sopenharmony_ci "abts: Abort Req Status = %s\n", 16648c2ecf20Sopenharmony_ci (ret == SUCCESS) ? "SUCCESS" : 16658c2ecf20Sopenharmony_ci ((ret == FAST_IO_FAIL) ? "FAST_IO_FAIL" : "FAILED")); 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci return ret; 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_cistatic int 16738c2ecf20Sopenharmony_cisnic_is_abts_pending(struct snic *snic, struct scsi_cmnd *lr_sc) 16748c2ecf20Sopenharmony_ci{ 16758c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 16768c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = NULL; 16778c2ecf20Sopenharmony_ci struct scsi_device *lr_sdev = NULL; 16788c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 16798c2ecf20Sopenharmony_ci u32 tag; 16808c2ecf20Sopenharmony_ci unsigned long flags; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci if (lr_sc) 16838c2ecf20Sopenharmony_ci lr_sdev = lr_sc->device; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci /* walk through the tag map, an dcheck if IOs are still pending in fw*/ 16868c2ecf20Sopenharmony_ci for (tag = 0; tag < snic->max_tag_id; tag++) { 16878c2ecf20Sopenharmony_ci io_lock = snic_io_lock_tag(snic, tag); 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 16908c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(snic->shost, tag); 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci if (!sc || (lr_sc && (sc->device != lr_sdev || sc == lr_sc))) { 16938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci continue; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 16998c2ecf20Sopenharmony_ci if (!rqi) { 17008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci continue; 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci /* 17068c2ecf20Sopenharmony_ci * Found IO that is still pending w/ firmware and belongs to 17078c2ecf20Sopenharmony_ci * the LUN that is under reset, if lr_sc != NULL 17088c2ecf20Sopenharmony_ci */ 17098c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "Found IO in %s on LUN\n", 17108c2ecf20Sopenharmony_ci snic_ioreq_state_to_str(CMD_STATE(sc))); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING) { 17138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci return 1; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci return 0; 17228c2ecf20Sopenharmony_ci} /* end of snic_is_abts_pending */ 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_cistatic int 17258c2ecf20Sopenharmony_cisnic_dr_clean_single_req(struct snic *snic, 17268c2ecf20Sopenharmony_ci u32 tag, 17278c2ecf20Sopenharmony_ci struct scsi_device *lr_sdev) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 17308c2ecf20Sopenharmony_ci struct snic_tgt *tgt = NULL; 17318c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = NULL; 17328c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 17338c2ecf20Sopenharmony_ci u32 sv_state = 0, tmf = 0; 17348c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(tm_done); 17358c2ecf20Sopenharmony_ci unsigned long flags; 17368c2ecf20Sopenharmony_ci int ret = 0; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci io_lock = snic_io_lock_tag(snic, tag); 17398c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 17408c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(snic->shost, tag); 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci /* Ignore Cmd that don't belong to Lun Reset device */ 17438c2ecf20Sopenharmony_ci if (!sc || sc->device != lr_sdev) 17448c2ecf20Sopenharmony_ci goto skip_clean; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci if (!rqi) 17498c2ecf20Sopenharmony_ci goto skip_clean; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING) 17538c2ecf20Sopenharmony_ci goto skip_clean; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci if ((CMD_FLAGS(sc) & SNIC_DEVICE_RESET) && 17578c2ecf20Sopenharmony_ci (!(CMD_FLAGS(sc) & SNIC_DEV_RST_ISSUED))) { 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 17608c2ecf20Sopenharmony_ci "clean_single_req: devrst is not pending sc 0x%p\n", 17618c2ecf20Sopenharmony_ci sc); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci goto skip_clean; 17648c2ecf20Sopenharmony_ci } 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 17678c2ecf20Sopenharmony_ci "clean_single_req: Found IO in %s on lun\n", 17688c2ecf20Sopenharmony_ci snic_ioreq_state_to_str(CMD_STATE(sc))); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci /* Save Command State */ 17718c2ecf20Sopenharmony_ci sv_state = CMD_STATE(sc); 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci /* 17748c2ecf20Sopenharmony_ci * Any pending IO issued prior to reset is expected to be 17758c2ecf20Sopenharmony_ci * in abts pending state, if not we need to set SNIC_IOREQ_ABTS_PENDING 17768c2ecf20Sopenharmony_ci * to indicate the IO is abort pending. 17778c2ecf20Sopenharmony_ci * When IO is completed, the IO will be handed over and handled 17788c2ecf20Sopenharmony_ci * in this function. 17798c2ecf20Sopenharmony_ci */ 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_ABTS_PENDING; 17828c2ecf20Sopenharmony_ci SNIC_BUG_ON(rqi->abts_done); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & SNIC_DEVICE_RESET) { 17858c2ecf20Sopenharmony_ci rqi->tm_tag = SNIC_TAG_DEV_RST; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 17888c2ecf20Sopenharmony_ci "clean_single_req:devrst sc 0x%p\n", sc); 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = SNIC_INVALID_CODE; 17928c2ecf20Sopenharmony_ci rqi->abts_done = &tm_done; 17938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci tgt = starget_to_tgt(scsi_target(sc->device)); 17968c2ecf20Sopenharmony_ci if ((snic_tgt_chkready(tgt) != 0) && (tgt->tdata.typ == SNIC_TGT_SAN)) 17978c2ecf20Sopenharmony_ci tmf = SNIC_ITMF_ABTS_TASK_TERM; 17988c2ecf20Sopenharmony_ci else 17998c2ecf20Sopenharmony_ci tmf = SNIC_ITMF_ABTS_TASK; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci /* Now queue the abort command to firmware */ 18028c2ecf20Sopenharmony_ci ret = snic_queue_abort_req(snic, rqi, sc, tmf); 18038c2ecf20Sopenharmony_ci if (ret) { 18048c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 18058c2ecf20Sopenharmony_ci "clean_single_req_err:sc %p, tag %d abt failed. tm_tag %d flags 0x%llx\n", 18068c2ecf20Sopenharmony_ci sc, tag, rqi->tm_tag, CMD_FLAGS(sc)); 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 18098c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 18108c2ecf20Sopenharmony_ci if (rqi) 18118c2ecf20Sopenharmony_ci rqi->abts_done = NULL; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci /* Restore Command State */ 18148c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING) 18158c2ecf20Sopenharmony_ci CMD_STATE(sc) = sv_state; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci ret = 1; 18188c2ecf20Sopenharmony_ci goto skip_clean; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 18228c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & SNIC_DEVICE_RESET) 18238c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_DEV_RST_TERM_ISSUED; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_INTERNAL_TERM_ISSUED; 18268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci wait_for_completion_timeout(&tm_done, SNIC_ABTS_TIMEOUT); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci /* Recheck cmd state to check if it now aborted. */ 18318c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 18328c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 18338c2ecf20Sopenharmony_ci if (!rqi) { 18348c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_REQ_NULL; 18358c2ecf20Sopenharmony_ci goto skip_clean; 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci rqi->abts_done = NULL; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci /* if abort is still pending w/ fw, fail */ 18408c2ecf20Sopenharmony_ci if (CMD_ABTS_STATUS(sc) == SNIC_INVALID_CODE) { 18418c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 18428c2ecf20Sopenharmony_ci "clean_single_req_err:sc %p tag %d abt still pending w/ fw, tm_tag %d flags 0x%llx\n", 18438c2ecf20Sopenharmony_ci sc, tag, rqi->tm_tag, CMD_FLAGS(sc)); 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_DONE; 18468c2ecf20Sopenharmony_ci ret = 1; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci goto skip_clean; 18498c2ecf20Sopenharmony_ci } 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_ABTS_COMPLETE; 18528c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 18538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci snic_release_req_buf(snic, rqi, sc); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci sc->result = (DID_ERROR << 16); 18588c2ecf20Sopenharmony_ci sc->scsi_done(sc); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci ret = 0; 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci return ret; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ciskip_clean: 18658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci return ret; 18688c2ecf20Sopenharmony_ci} /* end of snic_dr_clean_single_req */ 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_cistatic int 18718c2ecf20Sopenharmony_cisnic_dr_clean_pending_req(struct snic *snic, struct scsi_cmnd *lr_sc) 18728c2ecf20Sopenharmony_ci{ 18738c2ecf20Sopenharmony_ci struct scsi_device *lr_sdev = lr_sc->device; 18748c2ecf20Sopenharmony_ci u32 tag = 0; 18758c2ecf20Sopenharmony_ci int ret = FAILED; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci for (tag = 0; tag < snic->max_tag_id; tag++) { 18788c2ecf20Sopenharmony_ci if (tag == snic_cmd_tag(lr_sc)) 18798c2ecf20Sopenharmony_ci continue; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci ret = snic_dr_clean_single_req(snic, tag, lr_sdev); 18828c2ecf20Sopenharmony_ci if (ret) { 18838c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "clean_err:tag = %d\n", tag); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci goto clean_err; 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci } 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci schedule_timeout(msecs_to_jiffies(100)); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci /* Walk through all the cmds and check abts status. */ 18928c2ecf20Sopenharmony_ci if (snic_is_abts_pending(snic, lr_sc)) { 18938c2ecf20Sopenharmony_ci ret = FAILED; 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci goto clean_err; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci ret = 0; 18998c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "clean_pending_req: Success.\n"); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci return ret; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ciclean_err: 19048c2ecf20Sopenharmony_ci ret = FAILED; 19058c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 19068c2ecf20Sopenharmony_ci "Failed to Clean Pending IOs on %s device.\n", 19078c2ecf20Sopenharmony_ci dev_name(&lr_sdev->sdev_gendev)); 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci return ret; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci} /* end of snic_dr_clean_pending_req */ 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci/* 19148c2ecf20Sopenharmony_ci * snic_dr_finish : Called by snic_device_reset 19158c2ecf20Sopenharmony_ci */ 19168c2ecf20Sopenharmony_cistatic int 19178c2ecf20Sopenharmony_cisnic_dr_finish(struct snic *snic, struct scsi_cmnd *sc) 19188c2ecf20Sopenharmony_ci{ 19198c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 19208c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 19218c2ecf20Sopenharmony_ci unsigned long flags; 19228c2ecf20Sopenharmony_ci int lr_res = 0; 19238c2ecf20Sopenharmony_ci int ret = FAILED; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci io_lock = snic_io_lock_hash(snic, sc); 19268c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 19278c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 19288c2ecf20Sopenharmony_ci if (!rqi) { 19298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 19308c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 19318c2ecf20Sopenharmony_ci "dr_fini: rqi is null tag 0x%x sc 0x%p flags 0x%llx\n", 19328c2ecf20Sopenharmony_ci snic_cmd_tag(sc), sc, CMD_FLAGS(sc)); 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci ret = FAILED; 19358c2ecf20Sopenharmony_ci goto dr_fini_end; 19368c2ecf20Sopenharmony_ci } 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci rqi->dr_done = NULL; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci lr_res = CMD_LR_STATUS(sc); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci switch (lr_res) { 19438c2ecf20Sopenharmony_ci case SNIC_INVALID_CODE: 19448c2ecf20Sopenharmony_ci /* stats */ 19458c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 19468c2ecf20Sopenharmony_ci "dr_fini: Tag %x Dev Reset Timedout. flags 0x%llx\n", 19478c2ecf20Sopenharmony_ci snic_cmd_tag(sc), CMD_FLAGS(sc)); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_DEV_RST_TIMEDOUT; 19508c2ecf20Sopenharmony_ci ret = FAILED; 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci goto dr_failed; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci case SNIC_STAT_IO_SUCCESS: 19558c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 19568c2ecf20Sopenharmony_ci "dr_fini: Tag %x Dev Reset cmpl\n", 19578c2ecf20Sopenharmony_ci snic_cmd_tag(sc)); 19588c2ecf20Sopenharmony_ci ret = 0; 19598c2ecf20Sopenharmony_ci break; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci default: 19628c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 19638c2ecf20Sopenharmony_ci "dr_fini:Device Reset completed& failed.Tag = %x lr_status %s flags 0x%llx\n", 19648c2ecf20Sopenharmony_ci snic_cmd_tag(sc), 19658c2ecf20Sopenharmony_ci snic_io_status_to_str(lr_res), CMD_FLAGS(sc)); 19668c2ecf20Sopenharmony_ci ret = FAILED; 19678c2ecf20Sopenharmony_ci goto dr_failed; 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci /* 19728c2ecf20Sopenharmony_ci * Cleanup any IOs on this LUN that have still not completed. 19738c2ecf20Sopenharmony_ci * If any of these fail, then LUN Reset fails. 19748c2ecf20Sopenharmony_ci * Cleanup cleans all commands on this LUN except 19758c2ecf20Sopenharmony_ci * the lun reset command. If all cmds get cleaned, the LUN Reset 19768c2ecf20Sopenharmony_ci * succeeds. 19778c2ecf20Sopenharmony_ci */ 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci ret = snic_dr_clean_pending_req(snic, sc); 19808c2ecf20Sopenharmony_ci if (ret) { 19818c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 19828c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 19838c2ecf20Sopenharmony_ci "dr_fini: Device Reset Failed since could not abort all IOs. Tag = %x.\n", 19848c2ecf20Sopenharmony_ci snic_cmd_tag(sc)); 19858c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci goto dr_failed; 19888c2ecf20Sopenharmony_ci } else { 19898c2ecf20Sopenharmony_ci /* Cleanup LUN Reset Command */ 19908c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 19918c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 19928c2ecf20Sopenharmony_ci if (rqi) 19938c2ecf20Sopenharmony_ci ret = SUCCESS; /* Completed Successfully */ 19948c2ecf20Sopenharmony_ci else 19958c2ecf20Sopenharmony_ci ret = FAILED; 19968c2ecf20Sopenharmony_ci } 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_cidr_failed: 19998c2ecf20Sopenharmony_ci lockdep_assert_held(io_lock); 20008c2ecf20Sopenharmony_ci if (rqi) 20018c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 20028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci if (rqi) 20058c2ecf20Sopenharmony_ci snic_release_req_buf(snic, rqi, sc); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_cidr_fini_end: 20088c2ecf20Sopenharmony_ci return ret; 20098c2ecf20Sopenharmony_ci} /* end of snic_dr_finish */ 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_cistatic int 20128c2ecf20Sopenharmony_cisnic_queue_dr_req(struct snic *snic, 20138c2ecf20Sopenharmony_ci struct snic_req_info *rqi, 20148c2ecf20Sopenharmony_ci struct scsi_cmnd *sc) 20158c2ecf20Sopenharmony_ci{ 20168c2ecf20Sopenharmony_ci /* Add special tag for device reset */ 20178c2ecf20Sopenharmony_ci rqi->tm_tag |= SNIC_TAG_DEV_RST; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci return snic_issue_tm_req(snic, rqi, sc, SNIC_ITMF_LUN_RESET); 20208c2ecf20Sopenharmony_ci} 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_cistatic int 20238c2ecf20Sopenharmony_cisnic_send_dr_and_wait(struct snic *snic, struct scsi_cmnd *sc) 20248c2ecf20Sopenharmony_ci{ 20258c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 20268c2ecf20Sopenharmony_ci enum snic_ioreq_state sv_state; 20278c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 20288c2ecf20Sopenharmony_ci unsigned long flags; 20298c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(tm_done); 20308c2ecf20Sopenharmony_ci int ret = FAILED, tag = snic_cmd_tag(sc); 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci io_lock = snic_io_lock_hash(snic, sc); 20338c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 20348c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_DEVICE_RESET; 20358c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 20368c2ecf20Sopenharmony_ci if (!rqi) { 20378c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 20388c2ecf20Sopenharmony_ci "send_dr: rqi is null, Tag 0x%x flags 0x%llx\n", 20398c2ecf20Sopenharmony_ci tag, CMD_FLAGS(sc)); 20408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci ret = FAILED; 20438c2ecf20Sopenharmony_ci goto send_dr_end; 20448c2ecf20Sopenharmony_ci } 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci /* Save Command state to restore in case Queuing failed. */ 20478c2ecf20Sopenharmony_ci sv_state = CMD_STATE(sc); 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_LR_PENDING; 20508c2ecf20Sopenharmony_ci CMD_LR_STATUS(sc) = SNIC_INVALID_CODE; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "dr: TAG = %x\n", tag); 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci rqi->dr_done = &tm_done; 20558c2ecf20Sopenharmony_ci SNIC_BUG_ON(!rqi->dr_done); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 20588c2ecf20Sopenharmony_ci /* 20598c2ecf20Sopenharmony_ci * The Command state is changed to IOREQ_PENDING, 20608c2ecf20Sopenharmony_ci * in this case, if the command is completed, the icmnd_cmpl will 20618c2ecf20Sopenharmony_ci * mark the cmd as completed. 20628c2ecf20Sopenharmony_ci * This logic still makes LUN Reset is inevitable. 20638c2ecf20Sopenharmony_ci */ 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci ret = snic_queue_dr_req(snic, rqi, sc); 20668c2ecf20Sopenharmony_ci if (ret) { 20678c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 20688c2ecf20Sopenharmony_ci "send_dr: IO w/ Tag 0x%x Failed err = %d. flags 0x%llx\n", 20698c2ecf20Sopenharmony_ci tag, ret, CMD_FLAGS(sc)); 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 20728c2ecf20Sopenharmony_ci /* Restore State */ 20738c2ecf20Sopenharmony_ci CMD_STATE(sc) = sv_state; 20748c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 20758c2ecf20Sopenharmony_ci if (rqi) 20768c2ecf20Sopenharmony_ci rqi->dr_done = NULL; 20778c2ecf20Sopenharmony_ci /* rqi is freed in caller. */ 20788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 20798c2ecf20Sopenharmony_ci ret = FAILED; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci goto send_dr_end; 20828c2ecf20Sopenharmony_ci } 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 20858c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_DEV_RST_ISSUED; 20868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci ret = 0; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci wait_for_completion_timeout(&tm_done, SNIC_LUN_RESET_TIMEOUT); 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_cisend_dr_end: 20938c2ecf20Sopenharmony_ci return ret; 20948c2ecf20Sopenharmony_ci} 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci/* 20978c2ecf20Sopenharmony_ci * auxillary funciton to check lun reset op is supported or not 20988c2ecf20Sopenharmony_ci * Not supported if returns 0 20998c2ecf20Sopenharmony_ci */ 21008c2ecf20Sopenharmony_cistatic int 21018c2ecf20Sopenharmony_cisnic_dev_reset_supported(struct scsi_device *sdev) 21028c2ecf20Sopenharmony_ci{ 21038c2ecf20Sopenharmony_ci struct snic_tgt *tgt = starget_to_tgt(scsi_target(sdev)); 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci if (tgt->tdata.typ == SNIC_TGT_DAS) 21068c2ecf20Sopenharmony_ci return 0; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci return 1; 21098c2ecf20Sopenharmony_ci} 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_cistatic void 21128c2ecf20Sopenharmony_cisnic_unlink_and_release_req(struct snic *snic, struct scsi_cmnd *sc, int flag) 21138c2ecf20Sopenharmony_ci{ 21148c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 21158c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 21168c2ecf20Sopenharmony_ci unsigned long flags; 21178c2ecf20Sopenharmony_ci u32 start_time = jiffies; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci io_lock = snic_io_lock_hash(snic, sc); 21208c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 21218c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 21228c2ecf20Sopenharmony_ci if (rqi) { 21238c2ecf20Sopenharmony_ci start_time = rqi->start_time; 21248c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= flag; 21288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci if (rqi) 21318c2ecf20Sopenharmony_ci snic_release_req_buf(snic, rqi, sc); 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, snic_cmd_tag(sc), (ulong) sc, 21348c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), (ulong) rqi, 21358c2ecf20Sopenharmony_ci SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc)); 21368c2ecf20Sopenharmony_ci} 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci/* 21398c2ecf20Sopenharmony_ci * SCSI Eh thread issues a LUN Reset when one or more commands on a LUN 21408c2ecf20Sopenharmony_ci * fail to get aborted. It calls driver's eh_device_reset with a SCSI 21418c2ecf20Sopenharmony_ci * command on the LUN. 21428c2ecf20Sopenharmony_ci */ 21438c2ecf20Sopenharmony_ciint 21448c2ecf20Sopenharmony_cisnic_device_reset(struct scsi_cmnd *sc) 21458c2ecf20Sopenharmony_ci{ 21468c2ecf20Sopenharmony_ci struct Scsi_Host *shost = sc->device->host; 21478c2ecf20Sopenharmony_ci struct snic *snic = shost_priv(shost); 21488c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 21498c2ecf20Sopenharmony_ci int tag = snic_cmd_tag(sc); 21508c2ecf20Sopenharmony_ci int start_time = jiffies; 21518c2ecf20Sopenharmony_ci int ret = FAILED; 21528c2ecf20Sopenharmony_ci int dr_supp = 0; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(shost, "dev_reset:sc %p :0x%x :req = %p :tag = %d\n", 21558c2ecf20Sopenharmony_ci sc, sc->cmnd[0], sc->request, 21568c2ecf20Sopenharmony_ci snic_cmd_tag(sc)); 21578c2ecf20Sopenharmony_ci dr_supp = snic_dev_reset_supported(sc->device); 21588c2ecf20Sopenharmony_ci if (!dr_supp) { 21598c2ecf20Sopenharmony_ci /* device reset op is not supported */ 21608c2ecf20Sopenharmony_ci SNIC_HOST_INFO(shost, "LUN Reset Op not supported.\n"); 21618c2ecf20Sopenharmony_ci snic_unlink_and_release_req(snic, sc, SNIC_DEV_RST_NOTSUP); 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci goto dev_rst_end; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci if (unlikely(snic_get_state(snic) != SNIC_ONLINE)) { 21678c2ecf20Sopenharmony_ci snic_unlink_and_release_req(snic, sc, 0); 21688c2ecf20Sopenharmony_ci SNIC_HOST_ERR(shost, "Devrst: Parent Devs are not online.\n"); 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci goto dev_rst_end; 21718c2ecf20Sopenharmony_ci } 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci /* There is no tag when lun reset is issue through ioctl. */ 21748c2ecf20Sopenharmony_ci if (unlikely(tag <= SNIC_NO_TAG)) { 21758c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, 21768c2ecf20Sopenharmony_ci "Devrst: LUN Reset Recvd thru IOCTL.\n"); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci rqi = snic_req_init(snic, 0); 21798c2ecf20Sopenharmony_ci if (!rqi) 21808c2ecf20Sopenharmony_ci goto dev_rst_end; 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci memset(scsi_cmd_priv(sc), 0, 21838c2ecf20Sopenharmony_ci sizeof(struct snic_internal_io_state)); 21848c2ecf20Sopenharmony_ci CMD_SP(sc) = (char *)rqi; 21858c2ecf20Sopenharmony_ci CMD_FLAGS(sc) = SNIC_NO_FLAGS; 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci /* Add special tag for dr coming from user spc */ 21888c2ecf20Sopenharmony_ci rqi->tm_tag = SNIC_TAG_IOCTL_DEV_RST; 21898c2ecf20Sopenharmony_ci rqi->sc = sc; 21908c2ecf20Sopenharmony_ci } 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci ret = snic_send_dr_and_wait(snic, sc); 21938c2ecf20Sopenharmony_ci if (ret) { 21948c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 21958c2ecf20Sopenharmony_ci "Devrst: IO w/ Tag %x Failed w/ err = %d\n", 21968c2ecf20Sopenharmony_ci tag, ret); 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci snic_unlink_and_release_req(snic, sc, 0); 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci goto dev_rst_end; 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci ret = snic_dr_finish(snic, sc); 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_cidev_rst_end: 22068c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, tag, (ulong) sc, 22078c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 22088c2ecf20Sopenharmony_ci 0, SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc)); 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 22118c2ecf20Sopenharmony_ci "Devrst: Returning from Device Reset : %s\n", 22128c2ecf20Sopenharmony_ci (ret == SUCCESS) ? "SUCCESS" : "FAILED"); 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci return ret; 22158c2ecf20Sopenharmony_ci} /* end of snic_device_reset */ 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci/* 22188c2ecf20Sopenharmony_ci * SCSI Error handling calls driver's eh_host_reset if all prior 22198c2ecf20Sopenharmony_ci * error handling levels return FAILED. 22208c2ecf20Sopenharmony_ci * 22218c2ecf20Sopenharmony_ci * Host Reset is the highest level of error recovery. If this fails, then 22228c2ecf20Sopenharmony_ci * host is offlined by SCSI. 22238c2ecf20Sopenharmony_ci */ 22248c2ecf20Sopenharmony_ci/* 22258c2ecf20Sopenharmony_ci * snic_issue_hba_reset : Queues FW Reset Request. 22268c2ecf20Sopenharmony_ci */ 22278c2ecf20Sopenharmony_cistatic int 22288c2ecf20Sopenharmony_cisnic_issue_hba_reset(struct snic *snic, struct scsi_cmnd *sc) 22298c2ecf20Sopenharmony_ci{ 22308c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 22318c2ecf20Sopenharmony_ci struct snic_host_req *req = NULL; 22328c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 22338c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(wait); 22348c2ecf20Sopenharmony_ci unsigned long flags; 22358c2ecf20Sopenharmony_ci int ret = -ENOMEM; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci rqi = snic_req_init(snic, 0); 22388c2ecf20Sopenharmony_ci if (!rqi) { 22398c2ecf20Sopenharmony_ci ret = -ENOMEM; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci goto hba_rst_end; 22428c2ecf20Sopenharmony_ci } 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci if (snic_cmd_tag(sc) == SCSI_NO_TAG) { 22458c2ecf20Sopenharmony_ci memset(scsi_cmd_priv(sc), 0, 22468c2ecf20Sopenharmony_ci sizeof(struct snic_internal_io_state)); 22478c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "issu_hr:Host reset thru ioctl.\n"); 22488c2ecf20Sopenharmony_ci rqi->sc = sc; 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci req = rqi_to_req(rqi); 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci io_lock = snic_io_lock_hash(snic, sc); 22548c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 22558c2ecf20Sopenharmony_ci SNIC_BUG_ON(CMD_SP(sc) != NULL); 22568c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_PENDING; 22578c2ecf20Sopenharmony_ci CMD_SP(sc) = (char *) rqi; 22588c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_INITIALIZED; 22598c2ecf20Sopenharmony_ci snic->remove_wait = &wait; 22608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci /* Initialize Request */ 22638c2ecf20Sopenharmony_ci snic_io_hdr_enc(&req->hdr, SNIC_REQ_HBA_RESET, 0, snic_cmd_tag(sc), 22648c2ecf20Sopenharmony_ci snic->config.hid, 0, (ulong) rqi); 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci req->u.reset.flags = 0; 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci ret = snic_queue_wq_desc(snic, req, sizeof(*req)); 22698c2ecf20Sopenharmony_ci if (ret) { 22708c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 22718c2ecf20Sopenharmony_ci "issu_hr:Queuing HBA Reset Failed. w err %d\n", 22728c2ecf20Sopenharmony_ci ret); 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci goto hba_rst_err; 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 22788c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_HOST_RESET_ISSUED; 22798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 22808c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.reset.hba_resets); 22818c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "Queued HBA Reset Successfully.\n"); 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci wait_for_completion_timeout(snic->remove_wait, 22848c2ecf20Sopenharmony_ci SNIC_HOST_RESET_TIMEOUT); 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci if (snic_get_state(snic) == SNIC_FWRESET) { 22878c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "reset_cmpl: Reset Timedout.\n"); 22888c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci goto hba_rst_err; 22918c2ecf20Sopenharmony_ci } 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 22948c2ecf20Sopenharmony_ci snic->remove_wait = NULL; 22958c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 22968c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 22978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci if (rqi) 23008c2ecf20Sopenharmony_ci snic_req_free(snic, rqi); 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci ret = 0; 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci return ret; 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_cihba_rst_err: 23078c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 23088c2ecf20Sopenharmony_ci snic->remove_wait = NULL; 23098c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 23108c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 23118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci if (rqi) 23148c2ecf20Sopenharmony_ci snic_req_free(snic, rqi); 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_cihba_rst_end: 23178c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 23188c2ecf20Sopenharmony_ci "reset:HBA Reset Failed w/ err = %d.\n", 23198c2ecf20Sopenharmony_ci ret); 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci return ret; 23228c2ecf20Sopenharmony_ci} /* end of snic_issue_hba_reset */ 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ciint 23258c2ecf20Sopenharmony_cisnic_reset(struct Scsi_Host *shost, struct scsi_cmnd *sc) 23268c2ecf20Sopenharmony_ci{ 23278c2ecf20Sopenharmony_ci struct snic *snic = shost_priv(shost); 23288c2ecf20Sopenharmony_ci enum snic_state sv_state; 23298c2ecf20Sopenharmony_ci unsigned long flags; 23308c2ecf20Sopenharmony_ci int ret = FAILED; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci /* Set snic state as SNIC_FWRESET*/ 23338c2ecf20Sopenharmony_ci sv_state = snic_get_state(snic); 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci spin_lock_irqsave(&snic->snic_lock, flags); 23368c2ecf20Sopenharmony_ci if (snic_get_state(snic) == SNIC_FWRESET) { 23378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, flags); 23388c2ecf20Sopenharmony_ci SNIC_HOST_INFO(shost, "reset:prev reset is in progres\n"); 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci msleep(SNIC_HOST_RESET_TIMEOUT); 23418c2ecf20Sopenharmony_ci ret = SUCCESS; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci goto reset_end; 23448c2ecf20Sopenharmony_ci } 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci snic_set_state(snic, SNIC_FWRESET); 23478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, flags); 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci /* Wait for all the IOs that are entered in Qcmd */ 23518c2ecf20Sopenharmony_ci while (atomic_read(&snic->ios_inflight)) 23528c2ecf20Sopenharmony_ci schedule_timeout(msecs_to_jiffies(1)); 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci ret = snic_issue_hba_reset(snic, sc); 23558c2ecf20Sopenharmony_ci if (ret) { 23568c2ecf20Sopenharmony_ci SNIC_HOST_ERR(shost, 23578c2ecf20Sopenharmony_ci "reset:Host Reset Failed w/ err %d.\n", 23588c2ecf20Sopenharmony_ci ret); 23598c2ecf20Sopenharmony_ci spin_lock_irqsave(&snic->snic_lock, flags); 23608c2ecf20Sopenharmony_ci snic_set_state(snic, sv_state); 23618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, flags); 23628c2ecf20Sopenharmony_ci atomic64_inc(&snic->s_stats.reset.hba_reset_fail); 23638c2ecf20Sopenharmony_ci ret = FAILED; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci goto reset_end; 23668c2ecf20Sopenharmony_ci } 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci ret = SUCCESS; 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_cireset_end: 23718c2ecf20Sopenharmony_ci return ret; 23728c2ecf20Sopenharmony_ci} /* end of snic_reset */ 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci/* 23758c2ecf20Sopenharmony_ci * SCSI Error handling calls driver's eh_host_reset if all prior 23768c2ecf20Sopenharmony_ci * error handling levels return FAILED. 23778c2ecf20Sopenharmony_ci * 23788c2ecf20Sopenharmony_ci * Host Reset is the highest level of error recovery. If this fails, then 23798c2ecf20Sopenharmony_ci * host is offlined by SCSI. 23808c2ecf20Sopenharmony_ci */ 23818c2ecf20Sopenharmony_ciint 23828c2ecf20Sopenharmony_cisnic_host_reset(struct scsi_cmnd *sc) 23838c2ecf20Sopenharmony_ci{ 23848c2ecf20Sopenharmony_ci struct Scsi_Host *shost = sc->device->host; 23858c2ecf20Sopenharmony_ci u32 start_time = jiffies; 23868c2ecf20Sopenharmony_ci int ret = FAILED; 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(shost, 23898c2ecf20Sopenharmony_ci "host reset:sc %p sc_cmd 0x%x req %p tag %d flags 0x%llx\n", 23908c2ecf20Sopenharmony_ci sc, sc->cmnd[0], sc->request, 23918c2ecf20Sopenharmony_ci snic_cmd_tag(sc), CMD_FLAGS(sc)); 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci ret = snic_reset(shost, sc); 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci SNIC_TRC(shost->host_no, snic_cmd_tag(sc), (ulong) sc, 23968c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 23978c2ecf20Sopenharmony_ci 0, SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc)); 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci return ret; 24008c2ecf20Sopenharmony_ci} /* end of snic_host_reset */ 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci/* 24038c2ecf20Sopenharmony_ci * snic_cmpl_pending_tmreq : Caller should hold io_lock 24048c2ecf20Sopenharmony_ci */ 24058c2ecf20Sopenharmony_cistatic void 24068c2ecf20Sopenharmony_cisnic_cmpl_pending_tmreq(struct snic *snic, struct scsi_cmnd *sc) 24078c2ecf20Sopenharmony_ci{ 24088c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 24118c2ecf20Sopenharmony_ci "Completing Pending TM Req sc %p, state %s flags 0x%llx\n", 24128c2ecf20Sopenharmony_ci sc, snic_io_status_to_str(CMD_STATE(sc)), CMD_FLAGS(sc)); 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci /* 24158c2ecf20Sopenharmony_ci * CASE : FW didn't post itmf completion due to PCIe Errors. 24168c2ecf20Sopenharmony_ci * Marking the abort status as Success to call scsi completion 24178c2ecf20Sopenharmony_ci * in snic_abort_finish() 24188c2ecf20Sopenharmony_ci */ 24198c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = SNIC_STAT_IO_SUCCESS; 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 24228c2ecf20Sopenharmony_ci if (!rqi) 24238c2ecf20Sopenharmony_ci return; 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci if (rqi->dr_done) 24268c2ecf20Sopenharmony_ci complete(rqi->dr_done); 24278c2ecf20Sopenharmony_ci else if (rqi->abts_done) 24288c2ecf20Sopenharmony_ci complete(rqi->abts_done); 24298c2ecf20Sopenharmony_ci} 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci/* 24328c2ecf20Sopenharmony_ci * snic_scsi_cleanup: Walks through tag map and releases the reqs 24338c2ecf20Sopenharmony_ci */ 24348c2ecf20Sopenharmony_cistatic void 24358c2ecf20Sopenharmony_cisnic_scsi_cleanup(struct snic *snic, int ex_tag) 24368c2ecf20Sopenharmony_ci{ 24378c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 24388c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = NULL; 24398c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 24408c2ecf20Sopenharmony_ci unsigned long flags; 24418c2ecf20Sopenharmony_ci int tag; 24428c2ecf20Sopenharmony_ci u64 st_time = 0; 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "sc_clean: scsi cleanup.\n"); 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci for (tag = 0; tag < snic->max_tag_id; tag++) { 24478c2ecf20Sopenharmony_ci /* Skip ex_tag */ 24488c2ecf20Sopenharmony_ci if (tag == ex_tag) 24498c2ecf20Sopenharmony_ci continue; 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci io_lock = snic_io_lock_tag(snic, tag); 24528c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 24538c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(snic->shost, tag); 24548c2ecf20Sopenharmony_ci if (!sc) { 24558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci continue; 24588c2ecf20Sopenharmony_ci } 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci if (unlikely(snic_tmreq_pending(sc))) { 24618c2ecf20Sopenharmony_ci /* 24628c2ecf20Sopenharmony_ci * When FW Completes reset w/o sending completions 24638c2ecf20Sopenharmony_ci * for outstanding ios. 24648c2ecf20Sopenharmony_ci */ 24658c2ecf20Sopenharmony_ci snic_cmpl_pending_tmreq(snic, sc); 24668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci continue; 24698c2ecf20Sopenharmony_ci } 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 24728c2ecf20Sopenharmony_ci if (!rqi) { 24738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci goto cleanup; 24768c2ecf20Sopenharmony_ci } 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 24798c2ecf20Sopenharmony_ci "sc_clean: sc %p, rqi %p, tag %d flags 0x%llx\n", 24808c2ecf20Sopenharmony_ci sc, rqi, tag, CMD_FLAGS(sc)); 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 24838c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_SCSI_CLEANUP; 24848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24858c2ecf20Sopenharmony_ci st_time = rqi->start_time; 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, 24888c2ecf20Sopenharmony_ci "sc_clean: Releasing rqi %p : flags 0x%llx\n", 24898c2ecf20Sopenharmony_ci rqi, CMD_FLAGS(sc)); 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci snic_release_req_buf(snic, rqi, sc); 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_cicleanup: 24948c2ecf20Sopenharmony_ci sc->result = DID_TRANSPORT_DISRUPTED << 16; 24958c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, 24968c2ecf20Sopenharmony_ci "sc_clean: DID_TRANSPORT_DISRUPTED for sc %p, Tag %d flags 0x%llx rqi %p duration %u msecs\n", 24978c2ecf20Sopenharmony_ci sc, sc->request->tag, CMD_FLAGS(sc), rqi, 24988c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - st_time)); 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci /* Update IO stats */ 25018c2ecf20Sopenharmony_ci snic_stats_update_io_cmpl(&snic->s_stats); 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci if (sc->scsi_done) { 25048c2ecf20Sopenharmony_ci SNIC_TRC(snic->shost->host_no, tag, (ulong) sc, 25058c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - st_time), 0, 25068c2ecf20Sopenharmony_ci SNIC_TRC_CMD(sc), 25078c2ecf20Sopenharmony_ci SNIC_TRC_CMD_STATE_FLAGS(sc)); 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci sc->scsi_done(sc); 25108c2ecf20Sopenharmony_ci } 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci} /* end of snic_scsi_cleanup */ 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_civoid 25158c2ecf20Sopenharmony_cisnic_shutdown_scsi_cleanup(struct snic *snic) 25168c2ecf20Sopenharmony_ci{ 25178c2ecf20Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "Shutdown time SCSI Cleanup.\n"); 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci snic_scsi_cleanup(snic, SCSI_NO_TAG); 25208c2ecf20Sopenharmony_ci} /* end of snic_shutdown_scsi_cleanup */ 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci/* 25238c2ecf20Sopenharmony_ci * snic_internal_abort_io 25248c2ecf20Sopenharmony_ci * called by : snic_tgt_scsi_abort_io 25258c2ecf20Sopenharmony_ci */ 25268c2ecf20Sopenharmony_cistatic int 25278c2ecf20Sopenharmony_cisnic_internal_abort_io(struct snic *snic, struct scsi_cmnd *sc, int tmf) 25288c2ecf20Sopenharmony_ci{ 25298c2ecf20Sopenharmony_ci struct snic_req_info *rqi = NULL; 25308c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 25318c2ecf20Sopenharmony_ci unsigned long flags; 25328c2ecf20Sopenharmony_ci u32 sv_state = 0; 25338c2ecf20Sopenharmony_ci int ret = 0; 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci io_lock = snic_io_lock_hash(snic, sc); 25368c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 25378c2ecf20Sopenharmony_ci rqi = (struct snic_req_info *) CMD_SP(sc); 25388c2ecf20Sopenharmony_ci if (!rqi) 25398c2ecf20Sopenharmony_ci goto skip_internal_abts; 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING) 25428c2ecf20Sopenharmony_ci goto skip_internal_abts; 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci if ((CMD_FLAGS(sc) & SNIC_DEVICE_RESET) && 25458c2ecf20Sopenharmony_ci (!(CMD_FLAGS(sc) & SNIC_DEV_RST_ISSUED))) { 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 25488c2ecf20Sopenharmony_ci "internal_abts: dev rst not pending sc 0x%p\n", 25498c2ecf20Sopenharmony_ci sc); 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci goto skip_internal_abts; 25528c2ecf20Sopenharmony_ci } 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci if (!(CMD_FLAGS(sc) & SNIC_IO_ISSUED)) { 25568c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, 25578c2ecf20Sopenharmony_ci "internal_abts: IO not yet issued sc 0x%p tag 0x%x flags 0x%llx state %d\n", 25588c2ecf20Sopenharmony_ci sc, snic_cmd_tag(sc), CMD_FLAGS(sc), CMD_STATE(sc)); 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci goto skip_internal_abts; 25618c2ecf20Sopenharmony_ci } 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci sv_state = CMD_STATE(sc); 25648c2ecf20Sopenharmony_ci CMD_STATE(sc) = SNIC_IOREQ_ABTS_PENDING; 25658c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = SNIC_INVALID_CODE; 25668c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_INTERNAL_TERM_PENDING; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & SNIC_DEVICE_RESET) { 25698c2ecf20Sopenharmony_ci /* stats */ 25708c2ecf20Sopenharmony_ci rqi->tm_tag = SNIC_TAG_DEV_RST; 25718c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "internal_abts:dev rst sc %p\n", sc); 25728c2ecf20Sopenharmony_ci } 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "internal_abts: Issuing abts tag %x\n", 25758c2ecf20Sopenharmony_ci snic_cmd_tag(sc)); 25768c2ecf20Sopenharmony_ci SNIC_BUG_ON(rqi->abts_done); 25778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci ret = snic_queue_abort_req(snic, rqi, sc, tmf); 25808c2ecf20Sopenharmony_ci if (ret) { 25818c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 25828c2ecf20Sopenharmony_ci "internal_abts: Tag = %x , Failed w/ err = %d\n", 25838c2ecf20Sopenharmony_ci snic_cmd_tag(sc), ret); 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING) 25888c2ecf20Sopenharmony_ci CMD_STATE(sc) = sv_state; 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci goto skip_internal_abts; 25918c2ecf20Sopenharmony_ci } 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 25948c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & SNIC_DEVICE_RESET) 25958c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_DEV_RST_TERM_ISSUED; 25968c2ecf20Sopenharmony_ci else 25978c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= SNIC_IO_INTERNAL_TERM_ISSUED; 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci ret = SUCCESS; 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ciskip_internal_abts: 26028c2ecf20Sopenharmony_ci lockdep_assert_held(io_lock); 26038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci return ret; 26068c2ecf20Sopenharmony_ci} /* end of snic_internal_abort_io */ 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci/* 26098c2ecf20Sopenharmony_ci * snic_tgt_scsi_abort_io : called by snic_tgt_del 26108c2ecf20Sopenharmony_ci */ 26118c2ecf20Sopenharmony_ciint 26128c2ecf20Sopenharmony_cisnic_tgt_scsi_abort_io(struct snic_tgt *tgt) 26138c2ecf20Sopenharmony_ci{ 26148c2ecf20Sopenharmony_ci struct snic *snic = NULL; 26158c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = NULL; 26168c2ecf20Sopenharmony_ci struct snic_tgt *sc_tgt = NULL; 26178c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 26188c2ecf20Sopenharmony_ci unsigned long flags; 26198c2ecf20Sopenharmony_ci int ret = 0, tag, abt_cnt = 0, tmf = 0; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci if (!tgt) 26228c2ecf20Sopenharmony_ci return -1; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci snic = shost_priv(snic_tgt_to_shost(tgt)); 26258c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "tgt_abt_io: Cleaning Pending IOs.\n"); 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci if (tgt->tdata.typ == SNIC_TGT_DAS) 26288c2ecf20Sopenharmony_ci tmf = SNIC_ITMF_ABTS_TASK; 26298c2ecf20Sopenharmony_ci else 26308c2ecf20Sopenharmony_ci tmf = SNIC_ITMF_ABTS_TASK_TERM; 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci for (tag = 0; tag < snic->max_tag_id; tag++) { 26338c2ecf20Sopenharmony_ci io_lock = snic_io_lock_tag(snic, tag); 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 26368c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(snic->shost, tag); 26378c2ecf20Sopenharmony_ci if (!sc) { 26388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci continue; 26418c2ecf20Sopenharmony_ci } 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_ci sc_tgt = starget_to_tgt(scsi_target(sc->device)); 26448c2ecf20Sopenharmony_ci if (sc_tgt != tgt) { 26458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci continue; 26488c2ecf20Sopenharmony_ci } 26498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci ret = snic_internal_abort_io(snic, sc, tmf); 26528c2ecf20Sopenharmony_ci if (ret < 0) { 26538c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 26548c2ecf20Sopenharmony_ci "tgt_abt_io: Tag %x, Failed w err = %d\n", 26558c2ecf20Sopenharmony_ci tag, ret); 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci continue; 26588c2ecf20Sopenharmony_ci } 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci if (ret == SUCCESS) 26618c2ecf20Sopenharmony_ci abt_cnt++; 26628c2ecf20Sopenharmony_ci } 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "tgt_abt_io: abt_cnt = %d\n", abt_cnt); 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci return 0; 26678c2ecf20Sopenharmony_ci} /* end of snic_tgt_scsi_abort_io */ 2668