162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2008 Cisco Systems, Inc. All rights reserved. 462306a36Sopenharmony_ci * Copyright 2007 Nuova Systems, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/mempool.h> 762306a36Sopenharmony_ci#include <linux/errno.h> 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/workqueue.h> 1062306a36Sopenharmony_ci#include <linux/pci.h> 1162306a36Sopenharmony_ci#include <linux/scatterlist.h> 1262306a36Sopenharmony_ci#include <linux/skbuff.h> 1362306a36Sopenharmony_ci#include <linux/spinlock.h> 1462306a36Sopenharmony_ci#include <linux/etherdevice.h> 1562306a36Sopenharmony_ci#include <linux/if_ether.h> 1662306a36Sopenharmony_ci#include <linux/if_vlan.h> 1762306a36Sopenharmony_ci#include <linux/delay.h> 1862306a36Sopenharmony_ci#include <linux/gfp.h> 1962306a36Sopenharmony_ci#include <scsi/scsi.h> 2062306a36Sopenharmony_ci#include <scsi/scsi_host.h> 2162306a36Sopenharmony_ci#include <scsi/scsi_device.h> 2262306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 2362306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 2462306a36Sopenharmony_ci#include <scsi/fc/fc_els.h> 2562306a36Sopenharmony_ci#include <scsi/fc/fc_fcoe.h> 2662306a36Sopenharmony_ci#include <scsi/libfc.h> 2762306a36Sopenharmony_ci#include <scsi/fc_frame.h> 2862306a36Sopenharmony_ci#include "fnic_io.h" 2962306a36Sopenharmony_ci#include "fnic.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciconst char *fnic_state_str[] = { 3262306a36Sopenharmony_ci [FNIC_IN_FC_MODE] = "FNIC_IN_FC_MODE", 3362306a36Sopenharmony_ci [FNIC_IN_FC_TRANS_ETH_MODE] = "FNIC_IN_FC_TRANS_ETH_MODE", 3462306a36Sopenharmony_ci [FNIC_IN_ETH_MODE] = "FNIC_IN_ETH_MODE", 3562306a36Sopenharmony_ci [FNIC_IN_ETH_TRANS_FC_MODE] = "FNIC_IN_ETH_TRANS_FC_MODE", 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic const char *fnic_ioreq_state_str[] = { 3962306a36Sopenharmony_ci [FNIC_IOREQ_NOT_INITED] = "FNIC_IOREQ_NOT_INITED", 4062306a36Sopenharmony_ci [FNIC_IOREQ_CMD_PENDING] = "FNIC_IOREQ_CMD_PENDING", 4162306a36Sopenharmony_ci [FNIC_IOREQ_ABTS_PENDING] = "FNIC_IOREQ_ABTS_PENDING", 4262306a36Sopenharmony_ci [FNIC_IOREQ_ABTS_COMPLETE] = "FNIC_IOREQ_ABTS_COMPLETE", 4362306a36Sopenharmony_ci [FNIC_IOREQ_CMD_COMPLETE] = "FNIC_IOREQ_CMD_COMPLETE", 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic const char *fcpio_status_str[] = { 4762306a36Sopenharmony_ci [FCPIO_SUCCESS] = "FCPIO_SUCCESS", /*0x0*/ 4862306a36Sopenharmony_ci [FCPIO_INVALID_HEADER] = "FCPIO_INVALID_HEADER", 4962306a36Sopenharmony_ci [FCPIO_OUT_OF_RESOURCE] = "FCPIO_OUT_OF_RESOURCE", 5062306a36Sopenharmony_ci [FCPIO_INVALID_PARAM] = "FCPIO_INVALID_PARAM]", 5162306a36Sopenharmony_ci [FCPIO_REQ_NOT_SUPPORTED] = "FCPIO_REQ_NOT_SUPPORTED", 5262306a36Sopenharmony_ci [FCPIO_IO_NOT_FOUND] = "FCPIO_IO_NOT_FOUND", 5362306a36Sopenharmony_ci [FCPIO_ABORTED] = "FCPIO_ABORTED", /*0x41*/ 5462306a36Sopenharmony_ci [FCPIO_TIMEOUT] = "FCPIO_TIMEOUT", 5562306a36Sopenharmony_ci [FCPIO_SGL_INVALID] = "FCPIO_SGL_INVALID", 5662306a36Sopenharmony_ci [FCPIO_MSS_INVALID] = "FCPIO_MSS_INVALID", 5762306a36Sopenharmony_ci [FCPIO_DATA_CNT_MISMATCH] = "FCPIO_DATA_CNT_MISMATCH", 5862306a36Sopenharmony_ci [FCPIO_FW_ERR] = "FCPIO_FW_ERR", 5962306a36Sopenharmony_ci [FCPIO_ITMF_REJECTED] = "FCPIO_ITMF_REJECTED", 6062306a36Sopenharmony_ci [FCPIO_ITMF_FAILED] = "FCPIO_ITMF_FAILED", 6162306a36Sopenharmony_ci [FCPIO_ITMF_INCORRECT_LUN] = "FCPIO_ITMF_INCORRECT_LUN", 6262306a36Sopenharmony_ci [FCPIO_CMND_REJECTED] = "FCPIO_CMND_REJECTED", 6362306a36Sopenharmony_ci [FCPIO_NO_PATH_AVAIL] = "FCPIO_NO_PATH_AVAIL", 6462306a36Sopenharmony_ci [FCPIO_PATH_FAILED] = "FCPIO_PATH_FAILED", 6562306a36Sopenharmony_ci [FCPIO_LUNMAP_CHNG_PEND] = "FCPIO_LUNHMAP_CHNG_PEND", 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ciconst char *fnic_state_to_str(unsigned int state) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci if (state >= ARRAY_SIZE(fnic_state_str) || !fnic_state_str[state]) 7162306a36Sopenharmony_ci return "unknown"; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return fnic_state_str[state]; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic const char *fnic_ioreq_state_to_str(unsigned int state) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci if (state >= ARRAY_SIZE(fnic_ioreq_state_str) || 7962306a36Sopenharmony_ci !fnic_ioreq_state_str[state]) 8062306a36Sopenharmony_ci return "unknown"; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return fnic_ioreq_state_str[state]; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic const char *fnic_fcpio_status_to_str(unsigned int status) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci if (status >= ARRAY_SIZE(fcpio_status_str) || !fcpio_status_str[status]) 8862306a36Sopenharmony_ci return "unknown"; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return fcpio_status_str[status]; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic void fnic_cleanup_io(struct fnic *fnic); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic inline spinlock_t *fnic_io_lock_hash(struct fnic *fnic, 9662306a36Sopenharmony_ci struct scsi_cmnd *sc) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci u32 hash = scsi_cmd_to_rq(sc)->tag & (FNIC_IO_LOCKS - 1); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return &fnic->io_req_lock[hash]; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic inline spinlock_t *fnic_io_lock_tag(struct fnic *fnic, 10462306a36Sopenharmony_ci int tag) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci return &fnic->io_req_lock[tag & (FNIC_IO_LOCKS - 1)]; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* 11062306a36Sopenharmony_ci * Unmap the data buffer and sense buffer for an io_req, 11162306a36Sopenharmony_ci * also unmap and free the device-private scatter/gather list. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cistatic void fnic_release_ioreq_buf(struct fnic *fnic, 11462306a36Sopenharmony_ci struct fnic_io_req *io_req, 11562306a36Sopenharmony_ci struct scsi_cmnd *sc) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci if (io_req->sgl_list_pa) 11862306a36Sopenharmony_ci dma_unmap_single(&fnic->pdev->dev, io_req->sgl_list_pa, 11962306a36Sopenharmony_ci sizeof(io_req->sgl_list[0]) * io_req->sgl_cnt, 12062306a36Sopenharmony_ci DMA_TO_DEVICE); 12162306a36Sopenharmony_ci scsi_dma_unmap(sc); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (io_req->sgl_cnt) 12462306a36Sopenharmony_ci mempool_free(io_req->sgl_list_alloc, 12562306a36Sopenharmony_ci fnic->io_sgl_pool[io_req->sgl_type]); 12662306a36Sopenharmony_ci if (io_req->sense_buf_pa) 12762306a36Sopenharmony_ci dma_unmap_single(&fnic->pdev->dev, io_req->sense_buf_pa, 12862306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* Free up Copy Wq descriptors. Called with copy_wq lock held */ 13262306a36Sopenharmony_cistatic int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci /* if no Ack received from firmware, then nothing to clean */ 13562306a36Sopenharmony_ci if (!fnic->fw_ack_recd[0]) 13662306a36Sopenharmony_ci return 1; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* 13962306a36Sopenharmony_ci * Update desc_available count based on number of freed descriptors 14062306a36Sopenharmony_ci * Account for wraparound 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci if (wq->to_clean_index <= fnic->fw_ack_index[0]) 14362306a36Sopenharmony_ci wq->ring.desc_avail += (fnic->fw_ack_index[0] 14462306a36Sopenharmony_ci - wq->to_clean_index + 1); 14562306a36Sopenharmony_ci else 14662306a36Sopenharmony_ci wq->ring.desc_avail += (wq->ring.desc_count 14762306a36Sopenharmony_ci - wq->to_clean_index 14862306a36Sopenharmony_ci + fnic->fw_ack_index[0] + 1); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* 15162306a36Sopenharmony_ci * just bump clean index to ack_index+1 accounting for wraparound 15262306a36Sopenharmony_ci * this will essentially free up all descriptors between 15362306a36Sopenharmony_ci * to_clean_index and fw_ack_index, both inclusive 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ci wq->to_clean_index = 15662306a36Sopenharmony_ci (fnic->fw_ack_index[0] + 1) % wq->ring.desc_count; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* we have processed the acks received so far */ 15962306a36Sopenharmony_ci fnic->fw_ack_recd[0] = 0; 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* 16562306a36Sopenharmony_ci * __fnic_set_state_flags 16662306a36Sopenharmony_ci * Sets/Clears bits in fnic's state_flags 16762306a36Sopenharmony_ci **/ 16862306a36Sopenharmony_civoid 16962306a36Sopenharmony_ci__fnic_set_state_flags(struct fnic *fnic, unsigned long st_flags, 17062306a36Sopenharmony_ci unsigned long clearbits) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci unsigned long flags = 0; 17362306a36Sopenharmony_ci unsigned long host_lock_flags = 0; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 17662306a36Sopenharmony_ci spin_lock_irqsave(fnic->lport->host->host_lock, host_lock_flags); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (clearbits) 17962306a36Sopenharmony_ci fnic->state_flags &= ~st_flags; 18062306a36Sopenharmony_ci else 18162306a36Sopenharmony_ci fnic->state_flags |= st_flags; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci spin_unlock_irqrestore(fnic->lport->host->host_lock, host_lock_flags); 18462306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* 19162306a36Sopenharmony_ci * fnic_fw_reset_handler 19262306a36Sopenharmony_ci * Routine to send reset msg to fw 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ciint fnic_fw_reset_handler(struct fnic *fnic) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct vnic_wq_copy *wq = &fnic->wq_copy[0]; 19762306a36Sopenharmony_ci int ret = 0; 19862306a36Sopenharmony_ci unsigned long flags; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* indicate fwreset to io path */ 20162306a36Sopenharmony_ci fnic_set_state_flags(fnic, FNIC_FLAGS_FWRESET); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci skb_queue_purge(&fnic->frame_queue); 20462306a36Sopenharmony_ci skb_queue_purge(&fnic->tx_queue); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* wait for io cmpl */ 20762306a36Sopenharmony_ci while (atomic_read(&fnic->in_flight)) 20862306a36Sopenharmony_ci schedule_timeout(msecs_to_jiffies(1)); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) 21362306a36Sopenharmony_ci free_wq_copy_descs(fnic, wq); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (!vnic_wq_copy_desc_avail(wq)) 21662306a36Sopenharmony_ci ret = -EAGAIN; 21762306a36Sopenharmony_ci else { 21862306a36Sopenharmony_ci fnic_queue_wq_copy_desc_fw_reset(wq, SCSI_NO_TAG); 21962306a36Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); 22062306a36Sopenharmony_ci if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) > 22162306a36Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs)) 22262306a36Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, 22362306a36Sopenharmony_ci atomic64_read( 22462306a36Sopenharmony_ci &fnic->fnic_stats.fw_stats.active_fw_reqs)); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (!ret) { 23062306a36Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.reset_stats.fw_resets); 23162306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 23262306a36Sopenharmony_ci "Issued fw reset\n"); 23362306a36Sopenharmony_ci } else { 23462306a36Sopenharmony_ci fnic_clear_state_flags(fnic, FNIC_FLAGS_FWRESET); 23562306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 23662306a36Sopenharmony_ci "Failed to issue fw reset\n"); 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return ret; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* 24462306a36Sopenharmony_ci * fnic_flogi_reg_handler 24562306a36Sopenharmony_ci * Routine to send flogi register msg to fw 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ciint fnic_flogi_reg_handler(struct fnic *fnic, u32 fc_id) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct vnic_wq_copy *wq = &fnic->wq_copy[0]; 25062306a36Sopenharmony_ci enum fcpio_flogi_reg_format_type format; 25162306a36Sopenharmony_ci struct fc_lport *lp = fnic->lport; 25262306a36Sopenharmony_ci u8 gw_mac[ETH_ALEN]; 25362306a36Sopenharmony_ci int ret = 0; 25462306a36Sopenharmony_ci unsigned long flags; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) 25962306a36Sopenharmony_ci free_wq_copy_descs(fnic, wq); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (!vnic_wq_copy_desc_avail(wq)) { 26262306a36Sopenharmony_ci ret = -EAGAIN; 26362306a36Sopenharmony_ci goto flogi_reg_ioreq_end; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (fnic->ctlr.map_dest) { 26762306a36Sopenharmony_ci eth_broadcast_addr(gw_mac); 26862306a36Sopenharmony_ci format = FCPIO_FLOGI_REG_DEF_DEST; 26962306a36Sopenharmony_ci } else { 27062306a36Sopenharmony_ci memcpy(gw_mac, fnic->ctlr.dest_addr, ETH_ALEN); 27162306a36Sopenharmony_ci format = FCPIO_FLOGI_REG_GW_DEST; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if ((fnic->config.flags & VFCF_FIP_CAPABLE) && !fnic->ctlr.map_dest) { 27562306a36Sopenharmony_ci fnic_queue_wq_copy_desc_fip_reg(wq, SCSI_NO_TAG, 27662306a36Sopenharmony_ci fc_id, gw_mac, 27762306a36Sopenharmony_ci fnic->data_src_addr, 27862306a36Sopenharmony_ci lp->r_a_tov, lp->e_d_tov); 27962306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 28062306a36Sopenharmony_ci "FLOGI FIP reg issued fcid %x src %pM dest %pM\n", 28162306a36Sopenharmony_ci fc_id, fnic->data_src_addr, gw_mac); 28262306a36Sopenharmony_ci } else { 28362306a36Sopenharmony_ci fnic_queue_wq_copy_desc_flogi_reg(wq, SCSI_NO_TAG, 28462306a36Sopenharmony_ci format, fc_id, gw_mac); 28562306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 28662306a36Sopenharmony_ci "FLOGI reg issued fcid %x map %d dest %pM\n", 28762306a36Sopenharmony_ci fc_id, fnic->ctlr.map_dest, gw_mac); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); 29162306a36Sopenharmony_ci if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) > 29262306a36Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs)) 29362306a36Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, 29462306a36Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs)); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ciflogi_reg_ioreq_end: 29762306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); 29862306a36Sopenharmony_ci return ret; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/* 30262306a36Sopenharmony_ci * fnic_queue_wq_copy_desc 30362306a36Sopenharmony_ci * Routine to enqueue a wq copy desc 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_cistatic inline int fnic_queue_wq_copy_desc(struct fnic *fnic, 30662306a36Sopenharmony_ci struct vnic_wq_copy *wq, 30762306a36Sopenharmony_ci struct fnic_io_req *io_req, 30862306a36Sopenharmony_ci struct scsi_cmnd *sc, 30962306a36Sopenharmony_ci int sg_count) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct scatterlist *sg; 31262306a36Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(sc->device)); 31362306a36Sopenharmony_ci struct fc_rport_libfc_priv *rp = rport->dd_data; 31462306a36Sopenharmony_ci struct host_sg_desc *desc; 31562306a36Sopenharmony_ci struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; 31662306a36Sopenharmony_ci unsigned int i; 31762306a36Sopenharmony_ci unsigned long intr_flags; 31862306a36Sopenharmony_ci int flags; 31962306a36Sopenharmony_ci u8 exch_flags; 32062306a36Sopenharmony_ci struct scsi_lun fc_lun; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (sg_count) { 32362306a36Sopenharmony_ci /* For each SGE, create a device desc entry */ 32462306a36Sopenharmony_ci desc = io_req->sgl_list; 32562306a36Sopenharmony_ci for_each_sg(scsi_sglist(sc), sg, sg_count, i) { 32662306a36Sopenharmony_ci desc->addr = cpu_to_le64(sg_dma_address(sg)); 32762306a36Sopenharmony_ci desc->len = cpu_to_le32(sg_dma_len(sg)); 32862306a36Sopenharmony_ci desc->_resvd = 0; 32962306a36Sopenharmony_ci desc++; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci io_req->sgl_list_pa = dma_map_single(&fnic->pdev->dev, 33362306a36Sopenharmony_ci io_req->sgl_list, 33462306a36Sopenharmony_ci sizeof(io_req->sgl_list[0]) * sg_count, 33562306a36Sopenharmony_ci DMA_TO_DEVICE); 33662306a36Sopenharmony_ci if (dma_mapping_error(&fnic->pdev->dev, io_req->sgl_list_pa)) { 33762306a36Sopenharmony_ci printk(KERN_ERR "DMA mapping failed\n"); 33862306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci io_req->sense_buf_pa = dma_map_single(&fnic->pdev->dev, 34362306a36Sopenharmony_ci sc->sense_buffer, 34462306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 34562306a36Sopenharmony_ci DMA_FROM_DEVICE); 34662306a36Sopenharmony_ci if (dma_mapping_error(&fnic->pdev->dev, io_req->sense_buf_pa)) { 34762306a36Sopenharmony_ci dma_unmap_single(&fnic->pdev->dev, io_req->sgl_list_pa, 34862306a36Sopenharmony_ci sizeof(io_req->sgl_list[0]) * sg_count, 34962306a36Sopenharmony_ci DMA_TO_DEVICE); 35062306a36Sopenharmony_ci printk(KERN_ERR "DMA mapping failed\n"); 35162306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Enqueue the descriptor in the Copy WQ */ 35762306a36Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) 36062306a36Sopenharmony_ci free_wq_copy_descs(fnic, wq); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (unlikely(!vnic_wq_copy_desc_avail(wq))) { 36362306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); 36462306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 36562306a36Sopenharmony_ci "fnic_queue_wq_copy_desc failure - no descriptors\n"); 36662306a36Sopenharmony_ci atomic64_inc(&misc_stats->io_cpwq_alloc_failures); 36762306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci flags = 0; 37162306a36Sopenharmony_ci if (sc->sc_data_direction == DMA_FROM_DEVICE) 37262306a36Sopenharmony_ci flags = FCPIO_ICMND_RDDATA; 37362306a36Sopenharmony_ci else if (sc->sc_data_direction == DMA_TO_DEVICE) 37462306a36Sopenharmony_ci flags = FCPIO_ICMND_WRDATA; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci exch_flags = 0; 37762306a36Sopenharmony_ci if ((fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR) && 37862306a36Sopenharmony_ci (rp->flags & FC_RP_FLAGS_RETRY)) 37962306a36Sopenharmony_ci exch_flags |= FCPIO_ICMND_SRFLAG_RETRY; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci fnic_queue_wq_copy_desc_icmnd_16(wq, scsi_cmd_to_rq(sc)->tag, 38262306a36Sopenharmony_ci 0, exch_flags, io_req->sgl_cnt, 38362306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 38462306a36Sopenharmony_ci io_req->sgl_list_pa, 38562306a36Sopenharmony_ci io_req->sense_buf_pa, 38662306a36Sopenharmony_ci 0, /* scsi cmd ref, always 0 */ 38762306a36Sopenharmony_ci FCPIO_ICMND_PTA_SIMPLE, 38862306a36Sopenharmony_ci /* scsi pri and tag */ 38962306a36Sopenharmony_ci flags, /* command flags */ 39062306a36Sopenharmony_ci sc->cmnd, sc->cmd_len, 39162306a36Sopenharmony_ci scsi_bufflen(sc), 39262306a36Sopenharmony_ci fc_lun.scsi_lun, io_req->port_id, 39362306a36Sopenharmony_ci rport->maxframe_size, rp->r_a_tov, 39462306a36Sopenharmony_ci rp->e_d_tov); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); 39762306a36Sopenharmony_ci if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) > 39862306a36Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs)) 39962306a36Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, 40062306a36Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs)); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci/* 40762306a36Sopenharmony_ci * fnic_queuecommand 40862306a36Sopenharmony_ci * Routine to send a scsi cdb 40962306a36Sopenharmony_ci * Called with host_lock held and interrupts disabled. 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_cistatic int fnic_queuecommand_lck(struct scsi_cmnd *sc) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci void (*done)(struct scsi_cmnd *) = scsi_done; 41462306a36Sopenharmony_ci const int tag = scsi_cmd_to_rq(sc)->tag; 41562306a36Sopenharmony_ci struct fc_lport *lp = shost_priv(sc->device->host); 41662306a36Sopenharmony_ci struct fc_rport *rport; 41762306a36Sopenharmony_ci struct fnic_io_req *io_req = NULL; 41862306a36Sopenharmony_ci struct fnic *fnic = lport_priv(lp); 41962306a36Sopenharmony_ci struct fnic_stats *fnic_stats = &fnic->fnic_stats; 42062306a36Sopenharmony_ci struct vnic_wq_copy *wq; 42162306a36Sopenharmony_ci int ret; 42262306a36Sopenharmony_ci u64 cmd_trace; 42362306a36Sopenharmony_ci int sg_count = 0; 42462306a36Sopenharmony_ci unsigned long flags = 0; 42562306a36Sopenharmony_ci unsigned long ptr; 42662306a36Sopenharmony_ci spinlock_t *io_lock = NULL; 42762306a36Sopenharmony_ci int io_lock_acquired = 0; 42862306a36Sopenharmony_ci struct fc_rport_libfc_priv *rp; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED))) 43162306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_FWRESET))) 43462306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci rport = starget_to_rport(scsi_target(sc->device)); 43762306a36Sopenharmony_ci if (!rport) { 43862306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 43962306a36Sopenharmony_ci "returning DID_NO_CONNECT for IO as rport is NULL\n"); 44062306a36Sopenharmony_ci sc->result = DID_NO_CONNECT << 16; 44162306a36Sopenharmony_ci done(sc); 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci ret = fc_remote_port_chkready(rport); 44662306a36Sopenharmony_ci if (ret) { 44762306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 44862306a36Sopenharmony_ci "rport is not ready\n"); 44962306a36Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.rport_not_ready); 45062306a36Sopenharmony_ci sc->result = ret; 45162306a36Sopenharmony_ci done(sc); 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci rp = rport->dd_data; 45662306a36Sopenharmony_ci if (!rp || rp->rp_state == RPORT_ST_DELETE) { 45762306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 45862306a36Sopenharmony_ci "rport 0x%x removed, returning DID_NO_CONNECT\n", 45962306a36Sopenharmony_ci rport->port_id); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.rport_not_ready); 46262306a36Sopenharmony_ci sc->result = DID_NO_CONNECT<<16; 46362306a36Sopenharmony_ci done(sc); 46462306a36Sopenharmony_ci return 0; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (rp->rp_state != RPORT_ST_READY) { 46862306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 46962306a36Sopenharmony_ci "rport 0x%x in state 0x%x, returning DID_IMM_RETRY\n", 47062306a36Sopenharmony_ci rport->port_id, rp->rp_state); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci sc->result = DID_IMM_RETRY << 16; 47362306a36Sopenharmony_ci done(sc); 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (lp->state != LPORT_ST_READY || !(lp->link_up)) 47862306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci atomic_inc(&fnic->in_flight); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* 48362306a36Sopenharmony_ci * Release host lock, use driver resource specific locks from here. 48462306a36Sopenharmony_ci * Don't re-enable interrupts in case they were disabled prior to the 48562306a36Sopenharmony_ci * caller disabling them. 48662306a36Sopenharmony_ci */ 48762306a36Sopenharmony_ci spin_unlock(lp->host->host_lock); 48862306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_NOT_INITED; 48962306a36Sopenharmony_ci fnic_priv(sc)->flags = FNIC_NO_FLAGS; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* Get a new io_req for this SCSI IO */ 49262306a36Sopenharmony_ci io_req = mempool_alloc(fnic->io_req_pool, GFP_ATOMIC); 49362306a36Sopenharmony_ci if (!io_req) { 49462306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.alloc_failures); 49562306a36Sopenharmony_ci ret = SCSI_MLQUEUE_HOST_BUSY; 49662306a36Sopenharmony_ci goto out; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci memset(io_req, 0, sizeof(*io_req)); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* Map the data buffer */ 50162306a36Sopenharmony_ci sg_count = scsi_dma_map(sc); 50262306a36Sopenharmony_ci if (sg_count < 0) { 50362306a36Sopenharmony_ci FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, 50462306a36Sopenharmony_ci tag, sc, 0, sc->cmnd[0], sg_count, fnic_priv(sc)->state); 50562306a36Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 50662306a36Sopenharmony_ci goto out; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* Determine the type of scatter/gather list we need */ 51062306a36Sopenharmony_ci io_req->sgl_cnt = sg_count; 51162306a36Sopenharmony_ci io_req->sgl_type = FNIC_SGL_CACHE_DFLT; 51262306a36Sopenharmony_ci if (sg_count > FNIC_DFLT_SG_DESC_CNT) 51362306a36Sopenharmony_ci io_req->sgl_type = FNIC_SGL_CACHE_MAX; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (sg_count) { 51662306a36Sopenharmony_ci io_req->sgl_list = 51762306a36Sopenharmony_ci mempool_alloc(fnic->io_sgl_pool[io_req->sgl_type], 51862306a36Sopenharmony_ci GFP_ATOMIC); 51962306a36Sopenharmony_ci if (!io_req->sgl_list) { 52062306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.alloc_failures); 52162306a36Sopenharmony_ci ret = SCSI_MLQUEUE_HOST_BUSY; 52262306a36Sopenharmony_ci scsi_dma_unmap(sc); 52362306a36Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 52462306a36Sopenharmony_ci goto out; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* Cache sgl list allocated address before alignment */ 52862306a36Sopenharmony_ci io_req->sgl_list_alloc = io_req->sgl_list; 52962306a36Sopenharmony_ci ptr = (unsigned long) io_req->sgl_list; 53062306a36Sopenharmony_ci if (ptr % FNIC_SG_DESC_ALIGN) { 53162306a36Sopenharmony_ci io_req->sgl_list = (struct host_sg_desc *) 53262306a36Sopenharmony_ci (((unsigned long) ptr 53362306a36Sopenharmony_ci + FNIC_SG_DESC_ALIGN - 1) 53462306a36Sopenharmony_ci & ~(FNIC_SG_DESC_ALIGN - 1)); 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* 53962306a36Sopenharmony_ci * Will acquire lock defore setting to IO initialized. 54062306a36Sopenharmony_ci */ 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 54362306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* initialize rest of io_req */ 54662306a36Sopenharmony_ci io_lock_acquired = 1; 54762306a36Sopenharmony_ci io_req->port_id = rport->port_id; 54862306a36Sopenharmony_ci io_req->start_time = jiffies; 54962306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_CMD_PENDING; 55062306a36Sopenharmony_ci fnic_priv(sc)->io_req = io_req; 55162306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_INITIALIZED; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* create copy wq desc and enqueue it */ 55462306a36Sopenharmony_ci wq = &fnic->wq_copy[0]; 55562306a36Sopenharmony_ci ret = fnic_queue_wq_copy_desc(fnic, wq, io_req, sc, sg_count); 55662306a36Sopenharmony_ci if (ret) { 55762306a36Sopenharmony_ci /* 55862306a36Sopenharmony_ci * In case another thread cancelled the request, 55962306a36Sopenharmony_ci * refetch the pointer under the lock. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ci FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, 56262306a36Sopenharmony_ci tag, sc, 0, 0, 0, fnic_flags_and_state(sc)); 56362306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 56462306a36Sopenharmony_ci fnic_priv(sc)->io_req = NULL; 56562306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_CMD_COMPLETE; 56662306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 56762306a36Sopenharmony_ci if (io_req) { 56862306a36Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 56962306a36Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci atomic_dec(&fnic->in_flight); 57262306a36Sopenharmony_ci /* acquire host lock before returning to SCSI */ 57362306a36Sopenharmony_ci spin_lock(lp->host->host_lock); 57462306a36Sopenharmony_ci return ret; 57562306a36Sopenharmony_ci } else { 57662306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.active_ios); 57762306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.num_ios); 57862306a36Sopenharmony_ci if (atomic64_read(&fnic_stats->io_stats.active_ios) > 57962306a36Sopenharmony_ci atomic64_read(&fnic_stats->io_stats.max_active_ios)) 58062306a36Sopenharmony_ci atomic64_set(&fnic_stats->io_stats.max_active_ios, 58162306a36Sopenharmony_ci atomic64_read(&fnic_stats->io_stats.active_ios)); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* REVISIT: Use per IO lock in the final code */ 58462306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_ISSUED; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ciout: 58762306a36Sopenharmony_ci cmd_trace = ((u64)sc->cmnd[0] << 56 | (u64)sc->cmnd[7] << 40 | 58862306a36Sopenharmony_ci (u64)sc->cmnd[8] << 32 | (u64)sc->cmnd[2] << 24 | 58962306a36Sopenharmony_ci (u64)sc->cmnd[3] << 16 | (u64)sc->cmnd[4] << 8 | 59062306a36Sopenharmony_ci sc->cmnd[5]); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, 59362306a36Sopenharmony_ci tag, sc, io_req, sg_count, cmd_trace, 59462306a36Sopenharmony_ci fnic_flags_and_state(sc)); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* if only we issued IO, will we have the io lock */ 59762306a36Sopenharmony_ci if (io_lock_acquired) 59862306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci atomic_dec(&fnic->in_flight); 60162306a36Sopenharmony_ci /* acquire host lock before returning to SCSI */ 60262306a36Sopenharmony_ci spin_lock(lp->host->host_lock); 60362306a36Sopenharmony_ci return ret; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ciDEF_SCSI_QCMD(fnic_queuecommand) 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci/* 60962306a36Sopenharmony_ci * fnic_fcpio_fw_reset_cmpl_handler 61062306a36Sopenharmony_ci * Routine to handle fw reset completion 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_cistatic int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic, 61362306a36Sopenharmony_ci struct fcpio_fw_req *desc) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci u8 type; 61662306a36Sopenharmony_ci u8 hdr_status; 61762306a36Sopenharmony_ci struct fcpio_tag tag; 61862306a36Sopenharmony_ci int ret = 0; 61962306a36Sopenharmony_ci unsigned long flags; 62062306a36Sopenharmony_ci struct reset_stats *reset_stats = &fnic->fnic_stats.reset_stats; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci atomic64_inc(&reset_stats->fw_reset_completions); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* Clean up all outstanding io requests */ 62762306a36Sopenharmony_ci fnic_cleanup_io(fnic); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.active_fw_reqs, 0); 63062306a36Sopenharmony_ci atomic64_set(&fnic->fnic_stats.io_stats.active_ios, 0); 63162306a36Sopenharmony_ci atomic64_set(&fnic->io_cmpl_skip, 0); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* fnic should be in FC_TRANS_ETH_MODE */ 63662306a36Sopenharmony_ci if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) { 63762306a36Sopenharmony_ci /* Check status of reset completion */ 63862306a36Sopenharmony_ci if (!hdr_status) { 63962306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 64062306a36Sopenharmony_ci "reset cmpl success\n"); 64162306a36Sopenharmony_ci /* Ready to send flogi out */ 64262306a36Sopenharmony_ci fnic->state = FNIC_IN_ETH_MODE; 64362306a36Sopenharmony_ci } else { 64462306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 64562306a36Sopenharmony_ci fnic->lport->host, 64662306a36Sopenharmony_ci "fnic fw_reset : failed %s\n", 64762306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* 65062306a36Sopenharmony_ci * Unable to change to eth mode, cannot send out flogi 65162306a36Sopenharmony_ci * Change state to fc mode, so that subsequent Flogi 65262306a36Sopenharmony_ci * requests from libFC will cause more attempts to 65362306a36Sopenharmony_ci * reset the firmware. Free the cached flogi 65462306a36Sopenharmony_ci */ 65562306a36Sopenharmony_ci fnic->state = FNIC_IN_FC_MODE; 65662306a36Sopenharmony_ci atomic64_inc(&reset_stats->fw_reset_failures); 65762306a36Sopenharmony_ci ret = -1; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci } else { 66062306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 66162306a36Sopenharmony_ci fnic->lport->host, 66262306a36Sopenharmony_ci "Unexpected state %s while processing" 66362306a36Sopenharmony_ci " reset cmpl\n", fnic_state_to_str(fnic->state)); 66462306a36Sopenharmony_ci atomic64_inc(&reset_stats->fw_reset_failures); 66562306a36Sopenharmony_ci ret = -1; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* Thread removing device blocks till firmware reset is complete */ 66962306a36Sopenharmony_ci if (fnic->remove_wait) 67062306a36Sopenharmony_ci complete(fnic->remove_wait); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci /* 67362306a36Sopenharmony_ci * If fnic is being removed, or fw reset failed 67462306a36Sopenharmony_ci * free the flogi frame. Else, send it out 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_ci if (fnic->remove_wait || ret) { 67762306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 67862306a36Sopenharmony_ci skb_queue_purge(&fnic->tx_queue); 67962306a36Sopenharmony_ci goto reset_cmpl_handler_end; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci fnic_flush_tx(fnic); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci reset_cmpl_handler_end: 68762306a36Sopenharmony_ci fnic_clear_state_flags(fnic, FNIC_FLAGS_FWRESET); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci return ret; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci/* 69362306a36Sopenharmony_ci * fnic_fcpio_flogi_reg_cmpl_handler 69462306a36Sopenharmony_ci * Routine to handle flogi register completion 69562306a36Sopenharmony_ci */ 69662306a36Sopenharmony_cistatic int fnic_fcpio_flogi_reg_cmpl_handler(struct fnic *fnic, 69762306a36Sopenharmony_ci struct fcpio_fw_req *desc) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci u8 type; 70062306a36Sopenharmony_ci u8 hdr_status; 70162306a36Sopenharmony_ci struct fcpio_tag tag; 70262306a36Sopenharmony_ci int ret = 0; 70362306a36Sopenharmony_ci unsigned long flags; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* Update fnic state based on status of flogi reg completion */ 70862306a36Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE) { 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* Check flogi registration completion status */ 71362306a36Sopenharmony_ci if (!hdr_status) { 71462306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 71562306a36Sopenharmony_ci "flog reg succeeded\n"); 71662306a36Sopenharmony_ci fnic->state = FNIC_IN_FC_MODE; 71762306a36Sopenharmony_ci } else { 71862306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 71962306a36Sopenharmony_ci fnic->lport->host, 72062306a36Sopenharmony_ci "fnic flogi reg :failed %s\n", 72162306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 72262306a36Sopenharmony_ci fnic->state = FNIC_IN_ETH_MODE; 72362306a36Sopenharmony_ci ret = -1; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci } else { 72662306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 72762306a36Sopenharmony_ci "Unexpected fnic state %s while" 72862306a36Sopenharmony_ci " processing flogi reg completion\n", 72962306a36Sopenharmony_ci fnic_state_to_str(fnic->state)); 73062306a36Sopenharmony_ci ret = -1; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (!ret) { 73462306a36Sopenharmony_ci if (fnic->stop_rx_link_events) { 73562306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 73662306a36Sopenharmony_ci goto reg_cmpl_handler_end; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci fnic_flush_tx(fnic); 74162306a36Sopenharmony_ci queue_work(fnic_event_queue, &fnic->frame_work); 74262306a36Sopenharmony_ci } else { 74362306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cireg_cmpl_handler_end: 74762306a36Sopenharmony_ci return ret; 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic inline int is_ack_index_in_range(struct vnic_wq_copy *wq, 75162306a36Sopenharmony_ci u16 request_out) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci if (wq->to_clean_index <= wq->to_use_index) { 75462306a36Sopenharmony_ci /* out of range, stale request_out index */ 75562306a36Sopenharmony_ci if (request_out < wq->to_clean_index || 75662306a36Sopenharmony_ci request_out >= wq->to_use_index) 75762306a36Sopenharmony_ci return 0; 75862306a36Sopenharmony_ci } else { 75962306a36Sopenharmony_ci /* out of range, stale request_out index */ 76062306a36Sopenharmony_ci if (request_out < wq->to_clean_index && 76162306a36Sopenharmony_ci request_out >= wq->to_use_index) 76262306a36Sopenharmony_ci return 0; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci /* request_out index is in range */ 76562306a36Sopenharmony_ci return 1; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci/* 77062306a36Sopenharmony_ci * Mark that ack received and store the Ack index. If there are multiple 77162306a36Sopenharmony_ci * acks received before Tx thread cleans it up, the latest value will be 77262306a36Sopenharmony_ci * used which is correct behavior. This state should be in the copy Wq 77362306a36Sopenharmony_ci * instead of in the fnic 77462306a36Sopenharmony_ci */ 77562306a36Sopenharmony_cistatic inline void fnic_fcpio_ack_handler(struct fnic *fnic, 77662306a36Sopenharmony_ci unsigned int cq_index, 77762306a36Sopenharmony_ci struct fcpio_fw_req *desc) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci struct vnic_wq_copy *wq; 78062306a36Sopenharmony_ci u16 request_out = desc->u.ack.request_out; 78162306a36Sopenharmony_ci unsigned long flags; 78262306a36Sopenharmony_ci u64 *ox_id_tag = (u64 *)(void *)desc; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci /* mark the ack state */ 78562306a36Sopenharmony_ci wq = &fnic->wq_copy[cq_index - fnic->raw_wq_count - fnic->rq_count]; 78662306a36Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci fnic->fnic_stats.misc_stats.last_ack_time = jiffies; 78962306a36Sopenharmony_ci if (is_ack_index_in_range(wq, request_out)) { 79062306a36Sopenharmony_ci fnic->fw_ack_index[0] = request_out; 79162306a36Sopenharmony_ci fnic->fw_ack_recd[0] = 1; 79262306a36Sopenharmony_ci } else 79362306a36Sopenharmony_ci atomic64_inc( 79462306a36Sopenharmony_ci &fnic->fnic_stats.misc_stats.ack_index_out_of_range); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); 79762306a36Sopenharmony_ci FNIC_TRACE(fnic_fcpio_ack_handler, 79862306a36Sopenharmony_ci fnic->lport->host->host_no, 0, 0, ox_id_tag[2], ox_id_tag[3], 79962306a36Sopenharmony_ci ox_id_tag[4], ox_id_tag[5]); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci/* 80362306a36Sopenharmony_ci * fnic_fcpio_icmnd_cmpl_handler 80462306a36Sopenharmony_ci * Routine to handle icmnd completions 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_cistatic void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, 80762306a36Sopenharmony_ci struct fcpio_fw_req *desc) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci u8 type; 81062306a36Sopenharmony_ci u8 hdr_status; 81162306a36Sopenharmony_ci struct fcpio_tag tag; 81262306a36Sopenharmony_ci u32 id; 81362306a36Sopenharmony_ci u64 xfer_len = 0; 81462306a36Sopenharmony_ci struct fcpio_icmnd_cmpl *icmnd_cmpl; 81562306a36Sopenharmony_ci struct fnic_io_req *io_req; 81662306a36Sopenharmony_ci struct scsi_cmnd *sc; 81762306a36Sopenharmony_ci struct fnic_stats *fnic_stats = &fnic->fnic_stats; 81862306a36Sopenharmony_ci unsigned long flags; 81962306a36Sopenharmony_ci spinlock_t *io_lock; 82062306a36Sopenharmony_ci u64 cmd_trace; 82162306a36Sopenharmony_ci unsigned long start_time; 82262306a36Sopenharmony_ci unsigned long io_duration_time; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci /* Decode the cmpl description to get the io_req id */ 82562306a36Sopenharmony_ci fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); 82662306a36Sopenharmony_ci fcpio_tag_id_dec(&tag, &id); 82762306a36Sopenharmony_ci icmnd_cmpl = &desc->u.icmnd_cmpl; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (id >= fnic->fnic_max_tag_id) { 83062306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 83162306a36Sopenharmony_ci "Tag out of range tag %x hdr status = %s\n", 83262306a36Sopenharmony_ci id, fnic_fcpio_status_to_str(hdr_status)); 83362306a36Sopenharmony_ci return; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci sc = scsi_host_find_tag(fnic->lport->host, id); 83762306a36Sopenharmony_ci WARN_ON_ONCE(!sc); 83862306a36Sopenharmony_ci if (!sc) { 83962306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.sc_null); 84062306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 84162306a36Sopenharmony_ci "icmnd_cmpl sc is null - " 84262306a36Sopenharmony_ci "hdr status = %s tag = 0x%x desc = 0x%p\n", 84362306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status), id, desc); 84462306a36Sopenharmony_ci FNIC_TRACE(fnic_fcpio_icmnd_cmpl_handler, 84562306a36Sopenharmony_ci fnic->lport->host->host_no, id, 84662306a36Sopenharmony_ci ((u64)icmnd_cmpl->_resvd0[1] << 16 | 84762306a36Sopenharmony_ci (u64)icmnd_cmpl->_resvd0[0]), 84862306a36Sopenharmony_ci ((u64)hdr_status << 16 | 84962306a36Sopenharmony_ci (u64)icmnd_cmpl->scsi_status << 8 | 85062306a36Sopenharmony_ci (u64)icmnd_cmpl->flags), desc, 85162306a36Sopenharmony_ci (u64)icmnd_cmpl->residual, 0); 85262306a36Sopenharmony_ci return; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 85662306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 85762306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 85862306a36Sopenharmony_ci WARN_ON_ONCE(!io_req); 85962306a36Sopenharmony_ci if (!io_req) { 86062306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.ioreq_null); 86162306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_REQ_NULL; 86262306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 86362306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 86462306a36Sopenharmony_ci "icmnd_cmpl io_req is null - " 86562306a36Sopenharmony_ci "hdr status = %s tag = 0x%x sc 0x%p\n", 86662306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status), id, sc); 86762306a36Sopenharmony_ci return; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci start_time = io_req->start_time; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* firmware completed the io */ 87262306a36Sopenharmony_ci io_req->io_completed = 1; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* 87562306a36Sopenharmony_ci * if SCSI-ML has already issued abort on this command, 87662306a36Sopenharmony_ci * set completion of the IO. The abts path will clean it up 87762306a36Sopenharmony_ci */ 87862306a36Sopenharmony_ci if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) { 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* 88162306a36Sopenharmony_ci * set the FNIC_IO_DONE so that this doesn't get 88262306a36Sopenharmony_ci * flagged as 'out of order' if it was not aborted 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_DONE; 88562306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_ABTS_PENDING; 88662306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 88762306a36Sopenharmony_ci if(FCPIO_ABORTED == hdr_status) 88862306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_ABORTED; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 89162306a36Sopenharmony_ci "icmnd_cmpl abts pending " 89262306a36Sopenharmony_ci "hdr status = %s tag = 0x%x sc = 0x%p " 89362306a36Sopenharmony_ci "scsi_status = %x residual = %d\n", 89462306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status), 89562306a36Sopenharmony_ci id, sc, 89662306a36Sopenharmony_ci icmnd_cmpl->scsi_status, 89762306a36Sopenharmony_ci icmnd_cmpl->residual); 89862306a36Sopenharmony_ci return; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* Mark the IO as complete */ 90262306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_CMD_COMPLETE; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci icmnd_cmpl = &desc->u.icmnd_cmpl; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci switch (hdr_status) { 90762306a36Sopenharmony_ci case FCPIO_SUCCESS: 90862306a36Sopenharmony_ci sc->result = (DID_OK << 16) | icmnd_cmpl->scsi_status; 90962306a36Sopenharmony_ci xfer_len = scsi_bufflen(sc); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (icmnd_cmpl->flags & FCPIO_ICMND_CMPL_RESID_UNDER) { 91262306a36Sopenharmony_ci xfer_len -= icmnd_cmpl->residual; 91362306a36Sopenharmony_ci scsi_set_resid(sc, icmnd_cmpl->residual); 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (icmnd_cmpl->scsi_status == SAM_STAT_CHECK_CONDITION) 91762306a36Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.check_condition); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci if (icmnd_cmpl->scsi_status == SAM_STAT_TASK_SET_FULL) 92062306a36Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.queue_fulls); 92162306a36Sopenharmony_ci break; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci case FCPIO_TIMEOUT: /* request was timed out */ 92462306a36Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.fcpio_timeout); 92562306a36Sopenharmony_ci sc->result = (DID_TIME_OUT << 16) | icmnd_cmpl->scsi_status; 92662306a36Sopenharmony_ci break; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci case FCPIO_ABORTED: /* request was aborted */ 92962306a36Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.fcpio_aborted); 93062306a36Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 93162306a36Sopenharmony_ci break; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci case FCPIO_DATA_CNT_MISMATCH: /* recv/sent more/less data than exp. */ 93462306a36Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.data_count_mismatch); 93562306a36Sopenharmony_ci scsi_set_resid(sc, icmnd_cmpl->residual); 93662306a36Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 93762306a36Sopenharmony_ci break; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci case FCPIO_OUT_OF_RESOURCE: /* out of resources to complete request */ 94062306a36Sopenharmony_ci atomic64_inc(&fnic_stats->fw_stats.fw_out_of_resources); 94162306a36Sopenharmony_ci sc->result = (DID_REQUEUE << 16) | icmnd_cmpl->scsi_status; 94262306a36Sopenharmony_ci break; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci case FCPIO_IO_NOT_FOUND: /* requested I/O was not found */ 94562306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_not_found); 94662306a36Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 94762306a36Sopenharmony_ci break; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci case FCPIO_SGL_INVALID: /* request was aborted due to sgl error */ 95062306a36Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.sgl_invalid); 95162306a36Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 95262306a36Sopenharmony_ci break; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci case FCPIO_FW_ERR: /* request was terminated due fw error */ 95562306a36Sopenharmony_ci atomic64_inc(&fnic_stats->fw_stats.io_fw_errs); 95662306a36Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 95762306a36Sopenharmony_ci break; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci case FCPIO_MSS_INVALID: /* request was aborted due to mss error */ 96062306a36Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.mss_invalid); 96162306a36Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 96262306a36Sopenharmony_ci break; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci case FCPIO_INVALID_HEADER: /* header contains invalid data */ 96562306a36Sopenharmony_ci case FCPIO_INVALID_PARAM: /* some parameter in request invalid */ 96662306a36Sopenharmony_ci case FCPIO_REQ_NOT_SUPPORTED:/* request type is not supported */ 96762306a36Sopenharmony_ci default: 96862306a36Sopenharmony_ci sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; 96962306a36Sopenharmony_ci break; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci /* Break link with the SCSI command */ 97362306a36Sopenharmony_ci fnic_priv(sc)->io_req = NULL; 97462306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_DONE; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci if (hdr_status != FCPIO_SUCCESS) { 97762306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_failures); 97862306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, "hdr status = %s\n", 97962306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci cmd_trace = ((u64)hdr_status << 56) | 98562306a36Sopenharmony_ci (u64)icmnd_cmpl->scsi_status << 48 | 98662306a36Sopenharmony_ci (u64)icmnd_cmpl->flags << 40 | (u64)sc->cmnd[0] << 32 | 98762306a36Sopenharmony_ci (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | 98862306a36Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci FNIC_TRACE(fnic_fcpio_icmnd_cmpl_handler, 99162306a36Sopenharmony_ci sc->device->host->host_no, id, sc, 99262306a36Sopenharmony_ci ((u64)icmnd_cmpl->_resvd0[1] << 56 | 99362306a36Sopenharmony_ci (u64)icmnd_cmpl->_resvd0[0] << 48 | 99462306a36Sopenharmony_ci jiffies_to_msecs(jiffies - start_time)), 99562306a36Sopenharmony_ci desc, cmd_trace, fnic_flags_and_state(sc)); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci if (sc->sc_data_direction == DMA_FROM_DEVICE) { 99862306a36Sopenharmony_ci fnic->lport->host_stats.fcp_input_requests++; 99962306a36Sopenharmony_ci fnic->fcp_input_bytes += xfer_len; 100062306a36Sopenharmony_ci } else if (sc->sc_data_direction == DMA_TO_DEVICE) { 100162306a36Sopenharmony_ci fnic->lport->host_stats.fcp_output_requests++; 100262306a36Sopenharmony_ci fnic->fcp_output_bytes += xfer_len; 100362306a36Sopenharmony_ci } else 100462306a36Sopenharmony_ci fnic->lport->host_stats.fcp_control_requests++; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci /* Call SCSI completion function to complete the IO */ 100762306a36Sopenharmony_ci scsi_done(sc); 100862306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci atomic64_dec(&fnic_stats->io_stats.active_ios); 101362306a36Sopenharmony_ci if (atomic64_read(&fnic->io_cmpl_skip)) 101462306a36Sopenharmony_ci atomic64_dec(&fnic->io_cmpl_skip); 101562306a36Sopenharmony_ci else 101662306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_completions); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci io_duration_time = jiffies_to_msecs(jiffies) - 102062306a36Sopenharmony_ci jiffies_to_msecs(start_time); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if(io_duration_time <= 10) 102362306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_0_to_10_msec); 102462306a36Sopenharmony_ci else if(io_duration_time <= 100) 102562306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_10_to_100_msec); 102662306a36Sopenharmony_ci else if(io_duration_time <= 500) 102762306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_100_to_500_msec); 102862306a36Sopenharmony_ci else if(io_duration_time <= 5000) 102962306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_500_to_5000_msec); 103062306a36Sopenharmony_ci else if(io_duration_time <= 10000) 103162306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_5000_to_10000_msec); 103262306a36Sopenharmony_ci else if(io_duration_time <= 30000) 103362306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_btw_10000_to_30000_msec); 103462306a36Sopenharmony_ci else { 103562306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_greater_than_30000_msec); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if(io_duration_time > atomic64_read(&fnic_stats->io_stats.current_max_io_time)) 103862306a36Sopenharmony_ci atomic64_set(&fnic_stats->io_stats.current_max_io_time, io_duration_time); 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci/* fnic_fcpio_itmf_cmpl_handler 104362306a36Sopenharmony_ci * Routine to handle itmf completions 104462306a36Sopenharmony_ci */ 104562306a36Sopenharmony_cistatic void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, 104662306a36Sopenharmony_ci struct fcpio_fw_req *desc) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci u8 type; 104962306a36Sopenharmony_ci u8 hdr_status; 105062306a36Sopenharmony_ci struct fcpio_tag ftag; 105162306a36Sopenharmony_ci u32 id; 105262306a36Sopenharmony_ci struct scsi_cmnd *sc = NULL; 105362306a36Sopenharmony_ci struct fnic_io_req *io_req; 105462306a36Sopenharmony_ci struct fnic_stats *fnic_stats = &fnic->fnic_stats; 105562306a36Sopenharmony_ci struct abort_stats *abts_stats = &fnic->fnic_stats.abts_stats; 105662306a36Sopenharmony_ci struct terminate_stats *term_stats = &fnic->fnic_stats.term_stats; 105762306a36Sopenharmony_ci struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; 105862306a36Sopenharmony_ci unsigned long flags; 105962306a36Sopenharmony_ci spinlock_t *io_lock; 106062306a36Sopenharmony_ci unsigned long start_time; 106162306a36Sopenharmony_ci unsigned int tag; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci fcpio_header_dec(&desc->hdr, &type, &hdr_status, &ftag); 106462306a36Sopenharmony_ci fcpio_tag_id_dec(&ftag, &id); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci tag = id & FNIC_TAG_MASK; 106762306a36Sopenharmony_ci if (tag == fnic->fnic_max_tag_id) { 106862306a36Sopenharmony_ci if (!(id & FNIC_TAG_DEV_RST)) { 106962306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 107062306a36Sopenharmony_ci "Tag out of range id 0x%x hdr status = %s\n", 107162306a36Sopenharmony_ci id, fnic_fcpio_status_to_str(hdr_status)); 107262306a36Sopenharmony_ci return; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci } else if (tag > fnic->fnic_max_tag_id) { 107562306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 107662306a36Sopenharmony_ci "Tag out of range tag 0x%x hdr status = %s\n", 107762306a36Sopenharmony_ci tag, fnic_fcpio_status_to_str(hdr_status)); 107862306a36Sopenharmony_ci return; 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci if ((tag == fnic->fnic_max_tag_id) && (id & FNIC_TAG_DEV_RST)) { 108262306a36Sopenharmony_ci sc = fnic->sgreset_sc; 108362306a36Sopenharmony_ci io_lock = &fnic->sgreset_lock; 108462306a36Sopenharmony_ci } else { 108562306a36Sopenharmony_ci sc = scsi_host_find_tag(fnic->lport->host, id & FNIC_TAG_MASK); 108662306a36Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci WARN_ON_ONCE(!sc); 109062306a36Sopenharmony_ci if (!sc) { 109162306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.sc_null); 109262306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 109362306a36Sopenharmony_ci "itmf_cmpl sc is null - hdr status = %s tag = 0x%x\n", 109462306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status), tag); 109562306a36Sopenharmony_ci return; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 109962306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 110062306a36Sopenharmony_ci WARN_ON_ONCE(!io_req); 110162306a36Sopenharmony_ci if (!io_req) { 110262306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.ioreq_null); 110362306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 110462306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_REQ_NULL; 110562306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 110662306a36Sopenharmony_ci "itmf_cmpl io_req is null - " 110762306a36Sopenharmony_ci "hdr status = %s tag = 0x%x sc 0x%p\n", 110862306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status), tag, sc); 110962306a36Sopenharmony_ci return; 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci start_time = io_req->start_time; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci if ((id & FNIC_TAG_ABORT) && (id & FNIC_TAG_DEV_RST)) { 111462306a36Sopenharmony_ci /* Abort and terminate completion of device reset req */ 111562306a36Sopenharmony_ci /* REVISIT : Add asserts about various flags */ 111662306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 111762306a36Sopenharmony_ci "dev reset abts cmpl recd. id %x status %s\n", 111862306a36Sopenharmony_ci id, fnic_fcpio_status_to_str(hdr_status)); 111962306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_ABTS_COMPLETE; 112062306a36Sopenharmony_ci fnic_priv(sc)->abts_status = hdr_status; 112162306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_DEV_RST_DONE; 112262306a36Sopenharmony_ci if (io_req->abts_done) 112362306a36Sopenharmony_ci complete(io_req->abts_done); 112462306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 112562306a36Sopenharmony_ci } else if (id & FNIC_TAG_ABORT) { 112662306a36Sopenharmony_ci /* Completion of abort cmd */ 112762306a36Sopenharmony_ci switch (hdr_status) { 112862306a36Sopenharmony_ci case FCPIO_SUCCESS: 112962306a36Sopenharmony_ci break; 113062306a36Sopenharmony_ci case FCPIO_TIMEOUT: 113162306a36Sopenharmony_ci if (fnic_priv(sc)->flags & FNIC_IO_ABTS_ISSUED) 113262306a36Sopenharmony_ci atomic64_inc(&abts_stats->abort_fw_timeouts); 113362306a36Sopenharmony_ci else 113462306a36Sopenharmony_ci atomic64_inc( 113562306a36Sopenharmony_ci &term_stats->terminate_fw_timeouts); 113662306a36Sopenharmony_ci break; 113762306a36Sopenharmony_ci case FCPIO_ITMF_REJECTED: 113862306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 113962306a36Sopenharmony_ci "abort reject recd. id %d\n", 114062306a36Sopenharmony_ci (int)(id & FNIC_TAG_MASK)); 114162306a36Sopenharmony_ci break; 114262306a36Sopenharmony_ci case FCPIO_IO_NOT_FOUND: 114362306a36Sopenharmony_ci if (fnic_priv(sc)->flags & FNIC_IO_ABTS_ISSUED) 114462306a36Sopenharmony_ci atomic64_inc(&abts_stats->abort_io_not_found); 114562306a36Sopenharmony_ci else 114662306a36Sopenharmony_ci atomic64_inc( 114762306a36Sopenharmony_ci &term_stats->terminate_io_not_found); 114862306a36Sopenharmony_ci break; 114962306a36Sopenharmony_ci default: 115062306a36Sopenharmony_ci if (fnic_priv(sc)->flags & FNIC_IO_ABTS_ISSUED) 115162306a36Sopenharmony_ci atomic64_inc(&abts_stats->abort_failures); 115262306a36Sopenharmony_ci else 115362306a36Sopenharmony_ci atomic64_inc( 115462306a36Sopenharmony_ci &term_stats->terminate_failures); 115562306a36Sopenharmony_ci break; 115662306a36Sopenharmony_ci } 115762306a36Sopenharmony_ci if (fnic_priv(sc)->state != FNIC_IOREQ_ABTS_PENDING) { 115862306a36Sopenharmony_ci /* This is a late completion. Ignore it */ 115962306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 116062306a36Sopenharmony_ci return; 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_DONE; 116462306a36Sopenharmony_ci fnic_priv(sc)->abts_status = hdr_status; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci /* If the status is IO not found consider it as success */ 116762306a36Sopenharmony_ci if (hdr_status == FCPIO_IO_NOT_FOUND) 116862306a36Sopenharmony_ci fnic_priv(sc)->abts_status = FCPIO_SUCCESS; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci if (!(fnic_priv(sc)->flags & (FNIC_IO_ABORTED | FNIC_IO_DONE))) 117162306a36Sopenharmony_ci atomic64_inc(&misc_stats->no_icmnd_itmf_cmpls); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 117462306a36Sopenharmony_ci "abts cmpl recd. id %d status %s\n", 117562306a36Sopenharmony_ci (int)(id & FNIC_TAG_MASK), 117662306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci /* 117962306a36Sopenharmony_ci * If scsi_eh thread is blocked waiting for abts to complete, 118062306a36Sopenharmony_ci * signal completion to it. IO will be cleaned in the thread 118162306a36Sopenharmony_ci * else clean it in this context 118262306a36Sopenharmony_ci */ 118362306a36Sopenharmony_ci if (io_req->abts_done) { 118462306a36Sopenharmony_ci complete(io_req->abts_done); 118562306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 118662306a36Sopenharmony_ci } else { 118762306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 118862306a36Sopenharmony_ci "abts cmpl, completing IO\n"); 118962306a36Sopenharmony_ci fnic_priv(sc)->io_req = NULL; 119062306a36Sopenharmony_ci sc->result = (DID_ERROR << 16); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 119562306a36Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 119662306a36Sopenharmony_ci FNIC_TRACE(fnic_fcpio_itmf_cmpl_handler, 119762306a36Sopenharmony_ci sc->device->host->host_no, id, 119862306a36Sopenharmony_ci sc, 119962306a36Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 120062306a36Sopenharmony_ci desc, 120162306a36Sopenharmony_ci (((u64)hdr_status << 40) | 120262306a36Sopenharmony_ci (u64)sc->cmnd[0] << 32 | 120362306a36Sopenharmony_ci (u64)sc->cmnd[2] << 24 | 120462306a36Sopenharmony_ci (u64)sc->cmnd[3] << 16 | 120562306a36Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), 120662306a36Sopenharmony_ci fnic_flags_and_state(sc)); 120762306a36Sopenharmony_ci scsi_done(sc); 120862306a36Sopenharmony_ci atomic64_dec(&fnic_stats->io_stats.active_ios); 120962306a36Sopenharmony_ci if (atomic64_read(&fnic->io_cmpl_skip)) 121062306a36Sopenharmony_ci atomic64_dec(&fnic->io_cmpl_skip); 121162306a36Sopenharmony_ci else 121262306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_completions); 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci } else if (id & FNIC_TAG_DEV_RST) { 121562306a36Sopenharmony_ci /* Completion of device reset */ 121662306a36Sopenharmony_ci fnic_priv(sc)->lr_status = hdr_status; 121762306a36Sopenharmony_ci if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) { 121862306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 121962306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_DEV_RST_ABTS_PENDING; 122062306a36Sopenharmony_ci FNIC_TRACE(fnic_fcpio_itmf_cmpl_handler, 122162306a36Sopenharmony_ci sc->device->host->host_no, id, sc, 122262306a36Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 122362306a36Sopenharmony_ci desc, 0, fnic_flags_and_state(sc)); 122462306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 122562306a36Sopenharmony_ci "Terminate pending " 122662306a36Sopenharmony_ci "dev reset cmpl recd. id %d status %s\n", 122762306a36Sopenharmony_ci (int)(id & FNIC_TAG_MASK), 122862306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 122962306a36Sopenharmony_ci return; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci if (fnic_priv(sc)->flags & FNIC_DEV_RST_TIMED_OUT) { 123262306a36Sopenharmony_ci /* Need to wait for terminate completion */ 123362306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 123462306a36Sopenharmony_ci FNIC_TRACE(fnic_fcpio_itmf_cmpl_handler, 123562306a36Sopenharmony_ci sc->device->host->host_no, id, sc, 123662306a36Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 123762306a36Sopenharmony_ci desc, 0, fnic_flags_and_state(sc)); 123862306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 123962306a36Sopenharmony_ci "dev reset cmpl recd after time out. " 124062306a36Sopenharmony_ci "id %d status %s\n", 124162306a36Sopenharmony_ci (int)(id & FNIC_TAG_MASK), 124262306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 124362306a36Sopenharmony_ci return; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_CMD_COMPLETE; 124662306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_DEV_RST_DONE; 124762306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 124862306a36Sopenharmony_ci "dev reset cmpl recd. id %d status %s\n", 124962306a36Sopenharmony_ci (int)(id & FNIC_TAG_MASK), 125062306a36Sopenharmony_ci fnic_fcpio_status_to_str(hdr_status)); 125162306a36Sopenharmony_ci if (io_req->dr_done) 125262306a36Sopenharmony_ci complete(io_req->dr_done); 125362306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci } else { 125662306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 125762306a36Sopenharmony_ci "Unexpected itmf io state %s tag %x\n", 125862306a36Sopenharmony_ci fnic_ioreq_state_to_str(fnic_priv(sc)->state), id); 125962306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci} 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci/* 126562306a36Sopenharmony_ci * fnic_fcpio_cmpl_handler 126662306a36Sopenharmony_ci * Routine to service the cq for wq_copy 126762306a36Sopenharmony_ci */ 126862306a36Sopenharmony_cistatic int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev, 126962306a36Sopenharmony_ci unsigned int cq_index, 127062306a36Sopenharmony_ci struct fcpio_fw_req *desc) 127162306a36Sopenharmony_ci{ 127262306a36Sopenharmony_ci struct fnic *fnic = vnic_dev_priv(vdev); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci switch (desc->hdr.type) { 127562306a36Sopenharmony_ci case FCPIO_ICMND_CMPL: /* fw completed a command */ 127662306a36Sopenharmony_ci case FCPIO_ITMF_CMPL: /* fw completed itmf (abort cmd, lun reset)*/ 127762306a36Sopenharmony_ci case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */ 127862306a36Sopenharmony_ci case FCPIO_FLOGI_FIP_REG_CMPL: /* fw completed flogi_fip_reg */ 127962306a36Sopenharmony_ci case FCPIO_RESET_CMPL: /* fw completed reset */ 128062306a36Sopenharmony_ci atomic64_dec(&fnic->fnic_stats.fw_stats.active_fw_reqs); 128162306a36Sopenharmony_ci break; 128262306a36Sopenharmony_ci default: 128362306a36Sopenharmony_ci break; 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci switch (desc->hdr.type) { 128762306a36Sopenharmony_ci case FCPIO_ACK: /* fw copied copy wq desc to its queue */ 128862306a36Sopenharmony_ci fnic_fcpio_ack_handler(fnic, cq_index, desc); 128962306a36Sopenharmony_ci break; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci case FCPIO_ICMND_CMPL: /* fw completed a command */ 129262306a36Sopenharmony_ci fnic_fcpio_icmnd_cmpl_handler(fnic, desc); 129362306a36Sopenharmony_ci break; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci case FCPIO_ITMF_CMPL: /* fw completed itmf (abort cmd, lun reset)*/ 129662306a36Sopenharmony_ci fnic_fcpio_itmf_cmpl_handler(fnic, desc); 129762306a36Sopenharmony_ci break; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */ 130062306a36Sopenharmony_ci case FCPIO_FLOGI_FIP_REG_CMPL: /* fw completed flogi_fip_reg */ 130162306a36Sopenharmony_ci fnic_fcpio_flogi_reg_cmpl_handler(fnic, desc); 130262306a36Sopenharmony_ci break; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci case FCPIO_RESET_CMPL: /* fw completed reset */ 130562306a36Sopenharmony_ci fnic_fcpio_fw_reset_cmpl_handler(fnic, desc); 130662306a36Sopenharmony_ci break; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci default: 130962306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 131062306a36Sopenharmony_ci "firmware completion type %d\n", 131162306a36Sopenharmony_ci desc->hdr.type); 131262306a36Sopenharmony_ci break; 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci return 0; 131662306a36Sopenharmony_ci} 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci/* 131962306a36Sopenharmony_ci * fnic_wq_copy_cmpl_handler 132062306a36Sopenharmony_ci * Routine to process wq copy 132162306a36Sopenharmony_ci */ 132262306a36Sopenharmony_ciint fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do) 132362306a36Sopenharmony_ci{ 132462306a36Sopenharmony_ci unsigned int wq_work_done = 0; 132562306a36Sopenharmony_ci unsigned int i, cq_index; 132662306a36Sopenharmony_ci unsigned int cur_work_done; 132762306a36Sopenharmony_ci struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; 132862306a36Sopenharmony_ci u64 start_jiffies = 0; 132962306a36Sopenharmony_ci u64 end_jiffies = 0; 133062306a36Sopenharmony_ci u64 delta_jiffies = 0; 133162306a36Sopenharmony_ci u64 delta_ms = 0; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci for (i = 0; i < fnic->wq_copy_count; i++) { 133462306a36Sopenharmony_ci cq_index = i + fnic->raw_wq_count + fnic->rq_count; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci start_jiffies = jiffies; 133762306a36Sopenharmony_ci cur_work_done = vnic_cq_copy_service(&fnic->cq[cq_index], 133862306a36Sopenharmony_ci fnic_fcpio_cmpl_handler, 133962306a36Sopenharmony_ci copy_work_to_do); 134062306a36Sopenharmony_ci end_jiffies = jiffies; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci wq_work_done += cur_work_done; 134362306a36Sopenharmony_ci delta_jiffies = end_jiffies - start_jiffies; 134462306a36Sopenharmony_ci if (delta_jiffies > 134562306a36Sopenharmony_ci (u64) atomic64_read(&misc_stats->max_isr_jiffies)) { 134662306a36Sopenharmony_ci atomic64_set(&misc_stats->max_isr_jiffies, 134762306a36Sopenharmony_ci delta_jiffies); 134862306a36Sopenharmony_ci delta_ms = jiffies_to_msecs(delta_jiffies); 134962306a36Sopenharmony_ci atomic64_set(&misc_stats->max_isr_time_ms, delta_ms); 135062306a36Sopenharmony_ci atomic64_set(&misc_stats->corr_work_done, 135162306a36Sopenharmony_ci cur_work_done); 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci return wq_work_done; 135562306a36Sopenharmony_ci} 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_cistatic bool fnic_cleanup_io_iter(struct scsi_cmnd *sc, void *data) 135862306a36Sopenharmony_ci{ 135962306a36Sopenharmony_ci const int tag = scsi_cmd_to_rq(sc)->tag; 136062306a36Sopenharmony_ci struct fnic *fnic = data; 136162306a36Sopenharmony_ci struct fnic_io_req *io_req; 136262306a36Sopenharmony_ci unsigned long flags = 0; 136362306a36Sopenharmony_ci spinlock_t *io_lock; 136462306a36Sopenharmony_ci unsigned long start_time = 0; 136562306a36Sopenharmony_ci struct fnic_stats *fnic_stats = &fnic->fnic_stats; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci io_lock = fnic_io_lock_tag(fnic, tag); 136862306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 137162306a36Sopenharmony_ci if ((fnic_priv(sc)->flags & FNIC_DEVICE_RESET) && 137262306a36Sopenharmony_ci !(fnic_priv(sc)->flags & FNIC_DEV_RST_DONE)) { 137362306a36Sopenharmony_ci /* 137462306a36Sopenharmony_ci * We will be here only when FW completes reset 137562306a36Sopenharmony_ci * without sending completions for outstanding ios. 137662306a36Sopenharmony_ci */ 137762306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_DEV_RST_DONE; 137862306a36Sopenharmony_ci if (io_req && io_req->dr_done) 137962306a36Sopenharmony_ci complete(io_req->dr_done); 138062306a36Sopenharmony_ci else if (io_req && io_req->abts_done) 138162306a36Sopenharmony_ci complete(io_req->abts_done); 138262306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 138362306a36Sopenharmony_ci return true; 138462306a36Sopenharmony_ci } else if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) { 138562306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 138662306a36Sopenharmony_ci return true; 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci if (!io_req) { 138962306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 139062306a36Sopenharmony_ci goto cleanup_scsi_cmd; 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci fnic_priv(sc)->io_req = NULL; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci /* 139862306a36Sopenharmony_ci * If there is a scsi_cmnd associated with this io_req, then 139962306a36Sopenharmony_ci * free the corresponding state 140062306a36Sopenharmony_ci */ 140162306a36Sopenharmony_ci start_time = io_req->start_time; 140262306a36Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 140362306a36Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_cicleanup_scsi_cmd: 140662306a36Sopenharmony_ci sc->result = DID_TRANSPORT_DISRUPTED << 16; 140762306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 140862306a36Sopenharmony_ci "fnic_cleanup_io: tag:0x%x : sc:0x%p duration = %lu DID_TRANSPORT_DISRUPTED\n", 140962306a36Sopenharmony_ci tag, sc, jiffies - start_time); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci if (atomic64_read(&fnic->io_cmpl_skip)) 141262306a36Sopenharmony_ci atomic64_dec(&fnic->io_cmpl_skip); 141362306a36Sopenharmony_ci else 141462306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_completions); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci /* Complete the command to SCSI */ 141762306a36Sopenharmony_ci if (!(fnic_priv(sc)->flags & FNIC_IO_ISSUED)) 141862306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 141962306a36Sopenharmony_ci "Calling done for IO not issued to fw: tag:0x%x sc:0x%p\n", 142062306a36Sopenharmony_ci tag, sc); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci FNIC_TRACE(fnic_cleanup_io, 142362306a36Sopenharmony_ci sc->device->host->host_no, tag, sc, 142462306a36Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 142562306a36Sopenharmony_ci 0, ((u64)sc->cmnd[0] << 32 | 142662306a36Sopenharmony_ci (u64)sc->cmnd[2] << 24 | 142762306a36Sopenharmony_ci (u64)sc->cmnd[3] << 16 | 142862306a36Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), 142962306a36Sopenharmony_ci fnic_flags_and_state(sc)); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci scsi_done(sc); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci return true; 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_cistatic void fnic_cleanup_io(struct fnic *fnic) 143762306a36Sopenharmony_ci{ 143862306a36Sopenharmony_ci scsi_host_busy_iter(fnic->lport->host, 143962306a36Sopenharmony_ci fnic_cleanup_io_iter, fnic); 144062306a36Sopenharmony_ci} 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_civoid fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, 144362306a36Sopenharmony_ci struct fcpio_host_req *desc) 144462306a36Sopenharmony_ci{ 144562306a36Sopenharmony_ci u32 id; 144662306a36Sopenharmony_ci struct fnic *fnic = vnic_dev_priv(wq->vdev); 144762306a36Sopenharmony_ci struct fnic_io_req *io_req; 144862306a36Sopenharmony_ci struct scsi_cmnd *sc; 144962306a36Sopenharmony_ci unsigned long flags; 145062306a36Sopenharmony_ci spinlock_t *io_lock; 145162306a36Sopenharmony_ci unsigned long start_time = 0; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci /* get the tag reference */ 145462306a36Sopenharmony_ci fcpio_tag_id_dec(&desc->hdr.tag, &id); 145562306a36Sopenharmony_ci id &= FNIC_TAG_MASK; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci if (id >= fnic->fnic_max_tag_id) 145862306a36Sopenharmony_ci return; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci sc = scsi_host_find_tag(fnic->lport->host, id); 146162306a36Sopenharmony_ci if (!sc) 146262306a36Sopenharmony_ci return; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 146562306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci /* Get the IO context which this desc refers to */ 146862306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci /* fnic interrupts are turned off by now */ 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (!io_req) { 147362306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 147462306a36Sopenharmony_ci goto wq_copy_cleanup_scsi_cmd; 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci fnic_priv(sc)->io_req = NULL; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci start_time = io_req->start_time; 148262306a36Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 148362306a36Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ciwq_copy_cleanup_scsi_cmd: 148662306a36Sopenharmony_ci sc->result = DID_NO_CONNECT << 16; 148762306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "wq_copy_cleanup_handler:" 148862306a36Sopenharmony_ci " DID_NO_CONNECT\n"); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci FNIC_TRACE(fnic_wq_copy_cleanup_handler, 149162306a36Sopenharmony_ci sc->device->host->host_no, id, sc, 149262306a36Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 149362306a36Sopenharmony_ci 0, ((u64)sc->cmnd[0] << 32 | 149462306a36Sopenharmony_ci (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | 149562306a36Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), 149662306a36Sopenharmony_ci fnic_flags_and_state(sc)); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci scsi_done(sc); 149962306a36Sopenharmony_ci} 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_cistatic inline int fnic_queue_abort_io_req(struct fnic *fnic, int tag, 150262306a36Sopenharmony_ci u32 task_req, u8 *fc_lun, 150362306a36Sopenharmony_ci struct fnic_io_req *io_req) 150462306a36Sopenharmony_ci{ 150562306a36Sopenharmony_ci struct vnic_wq_copy *wq = &fnic->wq_copy[0]; 150662306a36Sopenharmony_ci struct Scsi_Host *host = fnic->lport->host; 150762306a36Sopenharmony_ci struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; 150862306a36Sopenharmony_ci unsigned long flags; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci spin_lock_irqsave(host->host_lock, flags); 151162306a36Sopenharmony_ci if (unlikely(fnic_chk_state_flags_locked(fnic, 151262306a36Sopenharmony_ci FNIC_FLAGS_IO_BLOCKED))) { 151362306a36Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, flags); 151462306a36Sopenharmony_ci return 1; 151562306a36Sopenharmony_ci } else 151662306a36Sopenharmony_ci atomic_inc(&fnic->in_flight); 151762306a36Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, flags); 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) 152262306a36Sopenharmony_ci free_wq_copy_descs(fnic, wq); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (!vnic_wq_copy_desc_avail(wq)) { 152562306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); 152662306a36Sopenharmony_ci atomic_dec(&fnic->in_flight); 152762306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 152862306a36Sopenharmony_ci "fnic_queue_abort_io_req: failure: no descriptors\n"); 152962306a36Sopenharmony_ci atomic64_inc(&misc_stats->abts_cpwq_alloc_failures); 153062306a36Sopenharmony_ci return 1; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci fnic_queue_wq_copy_desc_itmf(wq, tag | FNIC_TAG_ABORT, 153362306a36Sopenharmony_ci 0, task_req, tag, fc_lun, io_req->port_id, 153462306a36Sopenharmony_ci fnic->config.ra_tov, fnic->config.ed_tov); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); 153762306a36Sopenharmony_ci if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) > 153862306a36Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs)) 153962306a36Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, 154062306a36Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs)); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); 154362306a36Sopenharmony_ci atomic_dec(&fnic->in_flight); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci return 0; 154662306a36Sopenharmony_ci} 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_cistruct fnic_rport_abort_io_iter_data { 154962306a36Sopenharmony_ci struct fnic *fnic; 155062306a36Sopenharmony_ci u32 port_id; 155162306a36Sopenharmony_ci int term_cnt; 155262306a36Sopenharmony_ci}; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_cistatic bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data) 155562306a36Sopenharmony_ci{ 155662306a36Sopenharmony_ci struct fnic_rport_abort_io_iter_data *iter_data = data; 155762306a36Sopenharmony_ci struct fnic *fnic = iter_data->fnic; 155862306a36Sopenharmony_ci int abt_tag = scsi_cmd_to_rq(sc)->tag; 155962306a36Sopenharmony_ci struct fnic_io_req *io_req; 156062306a36Sopenharmony_ci spinlock_t *io_lock; 156162306a36Sopenharmony_ci unsigned long flags; 156262306a36Sopenharmony_ci struct reset_stats *reset_stats = &fnic->fnic_stats.reset_stats; 156362306a36Sopenharmony_ci struct terminate_stats *term_stats = &fnic->fnic_stats.term_stats; 156462306a36Sopenharmony_ci struct scsi_lun fc_lun; 156562306a36Sopenharmony_ci enum fnic_ioreq_state old_ioreq_state; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci io_lock = fnic_io_lock_tag(fnic, abt_tag); 156862306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci if (!io_req || io_req->port_id != iter_data->port_id) { 157362306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 157462306a36Sopenharmony_ci return true; 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci if ((fnic_priv(sc)->flags & FNIC_DEVICE_RESET) && 157862306a36Sopenharmony_ci !(fnic_priv(sc)->flags & FNIC_DEV_RST_ISSUED)) { 157962306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 158062306a36Sopenharmony_ci "fnic_rport_exch_reset dev rst not pending sc 0x%p\n", 158162306a36Sopenharmony_ci sc); 158262306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 158362306a36Sopenharmony_ci return true; 158462306a36Sopenharmony_ci } 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci /* 158762306a36Sopenharmony_ci * Found IO that is still pending with firmware and 158862306a36Sopenharmony_ci * belongs to rport that went away 158962306a36Sopenharmony_ci */ 159062306a36Sopenharmony_ci if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) { 159162306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 159262306a36Sopenharmony_ci return true; 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci if (io_req->abts_done) { 159562306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 159662306a36Sopenharmony_ci "fnic_rport_exch_reset: io_req->abts_done is set " 159762306a36Sopenharmony_ci "state is %s\n", 159862306a36Sopenharmony_ci fnic_ioreq_state_to_str(fnic_priv(sc)->state)); 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (!(fnic_priv(sc)->flags & FNIC_IO_ISSUED)) { 160262306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 160362306a36Sopenharmony_ci "rport_exch_reset " 160462306a36Sopenharmony_ci "IO not yet issued %p tag 0x%x flags " 160562306a36Sopenharmony_ci "%x state %d\n", 160662306a36Sopenharmony_ci sc, abt_tag, fnic_priv(sc)->flags, fnic_priv(sc)->state); 160762306a36Sopenharmony_ci } 160862306a36Sopenharmony_ci old_ioreq_state = fnic_priv(sc)->state; 160962306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_ABTS_PENDING; 161062306a36Sopenharmony_ci fnic_priv(sc)->abts_status = FCPIO_INVALID_CODE; 161162306a36Sopenharmony_ci if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) { 161262306a36Sopenharmony_ci atomic64_inc(&reset_stats->device_reset_terminates); 161362306a36Sopenharmony_ci abt_tag |= FNIC_TAG_DEV_RST; 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 161662306a36Sopenharmony_ci "fnic_rport_exch_reset dev rst sc 0x%p\n", sc); 161762306a36Sopenharmony_ci BUG_ON(io_req->abts_done); 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 162062306a36Sopenharmony_ci "fnic_rport_reset_exch: Issuing abts\n"); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci /* Now queue the abort command to firmware */ 162562306a36Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (fnic_queue_abort_io_req(fnic, abt_tag, 162862306a36Sopenharmony_ci FCPIO_ITMF_ABT_TASK_TERM, 162962306a36Sopenharmony_ci fc_lun.scsi_lun, io_req)) { 163062306a36Sopenharmony_ci /* 163162306a36Sopenharmony_ci * Revert the cmd state back to old state, if 163262306a36Sopenharmony_ci * it hasn't changed in between. This cmd will get 163362306a36Sopenharmony_ci * aborted later by scsi_eh, or cleaned up during 163462306a36Sopenharmony_ci * lun reset 163562306a36Sopenharmony_ci */ 163662306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 163762306a36Sopenharmony_ci if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) 163862306a36Sopenharmony_ci fnic_priv(sc)->state = old_ioreq_state; 163962306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 164062306a36Sopenharmony_ci } else { 164162306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 164262306a36Sopenharmony_ci if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) 164362306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_DEV_RST_TERM_ISSUED; 164462306a36Sopenharmony_ci else 164562306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_INTERNAL_TERM_ISSUED; 164662306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 164762306a36Sopenharmony_ci atomic64_inc(&term_stats->terminates); 164862306a36Sopenharmony_ci iter_data->term_cnt++; 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci return true; 165162306a36Sopenharmony_ci} 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_cistatic void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id) 165462306a36Sopenharmony_ci{ 165562306a36Sopenharmony_ci struct terminate_stats *term_stats = &fnic->fnic_stats.term_stats; 165662306a36Sopenharmony_ci struct fnic_rport_abort_io_iter_data iter_data = { 165762306a36Sopenharmony_ci .fnic = fnic, 165862306a36Sopenharmony_ci .port_id = port_id, 165962306a36Sopenharmony_ci .term_cnt = 0, 166062306a36Sopenharmony_ci }; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 166362306a36Sopenharmony_ci fnic->lport->host, 166462306a36Sopenharmony_ci "fnic_rport_exch_reset called portid 0x%06x\n", 166562306a36Sopenharmony_ci port_id); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci if (fnic->in_remove) 166862306a36Sopenharmony_ci return; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci scsi_host_busy_iter(fnic->lport->host, fnic_rport_abort_io_iter, 167162306a36Sopenharmony_ci &iter_data); 167262306a36Sopenharmony_ci if (iter_data.term_cnt > atomic64_read(&term_stats->max_terminates)) 167362306a36Sopenharmony_ci atomic64_set(&term_stats->max_terminates, iter_data.term_cnt); 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci} 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_civoid fnic_terminate_rport_io(struct fc_rport *rport) 167862306a36Sopenharmony_ci{ 167962306a36Sopenharmony_ci struct fc_rport_libfc_priv *rdata; 168062306a36Sopenharmony_ci struct fc_lport *lport; 168162306a36Sopenharmony_ci struct fnic *fnic; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci if (!rport) { 168462306a36Sopenharmony_ci printk(KERN_ERR "fnic_terminate_rport_io: rport is NULL\n"); 168562306a36Sopenharmony_ci return; 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci rdata = rport->dd_data; 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci if (!rdata) { 169062306a36Sopenharmony_ci printk(KERN_ERR "fnic_terminate_rport_io: rdata is NULL\n"); 169162306a36Sopenharmony_ci return; 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci lport = rdata->local_port; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci if (!lport) { 169662306a36Sopenharmony_ci printk(KERN_ERR "fnic_terminate_rport_io: lport is NULL\n"); 169762306a36Sopenharmony_ci return; 169862306a36Sopenharmony_ci } 169962306a36Sopenharmony_ci fnic = lport_priv(lport); 170062306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 170162306a36Sopenharmony_ci fnic->lport->host, "fnic_terminate_rport_io called" 170262306a36Sopenharmony_ci " wwpn 0x%llx, wwnn0x%llx, rport 0x%p, portid 0x%06x\n", 170362306a36Sopenharmony_ci rport->port_name, rport->node_name, rport, 170462306a36Sopenharmony_ci rport->port_id); 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci if (fnic->in_remove) 170762306a36Sopenharmony_ci return; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci fnic_rport_exch_reset(fnic, rport->port_id); 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci/* 171362306a36Sopenharmony_ci * This function is exported to SCSI for sending abort cmnds. 171462306a36Sopenharmony_ci * A SCSI IO is represented by a io_req in the driver. 171562306a36Sopenharmony_ci * The ioreq is linked to the SCSI Cmd, thus a link with the ULP's IO. 171662306a36Sopenharmony_ci */ 171762306a36Sopenharmony_ciint fnic_abort_cmd(struct scsi_cmnd *sc) 171862306a36Sopenharmony_ci{ 171962306a36Sopenharmony_ci struct request *const rq = scsi_cmd_to_rq(sc); 172062306a36Sopenharmony_ci struct fc_lport *lp; 172162306a36Sopenharmony_ci struct fnic *fnic; 172262306a36Sopenharmony_ci struct fnic_io_req *io_req = NULL; 172362306a36Sopenharmony_ci struct fc_rport *rport; 172462306a36Sopenharmony_ci spinlock_t *io_lock; 172562306a36Sopenharmony_ci unsigned long flags; 172662306a36Sopenharmony_ci unsigned long start_time = 0; 172762306a36Sopenharmony_ci int ret = SUCCESS; 172862306a36Sopenharmony_ci u32 task_req = 0; 172962306a36Sopenharmony_ci struct scsi_lun fc_lun; 173062306a36Sopenharmony_ci struct fnic_stats *fnic_stats; 173162306a36Sopenharmony_ci struct abort_stats *abts_stats; 173262306a36Sopenharmony_ci struct terminate_stats *term_stats; 173362306a36Sopenharmony_ci enum fnic_ioreq_state old_ioreq_state; 173462306a36Sopenharmony_ci const int tag = rq->tag; 173562306a36Sopenharmony_ci unsigned long abt_issued_time; 173662306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(tm_done); 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci /* Wait for rport to unblock */ 173962306a36Sopenharmony_ci fc_block_scsi_eh(sc); 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci /* Get local-port, check ready and link up */ 174262306a36Sopenharmony_ci lp = shost_priv(sc->device->host); 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci fnic = lport_priv(lp); 174562306a36Sopenharmony_ci fnic_stats = &fnic->fnic_stats; 174662306a36Sopenharmony_ci abts_stats = &fnic->fnic_stats.abts_stats; 174762306a36Sopenharmony_ci term_stats = &fnic->fnic_stats.term_stats; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci rport = starget_to_rport(scsi_target(sc->device)); 175062306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 175162306a36Sopenharmony_ci fnic->lport->host, 175262306a36Sopenharmony_ci "Abort Cmd called FCID 0x%x, LUN 0x%llx TAG %x flags %x\n", 175362306a36Sopenharmony_ci rport->port_id, sc->device->lun, tag, fnic_priv(sc)->flags); 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci fnic_priv(sc)->flags = FNIC_NO_FLAGS; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci if (lp->state != LPORT_ST_READY || !(lp->link_up)) { 175862306a36Sopenharmony_ci ret = FAILED; 175962306a36Sopenharmony_ci goto fnic_abort_cmd_end; 176062306a36Sopenharmony_ci } 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci /* 176362306a36Sopenharmony_ci * Avoid a race between SCSI issuing the abort and the device 176462306a36Sopenharmony_ci * completing the command. 176562306a36Sopenharmony_ci * 176662306a36Sopenharmony_ci * If the command is already completed by the fw cmpl code, 176762306a36Sopenharmony_ci * we just return SUCCESS from here. This means that the abort 176862306a36Sopenharmony_ci * succeeded. In the SCSI ML, since the timeout for command has 176962306a36Sopenharmony_ci * happened, the completion wont actually complete the command 177062306a36Sopenharmony_ci * and it will be considered as an aborted command 177162306a36Sopenharmony_ci * 177262306a36Sopenharmony_ci * .io_req will not be cleared except while holding io_req_lock. 177362306a36Sopenharmony_ci */ 177462306a36Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 177562306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 177662306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 177762306a36Sopenharmony_ci if (!io_req) { 177862306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 177962306a36Sopenharmony_ci goto fnic_abort_cmd_end; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci io_req->abts_done = &tm_done; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) { 178562306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 178662306a36Sopenharmony_ci goto wait_pending; 178762306a36Sopenharmony_ci } 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci abt_issued_time = jiffies_to_msecs(jiffies) - jiffies_to_msecs(io_req->start_time); 179062306a36Sopenharmony_ci if (abt_issued_time <= 6000) 179162306a36Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_0_to_6_sec); 179262306a36Sopenharmony_ci else if (abt_issued_time > 6000 && abt_issued_time <= 20000) 179362306a36Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_6_to_20_sec); 179462306a36Sopenharmony_ci else if (abt_issued_time > 20000 && abt_issued_time <= 30000) 179562306a36Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_20_to_30_sec); 179662306a36Sopenharmony_ci else if (abt_issued_time > 30000 && abt_issued_time <= 40000) 179762306a36Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_30_to_40_sec); 179862306a36Sopenharmony_ci else if (abt_issued_time > 40000 && abt_issued_time <= 50000) 179962306a36Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_40_to_50_sec); 180062306a36Sopenharmony_ci else if (abt_issued_time > 50000 && abt_issued_time <= 60000) 180162306a36Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_btw_50_to_60_sec); 180262306a36Sopenharmony_ci else 180362306a36Sopenharmony_ci atomic64_inc(&abts_stats->abort_issued_greater_than_60_sec); 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 180662306a36Sopenharmony_ci "CBD Opcode: %02x Abort issued time: %lu msec\n", sc->cmnd[0], abt_issued_time); 180762306a36Sopenharmony_ci /* 180862306a36Sopenharmony_ci * Command is still pending, need to abort it 180962306a36Sopenharmony_ci * If the firmware completes the command after this point, 181062306a36Sopenharmony_ci * the completion wont be done till mid-layer, since abort 181162306a36Sopenharmony_ci * has already started. 181262306a36Sopenharmony_ci */ 181362306a36Sopenharmony_ci old_ioreq_state = fnic_priv(sc)->state; 181462306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_ABTS_PENDING; 181562306a36Sopenharmony_ci fnic_priv(sc)->abts_status = FCPIO_INVALID_CODE; 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci /* 182062306a36Sopenharmony_ci * Check readiness of the remote port. If the path to remote 182162306a36Sopenharmony_ci * port is up, then send abts to the remote port to terminate 182262306a36Sopenharmony_ci * the IO. Else, just locally terminate the IO in the firmware 182362306a36Sopenharmony_ci */ 182462306a36Sopenharmony_ci if (fc_remote_port_chkready(rport) == 0) 182562306a36Sopenharmony_ci task_req = FCPIO_ITMF_ABT_TASK; 182662306a36Sopenharmony_ci else { 182762306a36Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.rport_not_ready); 182862306a36Sopenharmony_ci task_req = FCPIO_ITMF_ABT_TASK_TERM; 182962306a36Sopenharmony_ci } 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci /* Now queue the abort command to firmware */ 183262306a36Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci if (fnic_queue_abort_io_req(fnic, tag, task_req, fc_lun.scsi_lun, 183562306a36Sopenharmony_ci io_req)) { 183662306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 183762306a36Sopenharmony_ci if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) 183862306a36Sopenharmony_ci fnic_priv(sc)->state = old_ioreq_state; 183962306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 184062306a36Sopenharmony_ci if (io_req) 184162306a36Sopenharmony_ci io_req->abts_done = NULL; 184262306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 184362306a36Sopenharmony_ci ret = FAILED; 184462306a36Sopenharmony_ci goto fnic_abort_cmd_end; 184562306a36Sopenharmony_ci } 184662306a36Sopenharmony_ci if (task_req == FCPIO_ITMF_ABT_TASK) { 184762306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_ABTS_ISSUED; 184862306a36Sopenharmony_ci atomic64_inc(&fnic_stats->abts_stats.aborts); 184962306a36Sopenharmony_ci } else { 185062306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_TERM_ISSUED; 185162306a36Sopenharmony_ci atomic64_inc(&fnic_stats->term_stats.terminates); 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci /* 185562306a36Sopenharmony_ci * We queued an abort IO, wait for its completion. 185662306a36Sopenharmony_ci * Once the firmware completes the abort command, it will 185762306a36Sopenharmony_ci * wake up this thread. 185862306a36Sopenharmony_ci */ 185962306a36Sopenharmony_ci wait_pending: 186062306a36Sopenharmony_ci wait_for_completion_timeout(&tm_done, 186162306a36Sopenharmony_ci msecs_to_jiffies 186262306a36Sopenharmony_ci (2 * fnic->config.ra_tov + 186362306a36Sopenharmony_ci fnic->config.ed_tov)); 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci /* Check the abort status */ 186662306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 186962306a36Sopenharmony_ci if (!io_req) { 187062306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.ioreq_null); 187162306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 187262306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_REQ_NULL; 187362306a36Sopenharmony_ci ret = FAILED; 187462306a36Sopenharmony_ci goto fnic_abort_cmd_end; 187562306a36Sopenharmony_ci } 187662306a36Sopenharmony_ci io_req->abts_done = NULL; 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci /* fw did not complete abort, timed out */ 187962306a36Sopenharmony_ci if (fnic_priv(sc)->abts_status == FCPIO_INVALID_CODE) { 188062306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 188162306a36Sopenharmony_ci if (task_req == FCPIO_ITMF_ABT_TASK) { 188262306a36Sopenharmony_ci atomic64_inc(&abts_stats->abort_drv_timeouts); 188362306a36Sopenharmony_ci } else { 188462306a36Sopenharmony_ci atomic64_inc(&term_stats->terminate_drv_timeouts); 188562306a36Sopenharmony_ci } 188662306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_TIMED_OUT; 188762306a36Sopenharmony_ci ret = FAILED; 188862306a36Sopenharmony_ci goto fnic_abort_cmd_end; 188962306a36Sopenharmony_ci } 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci /* IO out of order */ 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci if (!(fnic_priv(sc)->flags & (FNIC_IO_ABORTED | FNIC_IO_DONE))) { 189462306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 189562306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 189662306a36Sopenharmony_ci "Issuing Host reset due to out of order IO\n"); 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci ret = FAILED; 189962306a36Sopenharmony_ci goto fnic_abort_cmd_end; 190062306a36Sopenharmony_ci } 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_ABTS_COMPLETE; 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci start_time = io_req->start_time; 190562306a36Sopenharmony_ci /* 190662306a36Sopenharmony_ci * firmware completed the abort, check the status, 190762306a36Sopenharmony_ci * free the io_req if successful. If abort fails, 190862306a36Sopenharmony_ci * Device reset will clean the I/O. 190962306a36Sopenharmony_ci */ 191062306a36Sopenharmony_ci if (fnic_priv(sc)->abts_status == FCPIO_SUCCESS) { 191162306a36Sopenharmony_ci fnic_priv(sc)->io_req = NULL; 191262306a36Sopenharmony_ci } else { 191362306a36Sopenharmony_ci ret = FAILED; 191462306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 191562306a36Sopenharmony_ci goto fnic_abort_cmd_end; 191662306a36Sopenharmony_ci } 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 192162306a36Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci /* Call SCSI completion function to complete the IO */ 192462306a36Sopenharmony_ci sc->result = DID_ABORT << 16; 192562306a36Sopenharmony_ci scsi_done(sc); 192662306a36Sopenharmony_ci atomic64_dec(&fnic_stats->io_stats.active_ios); 192762306a36Sopenharmony_ci if (atomic64_read(&fnic->io_cmpl_skip)) 192862306a36Sopenharmony_ci atomic64_dec(&fnic->io_cmpl_skip); 192962306a36Sopenharmony_ci else 193062306a36Sopenharmony_ci atomic64_inc(&fnic_stats->io_stats.io_completions); 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_cifnic_abort_cmd_end: 193362306a36Sopenharmony_ci FNIC_TRACE(fnic_abort_cmd, sc->device->host->host_no, tag, sc, 193462306a36Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 193562306a36Sopenharmony_ci 0, ((u64)sc->cmnd[0] << 32 | 193662306a36Sopenharmony_ci (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | 193762306a36Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), 193862306a36Sopenharmony_ci fnic_flags_and_state(sc)); 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 194162306a36Sopenharmony_ci "Returning from abort cmd type %x %s\n", task_req, 194262306a36Sopenharmony_ci (ret == SUCCESS) ? 194362306a36Sopenharmony_ci "SUCCESS" : "FAILED"); 194462306a36Sopenharmony_ci return ret; 194562306a36Sopenharmony_ci} 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_cistatic inline int fnic_queue_dr_io_req(struct fnic *fnic, 194862306a36Sopenharmony_ci struct scsi_cmnd *sc, 194962306a36Sopenharmony_ci struct fnic_io_req *io_req) 195062306a36Sopenharmony_ci{ 195162306a36Sopenharmony_ci struct vnic_wq_copy *wq = &fnic->wq_copy[0]; 195262306a36Sopenharmony_ci struct Scsi_Host *host = fnic->lport->host; 195362306a36Sopenharmony_ci struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; 195462306a36Sopenharmony_ci struct scsi_lun fc_lun; 195562306a36Sopenharmony_ci int ret = 0; 195662306a36Sopenharmony_ci unsigned long intr_flags; 195762306a36Sopenharmony_ci unsigned int tag = scsi_cmd_to_rq(sc)->tag; 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci if (tag == SCSI_NO_TAG) 196062306a36Sopenharmony_ci tag = io_req->tag; 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci spin_lock_irqsave(host->host_lock, intr_flags); 196362306a36Sopenharmony_ci if (unlikely(fnic_chk_state_flags_locked(fnic, 196462306a36Sopenharmony_ci FNIC_FLAGS_IO_BLOCKED))) { 196562306a36Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, intr_flags); 196662306a36Sopenharmony_ci return FAILED; 196762306a36Sopenharmony_ci } else 196862306a36Sopenharmony_ci atomic_inc(&fnic->in_flight); 196962306a36Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, intr_flags); 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags); 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) 197462306a36Sopenharmony_ci free_wq_copy_descs(fnic, wq); 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci if (!vnic_wq_copy_desc_avail(wq)) { 197762306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 197862306a36Sopenharmony_ci "queue_dr_io_req failure - no descriptors\n"); 197962306a36Sopenharmony_ci atomic64_inc(&misc_stats->devrst_cpwq_alloc_failures); 198062306a36Sopenharmony_ci ret = -EAGAIN; 198162306a36Sopenharmony_ci goto lr_io_req_end; 198262306a36Sopenharmony_ci } 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci /* fill in the lun info */ 198562306a36Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci tag |= FNIC_TAG_DEV_RST; 198862306a36Sopenharmony_ci fnic_queue_wq_copy_desc_itmf(wq, tag, 198962306a36Sopenharmony_ci 0, FCPIO_ITMF_LUN_RESET, SCSI_NO_TAG, 199062306a36Sopenharmony_ci fc_lun.scsi_lun, io_req->port_id, 199162306a36Sopenharmony_ci fnic->config.ra_tov, fnic->config.ed_tov); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); 199462306a36Sopenharmony_ci if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) > 199562306a36Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs)) 199662306a36Sopenharmony_ci atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, 199762306a36Sopenharmony_ci atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs)); 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_cilr_io_req_end: 200062306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); 200162306a36Sopenharmony_ci atomic_dec(&fnic->in_flight); 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci return ret; 200462306a36Sopenharmony_ci} 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_cistruct fnic_pending_aborts_iter_data { 200762306a36Sopenharmony_ci struct fnic *fnic; 200862306a36Sopenharmony_ci struct scsi_cmnd *lr_sc; 200962306a36Sopenharmony_ci struct scsi_device *lun_dev; 201062306a36Sopenharmony_ci int ret; 201162306a36Sopenharmony_ci}; 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_cistatic bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) 201462306a36Sopenharmony_ci{ 201562306a36Sopenharmony_ci struct fnic_pending_aborts_iter_data *iter_data = data; 201662306a36Sopenharmony_ci struct fnic *fnic = iter_data->fnic; 201762306a36Sopenharmony_ci struct scsi_device *lun_dev = iter_data->lun_dev; 201862306a36Sopenharmony_ci int abt_tag = scsi_cmd_to_rq(sc)->tag; 201962306a36Sopenharmony_ci struct fnic_io_req *io_req; 202062306a36Sopenharmony_ci spinlock_t *io_lock; 202162306a36Sopenharmony_ci unsigned long flags; 202262306a36Sopenharmony_ci struct scsi_lun fc_lun; 202362306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(tm_done); 202462306a36Sopenharmony_ci enum fnic_ioreq_state old_ioreq_state; 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci if (sc == iter_data->lr_sc || sc->device != lun_dev) 202762306a36Sopenharmony_ci return true; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci io_lock = fnic_io_lock_tag(fnic, abt_tag); 203062306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 203162306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 203262306a36Sopenharmony_ci if (!io_req) { 203362306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 203462306a36Sopenharmony_ci return true; 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci /* 203862306a36Sopenharmony_ci * Found IO that is still pending with firmware and 203962306a36Sopenharmony_ci * belongs to the LUN that we are resetting 204062306a36Sopenharmony_ci */ 204162306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 204262306a36Sopenharmony_ci "Found IO in %s on lun\n", 204362306a36Sopenharmony_ci fnic_ioreq_state_to_str(fnic_priv(sc)->state)); 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) { 204662306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 204762306a36Sopenharmony_ci return true; 204862306a36Sopenharmony_ci } 204962306a36Sopenharmony_ci if ((fnic_priv(sc)->flags & FNIC_DEVICE_RESET) && 205062306a36Sopenharmony_ci (!(fnic_priv(sc)->flags & FNIC_DEV_RST_ISSUED))) { 205162306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 205262306a36Sopenharmony_ci "%s dev rst not pending sc 0x%p\n", __func__, 205362306a36Sopenharmony_ci sc); 205462306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 205562306a36Sopenharmony_ci return true; 205662306a36Sopenharmony_ci } 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci if (io_req->abts_done) 205962306a36Sopenharmony_ci shost_printk(KERN_ERR, fnic->lport->host, 206062306a36Sopenharmony_ci "%s: io_req->abts_done is set state is %s\n", 206162306a36Sopenharmony_ci __func__, fnic_ioreq_state_to_str(fnic_priv(sc)->state)); 206262306a36Sopenharmony_ci old_ioreq_state = fnic_priv(sc)->state; 206362306a36Sopenharmony_ci /* 206462306a36Sopenharmony_ci * Any pending IO issued prior to reset is expected to be 206562306a36Sopenharmony_ci * in abts pending state, if not we need to set 206662306a36Sopenharmony_ci * FNIC_IOREQ_ABTS_PENDING to indicate the IO is abort pending. 206762306a36Sopenharmony_ci * When IO is completed, the IO will be handed over and 206862306a36Sopenharmony_ci * handled in this function. 206962306a36Sopenharmony_ci */ 207062306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_ABTS_PENDING; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci BUG_ON(io_req->abts_done); 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) { 207562306a36Sopenharmony_ci abt_tag |= FNIC_TAG_DEV_RST; 207662306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 207762306a36Sopenharmony_ci "%s: dev rst sc 0x%p\n", __func__, sc); 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci fnic_priv(sc)->abts_status = FCPIO_INVALID_CODE; 208162306a36Sopenharmony_ci io_req->abts_done = &tm_done; 208262306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci /* Now queue the abort command to firmware */ 208562306a36Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci if (fnic_queue_abort_io_req(fnic, abt_tag, 208862306a36Sopenharmony_ci FCPIO_ITMF_ABT_TASK_TERM, 208962306a36Sopenharmony_ci fc_lun.scsi_lun, io_req)) { 209062306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 209162306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 209262306a36Sopenharmony_ci if (io_req) 209362306a36Sopenharmony_ci io_req->abts_done = NULL; 209462306a36Sopenharmony_ci if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) 209562306a36Sopenharmony_ci fnic_priv(sc)->state = old_ioreq_state; 209662306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 209762306a36Sopenharmony_ci iter_data->ret = FAILED; 209862306a36Sopenharmony_ci return false; 209962306a36Sopenharmony_ci } else { 210062306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 210162306a36Sopenharmony_ci if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) 210262306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_DEV_RST_TERM_ISSUED; 210362306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 210462306a36Sopenharmony_ci } 210562306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_INTERNAL_TERM_ISSUED; 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci wait_for_completion_timeout(&tm_done, msecs_to_jiffies 210862306a36Sopenharmony_ci (fnic->config.ed_tov)); 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci /* Recheck cmd state to check if it is now aborted */ 211162306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 211262306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 211362306a36Sopenharmony_ci if (!io_req) { 211462306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 211562306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_REQ_NULL; 211662306a36Sopenharmony_ci return true; 211762306a36Sopenharmony_ci } 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci io_req->abts_done = NULL; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci /* if abort is still pending with fw, fail */ 212262306a36Sopenharmony_ci if (fnic_priv(sc)->abts_status == FCPIO_INVALID_CODE) { 212362306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 212462306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_DONE; 212562306a36Sopenharmony_ci iter_data->ret = FAILED; 212662306a36Sopenharmony_ci return false; 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_ABTS_COMPLETE; 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci /* original sc used for lr is handled by dev reset code */ 213162306a36Sopenharmony_ci if (sc != iter_data->lr_sc) 213262306a36Sopenharmony_ci fnic_priv(sc)->io_req = NULL; 213362306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci /* original sc used for lr is handled by dev reset code */ 213662306a36Sopenharmony_ci if (sc != iter_data->lr_sc) { 213762306a36Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 213862306a36Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 213962306a36Sopenharmony_ci } 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci /* 214262306a36Sopenharmony_ci * Any IO is returned during reset, it needs to call scsi_done 214362306a36Sopenharmony_ci * to return the scsi_cmnd to upper layer. 214462306a36Sopenharmony_ci */ 214562306a36Sopenharmony_ci /* Set result to let upper SCSI layer retry */ 214662306a36Sopenharmony_ci sc->result = DID_RESET << 16; 214762306a36Sopenharmony_ci scsi_done(sc); 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci return true; 215062306a36Sopenharmony_ci} 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci/* 215362306a36Sopenharmony_ci * Clean up any pending aborts on the lun 215462306a36Sopenharmony_ci * For each outstanding IO on this lun, whose abort is not completed by fw, 215562306a36Sopenharmony_ci * issue a local abort. Wait for abort to complete. Return 0 if all commands 215662306a36Sopenharmony_ci * successfully aborted, 1 otherwise 215762306a36Sopenharmony_ci */ 215862306a36Sopenharmony_cistatic int fnic_clean_pending_aborts(struct fnic *fnic, 215962306a36Sopenharmony_ci struct scsi_cmnd *lr_sc, 216062306a36Sopenharmony_ci bool new_sc) 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci{ 216362306a36Sopenharmony_ci int ret = 0; 216462306a36Sopenharmony_ci struct fnic_pending_aborts_iter_data iter_data = { 216562306a36Sopenharmony_ci .fnic = fnic, 216662306a36Sopenharmony_ci .lun_dev = lr_sc->device, 216762306a36Sopenharmony_ci .ret = SUCCESS, 216862306a36Sopenharmony_ci }; 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci iter_data.lr_sc = lr_sc; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci scsi_host_busy_iter(fnic->lport->host, 217362306a36Sopenharmony_ci fnic_pending_aborts_iter, &iter_data); 217462306a36Sopenharmony_ci if (iter_data.ret == FAILED) { 217562306a36Sopenharmony_ci ret = iter_data.ret; 217662306a36Sopenharmony_ci goto clean_pending_aborts_end; 217762306a36Sopenharmony_ci } 217862306a36Sopenharmony_ci schedule_timeout(msecs_to_jiffies(2 * fnic->config.ed_tov)); 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci /* walk again to check, if IOs are still pending in fw */ 218162306a36Sopenharmony_ci if (fnic_is_abts_pending(fnic, lr_sc)) 218262306a36Sopenharmony_ci ret = 1; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ciclean_pending_aborts_end: 218562306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 218662306a36Sopenharmony_ci "%s: exit status: %d\n", __func__, ret); 218762306a36Sopenharmony_ci return ret; 218862306a36Sopenharmony_ci} 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci/* 219162306a36Sopenharmony_ci * SCSI Eh thread issues a Lun Reset when one or more commands on a LUN 219262306a36Sopenharmony_ci * fail to get aborted. It calls driver's eh_device_reset with a SCSI command 219362306a36Sopenharmony_ci * on the LUN. 219462306a36Sopenharmony_ci */ 219562306a36Sopenharmony_ciint fnic_device_reset(struct scsi_cmnd *sc) 219662306a36Sopenharmony_ci{ 219762306a36Sopenharmony_ci struct request *rq = scsi_cmd_to_rq(sc); 219862306a36Sopenharmony_ci struct fc_lport *lp; 219962306a36Sopenharmony_ci struct fnic *fnic; 220062306a36Sopenharmony_ci struct fnic_io_req *io_req = NULL; 220162306a36Sopenharmony_ci struct fc_rport *rport; 220262306a36Sopenharmony_ci int status; 220362306a36Sopenharmony_ci int ret = FAILED; 220462306a36Sopenharmony_ci spinlock_t *io_lock; 220562306a36Sopenharmony_ci unsigned long flags; 220662306a36Sopenharmony_ci unsigned long start_time = 0; 220762306a36Sopenharmony_ci struct scsi_lun fc_lun; 220862306a36Sopenharmony_ci struct fnic_stats *fnic_stats; 220962306a36Sopenharmony_ci struct reset_stats *reset_stats; 221062306a36Sopenharmony_ci int tag = rq->tag; 221162306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(tm_done); 221262306a36Sopenharmony_ci bool new_sc = 0; 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci /* Wait for rport to unblock */ 221562306a36Sopenharmony_ci fc_block_scsi_eh(sc); 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci /* Get local-port, check ready and link up */ 221862306a36Sopenharmony_ci lp = shost_priv(sc->device->host); 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci fnic = lport_priv(lp); 222162306a36Sopenharmony_ci fnic_stats = &fnic->fnic_stats; 222262306a36Sopenharmony_ci reset_stats = &fnic->fnic_stats.reset_stats; 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci atomic64_inc(&reset_stats->device_resets); 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci rport = starget_to_rport(scsi_target(sc->device)); 222762306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 222862306a36Sopenharmony_ci "Device reset called FCID 0x%x, LUN 0x%llx sc 0x%p\n", 222962306a36Sopenharmony_ci rport->port_id, sc->device->lun, sc); 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci if (lp->state != LPORT_ST_READY || !(lp->link_up)) 223262306a36Sopenharmony_ci goto fnic_device_reset_end; 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci /* Check if remote port up */ 223562306a36Sopenharmony_ci if (fc_remote_port_chkready(rport)) { 223662306a36Sopenharmony_ci atomic64_inc(&fnic_stats->misc_stats.rport_not_ready); 223762306a36Sopenharmony_ci goto fnic_device_reset_end; 223862306a36Sopenharmony_ci } 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci fnic_priv(sc)->flags = FNIC_DEVICE_RESET; 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci if (unlikely(tag < 0)) { 224362306a36Sopenharmony_ci /* 224462306a36Sopenharmony_ci * For device reset issued through sg3utils, we let 224562306a36Sopenharmony_ci * only one LUN_RESET to go through and use a special 224662306a36Sopenharmony_ci * tag equal to max_tag_id so that we don't have to allocate 224762306a36Sopenharmony_ci * or free it. It won't interact with tags 224862306a36Sopenharmony_ci * allocated by mid layer. 224962306a36Sopenharmony_ci */ 225062306a36Sopenharmony_ci mutex_lock(&fnic->sgreset_mutex); 225162306a36Sopenharmony_ci tag = fnic->fnic_max_tag_id; 225262306a36Sopenharmony_ci new_sc = 1; 225362306a36Sopenharmony_ci fnic->sgreset_sc = sc; 225462306a36Sopenharmony_ci io_lock = &fnic->sgreset_lock; 225562306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 225662306a36Sopenharmony_ci "fcid: 0x%x lun: 0x%llx flags: 0x%x tag: 0x%x Issuing sgreset\n", 225762306a36Sopenharmony_ci rport->port_id, sc->device->lun, fnic_priv(sc)->flags, tag); 225862306a36Sopenharmony_ci } else 225962306a36Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 226262306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci /* 226562306a36Sopenharmony_ci * If there is a io_req attached to this command, then use it, 226662306a36Sopenharmony_ci * else allocate a new one. 226762306a36Sopenharmony_ci */ 226862306a36Sopenharmony_ci if (!io_req) { 226962306a36Sopenharmony_ci io_req = mempool_alloc(fnic->io_req_pool, GFP_ATOMIC); 227062306a36Sopenharmony_ci if (!io_req) { 227162306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 227262306a36Sopenharmony_ci goto fnic_device_reset_end; 227362306a36Sopenharmony_ci } 227462306a36Sopenharmony_ci memset(io_req, 0, sizeof(*io_req)); 227562306a36Sopenharmony_ci io_req->port_id = rport->port_id; 227662306a36Sopenharmony_ci io_req->tag = tag; 227762306a36Sopenharmony_ci io_req->sc = sc; 227862306a36Sopenharmony_ci fnic_priv(sc)->io_req = io_req; 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci io_req->dr_done = &tm_done; 228162306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_CMD_PENDING; 228262306a36Sopenharmony_ci fnic_priv(sc)->lr_status = FCPIO_INVALID_CODE; 228362306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "TAG %x\n", tag); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci /* 228862306a36Sopenharmony_ci * issue the device reset, if enqueue failed, clean up the ioreq 228962306a36Sopenharmony_ci * and break assoc with scsi cmd 229062306a36Sopenharmony_ci */ 229162306a36Sopenharmony_ci if (fnic_queue_dr_io_req(fnic, sc, io_req)) { 229262306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 229362306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 229462306a36Sopenharmony_ci if (io_req) 229562306a36Sopenharmony_ci io_req->dr_done = NULL; 229662306a36Sopenharmony_ci goto fnic_device_reset_clean; 229762306a36Sopenharmony_ci } 229862306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 229962306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_DEV_RST_ISSUED; 230062306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci /* 230362306a36Sopenharmony_ci * Wait on the local completion for LUN reset. The io_req may be 230462306a36Sopenharmony_ci * freed while we wait since we hold no lock. 230562306a36Sopenharmony_ci */ 230662306a36Sopenharmony_ci wait_for_completion_timeout(&tm_done, 230762306a36Sopenharmony_ci msecs_to_jiffies(FNIC_LUN_RESET_TIMEOUT)); 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 231062306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 231162306a36Sopenharmony_ci if (!io_req) { 231262306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 231362306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 231462306a36Sopenharmony_ci "io_req is null tag 0x%x sc 0x%p\n", tag, sc); 231562306a36Sopenharmony_ci goto fnic_device_reset_end; 231662306a36Sopenharmony_ci } 231762306a36Sopenharmony_ci io_req->dr_done = NULL; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci status = fnic_priv(sc)->lr_status; 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci /* 232262306a36Sopenharmony_ci * If lun reset not completed, bail out with failed. io_req 232362306a36Sopenharmony_ci * gets cleaned up during higher levels of EH 232462306a36Sopenharmony_ci */ 232562306a36Sopenharmony_ci if (status == FCPIO_INVALID_CODE) { 232662306a36Sopenharmony_ci atomic64_inc(&reset_stats->device_reset_timeouts); 232762306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 232862306a36Sopenharmony_ci "Device reset timed out\n"); 232962306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_DEV_RST_TIMED_OUT; 233062306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 233162306a36Sopenharmony_ci int_to_scsilun(sc->device->lun, &fc_lun); 233262306a36Sopenharmony_ci /* 233362306a36Sopenharmony_ci * Issue abort and terminate on device reset request. 233462306a36Sopenharmony_ci * If q'ing of terminate fails, retry it after a delay. 233562306a36Sopenharmony_ci */ 233662306a36Sopenharmony_ci while (1) { 233762306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 233862306a36Sopenharmony_ci if (fnic_priv(sc)->flags & FNIC_DEV_RST_TERM_ISSUED) { 233962306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 234062306a36Sopenharmony_ci break; 234162306a36Sopenharmony_ci } 234262306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 234362306a36Sopenharmony_ci if (fnic_queue_abort_io_req(fnic, 234462306a36Sopenharmony_ci tag | FNIC_TAG_DEV_RST, 234562306a36Sopenharmony_ci FCPIO_ITMF_ABT_TASK_TERM, 234662306a36Sopenharmony_ci fc_lun.scsi_lun, io_req)) { 234762306a36Sopenharmony_ci wait_for_completion_timeout(&tm_done, 234862306a36Sopenharmony_ci msecs_to_jiffies(FNIC_ABT_TERM_DELAY_TIMEOUT)); 234962306a36Sopenharmony_ci } else { 235062306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 235162306a36Sopenharmony_ci fnic_priv(sc)->flags |= FNIC_DEV_RST_TERM_ISSUED; 235262306a36Sopenharmony_ci fnic_priv(sc)->state = FNIC_IOREQ_ABTS_PENDING; 235362306a36Sopenharmony_ci io_req->abts_done = &tm_done; 235462306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 235562306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 235662306a36Sopenharmony_ci "Abort and terminate issued on Device reset " 235762306a36Sopenharmony_ci "tag 0x%x sc 0x%p\n", tag, sc); 235862306a36Sopenharmony_ci break; 235962306a36Sopenharmony_ci } 236062306a36Sopenharmony_ci } 236162306a36Sopenharmony_ci while (1) { 236262306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 236362306a36Sopenharmony_ci if (!(fnic_priv(sc)->flags & FNIC_DEV_RST_DONE)) { 236462306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 236562306a36Sopenharmony_ci wait_for_completion_timeout(&tm_done, 236662306a36Sopenharmony_ci msecs_to_jiffies(FNIC_LUN_RESET_TIMEOUT)); 236762306a36Sopenharmony_ci break; 236862306a36Sopenharmony_ci } else { 236962306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 237062306a36Sopenharmony_ci io_req->abts_done = NULL; 237162306a36Sopenharmony_ci goto fnic_device_reset_clean; 237262306a36Sopenharmony_ci } 237362306a36Sopenharmony_ci } 237462306a36Sopenharmony_ci } else { 237562306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 237662306a36Sopenharmony_ci } 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci /* Completed, but not successful, clean up the io_req, return fail */ 237962306a36Sopenharmony_ci if (status != FCPIO_SUCCESS) { 238062306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 238162306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, 238262306a36Sopenharmony_ci fnic->lport->host, 238362306a36Sopenharmony_ci "Device reset completed - failed\n"); 238462306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 238562306a36Sopenharmony_ci goto fnic_device_reset_clean; 238662306a36Sopenharmony_ci } 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci /* 238962306a36Sopenharmony_ci * Clean up any aborts on this lun that have still not 239062306a36Sopenharmony_ci * completed. If any of these fail, then LUN reset fails. 239162306a36Sopenharmony_ci * clean_pending_aborts cleans all cmds on this lun except 239262306a36Sopenharmony_ci * the lun reset cmd. If all cmds get cleaned, the lun reset 239362306a36Sopenharmony_ci * succeeds 239462306a36Sopenharmony_ci */ 239562306a36Sopenharmony_ci if (fnic_clean_pending_aborts(fnic, sc, new_sc)) { 239662306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 239762306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 239862306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 239962306a36Sopenharmony_ci "Device reset failed" 240062306a36Sopenharmony_ci " since could not abort all IOs\n"); 240162306a36Sopenharmony_ci goto fnic_device_reset_clean; 240262306a36Sopenharmony_ci } 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci /* Clean lun reset command */ 240562306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 240662306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 240762306a36Sopenharmony_ci if (io_req) 240862306a36Sopenharmony_ci /* Completed, and successful */ 240962306a36Sopenharmony_ci ret = SUCCESS; 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_cifnic_device_reset_clean: 241262306a36Sopenharmony_ci if (io_req) 241362306a36Sopenharmony_ci fnic_priv(sc)->io_req = NULL; 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci if (io_req) { 241862306a36Sopenharmony_ci start_time = io_req->start_time; 241962306a36Sopenharmony_ci fnic_release_ioreq_buf(fnic, io_req, sc); 242062306a36Sopenharmony_ci mempool_free(io_req, fnic->io_req_pool); 242162306a36Sopenharmony_ci } 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_cifnic_device_reset_end: 242462306a36Sopenharmony_ci FNIC_TRACE(fnic_device_reset, sc->device->host->host_no, rq->tag, sc, 242562306a36Sopenharmony_ci jiffies_to_msecs(jiffies - start_time), 242662306a36Sopenharmony_ci 0, ((u64)sc->cmnd[0] << 32 | 242762306a36Sopenharmony_ci (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | 242862306a36Sopenharmony_ci (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), 242962306a36Sopenharmony_ci fnic_flags_and_state(sc)); 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci if (new_sc) { 243262306a36Sopenharmony_ci fnic->sgreset_sc = NULL; 243362306a36Sopenharmony_ci mutex_unlock(&fnic->sgreset_mutex); 243462306a36Sopenharmony_ci } 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 243762306a36Sopenharmony_ci "Returning from device reset %s\n", 243862306a36Sopenharmony_ci (ret == SUCCESS) ? 243962306a36Sopenharmony_ci "SUCCESS" : "FAILED"); 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci if (ret == FAILED) 244262306a36Sopenharmony_ci atomic64_inc(&reset_stats->device_reset_failures); 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci return ret; 244562306a36Sopenharmony_ci} 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci/* Clean up all IOs, clean up libFC local port */ 244862306a36Sopenharmony_ciint fnic_reset(struct Scsi_Host *shost) 244962306a36Sopenharmony_ci{ 245062306a36Sopenharmony_ci struct fc_lport *lp; 245162306a36Sopenharmony_ci struct fnic *fnic; 245262306a36Sopenharmony_ci int ret = 0; 245362306a36Sopenharmony_ci struct reset_stats *reset_stats; 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci lp = shost_priv(shost); 245662306a36Sopenharmony_ci fnic = lport_priv(lp); 245762306a36Sopenharmony_ci reset_stats = &fnic->fnic_stats.reset_stats; 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 246062306a36Sopenharmony_ci "fnic_reset called\n"); 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci atomic64_inc(&reset_stats->fnic_resets); 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci /* 246562306a36Sopenharmony_ci * Reset local port, this will clean up libFC exchanges, 246662306a36Sopenharmony_ci * reset remote port sessions, and if link is up, begin flogi 246762306a36Sopenharmony_ci */ 246862306a36Sopenharmony_ci ret = fc_lport_reset(lp); 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 247162306a36Sopenharmony_ci "Returning from fnic reset %s\n", 247262306a36Sopenharmony_ci (ret == 0) ? 247362306a36Sopenharmony_ci "SUCCESS" : "FAILED"); 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci if (ret == 0) 247662306a36Sopenharmony_ci atomic64_inc(&reset_stats->fnic_reset_completions); 247762306a36Sopenharmony_ci else 247862306a36Sopenharmony_ci atomic64_inc(&reset_stats->fnic_reset_failures); 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci return ret; 248162306a36Sopenharmony_ci} 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci/* 248462306a36Sopenharmony_ci * SCSI Error handling calls driver's eh_host_reset if all prior 248562306a36Sopenharmony_ci * error handling levels return FAILED. If host reset completes 248662306a36Sopenharmony_ci * successfully, and if link is up, then Fabric login begins. 248762306a36Sopenharmony_ci * 248862306a36Sopenharmony_ci * Host Reset is the highest level of error recovery. If this fails, then 248962306a36Sopenharmony_ci * host is offlined by SCSI. 249062306a36Sopenharmony_ci * 249162306a36Sopenharmony_ci */ 249262306a36Sopenharmony_ciint fnic_host_reset(struct scsi_cmnd *sc) 249362306a36Sopenharmony_ci{ 249462306a36Sopenharmony_ci int ret; 249562306a36Sopenharmony_ci unsigned long wait_host_tmo; 249662306a36Sopenharmony_ci struct Scsi_Host *shost = sc->device->host; 249762306a36Sopenharmony_ci struct fc_lport *lp = shost_priv(shost); 249862306a36Sopenharmony_ci struct fnic *fnic = lport_priv(lp); 249962306a36Sopenharmony_ci unsigned long flags; 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 250262306a36Sopenharmony_ci if (!fnic->internal_reset_inprogress) { 250362306a36Sopenharmony_ci fnic->internal_reset_inprogress = true; 250462306a36Sopenharmony_ci } else { 250562306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 250662306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 250762306a36Sopenharmony_ci "host reset in progress skipping another host reset\n"); 250862306a36Sopenharmony_ci return SUCCESS; 250962306a36Sopenharmony_ci } 251062306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci /* 251362306a36Sopenharmony_ci * If fnic_reset is successful, wait for fabric login to complete 251462306a36Sopenharmony_ci * scsi-ml tries to send a TUR to every device if host reset is 251562306a36Sopenharmony_ci * successful, so before returning to scsi, fabric should be up 251662306a36Sopenharmony_ci */ 251762306a36Sopenharmony_ci ret = (fnic_reset(shost) == 0) ? SUCCESS : FAILED; 251862306a36Sopenharmony_ci if (ret == SUCCESS) { 251962306a36Sopenharmony_ci wait_host_tmo = jiffies + FNIC_HOST_RESET_SETTLE_TIME * HZ; 252062306a36Sopenharmony_ci ret = FAILED; 252162306a36Sopenharmony_ci while (time_before(jiffies, wait_host_tmo)) { 252262306a36Sopenharmony_ci if ((lp->state == LPORT_ST_READY) && 252362306a36Sopenharmony_ci (lp->link_up)) { 252462306a36Sopenharmony_ci ret = SUCCESS; 252562306a36Sopenharmony_ci break; 252662306a36Sopenharmony_ci } 252762306a36Sopenharmony_ci ssleep(1); 252862306a36Sopenharmony_ci } 252962306a36Sopenharmony_ci } 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 253262306a36Sopenharmony_ci fnic->internal_reset_inprogress = false; 253362306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 253462306a36Sopenharmony_ci return ret; 253562306a36Sopenharmony_ci} 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci/* 253862306a36Sopenharmony_ci * This fxn is called from libFC when host is removed 253962306a36Sopenharmony_ci */ 254062306a36Sopenharmony_civoid fnic_scsi_abort_io(struct fc_lport *lp) 254162306a36Sopenharmony_ci{ 254262306a36Sopenharmony_ci int err = 0; 254362306a36Sopenharmony_ci unsigned long flags; 254462306a36Sopenharmony_ci enum fnic_state old_state; 254562306a36Sopenharmony_ci struct fnic *fnic = lport_priv(lp); 254662306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(remove_wait); 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci /* Issue firmware reset for fnic, wait for reset to complete */ 254962306a36Sopenharmony_ciretry_fw_reset: 255062306a36Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 255162306a36Sopenharmony_ci if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) && 255262306a36Sopenharmony_ci fnic->link_events) { 255362306a36Sopenharmony_ci /* fw reset is in progress, poll for its completion */ 255462306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 255562306a36Sopenharmony_ci schedule_timeout(msecs_to_jiffies(100)); 255662306a36Sopenharmony_ci goto retry_fw_reset; 255762306a36Sopenharmony_ci } 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci fnic->remove_wait = &remove_wait; 256062306a36Sopenharmony_ci old_state = fnic->state; 256162306a36Sopenharmony_ci fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; 256262306a36Sopenharmony_ci fnic_update_mac_locked(fnic, fnic->ctlr.ctl_src_addr); 256362306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci err = fnic_fw_reset_handler(fnic); 256662306a36Sopenharmony_ci if (err) { 256762306a36Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 256862306a36Sopenharmony_ci if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) 256962306a36Sopenharmony_ci fnic->state = old_state; 257062306a36Sopenharmony_ci fnic->remove_wait = NULL; 257162306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 257262306a36Sopenharmony_ci return; 257362306a36Sopenharmony_ci } 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci /* Wait for firmware reset to complete */ 257662306a36Sopenharmony_ci wait_for_completion_timeout(&remove_wait, 257762306a36Sopenharmony_ci msecs_to_jiffies(FNIC_RMDEVICE_TIMEOUT)); 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 258062306a36Sopenharmony_ci fnic->remove_wait = NULL; 258162306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 258262306a36Sopenharmony_ci "fnic_scsi_abort_io %s\n", 258362306a36Sopenharmony_ci (fnic->state == FNIC_IN_ETH_MODE) ? 258462306a36Sopenharmony_ci "SUCCESS" : "FAILED"); 258562306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci} 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci/* 259062306a36Sopenharmony_ci * This fxn called from libFC to clean up driver IO state on link down 259162306a36Sopenharmony_ci */ 259262306a36Sopenharmony_civoid fnic_scsi_cleanup(struct fc_lport *lp) 259362306a36Sopenharmony_ci{ 259462306a36Sopenharmony_ci unsigned long flags; 259562306a36Sopenharmony_ci enum fnic_state old_state; 259662306a36Sopenharmony_ci struct fnic *fnic = lport_priv(lp); 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci /* issue fw reset */ 259962306a36Sopenharmony_ciretry_fw_reset: 260062306a36Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 260162306a36Sopenharmony_ci if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE)) { 260262306a36Sopenharmony_ci /* fw reset is in progress, poll for its completion */ 260362306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 260462306a36Sopenharmony_ci schedule_timeout(msecs_to_jiffies(100)); 260562306a36Sopenharmony_ci goto retry_fw_reset; 260662306a36Sopenharmony_ci } 260762306a36Sopenharmony_ci old_state = fnic->state; 260862306a36Sopenharmony_ci fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; 260962306a36Sopenharmony_ci fnic_update_mac_locked(fnic, fnic->ctlr.ctl_src_addr); 261062306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci if (fnic_fw_reset_handler(fnic)) { 261362306a36Sopenharmony_ci spin_lock_irqsave(&fnic->fnic_lock, flags); 261462306a36Sopenharmony_ci if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) 261562306a36Sopenharmony_ci fnic->state = old_state; 261662306a36Sopenharmony_ci spin_unlock_irqrestore(&fnic->fnic_lock, flags); 261762306a36Sopenharmony_ci } 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci} 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_civoid fnic_empty_scsi_cleanup(struct fc_lport *lp) 262262306a36Sopenharmony_ci{ 262362306a36Sopenharmony_ci} 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_civoid fnic_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did) 262662306a36Sopenharmony_ci{ 262762306a36Sopenharmony_ci struct fnic *fnic = lport_priv(lp); 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci /* Non-zero sid, nothing to do */ 263062306a36Sopenharmony_ci if (sid) 263162306a36Sopenharmony_ci goto call_fc_exch_mgr_reset; 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci if (did) { 263462306a36Sopenharmony_ci fnic_rport_exch_reset(fnic, did); 263562306a36Sopenharmony_ci goto call_fc_exch_mgr_reset; 263662306a36Sopenharmony_ci } 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci /* 263962306a36Sopenharmony_ci * sid = 0, did = 0 264062306a36Sopenharmony_ci * link down or device being removed 264162306a36Sopenharmony_ci */ 264262306a36Sopenharmony_ci if (!fnic->in_remove) 264362306a36Sopenharmony_ci fnic_scsi_cleanup(lp); 264462306a36Sopenharmony_ci else 264562306a36Sopenharmony_ci fnic_scsi_abort_io(lp); 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_ci /* call libFC exch mgr reset to reset its exchanges */ 264862306a36Sopenharmony_cicall_fc_exch_mgr_reset: 264962306a36Sopenharmony_ci fc_exch_mgr_reset(lp, sid, did); 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci} 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_cistatic bool fnic_abts_pending_iter(struct scsi_cmnd *sc, void *data) 265462306a36Sopenharmony_ci{ 265562306a36Sopenharmony_ci struct fnic_pending_aborts_iter_data *iter_data = data; 265662306a36Sopenharmony_ci struct fnic *fnic = iter_data->fnic; 265762306a36Sopenharmony_ci int cmd_state; 265862306a36Sopenharmony_ci struct fnic_io_req *io_req; 265962306a36Sopenharmony_ci spinlock_t *io_lock; 266062306a36Sopenharmony_ci unsigned long flags; 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci /* 266362306a36Sopenharmony_ci * ignore this lun reset cmd or cmds that do not belong to 266462306a36Sopenharmony_ci * this lun 266562306a36Sopenharmony_ci */ 266662306a36Sopenharmony_ci if (iter_data->lr_sc && sc == iter_data->lr_sc) 266762306a36Sopenharmony_ci return true; 266862306a36Sopenharmony_ci if (iter_data->lun_dev && sc->device != iter_data->lun_dev) 266962306a36Sopenharmony_ci return true; 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci io_lock = fnic_io_lock_hash(fnic, sc); 267262306a36Sopenharmony_ci spin_lock_irqsave(io_lock, flags); 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci io_req = fnic_priv(sc)->io_req; 267562306a36Sopenharmony_ci if (!io_req) { 267662306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 267762306a36Sopenharmony_ci return true; 267862306a36Sopenharmony_ci } 267962306a36Sopenharmony_ci 268062306a36Sopenharmony_ci /* 268162306a36Sopenharmony_ci * Found IO that is still pending with firmware and 268262306a36Sopenharmony_ci * belongs to the LUN that we are resetting 268362306a36Sopenharmony_ci */ 268462306a36Sopenharmony_ci FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, 268562306a36Sopenharmony_ci "Found IO in %s on lun\n", 268662306a36Sopenharmony_ci fnic_ioreq_state_to_str(fnic_priv(sc)->state)); 268762306a36Sopenharmony_ci cmd_state = fnic_priv(sc)->state; 268862306a36Sopenharmony_ci spin_unlock_irqrestore(io_lock, flags); 268962306a36Sopenharmony_ci if (cmd_state == FNIC_IOREQ_ABTS_PENDING) 269062306a36Sopenharmony_ci iter_data->ret = 1; 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ci return iter_data->ret ? false : true; 269362306a36Sopenharmony_ci} 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci/* 269662306a36Sopenharmony_ci * fnic_is_abts_pending() is a helper function that 269762306a36Sopenharmony_ci * walks through tag map to check if there is any IOs pending,if there is one, 269862306a36Sopenharmony_ci * then it returns 1 (true), otherwise 0 (false) 269962306a36Sopenharmony_ci * if @lr_sc is non NULL, then it checks IOs specific to particular LUN, 270062306a36Sopenharmony_ci * otherwise, it checks for all IOs. 270162306a36Sopenharmony_ci */ 270262306a36Sopenharmony_ciint fnic_is_abts_pending(struct fnic *fnic, struct scsi_cmnd *lr_sc) 270362306a36Sopenharmony_ci{ 270462306a36Sopenharmony_ci struct fnic_pending_aborts_iter_data iter_data = { 270562306a36Sopenharmony_ci .fnic = fnic, 270662306a36Sopenharmony_ci .lun_dev = NULL, 270762306a36Sopenharmony_ci .ret = 0, 270862306a36Sopenharmony_ci }; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci if (lr_sc) { 271162306a36Sopenharmony_ci iter_data.lun_dev = lr_sc->device; 271262306a36Sopenharmony_ci iter_data.lr_sc = lr_sc; 271362306a36Sopenharmony_ci } 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci /* walk again to check, if IOs are still pending in fw */ 271662306a36Sopenharmony_ci scsi_host_busy_iter(fnic->lport->host, 271762306a36Sopenharmony_ci fnic_abts_pending_iter, &iter_data); 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci return iter_data.ret; 272062306a36Sopenharmony_ci} 2721