18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2008 Cisco Systems, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright 2007 Nuova Systems, Inc. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This program is free software; you may redistribute it and/or modify 68c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 78c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 108c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 118c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 128c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 138c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 148c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 158c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 168c2ecf20Sopenharmony_ci * SOFTWARE. 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/scatterlist.h> 248c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 258c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 268c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 278c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 288c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 298c2ecf20Sopenharmony_ci#include <linux/delay.h> 308c2ecf20Sopenharmony_ci#include <linux/gfp.h> 318c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 328c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 338c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 348c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 358c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 368c2ecf20Sopenharmony_ci#include <scsi/fc/fc_els.h> 378c2ecf20Sopenharmony_ci#include <scsi/fc/fc_fcoe.h> 388c2ecf20Sopenharmony_ci#include <scsi/libfc.h> 398c2ecf20Sopenharmony_ci#include <scsi/fc_frame.h> 408c2ecf20Sopenharmony_ci#include "fnic_io.h" 418c2ecf20Sopenharmony_ci#include "fnic.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciconst char *fnic_state_str[] = { 448c2ecf20Sopenharmony_ci [FNIC_IN_FC_MODE] = "FNIC_IN_FC_MODE", 458c2ecf20Sopenharmony_ci [FNIC_IN_FC_TRANS_ETH_MODE] = "FNIC_IN_FC_TRANS_ETH_MODE", 468c2ecf20Sopenharmony_ci [FNIC_IN_ETH_MODE] = "FNIC_IN_ETH_MODE", 478c2ecf20Sopenharmony_ci [FNIC_IN_ETH_TRANS_FC_MODE] = "FNIC_IN_ETH_TRANS_FC_MODE", 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic const char *fnic_ioreq_state_str[] = { 518c2ecf20Sopenharmony_ci [FNIC_IOREQ_NOT_INITED] = "FNIC_IOREQ_NOT_INITED", 528c2ecf20Sopenharmony_ci [FNIC_IOREQ_CMD_PENDING] = "FNIC_IOREQ_CMD_PENDING", 538c2ecf20Sopenharmony_ci [FNIC_IOREQ_ABTS_PENDING] = "FNIC_IOREQ_ABTS_PENDING", 548c2ecf20Sopenharmony_ci [FNIC_IOREQ_ABTS_COMPLETE] = "FNIC_IOREQ_ABTS_COMPLETE", 558c2ecf20Sopenharmony_ci [FNIC_IOREQ_CMD_COMPLETE] = "FNIC_IOREQ_CMD_COMPLETE", 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic const char *fcpio_status_str[] = { 598c2ecf20Sopenharmony_ci [FCPIO_SUCCESS] = "FCPIO_SUCCESS", /*0x0*/ 608c2ecf20Sopenharmony_ci [FCPIO_INVALID_HEADER] = "FCPIO_INVALID_HEADER", 618c2ecf20Sopenharmony_ci [FCPIO_OUT_OF_RESOURCE] = "FCPIO_OUT_OF_RESOURCE", 628c2ecf20Sopenharmony_ci [FCPIO_INVALID_PARAM] = "FCPIO_INVALID_PARAM]", 638c2ecf20Sopenharmony_ci [FCPIO_REQ_NOT_SUPPORTED] = "FCPIO_REQ_NOT_SUPPORTED", 648c2ecf20Sopenharmony_ci [FCPIO_IO_NOT_FOUND] = "FCPIO_IO_NOT_FOUND", 658c2ecf20Sopenharmony_ci [FCPIO_ABORTED] = "FCPIO_ABORTED", /*0x41*/ 668c2ecf20Sopenharmony_ci [FCPIO_TIMEOUT] = "FCPIO_TIMEOUT", 678c2ecf20Sopenharmony_ci [FCPIO_SGL_INVALID] = "FCPIO_SGL_INVALID", 688c2ecf20Sopenharmony_ci [FCPIO_MSS_INVALID] = "FCPIO_MSS_INVALID", 698c2ecf20Sopenharmony_ci [FCPIO_DATA_CNT_MISMATCH] = "FCPIO_DATA_CNT_MISMATCH", 708c2ecf20Sopenharmony_ci [FCPIO_FW_ERR] = "FCPIO_FW_ERR", 718c2ecf20Sopenharmony_ci [FCPIO_ITMF_REJECTED] = "FCPIO_ITMF_REJECTED", 728c2ecf20Sopenharmony_ci [FCPIO_ITMF_FAILED] = "FCPIO_ITMF_FAILED", 738c2ecf20Sopenharmony_ci [FCPIO_ITMF_INCORRECT_LUN] = "FCPIO_ITMF_INCORRECT_LUN", 748c2ecf20Sopenharmony_ci [FCPIO_CMND_REJECTED] = "FCPIO_CMND_REJECTED", 758c2ecf20Sopenharmony_ci [FCPIO_NO_PATH_AVAIL] = "FCPIO_NO_PATH_AVAIL", 768c2ecf20Sopenharmony_ci [FCPIO_PATH_FAILED] = "FCPIO_PATH_FAILED", 778c2ecf20Sopenharmony_ci [FCPIO_LUNMAP_CHNG_PEND] = "FCPIO_LUNHMAP_CHNG_PEND", 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciconst char *fnic_state_to_str(unsigned int state) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci if (state >= ARRAY_SIZE(fnic_state_str) || !fnic_state_str[state]) 838c2ecf20Sopenharmony_ci return "unknown"; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return fnic_state_str[state]; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic const char *fnic_ioreq_state_to_str(unsigned int state) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci if (state >= ARRAY_SIZE(fnic_ioreq_state_str) || 918c2ecf20Sopenharmony_ci !fnic_ioreq_state_str[state]) 928c2ecf20Sopenharmony_ci return "unknown"; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return fnic_ioreq_state_str[state]; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic const char *fnic_fcpio_status_to_str(unsigned int status) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci if (status >= ARRAY_SIZE(fcpio_status_str) || !fcpio_status_str[status]) 1008c2ecf20Sopenharmony_ci return "unknown"; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return fcpio_status_str[status]; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic void fnic_cleanup_io(struct fnic *fnic, int exclude_id); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic inline spinlock_t *fnic_io_lock_hash(struct fnic *fnic, 1088c2ecf20Sopenharmony_ci struct scsi_cmnd *sc) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci u32 hash = sc->request->tag & (FNIC_IO_LOCKS - 1); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return &fnic->io_req_lock[hash]; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic inline spinlock_t *fnic_io_lock_tag(struct fnic *fnic, 1168c2ecf20Sopenharmony_ci int tag) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci return &fnic->io_req_lock[tag & (FNIC_IO_LOCKS - 1)]; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* 1228c2ecf20Sopenharmony_ci * Unmap the data buffer and sense buffer for an io_req, 1238c2ecf20Sopenharmony_ci * also unmap and free the device-private scatter/gather list. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_cistatic void fnic_release_ioreq_buf(struct fnic *fnic, 1268c2ecf20Sopenharmony_ci struct fnic_io_req *io_req, 1278c2ecf20Sopenharmony_ci struct scsi_cmnd *sc) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci if (io_req->sgl_list_pa) 1308c2ecf20Sopenharmony_ci dma_unmap_single(&fnic->pdev->dev, io_req->sgl_list_pa, 1318c2ecf20Sopenharmony_ci sizeof(io_req->sgl_list[0]) * io_req->sgl_cnt, 1328c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 1338c2ecf20Sopenharmony_ci scsi_dma_unmap(sc); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (io_req->sgl_cnt) 1368c2ecf20Sopenharmony_ci mempool_free(io_req->sgl_list_alloc, 1378c2ecf20Sopenharmony_ci fnic->io_sgl_pool[io_req->sgl_type]); 1388c2ecf20Sopenharmony_ci if (io_req->sense_buf_pa) 1398c2ecf20Sopenharmony_ci dma_unmap_single(&fnic->pdev->dev, io_req->sense_buf_pa, 1408c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* Free up Copy Wq descriptors. Called with copy_wq lock held */ 1448c2ecf20Sopenharmony_cistatic int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci /* if no Ack received from firmware, then nothing to clean */ 1478c2ecf20Sopenharmony_ci if (!fnic->fw_ack_recd[0]) 1488c2ecf20Sopenharmony_ci return 1; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* 1518c2ecf20Sopenharmony_ci * Update desc_available count based on number of freed descriptors 1528c2ecf20Sopenharmony_ci * Account for wraparound 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci if (wq->to_clean_index <= fnic->fw_ack_index[0]) 1558c2ecf20Sopenharmony_ci wq->ring.desc_avail += (fnic->fw_ack_index[0] 1568c2ecf20Sopenharmony_ci - wq->to_clean_index + 1); 1578c2ecf20Sopenharmony_ci else 1588c2ecf20Sopenharmony_ci wq->ring.desc_avail += (wq->ring.desc_count 1598c2ecf20Sopenharmony_ci - wq->to_clean_index 1608c2ecf20Sopenharmony_ci + fnic->fw_ack_index[0] + 1); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* 1638c2ecf20Sopenharmony_ci * just bump clean index to ack_index+1 accounting for wraparound 1648c2ecf20Sopenharmony_ci * this will essentially free up all descriptors between 1658c2ecf20Sopenharmony_ci * to_clean_index and fw_ack_index, both inclusive 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ci wq->to_clean_index = 1688c2ecf20Sopenharmony_ci (fnic->fw_ack_index[0] + 1) % wq->ring.desc_count; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* we have processed the acks received so far */ 1718c2ecf20Sopenharmony_ci fnic->fw_ack_recd[0] = 0; 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/** 1778c2ecf20Sopenharmony_ci * __fnic_set_state_flags 1788c2ecf20Sopenharmony_ci * Sets/Clears bits in fnic's state_flags 1798c2ecf20Sopenharmony_ci **/ 1808c2ecf20Sopenharmony_civoid 1818c2ecf20Sopenharmony_ci__fnic_set_state_flags(struct fnic *fnic, unsigned long st_flags, 1828c2ecf20Sopenharmony_ci unsigned long clearbits) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci unsigned long flags = 0; 1858c2ecf20Sopenharmony_ci unsigned long host_lock_flags = 0; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 1888c2ecf20Sopenharmony_ci spin_lock_irqsave(fnic->lport->host->host_lock, host_lock_flags); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (clearbits) 1918c2ecf20Sopenharmony_ci fnic->state_flags &= ~st_flags; 1928c2ecf20Sopenharmony_ci else 1938c2ecf20Sopenharmony_ci fnic->state_flags |= st_flags; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(fnic->lport->host->host_lock, host_lock_flags); 1968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* 2038c2ecf20Sopenharmony_ci * fnic_fw_reset_handler 2048c2ecf20Sopenharmony_ci * Routine to send reset msg to fw 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ciint fnic_fw_reset_handler(struct fnic *fnic) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct vnic_wq_copy *wq = &fnic->wq_copy[0]; 2098c2ecf20Sopenharmony_ci int ret = 0; 2108c2ecf20Sopenharmony_ci unsigned long flags; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* indicate fwreset to io path */ 2138c2ecf20Sopenharmony_ci fnic_set_state_flags(fnic, FNIC_FLAGS_FWRESET); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci skb_queue_purge(&fnic->frame_queue); 2168c2ecf20Sopenharmony_ci skb_queue_purge(&fnic->tx_queue); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* wait for io cmpl */ 2198c2ecf20Sopenharmony_ci while (atomic_read(&fnic->in_flight)) 2208c2ecf20Sopenharmony_ci schedule_timeout(msecs_to_jiffies(1)); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) 2258c2ecf20Sopenharmony_ci free_wq_copy_descs(fnic, wq); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (!vnic_wq_copy_desc_avail(wq)) 2288c2ecf20Sopenharmony_ci ret = -EAGAIN; 2298c2ecf20Sopenharmony_ci else { 2308c2ecf20Sopenharmony_ci fnic_queue_wq_copy_desc_fw_reset(wq, SCSI_NO_TAG); 2318c2ecf20Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); 2328c2ecf20Sopenharmony_ci if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) > 2338c2ecf20Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs)) 2348c2ecf20Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, 2358c2ecf20Sopenharmony_ci atomic64_read( 2368c2ecf20Sopenharmony_ci &fnic->fnic_stats.fw_stats.active_fw_reqs)); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (!ret) { 2428c2ecf20Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.reset_stats.fw_resets); 2438c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 2448c2ecf20Sopenharmony_ci "Issued fw reset\n"); 2458c2ecf20Sopenharmony_ci } else { 2468c2ecf20Sopenharmony_ci fnic_clear_state_flags(fnic, FNIC_FLAGS_FWRESET); 2478c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 2488c2ecf20Sopenharmony_ci "Failed to issue fw reset\n"); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return ret; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* 2568c2ecf20Sopenharmony_ci * fnic_flogi_reg_handler 2578c2ecf20Sopenharmony_ci * Routine to send flogi register msg to fw 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ciint fnic_flogi_reg_handler(struct fnic *fnic, u32 fc_id) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct vnic_wq_copy *wq = &fnic->wq_copy[0]; 2628c2ecf20Sopenharmony_ci enum fcpio_flogi_reg_format_type format; 2638c2ecf20Sopenharmony_ci struct fc_lport *lp = fnic->lport; 2648c2ecf20Sopenharmony_ci u8 gw_mac[ETH_ALEN]; 2658c2ecf20Sopenharmony_ci int ret = 0; 2668c2ecf20Sopenharmony_ci unsigned long flags; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) 2718c2ecf20Sopenharmony_ci free_wq_copy_descs(fnic, wq); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (!vnic_wq_copy_desc_avail(wq)) { 2748c2ecf20Sopenharmony_ci ret = -EAGAIN; 2758c2ecf20Sopenharmony_ci goto flogi_reg_ioreq_end; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (fnic->ctlr.map_dest) { 2798c2ecf20Sopenharmony_ci eth_broadcast_addr(gw_mac); 2808c2ecf20Sopenharmony_ci format = FCPIO_FLOGI_REG_DEF_DEST; 2818c2ecf20Sopenharmony_ci } else { 2828c2ecf20Sopenharmony_ci memcpy(gw_mac, fnic->ctlr.dest_addr, ETH_ALEN); 2838c2ecf20Sopenharmony_ci format = FCPIO_FLOGI_REG_GW_DEST; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if ((fnic->config.flags & VFCF_FIP_CAPABLE) && !fnic->ctlr.map_dest) { 2878c2ecf20Sopenharmony_ci fnic_queue_wq_copy_desc_fip_reg(wq, SCSI_NO_TAG, 2888c2ecf20Sopenharmony_ci fc_id, gw_mac, 2898c2ecf20Sopenharmony_ci fnic->data_src_addr, 2908c2ecf20Sopenharmony_ci lp->r_a_tov, lp->e_d_tov); 2918c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 2928c2ecf20Sopenharmony_ci "FLOGI FIP reg issued fcid %x src %pM dest %pM\n", 2938c2ecf20Sopenharmony_ci fc_id, fnic->data_src_addr, gw_mac); 2948c2ecf20Sopenharmony_ci } else { 2958c2ecf20Sopenharmony_ci fnic_queue_wq_copy_desc_flogi_reg(wq, SCSI_NO_TAG, 2968c2ecf20Sopenharmony_ci format, fc_id, gw_mac); 2978c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 2988c2ecf20Sopenharmony_ci "FLOGI reg issued fcid %x map %d dest %pM\n", 2998c2ecf20Sopenharmony_ci fc_id, fnic->ctlr.map_dest, gw_mac); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); 3038c2ecf20Sopenharmony_ci if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) > 3048c2ecf20Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs)) 3058c2ecf20Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, 3068c2ecf20Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs)); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ciflogi_reg_ioreq_end: 3098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); 3108c2ecf20Sopenharmony_ci return ret; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* 3148c2ecf20Sopenharmony_ci * fnic_queue_wq_copy_desc 3158c2ecf20Sopenharmony_ci * Routine to enqueue a wq copy desc 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_cistatic inline int fnic_queue_wq_copy_desc(struct fnic *fnic, 3188c2ecf20Sopenharmony_ci struct vnic_wq_copy *wq, 3198c2ecf20Sopenharmony_ci struct fnic_io_req *io_req, 3208c2ecf20Sopenharmony_ci struct scsi_cmnd *sc, 3218c2ecf20Sopenharmony_ci int sg_count) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct scatterlist *sg; 3248c2ecf20Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(sc->device)); 3258c2ecf20Sopenharmony_ci struct fc_rport_libfc_priv *rp = rport->dd_data; 3268c2ecf20Sopenharmony_ci struct host_sg_desc *desc; 3278c2ecf20Sopenharmony_ci struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; 3288c2ecf20Sopenharmony_ci unsigned int i; 3298c2ecf20Sopenharmony_ci unsigned long intr_flags; 3308c2ecf20Sopenharmony_ci int flags; 3318c2ecf20Sopenharmony_ci u8 exch_flags; 3328c2ecf20Sopenharmony_ci struct scsi_lun fc_lun; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (sg_count) { 3358c2ecf20Sopenharmony_ci /* For each SGE, create a device desc entry */ 3368c2ecf20Sopenharmony_ci desc = io_req->sgl_list; 3378c2ecf20Sopenharmony_ci for_each_sg(scsi_sglist(sc), sg, sg_count, i) { 3388c2ecf20Sopenharmony_ci desc->addr = cpu_to_le64(sg_dma_address(sg)); 3398c2ecf20Sopenharmony_ci desc->len = cpu_to_le32(sg_dma_len(sg)); 3408c2ecf20Sopenharmony_ci desc->_resvd = 0; 3418c2ecf20Sopenharmony_ci desc++; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci io_req->sgl_list_pa = dma_map_single(&fnic->pdev->dev, 3458c2ecf20Sopenharmony_ci io_req->sgl_list, 3468c2ecf20Sopenharmony_ci sizeof(io_req->sgl_list[0]) * sg_count, 3478c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 3488c2ecf20Sopenharmony_ci if (dma_mapping_error(&fnic->pdev->dev, io_req->sgl_list_pa)) { 3498c2ecf20Sopenharmony_ci printk(KERN_ERR "DMA mapping failed\n"); 3508c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci io_req->sense_buf_pa = dma_map_single(&fnic->pdev->dev, 3558c2ecf20Sopenharmony_ci sc->sense_buffer, 3568c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 3578c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 3588c2ecf20Sopenharmony_ci if (dma_mapping_error(&fnic->pdev->dev, io_req->sense_buf_pa)) { 3598c2ecf20Sopenharmony_ci dma_unmap_single(&fnic->pdev->dev, io_req->sgl_list_pa, 3608c2ecf20Sopenharmony_ci sizeof(io_req->sgl_list[0]) * sg_count, 3618c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 3628c2ecf20Sopenharmony_ci printk(KERN_ERR "DMA mapping failed\n"); 3638c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* Enqueue the descriptor in the Copy WQ */ 3698c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) 3728c2ecf20Sopenharmony_ci free_wq_copy_descs(fnic, wq); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (unlikely(!vnic_wq_copy_desc_avail(wq))) { 3758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); 3768c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 3778c2ecf20Sopenharmony_ci "fnic_queue_wq_copy_desc failure - no descriptors\n"); 3788c2ecf20Sopenharmony_ci atomic64_inc(&misc_stats->io_cpwq_alloc_failures); 3798c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci flags = 0; 3838c2ecf20Sopenharmony_ci if (sc->sc_data_direction == DMA_FROM_DEVICE) 3848c2ecf20Sopenharmony_ci flags = FCPIO_ICMND_RDDATA; 3858c2ecf20Sopenharmony_ci else if (sc->sc_data_direction == DMA_TO_DEVICE) 3868c2ecf20Sopenharmony_ci flags = FCPIO_ICMND_WRDATA; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci exch_flags = 0; 3898c2ecf20Sopenharmony_ci if ((fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR) && 3908c2ecf20Sopenharmony_ci (rp->flags & FC_RP_FLAGS_RETRY)) 3918c2ecf20Sopenharmony_ci exch_flags |= FCPIO_ICMND_SRFLAG_RETRY; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci fnic_queue_wq_copy_desc_icmnd_16(wq, sc->request->tag, 3948c2ecf20Sopenharmony_ci 0, exch_flags, io_req->sgl_cnt, 3958c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 3968c2ecf20Sopenharmony_ci io_req->sgl_list_pa, 3978c2ecf20Sopenharmony_ci io_req->sense_buf_pa, 3988c2ecf20Sopenharmony_ci 0, /* scsi cmd ref, always 0 */ 3998c2ecf20Sopenharmony_ci FCPIO_ICMND_PTA_SIMPLE, 4008c2ecf20Sopenharmony_ci /* scsi pri and tag */ 4018c2ecf20Sopenharmony_ci flags, /* command flags */ 4028c2ecf20Sopenharmony_ci sc->cmnd, sc->cmd_len, 4038c2ecf20Sopenharmony_ci scsi_bufflen(sc), 4048c2ecf20Sopenharmony_ci fc_lun.scsi_lun, io_req->port_id, 4058c2ecf20Sopenharmony_ci rport->maxframe_size, rp->r_a_tov, 4068c2ecf20Sopenharmony_ci rp->e_d_tov); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); 4098c2ecf20Sopenharmony_ci if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) > 4108c2ecf20Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs)) 4118c2ecf20Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, 4128c2ecf20Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs)); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci/* 4198c2ecf20Sopenharmony_ci * fnic_queuecommand 4208c2ecf20Sopenharmony_ci * Routine to send a scsi cdb 4218c2ecf20Sopenharmony_ci * Called with host_lock held and interrupts disabled. 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_cistatic int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct fc_lport *lp = shost_priv(sc->device->host); 4268c2ecf20Sopenharmony_ci struct fc_rport *rport; 4278c2ecf20Sopenharmony_ci struct fnic_io_req *io_req = NULL; 4288c2ecf20Sopenharmony_ci struct fnic *fnic = lport_priv(lp); 4298c2ecf20Sopenharmony_ci struct fnic_stats *fnic_stats = &fnic->fnic_stats; 4308c2ecf20Sopenharmony_ci struct vnic_wq_copy *wq; 4318c2ecf20Sopenharmony_ci int ret; 4328c2ecf20Sopenharmony_ci u64 cmd_trace; 4338c2ecf20Sopenharmony_ci int sg_count = 0; 4348c2ecf20Sopenharmony_ci unsigned long flags = 0; 4358c2ecf20Sopenharmony_ci unsigned long ptr; 4368c2ecf20Sopenharmony_ci spinlock_t *io_lock = NULL; 4378c2ecf20Sopenharmony_ci int io_lock_acquired = 0; 4388c2ecf20Sopenharmony_ci struct fc_rport_libfc_priv *rp; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED))) 4418c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_FWRESET))) 4448c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci rport = starget_to_rport(scsi_target(sc->device)); 4478c2ecf20Sopenharmony_ci if (!rport) { 4488c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 4498c2ecf20Sopenharmony_ci "returning DID_NO_CONNECT for IO as rport is NULL\n"); 4508c2ecf20Sopenharmony_ci sc->result = DID_NO_CONNECT << 16; 4518c2ecf20Sopenharmony_ci done(sc); 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci ret = fc_remote_port_chkready(rport); 4568c2ecf20Sopenharmony_ci if (ret) { 4578c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 4588c2ecf20Sopenharmony_ci "rport is not ready\n"); 4598c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.rport_not_ready); 4608c2ecf20Sopenharmony_ci sc->result = ret; 4618c2ecf20Sopenharmony_ci done(sc); 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci rp = rport->dd_data; 4668c2ecf20Sopenharmony_ci if (!rp || rp->rp_state == RPORT_ST_DELETE) { 4678c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 4688c2ecf20Sopenharmony_ci "rport 0x%x removed, returning DID_NO_CONNECT\n", 4698c2ecf20Sopenharmony_ci rport->port_id); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.rport_not_ready); 4728c2ecf20Sopenharmony_ci sc->result = DID_NO_CONNECT<<16; 4738c2ecf20Sopenharmony_ci done(sc); 4748c2ecf20Sopenharmony_ci return 0; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (rp->rp_state != RPORT_ST_READY) { 4788c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 4798c2ecf20Sopenharmony_ci "rport 0x%x in state 0x%x, returning DID_IMM_RETRY\n", 4808c2ecf20Sopenharmony_ci rport->port_id, rp->rp_state); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci sc->result = DID_IMM_RETRY << 16; 4838c2ecf20Sopenharmony_ci done(sc); 4848c2ecf20Sopenharmony_ci return 0; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (lp->state != LPORT_ST_READY || !(lp->link_up)) 4888c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci atomic_inc(&fnic->in_flight); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* 4938c2ecf20Sopenharmony_ci * Release host lock, use driver resource specific locks from here. 4948c2ecf20Sopenharmony_ci * Don't re-enable interrupts in case they were disabled prior to the 4958c2ecf20Sopenharmony_ci * caller disabling them. 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_ci spin_unlock(lp->host->host_lock); 4988c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_NOT_INITED; 4998c2ecf20Sopenharmony_ci CMD_FLAGS(sc) = FNIC_NO_FLAGS; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* Get a new io_req for this SCSI IO */ 5028c2ecf20Sopenharmony_ci io_req = mempool_alloc(fnic->io_req_pool, GFP_ATOMIC); 5038c2ecf20Sopenharmony_ci if (!io_req) { 5048c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.alloc_failures); 5058c2ecf20Sopenharmony_ci ret = SCSI_MLQUEUE_HOST_BUSY; 5068c2ecf20Sopenharmony_ci goto out; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci memset(io_req, 0, sizeof(*io_req)); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* Map the data buffer */ 5118c2ecf20Sopenharmony_ci sg_count = scsi_dma_map(sc); 5128c2ecf20Sopenharmony_ci if (sg_count < 0) { 5138c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, 5148c2ecf20Sopenharmony_ci sc->request->tag, sc, 0, sc->cmnd[0], 5158c2ecf20Sopenharmony_ci sg_count, CMD_STATE(sc)); 5168c2ecf20Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 5178c2ecf20Sopenharmony_ci goto out; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci /* Determine the type of scatter/gather list we need */ 5218c2ecf20Sopenharmony_ci io_req->sgl_cnt = sg_count; 5228c2ecf20Sopenharmony_ci io_req->sgl_type = FNIC_SGL_CACHE_DFLT; 5238c2ecf20Sopenharmony_ci if (sg_count > FNIC_DFLT_SG_DESC_CNT) 5248c2ecf20Sopenharmony_ci io_req->sgl_type = FNIC_SGL_CACHE_MAX; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (sg_count) { 5278c2ecf20Sopenharmony_ci io_req->sgl_list = 5288c2ecf20Sopenharmony_ci mempool_alloc(fnic->io_sgl_pool[io_req->sgl_type], 5298c2ecf20Sopenharmony_ci GFP_ATOMIC); 5308c2ecf20Sopenharmony_ci if (!io_req->sgl_list) { 5318c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.alloc_failures); 5328c2ecf20Sopenharmony_ci ret = SCSI_MLQUEUE_HOST_BUSY; 5338c2ecf20Sopenharmony_ci scsi_dma_unmap(sc); 5348c2ecf20Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 5358c2ecf20Sopenharmony_ci goto out; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* Cache sgl list allocated address before alignment */ 5398c2ecf20Sopenharmony_ci io_req->sgl_list_alloc = io_req->sgl_list; 5408c2ecf20Sopenharmony_ci ptr = (unsigned long) io_req->sgl_list; 5418c2ecf20Sopenharmony_ci if (ptr % FNIC_SG_DESC_ALIGN) { 5428c2ecf20Sopenharmony_ci io_req->sgl_list = (struct host_sg_desc *) 5438c2ecf20Sopenharmony_ci (((unsigned long) ptr 5448c2ecf20Sopenharmony_ci + FNIC_SG_DESC_ALIGN - 1) 5458c2ecf20Sopenharmony_ci & ~(FNIC_SG_DESC_ALIGN - 1)); 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* 5508c2ecf20Sopenharmony_ci * Will acquire lock defore setting to IO initialized. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 5548c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* initialize rest of io_req */ 5578c2ecf20Sopenharmony_ci io_lock_acquired = 1; 5588c2ecf20Sopenharmony_ci io_req->port_id = rport->port_id; 5598c2ecf20Sopenharmony_ci io_req->start_time = jiffies; 5608c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_CMD_PENDING; 5618c2ecf20Sopenharmony_ci CMD_SP(sc) = (char *)io_req; 5628c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_INITIALIZED; 5638c2ecf20Sopenharmony_ci sc->scsi_done = done; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* create copy wq desc and enqueue it */ 5668c2ecf20Sopenharmony_ci wq = &fnic->wq_copy[0]; 5678c2ecf20Sopenharmony_ci ret = fnic_queue_wq_copy_desc(fnic, wq, io_req, sc, sg_count); 5688c2ecf20Sopenharmony_ci if (ret) { 5698c2ecf20Sopenharmony_ci /* 5708c2ecf20Sopenharmony_ci * In case another thread cancelled the request, 5718c2ecf20Sopenharmony_ci * refetch the pointer under the lock. 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, 5748c2ecf20Sopenharmony_ci sc->request->tag, sc, 0, 0, 0, 5758c2ecf20Sopenharmony_ci (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); 5768c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 5778c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 5788c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE; 5798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 5808c2ecf20Sopenharmony_ci if (io_req) { 5818c2ecf20Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 5828c2ecf20Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci atomic_dec(&fnic->in_flight); 5858c2ecf20Sopenharmony_ci /* acquire host lock before returning to SCSI */ 5868c2ecf20Sopenharmony_ci spin_lock(lp->host->host_lock); 5878c2ecf20Sopenharmony_ci return ret; 5888c2ecf20Sopenharmony_ci } else { 5898c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.active_ios); 5908c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.num_ios); 5918c2ecf20Sopenharmony_ci if (atomic64_read(&fnic_stats->io_stats.active_ios) > 5928c2ecf20Sopenharmony_ci atomic64_read(&fnic_stats->io_stats.max_active_ios)) 5938c2ecf20Sopenharmony_ci atomic64_set(&fnic_stats->io_stats.max_active_ios, 5948c2ecf20Sopenharmony_ci atomic64_read(&fnic_stats->io_stats.active_ios)); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* REVISIT: Use per IO lock in the final code */ 5978c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_ISSUED; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ciout: 6008c2ecf20Sopenharmony_ci cmd_trace = ((u64)sc->cmnd[0] << 56 | (u64)sc->cmnd[7] << 40 | 6018c2ecf20Sopenharmony_ci (u64)sc->cmnd[8] << 32 | (u64)sc->cmnd[2] << 24 | 6028c2ecf20Sopenharmony_ci (u64)sc->cmnd[3] << 16 | (u64)sc->cmnd[4] << 8 | 6038c2ecf20Sopenharmony_ci sc->cmnd[5]); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, 6068c2ecf20Sopenharmony_ci sc->request->tag, sc, io_req, 6078c2ecf20Sopenharmony_ci sg_count, cmd_trace, 6088c2ecf20Sopenharmony_ci (((u64)CMD_FLAGS(sc) >> 32) | CMD_STATE(sc))); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* if only we issued IO, will we have the io lock */ 6118c2ecf20Sopenharmony_ci if (io_lock_acquired) 6128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci atomic_dec(&fnic->in_flight); 6158c2ecf20Sopenharmony_ci /* acquire host lock before returning to SCSI */ 6168c2ecf20Sopenharmony_ci spin_lock(lp->host->host_lock); 6178c2ecf20Sopenharmony_ci return ret; 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ciDEF_SCSI_QCMD(fnic_queuecommand) 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci/* 6238c2ecf20Sopenharmony_ci * fnic_fcpio_fw_reset_cmpl_handler 6248c2ecf20Sopenharmony_ci * Routine to handle fw reset completion 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_cistatic int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic, 6278c2ecf20Sopenharmony_ci struct fcpio_fw_req *desc) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci u8 type; 6308c2ecf20Sopenharmony_ci u8 hdr_status; 6318c2ecf20Sopenharmony_ci struct fcpio_tag tag; 6328c2ecf20Sopenharmony_ci int ret = 0; 6338c2ecf20Sopenharmony_ci unsigned long flags; 6348c2ecf20Sopenharmony_ci struct reset_stats *reset_stats = &fnic->fnic_stats.reset_stats; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci atomic64_inc(&reset_stats->fw_reset_completions); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* Clean up all outstanding io requests */ 6418c2ecf20Sopenharmony_ci fnic_cleanup_io(fnic, SCSI_NO_TAG); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.active_fw_reqs, 0); 6448c2ecf20Sopenharmony_ci atomic64_set(&fnic->fnic_stats.io_stats.active_ios, 0); 6458c2ecf20Sopenharmony_ci atomic64_set(&fnic->io_cmpl_skip, 0); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* fnic should be in FC_TRANS_ETH_MODE */ 6508c2ecf20Sopenharmony_ci if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) { 6518c2ecf20Sopenharmony_ci /* Check status of reset completion */ 6528c2ecf20Sopenharmony_ci if (!hdr_status) { 6538c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 6548c2ecf20Sopenharmony_ci "reset cmpl success\n"); 6558c2ecf20Sopenharmony_ci /* Ready to send flogi out */ 6568c2ecf20Sopenharmony_ci fnic->state = FNIC_IN_ETH_MODE; 6578c2ecf20Sopenharmony_ci } else { 6588c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 6598c2ecf20Sopenharmony_ci fnic->lport->host, 6608c2ecf20Sopenharmony_ci "fnic fw_reset : failed %s\n", 6618c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* 6648c2ecf20Sopenharmony_ci * Unable to change to eth mode, cannot send out flogi 6658c2ecf20Sopenharmony_ci * Change state to fc mode, so that subsequent Flogi 6668c2ecf20Sopenharmony_ci * requests from libFC will cause more attempts to 6678c2ecf20Sopenharmony_ci * reset the firmware. Free the cached flogi 6688c2ecf20Sopenharmony_ci */ 6698c2ecf20Sopenharmony_ci fnic->state = FNIC_IN_FC_MODE; 6708c2ecf20Sopenharmony_ci atomic64_inc(&reset_stats->fw_reset_failures); 6718c2ecf20Sopenharmony_ci ret = -1; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci } else { 6748c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 6758c2ecf20Sopenharmony_ci fnic->lport->host, 6768c2ecf20Sopenharmony_ci "Unexpected state %s while processing" 6778c2ecf20Sopenharmony_ci " reset cmpl\n", fnic_state_to_str(fnic->state)); 6788c2ecf20Sopenharmony_ci atomic64_inc(&reset_stats->fw_reset_failures); 6798c2ecf20Sopenharmony_ci ret = -1; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci /* Thread removing device blocks till firmware reset is complete */ 6838c2ecf20Sopenharmony_ci if (fnic->remove_wait) 6848c2ecf20Sopenharmony_ci complete(fnic->remove_wait); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* 6878c2ecf20Sopenharmony_ci * If fnic is being removed, or fw reset failed 6888c2ecf20Sopenharmony_ci * free the flogi frame. Else, send it out 6898c2ecf20Sopenharmony_ci */ 6908c2ecf20Sopenharmony_ci if (fnic->remove_wait || ret) { 6918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 6928c2ecf20Sopenharmony_ci skb_queue_purge(&fnic->tx_queue); 6938c2ecf20Sopenharmony_ci goto reset_cmpl_handler_end; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci fnic_flush_tx(fnic); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci reset_cmpl_handler_end: 7018c2ecf20Sopenharmony_ci fnic_clear_state_flags(fnic, FNIC_FLAGS_FWRESET); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci return ret; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci/* 7078c2ecf20Sopenharmony_ci * fnic_fcpio_flogi_reg_cmpl_handler 7088c2ecf20Sopenharmony_ci * Routine to handle flogi register completion 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_cistatic int fnic_fcpio_flogi_reg_cmpl_handler(struct fnic *fnic, 7118c2ecf20Sopenharmony_ci struct fcpio_fw_req *desc) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci u8 type; 7148c2ecf20Sopenharmony_ci u8 hdr_status; 7158c2ecf20Sopenharmony_ci struct fcpio_tag tag; 7168c2ecf20Sopenharmony_ci int ret = 0; 7178c2ecf20Sopenharmony_ci unsigned long flags; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* Update fnic state based on status of flogi reg completion */ 7228c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE) { 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* Check flogi registration completion status */ 7278c2ecf20Sopenharmony_ci if (!hdr_status) { 7288c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 7298c2ecf20Sopenharmony_ci "flog reg succeeded\n"); 7308c2ecf20Sopenharmony_ci fnic->state = FNIC_IN_FC_MODE; 7318c2ecf20Sopenharmony_ci } else { 7328c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 7338c2ecf20Sopenharmony_ci fnic->lport->host, 7348c2ecf20Sopenharmony_ci "fnic flogi reg :failed %s\n", 7358c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 7368c2ecf20Sopenharmony_ci fnic->state = FNIC_IN_ETH_MODE; 7378c2ecf20Sopenharmony_ci ret = -1; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci } else { 7408c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 7418c2ecf20Sopenharmony_ci "Unexpected fnic state %s while" 7428c2ecf20Sopenharmony_ci " processing flogi reg completion\n", 7438c2ecf20Sopenharmony_ci fnic_state_to_str(fnic->state)); 7448c2ecf20Sopenharmony_ci ret = -1; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (!ret) { 7488c2ecf20Sopenharmony_ci if (fnic->stop_rx_link_events) { 7498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 7508c2ecf20Sopenharmony_ci goto reg_cmpl_handler_end; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci fnic_flush_tx(fnic); 7558c2ecf20Sopenharmony_ci queue_work(fnic_event_queue, &fnic->frame_work); 7568c2ecf20Sopenharmony_ci } else { 7578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cireg_cmpl_handler_end: 7618c2ecf20Sopenharmony_ci return ret; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic inline int is_ack_index_in_range(struct vnic_wq_copy *wq, 7658c2ecf20Sopenharmony_ci u16 request_out) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci if (wq->to_clean_index <= wq->to_use_index) { 7688c2ecf20Sopenharmony_ci /* out of range, stale request_out index */ 7698c2ecf20Sopenharmony_ci if (request_out < wq->to_clean_index || 7708c2ecf20Sopenharmony_ci request_out >= wq->to_use_index) 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci } else { 7738c2ecf20Sopenharmony_ci /* out of range, stale request_out index */ 7748c2ecf20Sopenharmony_ci if (request_out < wq->to_clean_index && 7758c2ecf20Sopenharmony_ci request_out >= wq->to_use_index) 7768c2ecf20Sopenharmony_ci return 0; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci /* request_out index is in range */ 7798c2ecf20Sopenharmony_ci return 1; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci/* 7848c2ecf20Sopenharmony_ci * Mark that ack received and store the Ack index. If there are multiple 7858c2ecf20Sopenharmony_ci * acks received before Tx thread cleans it up, the latest value will be 7868c2ecf20Sopenharmony_ci * used which is correct behavior. This state should be in the copy Wq 7878c2ecf20Sopenharmony_ci * instead of in the fnic 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_cistatic inline void fnic_fcpio_ack_handler(struct fnic *fnic, 7908c2ecf20Sopenharmony_ci unsigned int cq_index, 7918c2ecf20Sopenharmony_ci struct fcpio_fw_req *desc) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci struct vnic_wq_copy *wq; 7948c2ecf20Sopenharmony_ci u16 request_out = desc->u.ack.request_out; 7958c2ecf20Sopenharmony_ci unsigned long flags; 7968c2ecf20Sopenharmony_ci u64 *ox_id_tag = (u64 *)(void *)desc; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci /* mark the ack state */ 7998c2ecf20Sopenharmony_ci wq = &fnic->wq_copy[cq_index - fnic->raw_wq_count - fnic->rq_count]; 8008c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci fnic->fnic_stats.misc_stats.last_ack_time = jiffies; 8038c2ecf20Sopenharmony_ci if (is_ack_index_in_range(wq, request_out)) { 8048c2ecf20Sopenharmony_ci fnic->fw_ack_index[0] = request_out; 8058c2ecf20Sopenharmony_ci fnic->fw_ack_recd[0] = 1; 8068c2ecf20Sopenharmony_ci } else 8078c2ecf20Sopenharmony_ci atomic64_inc( 8088c2ecf20Sopenharmony_ci &fnic->fnic_stats.misc_stats.ack_index_out_of_range); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); 8118c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_fcpio_ack_handler, 8128c2ecf20Sopenharmony_ci fnic->lport->host->host_no, 0, 0, ox_id_tag[2], ox_id_tag[3], 8138c2ecf20Sopenharmony_ci ox_id_tag[4], ox_id_tag[5]); 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci/* 8178c2ecf20Sopenharmony_ci * fnic_fcpio_icmnd_cmpl_handler 8188c2ecf20Sopenharmony_ci * Routine to handle icmnd completions 8198c2ecf20Sopenharmony_ci */ 8208c2ecf20Sopenharmony_cistatic void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, 8218c2ecf20Sopenharmony_ci struct fcpio_fw_req *desc) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci u8 type; 8248c2ecf20Sopenharmony_ci u8 hdr_status; 8258c2ecf20Sopenharmony_ci struct fcpio_tag tag; 8268c2ecf20Sopenharmony_ci u32 id; 8278c2ecf20Sopenharmony_ci u64 xfer_len = 0; 8288c2ecf20Sopenharmony_ci struct fcpio_icmnd_cmpl *icmnd_cmpl; 8298c2ecf20Sopenharmony_ci struct fnic_io_req *io_req; 8308c2ecf20Sopenharmony_ci struct scsi_cmnd *sc; 8318c2ecf20Sopenharmony_ci struct fnic_stats *fnic_stats = &fnic->fnic_stats; 8328c2ecf20Sopenharmony_ci unsigned long flags; 8338c2ecf20Sopenharmony_ci spinlock_t *io_lock; 8348c2ecf20Sopenharmony_ci u64 cmd_trace; 8358c2ecf20Sopenharmony_ci unsigned long start_time; 8368c2ecf20Sopenharmony_ci unsigned long io_duration_time; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci /* Decode the cmpl description to get the io_req id */ 8398c2ecf20Sopenharmony_ci fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); 8408c2ecf20Sopenharmony_ci fcpio_tag_id_dec(&tag, &id); 8418c2ecf20Sopenharmony_ci icmnd_cmpl = &desc->u.icmnd_cmpl; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci if (id >= fnic->fnic_max_tag_id) { 8448c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 8458c2ecf20Sopenharmony_ci "Tag out of range tag %x hdr status = %s\n", 8468c2ecf20Sopenharmony_ci id, fnic_fcpio_status_to_str(hdr_status)); 8478c2ecf20Sopenharmony_ci return; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(fnic->lport->host, id); 8518c2ecf20Sopenharmony_ci WARN_ON_ONCE(!sc); 8528c2ecf20Sopenharmony_ci if (!sc) { 8538c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.sc_null); 8548c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 8558c2ecf20Sopenharmony_ci "icmnd_cmpl sc is null - " 8568c2ecf20Sopenharmony_ci "hdr status = %s tag = 0x%x desc = 0x%p\n", 8578c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status), id, desc); 8588c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_fcpio_icmnd_cmpl_handler, 8598c2ecf20Sopenharmony_ci fnic->lport->host->host_no, id, 8608c2ecf20Sopenharmony_ci ((u64)icmnd_cmpl->_resvd0[1] << 16 | 8618c2ecf20Sopenharmony_ci (u64)icmnd_cmpl->_resvd0[0]), 8628c2ecf20Sopenharmony_ci ((u64)hdr_status << 16 | 8638c2ecf20Sopenharmony_ci (u64)icmnd_cmpl->scsi_status << 8 | 8648c2ecf20Sopenharmony_ci (u64)icmnd_cmpl->flags), desc, 8658c2ecf20Sopenharmony_ci (u64)icmnd_cmpl->residual, 0); 8668c2ecf20Sopenharmony_ci return; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 8708c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 8718c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 8728c2ecf20Sopenharmony_ci WARN_ON_ONCE(!io_req); 8738c2ecf20Sopenharmony_ci if (!io_req) { 8748c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.ioreq_null); 8758c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_REQ_NULL; 8768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 8778c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 8788c2ecf20Sopenharmony_ci "icmnd_cmpl io_req is null - " 8798c2ecf20Sopenharmony_ci "hdr status = %s tag = 0x%x sc 0x%p\n", 8808c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status), id, sc); 8818c2ecf20Sopenharmony_ci return; 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci start_time = io_req->start_time; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci /* firmware completed the io */ 8868c2ecf20Sopenharmony_ci io_req->io_completed = 1; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* 8898c2ecf20Sopenharmony_ci * if SCSI-ML has already issued abort on this command, 8908c2ecf20Sopenharmony_ci * set completion of the IO. The abts path will clean it up 8918c2ecf20Sopenharmony_ci */ 8928c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* 8958c2ecf20Sopenharmony_ci * set the FNIC_IO_DONE so that this doesn't get 8968c2ecf20Sopenharmony_ci * flagged as 'out of order' if it was not aborted 8978c2ecf20Sopenharmony_ci */ 8988c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_DONE; 8998c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_ABTS_PENDING; 9008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 9018c2ecf20Sopenharmony_ci if(FCPIO_ABORTED == hdr_status) 9028c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_ABORTED; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 9058c2ecf20Sopenharmony_ci "icmnd_cmpl abts pending " 9068c2ecf20Sopenharmony_ci "hdr status = %s tag = 0x%x sc = 0x%p " 9078c2ecf20Sopenharmony_ci "scsi_status = %x residual = %d\n", 9088c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status), 9098c2ecf20Sopenharmony_ci id, sc, 9108c2ecf20Sopenharmony_ci icmnd_cmpl->scsi_status, 9118c2ecf20Sopenharmony_ci icmnd_cmpl->residual); 9128c2ecf20Sopenharmony_ci return; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* Mark the IO as complete */ 9168c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci icmnd_cmpl = &desc->u.icmnd_cmpl; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci switch (hdr_status) { 9218c2ecf20Sopenharmony_ci case FCPIO_SUCCESS: 9228c2ecf20Sopenharmony_ci sc->result = (DID_OK << 16) | icmnd_cmpl->scsi_status; 9238c2ecf20Sopenharmony_ci xfer_len = scsi_bufflen(sc); 9248c2ecf20Sopenharmony_ci scsi_set_resid(sc, icmnd_cmpl->residual); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (icmnd_cmpl->flags & FCPIO_ICMND_CMPL_RESID_UNDER) 9278c2ecf20Sopenharmony_ci xfer_len -= icmnd_cmpl->residual; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci if (icmnd_cmpl->scsi_status == SAM_STAT_CHECK_CONDITION) 9308c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.check_condition); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (icmnd_cmpl->scsi_status == SAM_STAT_TASK_SET_FULL) 9338c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.queue_fulls); 9348c2ecf20Sopenharmony_ci break; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci case FCPIO_TIMEOUT: /* request was timed out */ 9378c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.fcpio_timeout); 9388c2ecf20Sopenharmony_ci sc->result = (DID_TIME_OUT << 16) | icmnd_cmpl->scsi_status; 9398c2ecf20Sopenharmony_ci break; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci case FCPIO_ABORTED: /* request was aborted */ 9428c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.fcpio_aborted); 9438c2ecf20Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 9448c2ecf20Sopenharmony_ci break; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci case FCPIO_DATA_CNT_MISMATCH: /* recv/sent more/less data than exp. */ 9478c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.data_count_mismatch); 9488c2ecf20Sopenharmony_ci scsi_set_resid(sc, icmnd_cmpl->residual); 9498c2ecf20Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 9508c2ecf20Sopenharmony_ci break; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci case FCPIO_OUT_OF_RESOURCE: /* out of resources to complete request */ 9538c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->fw_stats.fw_out_of_resources); 9548c2ecf20Sopenharmony_ci sc->result = (DID_REQUEUE << 16) | icmnd_cmpl->scsi_status; 9558c2ecf20Sopenharmony_ci break; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci case FCPIO_IO_NOT_FOUND: /* requested I/O was not found */ 9588c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_not_found); 9598c2ecf20Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 9608c2ecf20Sopenharmony_ci break; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci case FCPIO_SGL_INVALID: /* request was aborted due to sgl error */ 9638c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.sgl_invalid); 9648c2ecf20Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci case FCPIO_FW_ERR: /* request was terminated due fw error */ 9688c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->fw_stats.io_fw_errs); 9698c2ecf20Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 9708c2ecf20Sopenharmony_ci break; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci case FCPIO_MSS_INVALID: /* request was aborted due to mss error */ 9738c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.mss_invalid); 9748c2ecf20Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 9758c2ecf20Sopenharmony_ci break; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci case FCPIO_INVALID_HEADER: /* header contains invalid data */ 9788c2ecf20Sopenharmony_ci case FCPIO_INVALID_PARAM: /* some parameter in request invalid */ 9798c2ecf20Sopenharmony_ci case FCPIO_REQ_NOT_SUPPORTED:/* request type is not supported */ 9808c2ecf20Sopenharmony_ci default: 9818c2ecf20Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 9828c2ecf20Sopenharmony_ci break; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci /* Break link with the SCSI command */ 9868c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 9878c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_DONE; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci if (hdr_status != FCPIO_SUCCESS) { 9928c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_failures); 9938c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, "hdr status = %s\n", 9948c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci cmd_trace = ((u64)hdr_status << 56) | 10028c2ecf20Sopenharmony_ci (u64)icmnd_cmpl->scsi_status << 48 | 10038c2ecf20Sopenharmony_ci (u64)icmnd_cmpl->flags << 40 | (u64)sc->cmnd[0] << 32 | 10048c2ecf20Sopenharmony_ci (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | 10058c2ecf20Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_fcpio_icmnd_cmpl_handler, 10088c2ecf20Sopenharmony_ci sc->device->host->host_no, id, sc, 10098c2ecf20Sopenharmony_ci ((u64)icmnd_cmpl->_resvd0[1] << 56 | 10108c2ecf20Sopenharmony_ci (u64)icmnd_cmpl->_resvd0[0] << 48 | 10118c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time)), 10128c2ecf20Sopenharmony_ci desc, cmd_trace, 10138c2ecf20Sopenharmony_ci (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (sc->sc_data_direction == DMA_FROM_DEVICE) { 10168c2ecf20Sopenharmony_ci fnic->lport->host_stats.fcp_input_requests++; 10178c2ecf20Sopenharmony_ci fnic->fcp_input_bytes += xfer_len; 10188c2ecf20Sopenharmony_ci } else if (sc->sc_data_direction == DMA_TO_DEVICE) { 10198c2ecf20Sopenharmony_ci fnic->lport->host_stats.fcp_output_requests++; 10208c2ecf20Sopenharmony_ci fnic->fcp_output_bytes += xfer_len; 10218c2ecf20Sopenharmony_ci } else 10228c2ecf20Sopenharmony_ci fnic->lport->host_stats.fcp_control_requests++; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci atomic64_dec(&fnic_stats->io_stats.active_ios); 10258c2ecf20Sopenharmony_ci if (atomic64_read(&fnic->io_cmpl_skip)) 10268c2ecf20Sopenharmony_ci atomic64_dec(&fnic->io_cmpl_skip); 10278c2ecf20Sopenharmony_ci else 10288c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_completions); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci io_duration_time = jiffies_to_msecs(jiffies) - 10328c2ecf20Sopenharmony_ci jiffies_to_msecs(start_time); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci if(io_duration_time <= 10) 10358c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_0_to_10_msec); 10368c2ecf20Sopenharmony_ci else if(io_duration_time <= 100) 10378c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_10_to_100_msec); 10388c2ecf20Sopenharmony_ci else if(io_duration_time <= 500) 10398c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_100_to_500_msec); 10408c2ecf20Sopenharmony_ci else if(io_duration_time <= 5000) 10418c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_500_to_5000_msec); 10428c2ecf20Sopenharmony_ci else if(io_duration_time <= 10000) 10438c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_5000_to_10000_msec); 10448c2ecf20Sopenharmony_ci else if(io_duration_time <= 30000) 10458c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_10000_to_30000_msec); 10468c2ecf20Sopenharmony_ci else { 10478c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_greater_than_30000_msec); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if(io_duration_time > atomic64_read(&fnic_stats->io_stats.current_max_io_time)) 10508c2ecf20Sopenharmony_ci atomic64_set(&fnic_stats->io_stats.current_max_io_time, io_duration_time); 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* Call SCSI completion function to complete the IO */ 10548c2ecf20Sopenharmony_ci if (sc->scsi_done) 10558c2ecf20Sopenharmony_ci sc->scsi_done(sc); 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci/* fnic_fcpio_itmf_cmpl_handler 10598c2ecf20Sopenharmony_ci * Routine to handle itmf completions 10608c2ecf20Sopenharmony_ci */ 10618c2ecf20Sopenharmony_cistatic void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, 10628c2ecf20Sopenharmony_ci struct fcpio_fw_req *desc) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci u8 type; 10658c2ecf20Sopenharmony_ci u8 hdr_status; 10668c2ecf20Sopenharmony_ci struct fcpio_tag tag; 10678c2ecf20Sopenharmony_ci u32 id; 10688c2ecf20Sopenharmony_ci struct scsi_cmnd *sc; 10698c2ecf20Sopenharmony_ci struct fnic_io_req *io_req; 10708c2ecf20Sopenharmony_ci struct fnic_stats *fnic_stats = &fnic->fnic_stats; 10718c2ecf20Sopenharmony_ci struct abort_stats *abts_stats = &fnic->fnic_stats.abts_stats; 10728c2ecf20Sopenharmony_ci struct terminate_stats *term_stats = &fnic->fnic_stats.term_stats; 10738c2ecf20Sopenharmony_ci struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; 10748c2ecf20Sopenharmony_ci unsigned long flags; 10758c2ecf20Sopenharmony_ci spinlock_t *io_lock; 10768c2ecf20Sopenharmony_ci unsigned long start_time; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); 10798c2ecf20Sopenharmony_ci fcpio_tag_id_dec(&tag, &id); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if ((id & FNIC_TAG_MASK) >= fnic->fnic_max_tag_id) { 10828c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 10838c2ecf20Sopenharmony_ci "Tag out of range tag %x hdr status = %s\n", 10848c2ecf20Sopenharmony_ci id, fnic_fcpio_status_to_str(hdr_status)); 10858c2ecf20Sopenharmony_ci return; 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(fnic->lport->host, id & FNIC_TAG_MASK); 10898c2ecf20Sopenharmony_ci WARN_ON_ONCE(!sc); 10908c2ecf20Sopenharmony_ci if (!sc) { 10918c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.sc_null); 10928c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 10938c2ecf20Sopenharmony_ci "itmf_cmpl sc is null - hdr status = %s tag = 0x%x\n", 10948c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status), id); 10958c2ecf20Sopenharmony_ci return; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 10988c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 10998c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 11008c2ecf20Sopenharmony_ci WARN_ON_ONCE(!io_req); 11018c2ecf20Sopenharmony_ci if (!io_req) { 11028c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.ioreq_null); 11038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 11048c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_ABT_TERM_REQ_NULL; 11058c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 11068c2ecf20Sopenharmony_ci "itmf_cmpl io_req is null - " 11078c2ecf20Sopenharmony_ci "hdr status = %s tag = 0x%x sc 0x%p\n", 11088c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status), id, sc); 11098c2ecf20Sopenharmony_ci return; 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci start_time = io_req->start_time; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if ((id & FNIC_TAG_ABORT) && (id & FNIC_TAG_DEV_RST)) { 11148c2ecf20Sopenharmony_ci /* Abort and terminate completion of device reset req */ 11158c2ecf20Sopenharmony_ci /* REVISIT : Add asserts about various flags */ 11168c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 11178c2ecf20Sopenharmony_ci "dev reset abts cmpl recd. id %x status %s\n", 11188c2ecf20Sopenharmony_ci id, fnic_fcpio_status_to_str(hdr_status)); 11198c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_ABTS_COMPLETE; 11208c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = hdr_status; 11218c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_DEV_RST_DONE; 11228c2ecf20Sopenharmony_ci if (io_req->abts_done) 11238c2ecf20Sopenharmony_ci complete(io_req->abts_done); 11248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 11258c2ecf20Sopenharmony_ci } else if (id & FNIC_TAG_ABORT) { 11268c2ecf20Sopenharmony_ci /* Completion of abort cmd */ 11278c2ecf20Sopenharmony_ci switch (hdr_status) { 11288c2ecf20Sopenharmony_ci case FCPIO_SUCCESS: 11298c2ecf20Sopenharmony_ci break; 11308c2ecf20Sopenharmony_ci case FCPIO_TIMEOUT: 11318c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & FNIC_IO_ABTS_ISSUED) 11328c2ecf20Sopenharmony_ci atomic64_inc(&abts_stats->abort_fw_timeouts); 11338c2ecf20Sopenharmony_ci else 11348c2ecf20Sopenharmony_ci atomic64_inc( 11358c2ecf20Sopenharmony_ci &term_stats->terminate_fw_timeouts); 11368c2ecf20Sopenharmony_ci break; 11378c2ecf20Sopenharmony_ci case FCPIO_ITMF_REJECTED: 11388c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 11398c2ecf20Sopenharmony_ci "abort reject recd. id %d\n", 11408c2ecf20Sopenharmony_ci (int)(id & FNIC_TAG_MASK)); 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci case FCPIO_IO_NOT_FOUND: 11438c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & FNIC_IO_ABTS_ISSUED) 11448c2ecf20Sopenharmony_ci atomic64_inc(&abts_stats->abort_io_not_found); 11458c2ecf20Sopenharmony_ci else 11468c2ecf20Sopenharmony_ci atomic64_inc( 11478c2ecf20Sopenharmony_ci &term_stats->terminate_io_not_found); 11488c2ecf20Sopenharmony_ci break; 11498c2ecf20Sopenharmony_ci default: 11508c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & FNIC_IO_ABTS_ISSUED) 11518c2ecf20Sopenharmony_ci atomic64_inc(&abts_stats->abort_failures); 11528c2ecf20Sopenharmony_ci else 11538c2ecf20Sopenharmony_ci atomic64_inc( 11548c2ecf20Sopenharmony_ci &term_stats->terminate_failures); 11558c2ecf20Sopenharmony_ci break; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci if (CMD_STATE(sc) != FNIC_IOREQ_ABTS_PENDING) { 11588c2ecf20Sopenharmony_ci /* This is a late completion. Ignore it */ 11598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 11608c2ecf20Sopenharmony_ci return; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_ABT_TERM_DONE; 11648c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = hdr_status; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci /* If the status is IO not found consider it as success */ 11678c2ecf20Sopenharmony_ci if (hdr_status == FCPIO_IO_NOT_FOUND) 11688c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = FCPIO_SUCCESS; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (!(CMD_FLAGS(sc) & (FNIC_IO_ABORTED | FNIC_IO_DONE))) 11718c2ecf20Sopenharmony_ci atomic64_inc(&misc_stats->no_icmnd_itmf_cmpls); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 11748c2ecf20Sopenharmony_ci "abts cmpl recd. id %d status %s\n", 11758c2ecf20Sopenharmony_ci (int)(id & FNIC_TAG_MASK), 11768c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* 11798c2ecf20Sopenharmony_ci * If scsi_eh thread is blocked waiting for abts to complete, 11808c2ecf20Sopenharmony_ci * signal completion to it. IO will be cleaned in the thread 11818c2ecf20Sopenharmony_ci * else clean it in this context 11828c2ecf20Sopenharmony_ci */ 11838c2ecf20Sopenharmony_ci if (io_req->abts_done) { 11848c2ecf20Sopenharmony_ci complete(io_req->abts_done); 11858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 11868c2ecf20Sopenharmony_ci } else { 11878c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 11888c2ecf20Sopenharmony_ci "abts cmpl, completing IO\n"); 11898c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 11908c2ecf20Sopenharmony_ci sc->result = (DID_ERROR << 16); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 11958c2ecf20Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 11968c2ecf20Sopenharmony_ci if (sc->scsi_done) { 11978c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_fcpio_itmf_cmpl_handler, 11988c2ecf20Sopenharmony_ci sc->device->host->host_no, id, 11998c2ecf20Sopenharmony_ci sc, 12008c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 12018c2ecf20Sopenharmony_ci desc, 12028c2ecf20Sopenharmony_ci (((u64)hdr_status << 40) | 12038c2ecf20Sopenharmony_ci (u64)sc->cmnd[0] << 32 | 12048c2ecf20Sopenharmony_ci (u64)sc->cmnd[2] << 24 | 12058c2ecf20Sopenharmony_ci (u64)sc->cmnd[3] << 16 | 12068c2ecf20Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), 12078c2ecf20Sopenharmony_ci (((u64)CMD_FLAGS(sc) << 32) | 12088c2ecf20Sopenharmony_ci CMD_STATE(sc))); 12098c2ecf20Sopenharmony_ci sc->scsi_done(sc); 12108c2ecf20Sopenharmony_ci atomic64_dec(&fnic_stats->io_stats.active_ios); 12118c2ecf20Sopenharmony_ci if (atomic64_read(&fnic->io_cmpl_skip)) 12128c2ecf20Sopenharmony_ci atomic64_dec(&fnic->io_cmpl_skip); 12138c2ecf20Sopenharmony_ci else 12148c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_completions); 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci } else if (id & FNIC_TAG_DEV_RST) { 12198c2ecf20Sopenharmony_ci /* Completion of device reset */ 12208c2ecf20Sopenharmony_ci CMD_LR_STATUS(sc) = hdr_status; 12218c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { 12228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 12238c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_DEV_RST_ABTS_PENDING; 12248c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_fcpio_itmf_cmpl_handler, 12258c2ecf20Sopenharmony_ci sc->device->host->host_no, id, sc, 12268c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 12278c2ecf20Sopenharmony_ci desc, 0, 12288c2ecf20Sopenharmony_ci (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); 12298c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 12308c2ecf20Sopenharmony_ci "Terminate pending " 12318c2ecf20Sopenharmony_ci "dev reset cmpl recd. id %d status %s\n", 12328c2ecf20Sopenharmony_ci (int)(id & FNIC_TAG_MASK), 12338c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 12348c2ecf20Sopenharmony_ci return; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & FNIC_DEV_RST_TIMED_OUT) { 12378c2ecf20Sopenharmony_ci /* Need to wait for terminate completion */ 12388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 12398c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_fcpio_itmf_cmpl_handler, 12408c2ecf20Sopenharmony_ci sc->device->host->host_no, id, sc, 12418c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 12428c2ecf20Sopenharmony_ci desc, 0, 12438c2ecf20Sopenharmony_ci (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); 12448c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 12458c2ecf20Sopenharmony_ci "dev reset cmpl recd after time out. " 12468c2ecf20Sopenharmony_ci "id %d status %s\n", 12478c2ecf20Sopenharmony_ci (int)(id & FNIC_TAG_MASK), 12488c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 12498c2ecf20Sopenharmony_ci return; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE; 12528c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_DEV_RST_DONE; 12538c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 12548c2ecf20Sopenharmony_ci "dev reset cmpl recd. id %d status %s\n", 12558c2ecf20Sopenharmony_ci (int)(id & FNIC_TAG_MASK), 12568c2ecf20Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 12578c2ecf20Sopenharmony_ci if (io_req->dr_done) 12588c2ecf20Sopenharmony_ci complete(io_req->dr_done); 12598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci } else { 12628c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 12638c2ecf20Sopenharmony_ci "Unexpected itmf io state %s tag %x\n", 12648c2ecf20Sopenharmony_ci fnic_ioreq_state_to_str(CMD_STATE(sc)), id); 12658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci} 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci/* 12718c2ecf20Sopenharmony_ci * fnic_fcpio_cmpl_handler 12728c2ecf20Sopenharmony_ci * Routine to service the cq for wq_copy 12738c2ecf20Sopenharmony_ci */ 12748c2ecf20Sopenharmony_cistatic int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev, 12758c2ecf20Sopenharmony_ci unsigned int cq_index, 12768c2ecf20Sopenharmony_ci struct fcpio_fw_req *desc) 12778c2ecf20Sopenharmony_ci{ 12788c2ecf20Sopenharmony_ci struct fnic *fnic = vnic_dev_priv(vdev); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci switch (desc->hdr.type) { 12818c2ecf20Sopenharmony_ci case FCPIO_ICMND_CMPL: /* fw completed a command */ 12828c2ecf20Sopenharmony_ci case FCPIO_ITMF_CMPL: /* fw completed itmf (abort cmd, lun reset)*/ 12838c2ecf20Sopenharmony_ci case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */ 12848c2ecf20Sopenharmony_ci case FCPIO_FLOGI_FIP_REG_CMPL: /* fw completed flogi_fip_reg */ 12858c2ecf20Sopenharmony_ci case FCPIO_RESET_CMPL: /* fw completed reset */ 12868c2ecf20Sopenharmony_ci atomic64_dec(&fnic->fnic_stats.fw_stats.active_fw_reqs); 12878c2ecf20Sopenharmony_ci break; 12888c2ecf20Sopenharmony_ci default: 12898c2ecf20Sopenharmony_ci break; 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci switch (desc->hdr.type) { 12938c2ecf20Sopenharmony_ci case FCPIO_ACK: /* fw copied copy wq desc to its queue */ 12948c2ecf20Sopenharmony_ci fnic_fcpio_ack_handler(fnic, cq_index, desc); 12958c2ecf20Sopenharmony_ci break; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci case FCPIO_ICMND_CMPL: /* fw completed a command */ 12988c2ecf20Sopenharmony_ci fnic_fcpio_icmnd_cmpl_handler(fnic, desc); 12998c2ecf20Sopenharmony_ci break; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci case FCPIO_ITMF_CMPL: /* fw completed itmf (abort cmd, lun reset)*/ 13028c2ecf20Sopenharmony_ci fnic_fcpio_itmf_cmpl_handler(fnic, desc); 13038c2ecf20Sopenharmony_ci break; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */ 13068c2ecf20Sopenharmony_ci case FCPIO_FLOGI_FIP_REG_CMPL: /* fw completed flogi_fip_reg */ 13078c2ecf20Sopenharmony_ci fnic_fcpio_flogi_reg_cmpl_handler(fnic, desc); 13088c2ecf20Sopenharmony_ci break; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci case FCPIO_RESET_CMPL: /* fw completed reset */ 13118c2ecf20Sopenharmony_ci fnic_fcpio_fw_reset_cmpl_handler(fnic, desc); 13128c2ecf20Sopenharmony_ci break; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci default: 13158c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 13168c2ecf20Sopenharmony_ci "firmware completion type %d\n", 13178c2ecf20Sopenharmony_ci desc->hdr.type); 13188c2ecf20Sopenharmony_ci break; 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci return 0; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci/* 13258c2ecf20Sopenharmony_ci * fnic_wq_copy_cmpl_handler 13268c2ecf20Sopenharmony_ci * Routine to process wq copy 13278c2ecf20Sopenharmony_ci */ 13288c2ecf20Sopenharmony_ciint fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do) 13298c2ecf20Sopenharmony_ci{ 13308c2ecf20Sopenharmony_ci unsigned int wq_work_done = 0; 13318c2ecf20Sopenharmony_ci unsigned int i, cq_index; 13328c2ecf20Sopenharmony_ci unsigned int cur_work_done; 13338c2ecf20Sopenharmony_ci struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; 13348c2ecf20Sopenharmony_ci u64 start_jiffies = 0; 13358c2ecf20Sopenharmony_ci u64 end_jiffies = 0; 13368c2ecf20Sopenharmony_ci u64 delta_jiffies = 0; 13378c2ecf20Sopenharmony_ci u64 delta_ms = 0; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci for (i = 0; i < fnic->wq_copy_count; i++) { 13408c2ecf20Sopenharmony_ci cq_index = i + fnic->raw_wq_count + fnic->rq_count; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci start_jiffies = jiffies; 13438c2ecf20Sopenharmony_ci cur_work_done = vnic_cq_copy_service(&fnic->cq[cq_index], 13448c2ecf20Sopenharmony_ci fnic_fcpio_cmpl_handler, 13458c2ecf20Sopenharmony_ci copy_work_to_do); 13468c2ecf20Sopenharmony_ci end_jiffies = jiffies; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci wq_work_done += cur_work_done; 13498c2ecf20Sopenharmony_ci delta_jiffies = end_jiffies - start_jiffies; 13508c2ecf20Sopenharmony_ci if (delta_jiffies > 13518c2ecf20Sopenharmony_ci (u64) atomic64_read(&misc_stats->max_isr_jiffies)) { 13528c2ecf20Sopenharmony_ci atomic64_set(&misc_stats->max_isr_jiffies, 13538c2ecf20Sopenharmony_ci delta_jiffies); 13548c2ecf20Sopenharmony_ci delta_ms = jiffies_to_msecs(delta_jiffies); 13558c2ecf20Sopenharmony_ci atomic64_set(&misc_stats->max_isr_time_ms, delta_ms); 13568c2ecf20Sopenharmony_ci atomic64_set(&misc_stats->corr_work_done, 13578c2ecf20Sopenharmony_ci cur_work_done); 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci return wq_work_done; 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cistatic void fnic_cleanup_io(struct fnic *fnic, int exclude_id) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci int i; 13668c2ecf20Sopenharmony_ci struct fnic_io_req *io_req; 13678c2ecf20Sopenharmony_ci unsigned long flags = 0; 13688c2ecf20Sopenharmony_ci struct scsi_cmnd *sc; 13698c2ecf20Sopenharmony_ci spinlock_t *io_lock; 13708c2ecf20Sopenharmony_ci unsigned long start_time = 0; 13718c2ecf20Sopenharmony_ci struct fnic_stats *fnic_stats = &fnic->fnic_stats; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci for (i = 0; i < fnic->fnic_max_tag_id; i++) { 13748c2ecf20Sopenharmony_ci if (i == exclude_id) 13758c2ecf20Sopenharmony_ci continue; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci io_lock = fnic_io_lock_tag(fnic, i); 13788c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 13798c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(fnic->lport->host, i); 13808c2ecf20Sopenharmony_ci if (!sc) { 13818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 13828c2ecf20Sopenharmony_ci continue; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 13868c2ecf20Sopenharmony_ci if ((CMD_FLAGS(sc) & FNIC_DEVICE_RESET) && 13878c2ecf20Sopenharmony_ci !(CMD_FLAGS(sc) & FNIC_DEV_RST_DONE)) { 13888c2ecf20Sopenharmony_ci /* 13898c2ecf20Sopenharmony_ci * We will be here only when FW completes reset 13908c2ecf20Sopenharmony_ci * without sending completions for outstanding ios. 13918c2ecf20Sopenharmony_ci */ 13928c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_DEV_RST_DONE; 13938c2ecf20Sopenharmony_ci if (io_req && io_req->dr_done) 13948c2ecf20Sopenharmony_ci complete(io_req->dr_done); 13958c2ecf20Sopenharmony_ci else if (io_req && io_req->abts_done) 13968c2ecf20Sopenharmony_ci complete(io_req->abts_done); 13978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 13988c2ecf20Sopenharmony_ci continue; 13998c2ecf20Sopenharmony_ci } else if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) { 14008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 14018c2ecf20Sopenharmony_ci continue; 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci if (!io_req) { 14048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 14058c2ecf20Sopenharmony_ci continue; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci /* 14138c2ecf20Sopenharmony_ci * If there is a scsi_cmnd associated with this io_req, then 14148c2ecf20Sopenharmony_ci * free the corresponding state 14158c2ecf20Sopenharmony_ci */ 14168c2ecf20Sopenharmony_ci start_time = io_req->start_time; 14178c2ecf20Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 14188c2ecf20Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci sc->result = DID_TRANSPORT_DISRUPTED << 16; 14218c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 14228c2ecf20Sopenharmony_ci "%s: tag:0x%x : sc:0x%p duration = %lu DID_TRANSPORT_DISRUPTED\n", 14238c2ecf20Sopenharmony_ci __func__, sc->request->tag, sc, 14248c2ecf20Sopenharmony_ci (jiffies - start_time)); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (atomic64_read(&fnic->io_cmpl_skip)) 14278c2ecf20Sopenharmony_ci atomic64_dec(&fnic->io_cmpl_skip); 14288c2ecf20Sopenharmony_ci else 14298c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_completions); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci /* Complete the command to SCSI */ 14328c2ecf20Sopenharmony_ci if (sc->scsi_done) { 14338c2ecf20Sopenharmony_ci if (!(CMD_FLAGS(sc) & FNIC_IO_ISSUED)) 14348c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 14358c2ecf20Sopenharmony_ci "Calling done for IO not issued to fw: tag:0x%x sc:0x%p\n", 14368c2ecf20Sopenharmony_ci sc->request->tag, sc); 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_cleanup_io, 14398c2ecf20Sopenharmony_ci sc->device->host->host_no, i, sc, 14408c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 14418c2ecf20Sopenharmony_ci 0, ((u64)sc->cmnd[0] << 32 | 14428c2ecf20Sopenharmony_ci (u64)sc->cmnd[2] << 24 | 14438c2ecf20Sopenharmony_ci (u64)sc->cmnd[3] << 16 | 14448c2ecf20Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), 14458c2ecf20Sopenharmony_ci (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci sc->scsi_done(sc); 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci} 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_civoid fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, 14538c2ecf20Sopenharmony_ci struct fcpio_host_req *desc) 14548c2ecf20Sopenharmony_ci{ 14558c2ecf20Sopenharmony_ci u32 id; 14568c2ecf20Sopenharmony_ci struct fnic *fnic = vnic_dev_priv(wq->vdev); 14578c2ecf20Sopenharmony_ci struct fnic_io_req *io_req; 14588c2ecf20Sopenharmony_ci struct scsi_cmnd *sc; 14598c2ecf20Sopenharmony_ci unsigned long flags; 14608c2ecf20Sopenharmony_ci spinlock_t *io_lock; 14618c2ecf20Sopenharmony_ci unsigned long start_time = 0; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci /* get the tag reference */ 14648c2ecf20Sopenharmony_ci fcpio_tag_id_dec(&desc->hdr.tag, &id); 14658c2ecf20Sopenharmony_ci id &= FNIC_TAG_MASK; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci if (id >= fnic->fnic_max_tag_id) 14688c2ecf20Sopenharmony_ci return; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(fnic->lport->host, id); 14718c2ecf20Sopenharmony_ci if (!sc) 14728c2ecf20Sopenharmony_ci return; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 14758c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci /* Get the IO context which this desc refers to */ 14788c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci /* fnic interrupts are turned off by now */ 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci if (!io_req) { 14838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 14848c2ecf20Sopenharmony_ci goto wq_copy_cleanup_scsi_cmd; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci start_time = io_req->start_time; 14928c2ecf20Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 14938c2ecf20Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ciwq_copy_cleanup_scsi_cmd: 14968c2ecf20Sopenharmony_ci sc->result = DID_NO_CONNECT << 16; 14978c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "wq_copy_cleanup_handler:" 14988c2ecf20Sopenharmony_ci " DID_NO_CONNECT\n"); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci if (sc->scsi_done) { 15018c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_wq_copy_cleanup_handler, 15028c2ecf20Sopenharmony_ci sc->device->host->host_no, id, sc, 15038c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 15048c2ecf20Sopenharmony_ci 0, ((u64)sc->cmnd[0] << 32 | 15058c2ecf20Sopenharmony_ci (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | 15068c2ecf20Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), 15078c2ecf20Sopenharmony_ci (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci sc->scsi_done(sc); 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci} 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_cistatic inline int fnic_queue_abort_io_req(struct fnic *fnic, int tag, 15148c2ecf20Sopenharmony_ci u32 task_req, u8 *fc_lun, 15158c2ecf20Sopenharmony_ci struct fnic_io_req *io_req) 15168c2ecf20Sopenharmony_ci{ 15178c2ecf20Sopenharmony_ci struct vnic_wq_copy *wq = &fnic->wq_copy[0]; 15188c2ecf20Sopenharmony_ci struct Scsi_Host *host = fnic->lport->host; 15198c2ecf20Sopenharmony_ci struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; 15208c2ecf20Sopenharmony_ci unsigned long flags; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci spin_lock_irqsave(host->host_lock, flags); 15238c2ecf20Sopenharmony_ci if (unlikely(fnic_chk_state_flags_locked(fnic, 15248c2ecf20Sopenharmony_ci FNIC_FLAGS_IO_BLOCKED))) { 15258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, flags); 15268c2ecf20Sopenharmony_ci return 1; 15278c2ecf20Sopenharmony_ci } else 15288c2ecf20Sopenharmony_ci atomic_inc(&fnic->in_flight); 15298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, flags); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) 15348c2ecf20Sopenharmony_ci free_wq_copy_descs(fnic, wq); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci if (!vnic_wq_copy_desc_avail(wq)) { 15378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); 15388c2ecf20Sopenharmony_ci atomic_dec(&fnic->in_flight); 15398c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 15408c2ecf20Sopenharmony_ci "fnic_queue_abort_io_req: failure: no descriptors\n"); 15418c2ecf20Sopenharmony_ci atomic64_inc(&misc_stats->abts_cpwq_alloc_failures); 15428c2ecf20Sopenharmony_ci return 1; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci fnic_queue_wq_copy_desc_itmf(wq, tag | FNIC_TAG_ABORT, 15458c2ecf20Sopenharmony_ci 0, task_req, tag, fc_lun, io_req->port_id, 15468c2ecf20Sopenharmony_ci fnic->config.ra_tov, fnic->config.ed_tov); 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); 15498c2ecf20Sopenharmony_ci if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) > 15508c2ecf20Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs)) 15518c2ecf20Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, 15528c2ecf20Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs)); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); 15558c2ecf20Sopenharmony_ci atomic_dec(&fnic->in_flight); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci return 0; 15588c2ecf20Sopenharmony_ci} 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_cistatic void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id) 15618c2ecf20Sopenharmony_ci{ 15628c2ecf20Sopenharmony_ci int tag; 15638c2ecf20Sopenharmony_ci int abt_tag; 15648c2ecf20Sopenharmony_ci int term_cnt = 0; 15658c2ecf20Sopenharmony_ci struct fnic_io_req *io_req; 15668c2ecf20Sopenharmony_ci spinlock_t *io_lock; 15678c2ecf20Sopenharmony_ci unsigned long flags; 15688c2ecf20Sopenharmony_ci struct scsi_cmnd *sc; 15698c2ecf20Sopenharmony_ci struct reset_stats *reset_stats = &fnic->fnic_stats.reset_stats; 15708c2ecf20Sopenharmony_ci struct terminate_stats *term_stats = &fnic->fnic_stats.term_stats; 15718c2ecf20Sopenharmony_ci struct scsi_lun fc_lun; 15728c2ecf20Sopenharmony_ci enum fnic_ioreq_state old_ioreq_state; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 15758c2ecf20Sopenharmony_ci fnic->lport->host, 15768c2ecf20Sopenharmony_ci "fnic_rport_exch_reset called portid 0x%06x\n", 15778c2ecf20Sopenharmony_ci port_id); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci if (fnic->in_remove) 15808c2ecf20Sopenharmony_ci return; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci for (tag = 0; tag < fnic->fnic_max_tag_id; tag++) { 15838c2ecf20Sopenharmony_ci abt_tag = tag; 15848c2ecf20Sopenharmony_ci io_lock = fnic_io_lock_tag(fnic, tag); 15858c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 15868c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(fnic->lport->host, tag); 15878c2ecf20Sopenharmony_ci if (!sc) { 15888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 15898c2ecf20Sopenharmony_ci continue; 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci if (!io_req || io_req->port_id != port_id) { 15958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 15968c2ecf20Sopenharmony_ci continue; 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci if ((CMD_FLAGS(sc) & FNIC_DEVICE_RESET) && 16008c2ecf20Sopenharmony_ci (!(CMD_FLAGS(sc) & FNIC_DEV_RST_ISSUED))) { 16018c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 16028c2ecf20Sopenharmony_ci "fnic_rport_exch_reset dev rst not pending sc 0x%p\n", 16038c2ecf20Sopenharmony_ci sc); 16048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 16058c2ecf20Sopenharmony_ci continue; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci /* 16098c2ecf20Sopenharmony_ci * Found IO that is still pending with firmware and 16108c2ecf20Sopenharmony_ci * belongs to rport that went away 16118c2ecf20Sopenharmony_ci */ 16128c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { 16138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 16148c2ecf20Sopenharmony_ci continue; 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci if (io_req->abts_done) { 16178c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 16188c2ecf20Sopenharmony_ci "fnic_rport_exch_reset: io_req->abts_done is set " 16198c2ecf20Sopenharmony_ci "state is %s\n", 16208c2ecf20Sopenharmony_ci fnic_ioreq_state_to_str(CMD_STATE(sc))); 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (!(CMD_FLAGS(sc) & FNIC_IO_ISSUED)) { 16248c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 16258c2ecf20Sopenharmony_ci "rport_exch_reset " 16268c2ecf20Sopenharmony_ci "IO not yet issued %p tag 0x%x flags " 16278c2ecf20Sopenharmony_ci "%x state %d\n", 16288c2ecf20Sopenharmony_ci sc, tag, CMD_FLAGS(sc), CMD_STATE(sc)); 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci old_ioreq_state = CMD_STATE(sc); 16318c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; 16328c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; 16338c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) { 16348c2ecf20Sopenharmony_ci atomic64_inc(&reset_stats->device_reset_terminates); 16358c2ecf20Sopenharmony_ci abt_tag = (tag | FNIC_TAG_DEV_RST); 16368c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 16378c2ecf20Sopenharmony_ci "fnic_rport_exch_reset dev rst sc 0x%p\n", 16388c2ecf20Sopenharmony_ci sc); 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci BUG_ON(io_req->abts_done); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 16448c2ecf20Sopenharmony_ci "fnic_rport_reset_exch: Issuing abts\n"); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci /* Now queue the abort command to firmware */ 16498c2ecf20Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci if (fnic_queue_abort_io_req(fnic, abt_tag, 16528c2ecf20Sopenharmony_ci FCPIO_ITMF_ABT_TASK_TERM, 16538c2ecf20Sopenharmony_ci fc_lun.scsi_lun, io_req)) { 16548c2ecf20Sopenharmony_ci /* 16558c2ecf20Sopenharmony_ci * Revert the cmd state back to old state, if 16568c2ecf20Sopenharmony_ci * it hasn't changed in between. This cmd will get 16578c2ecf20Sopenharmony_ci * aborted later by scsi_eh, or cleaned up during 16588c2ecf20Sopenharmony_ci * lun reset 16598c2ecf20Sopenharmony_ci */ 16608c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 16618c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) 16628c2ecf20Sopenharmony_ci CMD_STATE(sc) = old_ioreq_state; 16638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 16648c2ecf20Sopenharmony_ci } else { 16658c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 16668c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) 16678c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED; 16688c2ecf20Sopenharmony_ci else 16698c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_INTERNAL_TERM_ISSUED; 16708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 16718c2ecf20Sopenharmony_ci atomic64_inc(&term_stats->terminates); 16728c2ecf20Sopenharmony_ci term_cnt++; 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci } 16758c2ecf20Sopenharmony_ci if (term_cnt > atomic64_read(&term_stats->max_terminates)) 16768c2ecf20Sopenharmony_ci atomic64_set(&term_stats->max_terminates, term_cnt); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci} 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_civoid fnic_terminate_rport_io(struct fc_rport *rport) 16818c2ecf20Sopenharmony_ci{ 16828c2ecf20Sopenharmony_ci int tag; 16838c2ecf20Sopenharmony_ci int abt_tag; 16848c2ecf20Sopenharmony_ci int term_cnt = 0; 16858c2ecf20Sopenharmony_ci struct fnic_io_req *io_req; 16868c2ecf20Sopenharmony_ci spinlock_t *io_lock; 16878c2ecf20Sopenharmony_ci unsigned long flags; 16888c2ecf20Sopenharmony_ci struct scsi_cmnd *sc; 16898c2ecf20Sopenharmony_ci struct scsi_lun fc_lun; 16908c2ecf20Sopenharmony_ci struct fc_rport_libfc_priv *rdata; 16918c2ecf20Sopenharmony_ci struct fc_lport *lport; 16928c2ecf20Sopenharmony_ci struct fnic *fnic; 16938c2ecf20Sopenharmony_ci struct fc_rport *cmd_rport; 16948c2ecf20Sopenharmony_ci struct reset_stats *reset_stats; 16958c2ecf20Sopenharmony_ci struct terminate_stats *term_stats; 16968c2ecf20Sopenharmony_ci enum fnic_ioreq_state old_ioreq_state; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci if (!rport) { 16998c2ecf20Sopenharmony_ci printk(KERN_ERR "fnic_terminate_rport_io: rport is NULL\n"); 17008c2ecf20Sopenharmony_ci return; 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci rdata = rport->dd_data; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci if (!rdata) { 17058c2ecf20Sopenharmony_ci printk(KERN_ERR "fnic_terminate_rport_io: rdata is NULL\n"); 17068c2ecf20Sopenharmony_ci return; 17078c2ecf20Sopenharmony_ci } 17088c2ecf20Sopenharmony_ci lport = rdata->local_port; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci if (!lport) { 17118c2ecf20Sopenharmony_ci printk(KERN_ERR "fnic_terminate_rport_io: lport is NULL\n"); 17128c2ecf20Sopenharmony_ci return; 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci fnic = lport_priv(lport); 17158c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 17168c2ecf20Sopenharmony_ci fnic->lport->host, "fnic_terminate_rport_io called" 17178c2ecf20Sopenharmony_ci " wwpn 0x%llx, wwnn0x%llx, rport 0x%p, portid 0x%06x\n", 17188c2ecf20Sopenharmony_ci rport->port_name, rport->node_name, rport, 17198c2ecf20Sopenharmony_ci rport->port_id); 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci if (fnic->in_remove) 17228c2ecf20Sopenharmony_ci return; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci reset_stats = &fnic->fnic_stats.reset_stats; 17258c2ecf20Sopenharmony_ci term_stats = &fnic->fnic_stats.term_stats; 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci for (tag = 0; tag < fnic->fnic_max_tag_id; tag++) { 17288c2ecf20Sopenharmony_ci abt_tag = tag; 17298c2ecf20Sopenharmony_ci io_lock = fnic_io_lock_tag(fnic, tag); 17308c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 17318c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(fnic->lport->host, tag); 17328c2ecf20Sopenharmony_ci if (!sc) { 17338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 17348c2ecf20Sopenharmony_ci continue; 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci cmd_rport = starget_to_rport(scsi_target(sc->device)); 17388c2ecf20Sopenharmony_ci if (rport != cmd_rport) { 17398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 17408c2ecf20Sopenharmony_ci continue; 17418c2ecf20Sopenharmony_ci } 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci if (!io_req || rport != cmd_rport) { 17468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 17478c2ecf20Sopenharmony_ci continue; 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci if ((CMD_FLAGS(sc) & FNIC_DEVICE_RESET) && 17518c2ecf20Sopenharmony_ci (!(CMD_FLAGS(sc) & FNIC_DEV_RST_ISSUED))) { 17528c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 17538c2ecf20Sopenharmony_ci "fnic_terminate_rport_io dev rst not pending sc 0x%p\n", 17548c2ecf20Sopenharmony_ci sc); 17558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 17568c2ecf20Sopenharmony_ci continue; 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci /* 17598c2ecf20Sopenharmony_ci * Found IO that is still pending with firmware and 17608c2ecf20Sopenharmony_ci * belongs to rport that went away 17618c2ecf20Sopenharmony_ci */ 17628c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { 17638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 17648c2ecf20Sopenharmony_ci continue; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci if (io_req->abts_done) { 17678c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 17688c2ecf20Sopenharmony_ci "fnic_terminate_rport_io: io_req->abts_done is set " 17698c2ecf20Sopenharmony_ci "state is %s\n", 17708c2ecf20Sopenharmony_ci fnic_ioreq_state_to_str(CMD_STATE(sc))); 17718c2ecf20Sopenharmony_ci } 17728c2ecf20Sopenharmony_ci if (!(CMD_FLAGS(sc) & FNIC_IO_ISSUED)) { 17738c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 17748c2ecf20Sopenharmony_ci "fnic_terminate_rport_io " 17758c2ecf20Sopenharmony_ci "IO not yet issued %p tag 0x%x flags " 17768c2ecf20Sopenharmony_ci "%x state %d\n", 17778c2ecf20Sopenharmony_ci sc, tag, CMD_FLAGS(sc), CMD_STATE(sc)); 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci old_ioreq_state = CMD_STATE(sc); 17808c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; 17818c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; 17828c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) { 17838c2ecf20Sopenharmony_ci atomic64_inc(&reset_stats->device_reset_terminates); 17848c2ecf20Sopenharmony_ci abt_tag = (tag | FNIC_TAG_DEV_RST); 17858c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 17868c2ecf20Sopenharmony_ci "fnic_terminate_rport_io dev rst sc 0x%p\n", sc); 17878c2ecf20Sopenharmony_ci } 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci BUG_ON(io_req->abts_done); 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 17928c2ecf20Sopenharmony_ci fnic->lport->host, 17938c2ecf20Sopenharmony_ci "fnic_terminate_rport_io: Issuing abts\n"); 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci /* Now queue the abort command to firmware */ 17988c2ecf20Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci if (fnic_queue_abort_io_req(fnic, abt_tag, 18018c2ecf20Sopenharmony_ci FCPIO_ITMF_ABT_TASK_TERM, 18028c2ecf20Sopenharmony_ci fc_lun.scsi_lun, io_req)) { 18038c2ecf20Sopenharmony_ci /* 18048c2ecf20Sopenharmony_ci * Revert the cmd state back to old state, if 18058c2ecf20Sopenharmony_ci * it hasn't changed in between. This cmd will get 18068c2ecf20Sopenharmony_ci * aborted later by scsi_eh, or cleaned up during 18078c2ecf20Sopenharmony_ci * lun reset 18088c2ecf20Sopenharmony_ci */ 18098c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 18108c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) 18118c2ecf20Sopenharmony_ci CMD_STATE(sc) = old_ioreq_state; 18128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 18138c2ecf20Sopenharmony_ci } else { 18148c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 18158c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) 18168c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED; 18178c2ecf20Sopenharmony_ci else 18188c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_INTERNAL_TERM_ISSUED; 18198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 18208c2ecf20Sopenharmony_ci atomic64_inc(&term_stats->terminates); 18218c2ecf20Sopenharmony_ci term_cnt++; 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci } 18248c2ecf20Sopenharmony_ci if (term_cnt > atomic64_read(&term_stats->max_terminates)) 18258c2ecf20Sopenharmony_ci atomic64_set(&term_stats->max_terminates, term_cnt); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci} 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci/* 18308c2ecf20Sopenharmony_ci * This function is exported to SCSI for sending abort cmnds. 18318c2ecf20Sopenharmony_ci * A SCSI IO is represented by a io_req in the driver. 18328c2ecf20Sopenharmony_ci * The ioreq is linked to the SCSI Cmd, thus a link with the ULP's IO. 18338c2ecf20Sopenharmony_ci */ 18348c2ecf20Sopenharmony_ciint fnic_abort_cmd(struct scsi_cmnd *sc) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct fc_lport *lp; 18378c2ecf20Sopenharmony_ci struct fnic *fnic; 18388c2ecf20Sopenharmony_ci struct fnic_io_req *io_req = NULL; 18398c2ecf20Sopenharmony_ci struct fc_rport *rport; 18408c2ecf20Sopenharmony_ci spinlock_t *io_lock; 18418c2ecf20Sopenharmony_ci unsigned long flags; 18428c2ecf20Sopenharmony_ci unsigned long start_time = 0; 18438c2ecf20Sopenharmony_ci int ret = SUCCESS; 18448c2ecf20Sopenharmony_ci u32 task_req = 0; 18458c2ecf20Sopenharmony_ci struct scsi_lun fc_lun; 18468c2ecf20Sopenharmony_ci struct fnic_stats *fnic_stats; 18478c2ecf20Sopenharmony_ci struct abort_stats *abts_stats; 18488c2ecf20Sopenharmony_ci struct terminate_stats *term_stats; 18498c2ecf20Sopenharmony_ci enum fnic_ioreq_state old_ioreq_state; 18508c2ecf20Sopenharmony_ci int tag; 18518c2ecf20Sopenharmony_ci unsigned long abt_issued_time; 18528c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(tm_done); 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci /* Wait for rport to unblock */ 18558c2ecf20Sopenharmony_ci fc_block_scsi_eh(sc); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci /* Get local-port, check ready and link up */ 18588c2ecf20Sopenharmony_ci lp = shost_priv(sc->device->host); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci fnic = lport_priv(lp); 18618c2ecf20Sopenharmony_ci fnic_stats = &fnic->fnic_stats; 18628c2ecf20Sopenharmony_ci abts_stats = &fnic->fnic_stats.abts_stats; 18638c2ecf20Sopenharmony_ci term_stats = &fnic->fnic_stats.term_stats; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci rport = starget_to_rport(scsi_target(sc->device)); 18668c2ecf20Sopenharmony_ci tag = sc->request->tag; 18678c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 18688c2ecf20Sopenharmony_ci fnic->lport->host, 18698c2ecf20Sopenharmony_ci "Abort Cmd called FCID 0x%x, LUN 0x%llx TAG %x flags %x\n", 18708c2ecf20Sopenharmony_ci rport->port_id, sc->device->lun, tag, CMD_FLAGS(sc)); 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci CMD_FLAGS(sc) = FNIC_NO_FLAGS; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci if (lp->state != LPORT_ST_READY || !(lp->link_up)) { 18758c2ecf20Sopenharmony_ci ret = FAILED; 18768c2ecf20Sopenharmony_ci goto fnic_abort_cmd_end; 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci /* 18808c2ecf20Sopenharmony_ci * Avoid a race between SCSI issuing the abort and the device 18818c2ecf20Sopenharmony_ci * completing the command. 18828c2ecf20Sopenharmony_ci * 18838c2ecf20Sopenharmony_ci * If the command is already completed by the fw cmpl code, 18848c2ecf20Sopenharmony_ci * we just return SUCCESS from here. This means that the abort 18858c2ecf20Sopenharmony_ci * succeeded. In the SCSI ML, since the timeout for command has 18868c2ecf20Sopenharmony_ci * happened, the completion wont actually complete the command 18878c2ecf20Sopenharmony_ci * and it will be considered as an aborted command 18888c2ecf20Sopenharmony_ci * 18898c2ecf20Sopenharmony_ci * The CMD_SP will not be cleared except while holding io_req_lock. 18908c2ecf20Sopenharmony_ci */ 18918c2ecf20Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 18928c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 18938c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 18948c2ecf20Sopenharmony_ci if (!io_req) { 18958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 18968c2ecf20Sopenharmony_ci goto fnic_abort_cmd_end; 18978c2ecf20Sopenharmony_ci } 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci io_req->abts_done = &tm_done; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { 19028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 19038c2ecf20Sopenharmony_ci goto wait_pending; 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci abt_issued_time = jiffies_to_msecs(jiffies) - jiffies_to_msecs(io_req->start_time); 19078c2ecf20Sopenharmony_ci if (abt_issued_time <= 6000) 19088c2ecf20Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_0_to_6_sec); 19098c2ecf20Sopenharmony_ci else if (abt_issued_time > 6000 && abt_issued_time <= 20000) 19108c2ecf20Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_6_to_20_sec); 19118c2ecf20Sopenharmony_ci else if (abt_issued_time > 20000 && abt_issued_time <= 30000) 19128c2ecf20Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_20_to_30_sec); 19138c2ecf20Sopenharmony_ci else if (abt_issued_time > 30000 && abt_issued_time <= 40000) 19148c2ecf20Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_30_to_40_sec); 19158c2ecf20Sopenharmony_ci else if (abt_issued_time > 40000 && abt_issued_time <= 50000) 19168c2ecf20Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_40_to_50_sec); 19178c2ecf20Sopenharmony_ci else if (abt_issued_time > 50000 && abt_issued_time <= 60000) 19188c2ecf20Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_50_to_60_sec); 19198c2ecf20Sopenharmony_ci else 19208c2ecf20Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_greater_than_60_sec); 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 19238c2ecf20Sopenharmony_ci "CBD Opcode: %02x Abort issued time: %lu msec\n", sc->cmnd[0], abt_issued_time); 19248c2ecf20Sopenharmony_ci /* 19258c2ecf20Sopenharmony_ci * Command is still pending, need to abort it 19268c2ecf20Sopenharmony_ci * If the firmware completes the command after this point, 19278c2ecf20Sopenharmony_ci * the completion wont be done till mid-layer, since abort 19288c2ecf20Sopenharmony_ci * has already started. 19298c2ecf20Sopenharmony_ci */ 19308c2ecf20Sopenharmony_ci old_ioreq_state = CMD_STATE(sc); 19318c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; 19328c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci /* 19378c2ecf20Sopenharmony_ci * Check readiness of the remote port. If the path to remote 19388c2ecf20Sopenharmony_ci * port is up, then send abts to the remote port to terminate 19398c2ecf20Sopenharmony_ci * the IO. Else, just locally terminate the IO in the firmware 19408c2ecf20Sopenharmony_ci */ 19418c2ecf20Sopenharmony_ci if (fc_remote_port_chkready(rport) == 0) 19428c2ecf20Sopenharmony_ci task_req = FCPIO_ITMF_ABT_TASK; 19438c2ecf20Sopenharmony_ci else { 19448c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.rport_not_ready); 19458c2ecf20Sopenharmony_ci task_req = FCPIO_ITMF_ABT_TASK_TERM; 19468c2ecf20Sopenharmony_ci } 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci /* Now queue the abort command to firmware */ 19498c2ecf20Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci if (fnic_queue_abort_io_req(fnic, sc->request->tag, task_req, 19528c2ecf20Sopenharmony_ci fc_lun.scsi_lun, io_req)) { 19538c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 19548c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) 19558c2ecf20Sopenharmony_ci CMD_STATE(sc) = old_ioreq_state; 19568c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 19578c2ecf20Sopenharmony_ci if (io_req) 19588c2ecf20Sopenharmony_ci io_req->abts_done = NULL; 19598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 19608c2ecf20Sopenharmony_ci ret = FAILED; 19618c2ecf20Sopenharmony_ci goto fnic_abort_cmd_end; 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ci if (task_req == FCPIO_ITMF_ABT_TASK) { 19648c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_ABTS_ISSUED; 19658c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->abts_stats.aborts); 19668c2ecf20Sopenharmony_ci } else { 19678c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_TERM_ISSUED; 19688c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->term_stats.terminates); 19698c2ecf20Sopenharmony_ci } 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci /* 19728c2ecf20Sopenharmony_ci * We queued an abort IO, wait for its completion. 19738c2ecf20Sopenharmony_ci * Once the firmware completes the abort command, it will 19748c2ecf20Sopenharmony_ci * wake up this thread. 19758c2ecf20Sopenharmony_ci */ 19768c2ecf20Sopenharmony_ci wait_pending: 19778c2ecf20Sopenharmony_ci wait_for_completion_timeout(&tm_done, 19788c2ecf20Sopenharmony_ci msecs_to_jiffies 19798c2ecf20Sopenharmony_ci (2 * fnic->config.ra_tov + 19808c2ecf20Sopenharmony_ci fnic->config.ed_tov)); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci /* Check the abort status */ 19838c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 19868c2ecf20Sopenharmony_ci if (!io_req) { 19878c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.ioreq_null); 19888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 19898c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_ABT_TERM_REQ_NULL; 19908c2ecf20Sopenharmony_ci ret = FAILED; 19918c2ecf20Sopenharmony_ci goto fnic_abort_cmd_end; 19928c2ecf20Sopenharmony_ci } 19938c2ecf20Sopenharmony_ci io_req->abts_done = NULL; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci /* fw did not complete abort, timed out */ 19968c2ecf20Sopenharmony_ci if (CMD_ABTS_STATUS(sc) == FCPIO_INVALID_CODE) { 19978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 19988c2ecf20Sopenharmony_ci if (task_req == FCPIO_ITMF_ABT_TASK) { 19998c2ecf20Sopenharmony_ci atomic64_inc(&abts_stats->abort_drv_timeouts); 20008c2ecf20Sopenharmony_ci } else { 20018c2ecf20Sopenharmony_ci atomic64_inc(&term_stats->terminate_drv_timeouts); 20028c2ecf20Sopenharmony_ci } 20038c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_ABT_TERM_TIMED_OUT; 20048c2ecf20Sopenharmony_ci ret = FAILED; 20058c2ecf20Sopenharmony_ci goto fnic_abort_cmd_end; 20068c2ecf20Sopenharmony_ci } 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci /* IO out of order */ 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci if (!(CMD_FLAGS(sc) & (FNIC_IO_ABORTED | FNIC_IO_DONE))) { 20118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 20128c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 20138c2ecf20Sopenharmony_ci "Issuing Host reset due to out of order IO\n"); 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci ret = FAILED; 20168c2ecf20Sopenharmony_ci goto fnic_abort_cmd_end; 20178c2ecf20Sopenharmony_ci } 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_ABTS_COMPLETE; 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci start_time = io_req->start_time; 20228c2ecf20Sopenharmony_ci /* 20238c2ecf20Sopenharmony_ci * firmware completed the abort, check the status, 20248c2ecf20Sopenharmony_ci * free the io_req if successful. If abort fails, 20258c2ecf20Sopenharmony_ci * Device reset will clean the I/O. 20268c2ecf20Sopenharmony_ci */ 20278c2ecf20Sopenharmony_ci if (CMD_ABTS_STATUS(sc) == FCPIO_SUCCESS) 20288c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 20298c2ecf20Sopenharmony_ci else { 20308c2ecf20Sopenharmony_ci ret = FAILED; 20318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 20328c2ecf20Sopenharmony_ci goto fnic_abort_cmd_end; 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 20388c2ecf20Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci if (sc->scsi_done) { 20418c2ecf20Sopenharmony_ci /* Call SCSI completion function to complete the IO */ 20428c2ecf20Sopenharmony_ci sc->result = (DID_ABORT << 16); 20438c2ecf20Sopenharmony_ci sc->scsi_done(sc); 20448c2ecf20Sopenharmony_ci atomic64_dec(&fnic_stats->io_stats.active_ios); 20458c2ecf20Sopenharmony_ci if (atomic64_read(&fnic->io_cmpl_skip)) 20468c2ecf20Sopenharmony_ci atomic64_dec(&fnic->io_cmpl_skip); 20478c2ecf20Sopenharmony_ci else 20488c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_completions); 20498c2ecf20Sopenharmony_ci } 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_cifnic_abort_cmd_end: 20528c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_abort_cmd, sc->device->host->host_no, 20538c2ecf20Sopenharmony_ci sc->request->tag, sc, 20548c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 20558c2ecf20Sopenharmony_ci 0, ((u64)sc->cmnd[0] << 32 | 20568c2ecf20Sopenharmony_ci (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | 20578c2ecf20Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), 20588c2ecf20Sopenharmony_ci (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 20618c2ecf20Sopenharmony_ci "Returning from abort cmd type %x %s\n", task_req, 20628c2ecf20Sopenharmony_ci (ret == SUCCESS) ? 20638c2ecf20Sopenharmony_ci "SUCCESS" : "FAILED"); 20648c2ecf20Sopenharmony_ci return ret; 20658c2ecf20Sopenharmony_ci} 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_cistatic inline int fnic_queue_dr_io_req(struct fnic *fnic, 20688c2ecf20Sopenharmony_ci struct scsi_cmnd *sc, 20698c2ecf20Sopenharmony_ci struct fnic_io_req *io_req) 20708c2ecf20Sopenharmony_ci{ 20718c2ecf20Sopenharmony_ci struct vnic_wq_copy *wq = &fnic->wq_copy[0]; 20728c2ecf20Sopenharmony_ci struct Scsi_Host *host = fnic->lport->host; 20738c2ecf20Sopenharmony_ci struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; 20748c2ecf20Sopenharmony_ci struct scsi_lun fc_lun; 20758c2ecf20Sopenharmony_ci int ret = 0; 20768c2ecf20Sopenharmony_ci unsigned long intr_flags; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci spin_lock_irqsave(host->host_lock, intr_flags); 20798c2ecf20Sopenharmony_ci if (unlikely(fnic_chk_state_flags_locked(fnic, 20808c2ecf20Sopenharmony_ci FNIC_FLAGS_IO_BLOCKED))) { 20818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, intr_flags); 20828c2ecf20Sopenharmony_ci return FAILED; 20838c2ecf20Sopenharmony_ci } else 20848c2ecf20Sopenharmony_ci atomic_inc(&fnic->in_flight); 20858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, intr_flags); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) 20908c2ecf20Sopenharmony_ci free_wq_copy_descs(fnic, wq); 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci if (!vnic_wq_copy_desc_avail(wq)) { 20938c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 20948c2ecf20Sopenharmony_ci "queue_dr_io_req failure - no descriptors\n"); 20958c2ecf20Sopenharmony_ci atomic64_inc(&misc_stats->devrst_cpwq_alloc_failures); 20968c2ecf20Sopenharmony_ci ret = -EAGAIN; 20978c2ecf20Sopenharmony_ci goto lr_io_req_end; 20988c2ecf20Sopenharmony_ci } 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci /* fill in the lun info */ 21018c2ecf20Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci fnic_queue_wq_copy_desc_itmf(wq, sc->request->tag | FNIC_TAG_DEV_RST, 21048c2ecf20Sopenharmony_ci 0, FCPIO_ITMF_LUN_RESET, SCSI_NO_TAG, 21058c2ecf20Sopenharmony_ci fc_lun.scsi_lun, io_req->port_id, 21068c2ecf20Sopenharmony_ci fnic->config.ra_tov, fnic->config.ed_tov); 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); 21098c2ecf20Sopenharmony_ci if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) > 21108c2ecf20Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs)) 21118c2ecf20Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, 21128c2ecf20Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs)); 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_cilr_io_req_end: 21158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); 21168c2ecf20Sopenharmony_ci atomic_dec(&fnic->in_flight); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci return ret; 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci/* 21228c2ecf20Sopenharmony_ci * Clean up any pending aborts on the lun 21238c2ecf20Sopenharmony_ci * For each outstanding IO on this lun, whose abort is not completed by fw, 21248c2ecf20Sopenharmony_ci * issue a local abort. Wait for abort to complete. Return 0 if all commands 21258c2ecf20Sopenharmony_ci * successfully aborted, 1 otherwise 21268c2ecf20Sopenharmony_ci */ 21278c2ecf20Sopenharmony_cistatic int fnic_clean_pending_aborts(struct fnic *fnic, 21288c2ecf20Sopenharmony_ci struct scsi_cmnd *lr_sc, 21298c2ecf20Sopenharmony_ci bool new_sc) 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci{ 21328c2ecf20Sopenharmony_ci int tag, abt_tag; 21338c2ecf20Sopenharmony_ci struct fnic_io_req *io_req; 21348c2ecf20Sopenharmony_ci spinlock_t *io_lock; 21358c2ecf20Sopenharmony_ci unsigned long flags; 21368c2ecf20Sopenharmony_ci int ret = 0; 21378c2ecf20Sopenharmony_ci struct scsi_cmnd *sc; 21388c2ecf20Sopenharmony_ci struct scsi_lun fc_lun; 21398c2ecf20Sopenharmony_ci struct scsi_device *lun_dev = lr_sc->device; 21408c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(tm_done); 21418c2ecf20Sopenharmony_ci enum fnic_ioreq_state old_ioreq_state; 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci for (tag = 0; tag < fnic->fnic_max_tag_id; tag++) { 21448c2ecf20Sopenharmony_ci io_lock = fnic_io_lock_tag(fnic, tag); 21458c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 21468c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(fnic->lport->host, tag); 21478c2ecf20Sopenharmony_ci /* 21488c2ecf20Sopenharmony_ci * ignore this lun reset cmd if issued using new SC 21498c2ecf20Sopenharmony_ci * or cmds that do not belong to this lun 21508c2ecf20Sopenharmony_ci */ 21518c2ecf20Sopenharmony_ci if (!sc || ((sc == lr_sc) && new_sc) || sc->device != lun_dev) { 21528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 21538c2ecf20Sopenharmony_ci continue; 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci if (!io_req || sc->device != lun_dev) { 21598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 21608c2ecf20Sopenharmony_ci continue; 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci /* 21648c2ecf20Sopenharmony_ci * Found IO that is still pending with firmware and 21658c2ecf20Sopenharmony_ci * belongs to the LUN that we are resetting 21668c2ecf20Sopenharmony_ci */ 21678c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 21688c2ecf20Sopenharmony_ci "Found IO in %s on lun\n", 21698c2ecf20Sopenharmony_ci fnic_ioreq_state_to_str(CMD_STATE(sc))); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { 21728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 21738c2ecf20Sopenharmony_ci continue; 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci if ((CMD_FLAGS(sc) & FNIC_DEVICE_RESET) && 21768c2ecf20Sopenharmony_ci (!(CMD_FLAGS(sc) & FNIC_DEV_RST_ISSUED))) { 21778c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 21788c2ecf20Sopenharmony_ci "%s dev rst not pending sc 0x%p\n", __func__, 21798c2ecf20Sopenharmony_ci sc); 21808c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 21818c2ecf20Sopenharmony_ci continue; 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci if (io_req->abts_done) 21858c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 21868c2ecf20Sopenharmony_ci "%s: io_req->abts_done is set state is %s\n", 21878c2ecf20Sopenharmony_ci __func__, fnic_ioreq_state_to_str(CMD_STATE(sc))); 21888c2ecf20Sopenharmony_ci old_ioreq_state = CMD_STATE(sc); 21898c2ecf20Sopenharmony_ci /* 21908c2ecf20Sopenharmony_ci * Any pending IO issued prior to reset is expected to be 21918c2ecf20Sopenharmony_ci * in abts pending state, if not we need to set 21928c2ecf20Sopenharmony_ci * FNIC_IOREQ_ABTS_PENDING to indicate the IO is abort pending. 21938c2ecf20Sopenharmony_ci * When IO is completed, the IO will be handed over and 21948c2ecf20Sopenharmony_ci * handled in this function. 21958c2ecf20Sopenharmony_ci */ 21968c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci BUG_ON(io_req->abts_done); 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci abt_tag = tag; 22018c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) { 22028c2ecf20Sopenharmony_ci abt_tag |= FNIC_TAG_DEV_RST; 22038c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 22048c2ecf20Sopenharmony_ci "%s: dev rst sc 0x%p\n", __func__, sc); 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; 22088c2ecf20Sopenharmony_ci io_req->abts_done = &tm_done; 22098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci /* Now queue the abort command to firmware */ 22128c2ecf20Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci if (fnic_queue_abort_io_req(fnic, abt_tag, 22158c2ecf20Sopenharmony_ci FCPIO_ITMF_ABT_TASK_TERM, 22168c2ecf20Sopenharmony_ci fc_lun.scsi_lun, io_req)) { 22178c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 22188c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 22198c2ecf20Sopenharmony_ci if (io_req) 22208c2ecf20Sopenharmony_ci io_req->abts_done = NULL; 22218c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) 22228c2ecf20Sopenharmony_ci CMD_STATE(sc) = old_ioreq_state; 22238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 22248c2ecf20Sopenharmony_ci ret = 1; 22258c2ecf20Sopenharmony_ci goto clean_pending_aborts_end; 22268c2ecf20Sopenharmony_ci } else { 22278c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 22288c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) 22298c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED; 22308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 22318c2ecf20Sopenharmony_ci } 22328c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_INTERNAL_TERM_ISSUED; 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci wait_for_completion_timeout(&tm_done, 22358c2ecf20Sopenharmony_ci msecs_to_jiffies 22368c2ecf20Sopenharmony_ci (fnic->config.ed_tov)); 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci /* Recheck cmd state to check if it is now aborted */ 22398c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 22408c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 22418c2ecf20Sopenharmony_ci if (!io_req) { 22428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 22438c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_ABT_TERM_REQ_NULL; 22448c2ecf20Sopenharmony_ci continue; 22458c2ecf20Sopenharmony_ci } 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci io_req->abts_done = NULL; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci /* if abort is still pending with fw, fail */ 22508c2ecf20Sopenharmony_ci if (CMD_ABTS_STATUS(sc) == FCPIO_INVALID_CODE) { 22518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 22528c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_IO_ABT_TERM_DONE; 22538c2ecf20Sopenharmony_ci ret = 1; 22548c2ecf20Sopenharmony_ci goto clean_pending_aborts_end; 22558c2ecf20Sopenharmony_ci } 22568c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_ABTS_COMPLETE; 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci /* original sc used for lr is handled by dev reset code */ 22598c2ecf20Sopenharmony_ci if (sc != lr_sc) 22608c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 22618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci /* original sc used for lr is handled by dev reset code */ 22648c2ecf20Sopenharmony_ci if (sc != lr_sc) { 22658c2ecf20Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 22668c2ecf20Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 22678c2ecf20Sopenharmony_ci } 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci /* 22708c2ecf20Sopenharmony_ci * Any IO is returned during reset, it needs to call scsi_done 22718c2ecf20Sopenharmony_ci * to return the scsi_cmnd to upper layer. 22728c2ecf20Sopenharmony_ci */ 22738c2ecf20Sopenharmony_ci if (sc->scsi_done) { 22748c2ecf20Sopenharmony_ci /* Set result to let upper SCSI layer retry */ 22758c2ecf20Sopenharmony_ci sc->result = DID_RESET << 16; 22768c2ecf20Sopenharmony_ci sc->scsi_done(sc); 22778c2ecf20Sopenharmony_ci } 22788c2ecf20Sopenharmony_ci } 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci schedule_timeout(msecs_to_jiffies(2 * fnic->config.ed_tov)); 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci /* walk again to check, if IOs are still pending in fw */ 22838c2ecf20Sopenharmony_ci if (fnic_is_abts_pending(fnic, lr_sc)) 22848c2ecf20Sopenharmony_ci ret = FAILED; 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ciclean_pending_aborts_end: 22878c2ecf20Sopenharmony_ci return ret; 22888c2ecf20Sopenharmony_ci} 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci/** 22918c2ecf20Sopenharmony_ci * fnic_scsi_host_start_tag 22928c2ecf20Sopenharmony_ci * Allocates tagid from host's tag list 22938c2ecf20Sopenharmony_ci **/ 22948c2ecf20Sopenharmony_cistatic inline int 22958c2ecf20Sopenharmony_cifnic_scsi_host_start_tag(struct fnic *fnic, struct scsi_cmnd *sc) 22968c2ecf20Sopenharmony_ci{ 22978c2ecf20Sopenharmony_ci struct request_queue *q = sc->request->q; 22988c2ecf20Sopenharmony_ci struct request *dummy; 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci dummy = blk_mq_alloc_request(q, REQ_OP_WRITE, BLK_MQ_REQ_NOWAIT); 23018c2ecf20Sopenharmony_ci if (IS_ERR(dummy)) 23028c2ecf20Sopenharmony_ci return SCSI_NO_TAG; 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci sc->tag = sc->request->tag = dummy->tag; 23058c2ecf20Sopenharmony_ci sc->host_scribble = (unsigned char *)dummy; 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci return dummy->tag; 23088c2ecf20Sopenharmony_ci} 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci/** 23118c2ecf20Sopenharmony_ci * fnic_scsi_host_end_tag 23128c2ecf20Sopenharmony_ci * frees tag allocated by fnic_scsi_host_start_tag. 23138c2ecf20Sopenharmony_ci **/ 23148c2ecf20Sopenharmony_cistatic inline void 23158c2ecf20Sopenharmony_cifnic_scsi_host_end_tag(struct fnic *fnic, struct scsi_cmnd *sc) 23168c2ecf20Sopenharmony_ci{ 23178c2ecf20Sopenharmony_ci struct request *dummy = (struct request *)sc->host_scribble; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci blk_mq_free_request(dummy); 23208c2ecf20Sopenharmony_ci} 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci/* 23238c2ecf20Sopenharmony_ci * SCSI Eh thread issues a Lun Reset when one or more commands on a LUN 23248c2ecf20Sopenharmony_ci * fail to get aborted. It calls driver's eh_device_reset with a SCSI command 23258c2ecf20Sopenharmony_ci * on the LUN. 23268c2ecf20Sopenharmony_ci */ 23278c2ecf20Sopenharmony_ciint fnic_device_reset(struct scsi_cmnd *sc) 23288c2ecf20Sopenharmony_ci{ 23298c2ecf20Sopenharmony_ci struct fc_lport *lp; 23308c2ecf20Sopenharmony_ci struct fnic *fnic; 23318c2ecf20Sopenharmony_ci struct fnic_io_req *io_req = NULL; 23328c2ecf20Sopenharmony_ci struct fc_rport *rport; 23338c2ecf20Sopenharmony_ci int status; 23348c2ecf20Sopenharmony_ci int ret = FAILED; 23358c2ecf20Sopenharmony_ci spinlock_t *io_lock; 23368c2ecf20Sopenharmony_ci unsigned long flags; 23378c2ecf20Sopenharmony_ci unsigned long start_time = 0; 23388c2ecf20Sopenharmony_ci struct scsi_lun fc_lun; 23398c2ecf20Sopenharmony_ci struct fnic_stats *fnic_stats; 23408c2ecf20Sopenharmony_ci struct reset_stats *reset_stats; 23418c2ecf20Sopenharmony_ci int tag = 0; 23428c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(tm_done); 23438c2ecf20Sopenharmony_ci int tag_gen_flag = 0; /*to track tags allocated by fnic driver*/ 23448c2ecf20Sopenharmony_ci bool new_sc = 0; 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci /* Wait for rport to unblock */ 23478c2ecf20Sopenharmony_ci fc_block_scsi_eh(sc); 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci /* Get local-port, check ready and link up */ 23508c2ecf20Sopenharmony_ci lp = shost_priv(sc->device->host); 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci fnic = lport_priv(lp); 23538c2ecf20Sopenharmony_ci fnic_stats = &fnic->fnic_stats; 23548c2ecf20Sopenharmony_ci reset_stats = &fnic->fnic_stats.reset_stats; 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci atomic64_inc(&reset_stats->device_resets); 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci rport = starget_to_rport(scsi_target(sc->device)); 23598c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 23608c2ecf20Sopenharmony_ci "Device reset called FCID 0x%x, LUN 0x%llx sc 0x%p\n", 23618c2ecf20Sopenharmony_ci rport->port_id, sc->device->lun, sc); 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci if (lp->state != LPORT_ST_READY || !(lp->link_up)) 23648c2ecf20Sopenharmony_ci goto fnic_device_reset_end; 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci /* Check if remote port up */ 23678c2ecf20Sopenharmony_ci if (fc_remote_port_chkready(rport)) { 23688c2ecf20Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.rport_not_ready); 23698c2ecf20Sopenharmony_ci goto fnic_device_reset_end; 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci CMD_FLAGS(sc) = FNIC_DEVICE_RESET; 23738c2ecf20Sopenharmony_ci /* Allocate tag if not present */ 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci tag = sc->request->tag; 23768c2ecf20Sopenharmony_ci if (unlikely(tag < 0)) { 23778c2ecf20Sopenharmony_ci /* 23788c2ecf20Sopenharmony_ci * Really should fix the midlayer to pass in a proper 23798c2ecf20Sopenharmony_ci * request for ioctls... 23808c2ecf20Sopenharmony_ci */ 23818c2ecf20Sopenharmony_ci tag = fnic_scsi_host_start_tag(fnic, sc); 23828c2ecf20Sopenharmony_ci if (unlikely(tag == SCSI_NO_TAG)) 23838c2ecf20Sopenharmony_ci goto fnic_device_reset_end; 23848c2ecf20Sopenharmony_ci tag_gen_flag = 1; 23858c2ecf20Sopenharmony_ci new_sc = 1; 23868c2ecf20Sopenharmony_ci } 23878c2ecf20Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 23888c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 23898c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci /* 23928c2ecf20Sopenharmony_ci * If there is a io_req attached to this command, then use it, 23938c2ecf20Sopenharmony_ci * else allocate a new one. 23948c2ecf20Sopenharmony_ci */ 23958c2ecf20Sopenharmony_ci if (!io_req) { 23968c2ecf20Sopenharmony_ci io_req = mempool_alloc(fnic->io_req_pool, GFP_ATOMIC); 23978c2ecf20Sopenharmony_ci if (!io_req) { 23988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 23998c2ecf20Sopenharmony_ci goto fnic_device_reset_end; 24008c2ecf20Sopenharmony_ci } 24018c2ecf20Sopenharmony_ci memset(io_req, 0, sizeof(*io_req)); 24028c2ecf20Sopenharmony_ci io_req->port_id = rport->port_id; 24038c2ecf20Sopenharmony_ci CMD_SP(sc) = (char *)io_req; 24048c2ecf20Sopenharmony_ci } 24058c2ecf20Sopenharmony_ci io_req->dr_done = &tm_done; 24068c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_CMD_PENDING; 24078c2ecf20Sopenharmony_ci CMD_LR_STATUS(sc) = FCPIO_INVALID_CODE; 24088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "TAG %x\n", tag); 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci /* 24138c2ecf20Sopenharmony_ci * issue the device reset, if enqueue failed, clean up the ioreq 24148c2ecf20Sopenharmony_ci * and break assoc with scsi cmd 24158c2ecf20Sopenharmony_ci */ 24168c2ecf20Sopenharmony_ci if (fnic_queue_dr_io_req(fnic, sc, io_req)) { 24178c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 24188c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 24198c2ecf20Sopenharmony_ci if (io_req) 24208c2ecf20Sopenharmony_ci io_req->dr_done = NULL; 24218c2ecf20Sopenharmony_ci goto fnic_device_reset_clean; 24228c2ecf20Sopenharmony_ci } 24238c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 24248c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_DEV_RST_ISSUED; 24258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci /* 24288c2ecf20Sopenharmony_ci * Wait on the local completion for LUN reset. The io_req may be 24298c2ecf20Sopenharmony_ci * freed while we wait since we hold no lock. 24308c2ecf20Sopenharmony_ci */ 24318c2ecf20Sopenharmony_ci wait_for_completion_timeout(&tm_done, 24328c2ecf20Sopenharmony_ci msecs_to_jiffies(FNIC_LUN_RESET_TIMEOUT)); 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 24358c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 24368c2ecf20Sopenharmony_ci if (!io_req) { 24378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24388c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 24398c2ecf20Sopenharmony_ci "io_req is null tag 0x%x sc 0x%p\n", tag, sc); 24408c2ecf20Sopenharmony_ci goto fnic_device_reset_end; 24418c2ecf20Sopenharmony_ci } 24428c2ecf20Sopenharmony_ci io_req->dr_done = NULL; 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci status = CMD_LR_STATUS(sc); 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci /* 24478c2ecf20Sopenharmony_ci * If lun reset not completed, bail out with failed. io_req 24488c2ecf20Sopenharmony_ci * gets cleaned up during higher levels of EH 24498c2ecf20Sopenharmony_ci */ 24508c2ecf20Sopenharmony_ci if (status == FCPIO_INVALID_CODE) { 24518c2ecf20Sopenharmony_ci atomic64_inc(&reset_stats->device_reset_timeouts); 24528c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 24538c2ecf20Sopenharmony_ci "Device reset timed out\n"); 24548c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_DEV_RST_TIMED_OUT; 24558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24568c2ecf20Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 24578c2ecf20Sopenharmony_ci /* 24588c2ecf20Sopenharmony_ci * Issue abort and terminate on device reset request. 24598c2ecf20Sopenharmony_ci * If q'ing of terminate fails, retry it after a delay. 24608c2ecf20Sopenharmony_ci */ 24618c2ecf20Sopenharmony_ci while (1) { 24628c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 24638c2ecf20Sopenharmony_ci if (CMD_FLAGS(sc) & FNIC_DEV_RST_TERM_ISSUED) { 24648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24658c2ecf20Sopenharmony_ci break; 24668c2ecf20Sopenharmony_ci } 24678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24688c2ecf20Sopenharmony_ci if (fnic_queue_abort_io_req(fnic, 24698c2ecf20Sopenharmony_ci tag | FNIC_TAG_DEV_RST, 24708c2ecf20Sopenharmony_ci FCPIO_ITMF_ABT_TASK_TERM, 24718c2ecf20Sopenharmony_ci fc_lun.scsi_lun, io_req)) { 24728c2ecf20Sopenharmony_ci wait_for_completion_timeout(&tm_done, 24738c2ecf20Sopenharmony_ci msecs_to_jiffies(FNIC_ABT_TERM_DELAY_TIMEOUT)); 24748c2ecf20Sopenharmony_ci } else { 24758c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 24768c2ecf20Sopenharmony_ci CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED; 24778c2ecf20Sopenharmony_ci CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; 24788c2ecf20Sopenharmony_ci io_req->abts_done = &tm_done; 24798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24808c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 24818c2ecf20Sopenharmony_ci "Abort and terminate issued on Device reset " 24828c2ecf20Sopenharmony_ci "tag 0x%x sc 0x%p\n", tag, sc); 24838c2ecf20Sopenharmony_ci break; 24848c2ecf20Sopenharmony_ci } 24858c2ecf20Sopenharmony_ci } 24868c2ecf20Sopenharmony_ci while (1) { 24878c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 24888c2ecf20Sopenharmony_ci if (!(CMD_FLAGS(sc) & FNIC_DEV_RST_DONE)) { 24898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 24908c2ecf20Sopenharmony_ci wait_for_completion_timeout(&tm_done, 24918c2ecf20Sopenharmony_ci msecs_to_jiffies(FNIC_LUN_RESET_TIMEOUT)); 24928c2ecf20Sopenharmony_ci break; 24938c2ecf20Sopenharmony_ci } else { 24948c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 24958c2ecf20Sopenharmony_ci io_req->abts_done = NULL; 24968c2ecf20Sopenharmony_ci goto fnic_device_reset_clean; 24978c2ecf20Sopenharmony_ci } 24988c2ecf20Sopenharmony_ci } 24998c2ecf20Sopenharmony_ci } else { 25008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 25018c2ecf20Sopenharmony_ci } 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci /* Completed, but not successful, clean up the io_req, return fail */ 25048c2ecf20Sopenharmony_ci if (status != FCPIO_SUCCESS) { 25058c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 25068c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 25078c2ecf20Sopenharmony_ci fnic->lport->host, 25088c2ecf20Sopenharmony_ci "Device reset completed - failed\n"); 25098c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 25108c2ecf20Sopenharmony_ci goto fnic_device_reset_clean; 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci /* 25148c2ecf20Sopenharmony_ci * Clean up any aborts on this lun that have still not 25158c2ecf20Sopenharmony_ci * completed. If any of these fail, then LUN reset fails. 25168c2ecf20Sopenharmony_ci * clean_pending_aborts cleans all cmds on this lun except 25178c2ecf20Sopenharmony_ci * the lun reset cmd. If all cmds get cleaned, the lun reset 25188c2ecf20Sopenharmony_ci * succeeds 25198c2ecf20Sopenharmony_ci */ 25208c2ecf20Sopenharmony_ci if (fnic_clean_pending_aborts(fnic, sc, new_sc)) { 25218c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 25228c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 25238c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 25248c2ecf20Sopenharmony_ci "Device reset failed" 25258c2ecf20Sopenharmony_ci " since could not abort all IOs\n"); 25268c2ecf20Sopenharmony_ci goto fnic_device_reset_clean; 25278c2ecf20Sopenharmony_ci } 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci /* Clean lun reset command */ 25308c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 25318c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 25328c2ecf20Sopenharmony_ci if (io_req) 25338c2ecf20Sopenharmony_ci /* Completed, and successful */ 25348c2ecf20Sopenharmony_ci ret = SUCCESS; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_cifnic_device_reset_clean: 25378c2ecf20Sopenharmony_ci if (io_req) 25388c2ecf20Sopenharmony_ci CMD_SP(sc) = NULL; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci if (io_req) { 25438c2ecf20Sopenharmony_ci start_time = io_req->start_time; 25448c2ecf20Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 25458c2ecf20Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 25468c2ecf20Sopenharmony_ci } 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_cifnic_device_reset_end: 25498c2ecf20Sopenharmony_ci FNIC_TRACE(fnic_device_reset, sc->device->host->host_no, 25508c2ecf20Sopenharmony_ci sc->request->tag, sc, 25518c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 25528c2ecf20Sopenharmony_ci 0, ((u64)sc->cmnd[0] << 32 | 25538c2ecf20Sopenharmony_ci (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | 25548c2ecf20Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), 25558c2ecf20Sopenharmony_ci (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci /* free tag if it is allocated */ 25588c2ecf20Sopenharmony_ci if (unlikely(tag_gen_flag)) 25598c2ecf20Sopenharmony_ci fnic_scsi_host_end_tag(fnic, sc); 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 25628c2ecf20Sopenharmony_ci "Returning from device reset %s\n", 25638c2ecf20Sopenharmony_ci (ret == SUCCESS) ? 25648c2ecf20Sopenharmony_ci "SUCCESS" : "FAILED"); 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci if (ret == FAILED) 25678c2ecf20Sopenharmony_ci atomic64_inc(&reset_stats->device_reset_failures); 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci return ret; 25708c2ecf20Sopenharmony_ci} 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci/* Clean up all IOs, clean up libFC local port */ 25738c2ecf20Sopenharmony_ciint fnic_reset(struct Scsi_Host *shost) 25748c2ecf20Sopenharmony_ci{ 25758c2ecf20Sopenharmony_ci struct fc_lport *lp; 25768c2ecf20Sopenharmony_ci struct fnic *fnic; 25778c2ecf20Sopenharmony_ci int ret = 0; 25788c2ecf20Sopenharmony_ci struct reset_stats *reset_stats; 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci lp = shost_priv(shost); 25818c2ecf20Sopenharmony_ci fnic = lport_priv(lp); 25828c2ecf20Sopenharmony_ci reset_stats = &fnic->fnic_stats.reset_stats; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 25858c2ecf20Sopenharmony_ci "fnic_reset called\n"); 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci atomic64_inc(&reset_stats->fnic_resets); 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci /* 25908c2ecf20Sopenharmony_ci * Reset local port, this will clean up libFC exchanges, 25918c2ecf20Sopenharmony_ci * reset remote port sessions, and if link is up, begin flogi 25928c2ecf20Sopenharmony_ci */ 25938c2ecf20Sopenharmony_ci ret = fc_lport_reset(lp); 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 25968c2ecf20Sopenharmony_ci "Returning from fnic reset %s\n", 25978c2ecf20Sopenharmony_ci (ret == 0) ? 25988c2ecf20Sopenharmony_ci "SUCCESS" : "FAILED"); 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci if (ret == 0) 26018c2ecf20Sopenharmony_ci atomic64_inc(&reset_stats->fnic_reset_completions); 26028c2ecf20Sopenharmony_ci else 26038c2ecf20Sopenharmony_ci atomic64_inc(&reset_stats->fnic_reset_failures); 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci return ret; 26068c2ecf20Sopenharmony_ci} 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci/* 26098c2ecf20Sopenharmony_ci * SCSI Error handling calls driver's eh_host_reset if all prior 26108c2ecf20Sopenharmony_ci * error handling levels return FAILED. If host reset completes 26118c2ecf20Sopenharmony_ci * successfully, and if link is up, then Fabric login begins. 26128c2ecf20Sopenharmony_ci * 26138c2ecf20Sopenharmony_ci * Host Reset is the highest level of error recovery. If this fails, then 26148c2ecf20Sopenharmony_ci * host is offlined by SCSI. 26158c2ecf20Sopenharmony_ci * 26168c2ecf20Sopenharmony_ci */ 26178c2ecf20Sopenharmony_ciint fnic_host_reset(struct scsi_cmnd *sc) 26188c2ecf20Sopenharmony_ci{ 26198c2ecf20Sopenharmony_ci int ret; 26208c2ecf20Sopenharmony_ci unsigned long wait_host_tmo; 26218c2ecf20Sopenharmony_ci struct Scsi_Host *shost = sc->device->host; 26228c2ecf20Sopenharmony_ci struct fc_lport *lp = shost_priv(shost); 26238c2ecf20Sopenharmony_ci struct fnic *fnic = lport_priv(lp); 26248c2ecf20Sopenharmony_ci unsigned long flags; 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 26278c2ecf20Sopenharmony_ci if (!fnic->internal_reset_inprogress) { 26288c2ecf20Sopenharmony_ci fnic->internal_reset_inprogress = true; 26298c2ecf20Sopenharmony_ci } else { 26308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 26318c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 26328c2ecf20Sopenharmony_ci "host reset in progress skipping another host reset\n"); 26338c2ecf20Sopenharmony_ci return SUCCESS; 26348c2ecf20Sopenharmony_ci } 26358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci /* 26388c2ecf20Sopenharmony_ci * If fnic_reset is successful, wait for fabric login to complete 26398c2ecf20Sopenharmony_ci * scsi-ml tries to send a TUR to every device if host reset is 26408c2ecf20Sopenharmony_ci * successful, so before returning to scsi, fabric should be up 26418c2ecf20Sopenharmony_ci */ 26428c2ecf20Sopenharmony_ci ret = (fnic_reset(shost) == 0) ? SUCCESS : FAILED; 26438c2ecf20Sopenharmony_ci if (ret == SUCCESS) { 26448c2ecf20Sopenharmony_ci wait_host_tmo = jiffies + FNIC_HOST_RESET_SETTLE_TIME * HZ; 26458c2ecf20Sopenharmony_ci ret = FAILED; 26468c2ecf20Sopenharmony_ci while (time_before(jiffies, wait_host_tmo)) { 26478c2ecf20Sopenharmony_ci if ((lp->state == LPORT_ST_READY) && 26488c2ecf20Sopenharmony_ci (lp->link_up)) { 26498c2ecf20Sopenharmony_ci ret = SUCCESS; 26508c2ecf20Sopenharmony_ci break; 26518c2ecf20Sopenharmony_ci } 26528c2ecf20Sopenharmony_ci ssleep(1); 26538c2ecf20Sopenharmony_ci } 26548c2ecf20Sopenharmony_ci } 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 26578c2ecf20Sopenharmony_ci fnic->internal_reset_inprogress = false; 26588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 26598c2ecf20Sopenharmony_ci return ret; 26608c2ecf20Sopenharmony_ci} 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci/* 26638c2ecf20Sopenharmony_ci * This fxn is called from libFC when host is removed 26648c2ecf20Sopenharmony_ci */ 26658c2ecf20Sopenharmony_civoid fnic_scsi_abort_io(struct fc_lport *lp) 26668c2ecf20Sopenharmony_ci{ 26678c2ecf20Sopenharmony_ci int err = 0; 26688c2ecf20Sopenharmony_ci unsigned long flags; 26698c2ecf20Sopenharmony_ci enum fnic_state old_state; 26708c2ecf20Sopenharmony_ci struct fnic *fnic = lport_priv(lp); 26718c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(remove_wait); 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci /* Issue firmware reset for fnic, wait for reset to complete */ 26748c2ecf20Sopenharmony_ciretry_fw_reset: 26758c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 26768c2ecf20Sopenharmony_ci if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE)) { 26778c2ecf20Sopenharmony_ci /* fw reset is in progress, poll for its completion */ 26788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 26798c2ecf20Sopenharmony_ci schedule_timeout(msecs_to_jiffies(100)); 26808c2ecf20Sopenharmony_ci goto retry_fw_reset; 26818c2ecf20Sopenharmony_ci } 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci fnic->remove_wait = &remove_wait; 26848c2ecf20Sopenharmony_ci old_state = fnic->state; 26858c2ecf20Sopenharmony_ci fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; 26868c2ecf20Sopenharmony_ci fnic_update_mac_locked(fnic, fnic->ctlr.ctl_src_addr); 26878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci err = fnic_fw_reset_handler(fnic); 26908c2ecf20Sopenharmony_ci if (err) { 26918c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 26928c2ecf20Sopenharmony_ci if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) 26938c2ecf20Sopenharmony_ci fnic->state = old_state; 26948c2ecf20Sopenharmony_ci fnic->remove_wait = NULL; 26958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 26968c2ecf20Sopenharmony_ci return; 26978c2ecf20Sopenharmony_ci } 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci /* Wait for firmware reset to complete */ 27008c2ecf20Sopenharmony_ci wait_for_completion_timeout(&remove_wait, 27018c2ecf20Sopenharmony_ci msecs_to_jiffies(FNIC_RMDEVICE_TIMEOUT)); 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 27048c2ecf20Sopenharmony_ci fnic->remove_wait = NULL; 27058c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 27068c2ecf20Sopenharmony_ci "fnic_scsi_abort_io %s\n", 27078c2ecf20Sopenharmony_ci (fnic->state == FNIC_IN_ETH_MODE) ? 27088c2ecf20Sopenharmony_ci "SUCCESS" : "FAILED"); 27098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci} 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci/* 27148c2ecf20Sopenharmony_ci * This fxn called from libFC to clean up driver IO state on link down 27158c2ecf20Sopenharmony_ci */ 27168c2ecf20Sopenharmony_civoid fnic_scsi_cleanup(struct fc_lport *lp) 27178c2ecf20Sopenharmony_ci{ 27188c2ecf20Sopenharmony_ci unsigned long flags; 27198c2ecf20Sopenharmony_ci enum fnic_state old_state; 27208c2ecf20Sopenharmony_ci struct fnic *fnic = lport_priv(lp); 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci /* issue fw reset */ 27238c2ecf20Sopenharmony_ciretry_fw_reset: 27248c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 27258c2ecf20Sopenharmony_ci if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE)) { 27268c2ecf20Sopenharmony_ci /* fw reset is in progress, poll for its completion */ 27278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 27288c2ecf20Sopenharmony_ci schedule_timeout(msecs_to_jiffies(100)); 27298c2ecf20Sopenharmony_ci goto retry_fw_reset; 27308c2ecf20Sopenharmony_ci } 27318c2ecf20Sopenharmony_ci old_state = fnic->state; 27328c2ecf20Sopenharmony_ci fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; 27338c2ecf20Sopenharmony_ci fnic_update_mac_locked(fnic, fnic->ctlr.ctl_src_addr); 27348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci if (fnic_fw_reset_handler(fnic)) { 27378c2ecf20Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 27388c2ecf20Sopenharmony_ci if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) 27398c2ecf20Sopenharmony_ci fnic->state = old_state; 27408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 27418c2ecf20Sopenharmony_ci } 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci} 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_civoid fnic_empty_scsi_cleanup(struct fc_lport *lp) 27468c2ecf20Sopenharmony_ci{ 27478c2ecf20Sopenharmony_ci} 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_civoid fnic_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did) 27508c2ecf20Sopenharmony_ci{ 27518c2ecf20Sopenharmony_ci struct fnic *fnic = lport_priv(lp); 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci /* Non-zero sid, nothing to do */ 27548c2ecf20Sopenharmony_ci if (sid) 27558c2ecf20Sopenharmony_ci goto call_fc_exch_mgr_reset; 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_ci if (did) { 27588c2ecf20Sopenharmony_ci fnic_rport_exch_reset(fnic, did); 27598c2ecf20Sopenharmony_ci goto call_fc_exch_mgr_reset; 27608c2ecf20Sopenharmony_ci } 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci /* 27638c2ecf20Sopenharmony_ci * sid = 0, did = 0 27648c2ecf20Sopenharmony_ci * link down or device being removed 27658c2ecf20Sopenharmony_ci */ 27668c2ecf20Sopenharmony_ci if (!fnic->in_remove) 27678c2ecf20Sopenharmony_ci fnic_scsi_cleanup(lp); 27688c2ecf20Sopenharmony_ci else 27698c2ecf20Sopenharmony_ci fnic_scsi_abort_io(lp); 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci /* call libFC exch mgr reset to reset its exchanges */ 27728c2ecf20Sopenharmony_cicall_fc_exch_mgr_reset: 27738c2ecf20Sopenharmony_ci fc_exch_mgr_reset(lp, sid, did); 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci} 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ci/* 27788c2ecf20Sopenharmony_ci * fnic_is_abts_pending() is a helper function that 27798c2ecf20Sopenharmony_ci * walks through tag map to check if there is any IOs pending,if there is one, 27808c2ecf20Sopenharmony_ci * then it returns 1 (true), otherwise 0 (false) 27818c2ecf20Sopenharmony_ci * if @lr_sc is non NULL, then it checks IOs specific to particular LUN, 27828c2ecf20Sopenharmony_ci * otherwise, it checks for all IOs. 27838c2ecf20Sopenharmony_ci */ 27848c2ecf20Sopenharmony_ciint fnic_is_abts_pending(struct fnic *fnic, struct scsi_cmnd *lr_sc) 27858c2ecf20Sopenharmony_ci{ 27868c2ecf20Sopenharmony_ci int tag; 27878c2ecf20Sopenharmony_ci struct fnic_io_req *io_req; 27888c2ecf20Sopenharmony_ci spinlock_t *io_lock; 27898c2ecf20Sopenharmony_ci unsigned long flags; 27908c2ecf20Sopenharmony_ci int ret = 0; 27918c2ecf20Sopenharmony_ci struct scsi_cmnd *sc; 27928c2ecf20Sopenharmony_ci struct scsi_device *lun_dev = NULL; 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci if (lr_sc) 27958c2ecf20Sopenharmony_ci lun_dev = lr_sc->device; 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci /* walk again to check, if IOs are still pending in fw */ 27988c2ecf20Sopenharmony_ci for (tag = 0; tag < fnic->fnic_max_tag_id; tag++) { 27998c2ecf20Sopenharmony_ci sc = scsi_host_find_tag(fnic->lport->host, tag); 28008c2ecf20Sopenharmony_ci /* 28018c2ecf20Sopenharmony_ci * ignore this lun reset cmd or cmds that do not belong to 28028c2ecf20Sopenharmony_ci * this lun 28038c2ecf20Sopenharmony_ci */ 28048c2ecf20Sopenharmony_ci if (!sc || (lr_sc && (sc->device != lun_dev || sc == lr_sc))) 28058c2ecf20Sopenharmony_ci continue; 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 28088c2ecf20Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci io_req = (struct fnic_io_req *)CMD_SP(sc); 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci if (!io_req || sc->device != lun_dev) { 28138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 28148c2ecf20Sopenharmony_ci continue; 28158c2ecf20Sopenharmony_ci } 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci /* 28188c2ecf20Sopenharmony_ci * Found IO that is still pending with firmware and 28198c2ecf20Sopenharmony_ci * belongs to the LUN that we are resetting 28208c2ecf20Sopenharmony_ci */ 28218c2ecf20Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 28228c2ecf20Sopenharmony_ci "Found IO in %s on lun\n", 28238c2ecf20Sopenharmony_ci fnic_ioreq_state_to_str(CMD_STATE(sc))); 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) 28268c2ecf20Sopenharmony_ci ret = 1; 28278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 28288c2ecf20Sopenharmony_ci } 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci return ret; 28318c2ecf20Sopenharmony_ci} 2832