diff options
Diffstat (limited to 'drivers/scsi/qedf')
-rw-r--r-- | drivers/scsi/qedf/qedf.h | 57 | ||||
-rw-r--r-- | drivers/scsi/qedf/qedf_dbg.c | 32 | ||||
-rw-r--r-- | drivers/scsi/qedf/qedf_debugfs.c | 57 | ||||
-rw-r--r-- | drivers/scsi/qedf/qedf_els.c | 82 | ||||
-rw-r--r-- | drivers/scsi/qedf/qedf_fip.c | 95 | ||||
-rw-r--r-- | drivers/scsi/qedf/qedf_io.c | 753 | ||||
-rw-r--r-- | drivers/scsi/qedf/qedf_main.c | 281 | ||||
-rw-r--r-- | drivers/scsi/qedf/qedf_version.h | 6 |
8 files changed, 1017 insertions, 346 deletions
diff --git a/drivers/scsi/qedf/qedf.h b/drivers/scsi/qedf/qedf.h index 2c78d8fb9122..2c08f6f4db42 100644 --- a/drivers/scsi/qedf/qedf.h +++ b/drivers/scsi/qedf/qedf.h @@ -35,9 +35,6 @@ #define QEDF_DESCR "QLogic FCoE Offload Driver" #define QEDF_MODULE_NAME "qedf" -#define QEDF_MIN_XID 0 -#define QEDF_MAX_SCSI_XID (NUM_TASKS_PER_CONNECTION - 1) -#define QEDF_MAX_ELS_XID 4095 #define QEDF_FLOGI_RETRY_CNT 3 #define QEDF_RPORT_RETRY_CNT 255 #define QEDF_MAX_SESSIONS 1024 @@ -52,8 +49,8 @@ sizeof(struct fc_frame_header)) #define QEDF_MAX_NPIV 64 #define QEDF_TM_TIMEOUT 10 -#define QEDF_ABORT_TIMEOUT 10 -#define QEDF_CLEANUP_TIMEOUT 10 +#define QEDF_ABORT_TIMEOUT (10 * 1000) +#define QEDF_CLEANUP_TIMEOUT 1 #define QEDF_MAX_CDB_LEN 16 #define UPSTREAM_REMOVE 1 @@ -85,6 +82,7 @@ struct qedf_els_cb_arg { }; enum qedf_ioreq_event { + QEDF_IOREQ_EV_NONE, QEDF_IOREQ_EV_ABORT_SUCCESS, QEDF_IOREQ_EV_ABORT_FAILED, QEDF_IOREQ_EV_SEND_RRQ, @@ -105,7 +103,6 @@ struct qedf_ioreq { struct list_head link; uint16_t xid; struct scsi_cmnd *sc_cmd; - bool use_slowpath; /* Use slow SGL for this I/O */ #define QEDF_SCSI_CMD 1 #define QEDF_TASK_MGMT_CMD 2 #define QEDF_ABTS 3 @@ -117,22 +114,43 @@ struct qedf_ioreq { #define QEDF_CMD_IN_ABORT 0x1 #define QEDF_CMD_IN_CLEANUP 0x2 #define QEDF_CMD_SRR_SENT 0x3 +#define QEDF_CMD_DIRTY 0x4 +#define QEDF_CMD_ERR_SCSI_DONE 0x5 u8 io_req_flags; uint8_t tm_flags; struct qedf_rport *fcport; +#define QEDF_CMD_ST_INACTIVE 0 +#define QEDFC_CMD_ST_IO_ACTIVE 1 +#define QEDFC_CMD_ST_ABORT_ACTIVE 2 +#define QEDFC_CMD_ST_ABORT_ACTIVE_EH 3 +#define QEDFC_CMD_ST_CLEANUP_ACTIVE 4 +#define QEDFC_CMD_ST_CLEANUP_ACTIVE_EH 5 +#define QEDFC_CMD_ST_RRQ_ACTIVE 6 +#define QEDFC_CMD_ST_RRQ_WAIT 7 +#define QEDFC_CMD_ST_OXID_RETIRE_WAIT 8 +#define QEDFC_CMD_ST_TMF_ACTIVE 9 +#define QEDFC_CMD_ST_DRAIN_ACTIVE 10 +#define QEDFC_CMD_ST_CLEANED 11 +#define QEDFC_CMD_ST_ELS_ACTIVE 12 + atomic_t state; unsigned long flags; enum qedf_ioreq_event event; size_t data_xfer_len; + /* ID: 001: Alloc cmd (qedf_alloc_cmd) */ + /* ID: 002: Initiate ABTS (qedf_initiate_abts) */ + /* ID: 003: For RRQ (qedf_process_abts_compl) */ struct kref refcount; struct qedf_cmd_mgr *cmd_mgr; struct io_bdt *bd_tbl; struct delayed_work timeout_work; struct completion tm_done; struct completion abts_done; + struct completion cleanup_done; struct e4_fcoe_task_context *task; struct fcoe_task_params *task_params; struct scsi_sgl_task_params *sgl_task_params; int idx; + int lun; /* * Need to allocate enough room for both sense data and FCP response data * which has a max length of 8 bytes according to spec. @@ -155,9 +173,9 @@ struct qedf_ioreq { int fp_idx; unsigned int cpu; unsigned int int_cpu; -#define QEDF_IOREQ_SLOW_SGE 0 -#define QEDF_IOREQ_SINGLE_SGE 1 -#define QEDF_IOREQ_FAST_SGE 2 +#define QEDF_IOREQ_UNKNOWN_SGE 1 +#define QEDF_IOREQ_SLOW_SGE 2 +#define QEDF_IOREQ_FAST_SGE 3 u8 sge_type; struct delayed_work rrq_work; @@ -172,6 +190,8 @@ struct qedf_ioreq { * during some form of error processing. */ bool return_scsi_cmd_on_abts; + + unsigned int alloc; }; extern struct workqueue_struct *qedf_io_wq; @@ -181,7 +201,10 @@ struct qedf_rport { #define QEDF_RPORT_SESSION_READY 1 #define QEDF_RPORT_UPLOADING_CONNECTION 2 #define QEDF_RPORT_IN_RESET 3 +#define QEDF_RPORT_IN_LUN_RESET 4 +#define QEDF_RPORT_IN_TARGET_RESET 5 unsigned long flags; + int lun_reset_lun; unsigned long retry_delay_timestamp; struct fc_rport *rport; struct fc_rport_priv *rdata; @@ -191,6 +214,7 @@ struct qedf_rport { void __iomem *p_doorbell; /* Send queue management */ atomic_t free_sqes; + atomic_t ios_to_queue; atomic_t num_active_ios; struct fcoe_wqe *sq; dma_addr_t sq_dma; @@ -295,8 +319,6 @@ struct qedf_ctx { #define QEDF_DCBX_PENDING 0 #define QEDF_DCBX_DONE 1 atomic_t dcbx; - uint16_t max_scsi_xid; - uint16_t max_els_xid; #define QEDF_NULL_VLAN_ID -1 #define QEDF_FALLBACK_VLAN 1002 #define QEDF_DEFAULT_PRIO 3 @@ -371,7 +393,6 @@ struct qedf_ctx { u32 slow_sge_ios; u32 fast_sge_ios; - u32 single_sge_ios; uint8_t *grcdump; uint32_t grcdump_size; @@ -396,6 +417,8 @@ struct qedf_ctx { u8 target_resets; u8 task_set_fulls; u8 busy; + /* Used for flush routine */ + struct mutex flush_mutex; }; struct io_bdt { @@ -435,6 +458,12 @@ static inline void qedf_stop_all_io(struct qedf_ctx *qedf) /* * Externs */ + +/* + * (QEDF_LOG_NPIV | QEDF_LOG_SESS | QEDF_LOG_LPORT | QEDF_LOG_ELS | QEDF_LOG_MQ + * | QEDF_LOG_IO | QEDF_LOG_UNSOL | QEDF_LOG_SCSI_TM | QEDF_LOG_MP_REQ | + * QEDF_LOG_EVT | QEDF_LOG_CONN | QEDF_LOG_DISC | QEDF_LOG_INFO) + */ #define QEDF_DEFAULT_LOG_MASK 0x3CFB6 extern const struct qed_fcoe_ops *qed_ops; extern uint qedf_dump_frames; @@ -494,7 +523,7 @@ extern void qedf_set_vlan_id(struct qedf_ctx *qedf, int vlan_id); extern void qedf_create_sysfs_ctx_attr(struct qedf_ctx *qedf); extern void qedf_remove_sysfs_ctx_attr(struct qedf_ctx *qedf); extern void qedf_capture_grc_dump(struct qedf_ctx *qedf); -extern void qedf_wait_for_upload(struct qedf_ctx *qedf); +bool qedf_wait_for_upload(struct qedf_ctx *qedf); extern void qedf_process_unsol_compl(struct qedf_ctx *qedf, uint16_t que_idx, struct fcoe_cqe *cqe); extern void qedf_restart_rport(struct qedf_rport *fcport); @@ -508,6 +537,8 @@ extern void qedf_get_protocol_tlv_data(void *dev, void *data); extern void qedf_fp_io_handler(struct work_struct *work); extern void qedf_get_generic_tlv_data(void *dev, struct qed_generic_tlvs *data); extern void qedf_wq_grcdump(struct work_struct *work); +void qedf_stag_change_work(struct work_struct *work); +void qedf_ctx_soft_reset(struct fc_lport *lport); #define FCOE_WORD_TO_BYTE 4 #define QEDF_MAX_TASK_NUM 0xFFFF diff --git a/drivers/scsi/qedf/qedf_dbg.c b/drivers/scsi/qedf/qedf_dbg.c index f2397ee9ba69..f7d170bffc82 100644 --- a/drivers/scsi/qedf/qedf_dbg.c +++ b/drivers/scsi/qedf/qedf_dbg.c @@ -15,10 +15,6 @@ qedf_dbg_err(struct qedf_dbg_ctx *qedf, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -27,9 +23,9 @@ qedf_dbg_err(struct qedf_dbg_ctx *qedf, const char *func, u32 line, if (likely(qedf) && likely(qedf->pdev)) pr_err("[%s]:[%s:%d]:%d: %pV", dev_name(&(qedf->pdev->dev)), - nfunc, line, qedf->host_no, &vaf); + func, line, qedf->host_no, &vaf); else - pr_err("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_err("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); va_end(va); } @@ -40,10 +36,6 @@ qedf_dbg_warn(struct qedf_dbg_ctx *qedf, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -55,9 +47,9 @@ qedf_dbg_warn(struct qedf_dbg_ctx *qedf, const char *func, u32 line, if (likely(qedf) && likely(qedf->pdev)) pr_warn("[%s]:[%s:%d]:%d: %pV", dev_name(&(qedf->pdev->dev)), - nfunc, line, qedf->host_no, &vaf); + func, line, qedf->host_no, &vaf); else - pr_warn("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_warn("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); ret: va_end(va); @@ -69,10 +61,6 @@ qedf_dbg_notice(struct qedf_dbg_ctx *qedf, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -84,10 +72,10 @@ qedf_dbg_notice(struct qedf_dbg_ctx *qedf, const char *func, u32 line, if (likely(qedf) && likely(qedf->pdev)) pr_notice("[%s]:[%s:%d]:%d: %pV", - dev_name(&(qedf->pdev->dev)), nfunc, line, + dev_name(&(qedf->pdev->dev)), func, line, qedf->host_no, &vaf); else - pr_notice("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_notice("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); ret: va_end(va); @@ -99,10 +87,6 @@ qedf_dbg_info(struct qedf_dbg_ctx *qedf, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -114,9 +98,9 @@ qedf_dbg_info(struct qedf_dbg_ctx *qedf, const char *func, u32 line, if (likely(qedf) && likely(qedf->pdev)) pr_info("[%s]:[%s:%d]:%d: %pV", dev_name(&(qedf->pdev->dev)), - nfunc, line, qedf->host_no, &vaf); + func, line, qedf->host_no, &vaf); else - pr_info("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_info("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); ret: va_end(va); diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c index a32d8ee4666e..235389209689 100644 --- a/drivers/scsi/qedf/qedf_debugfs.c +++ b/drivers/scsi/qedf/qedf_debugfs.c @@ -293,6 +293,33 @@ qedf_dbg_io_trace_open(struct inode *inode, struct file *file) return single_open(file, qedf_io_trace_show, qedf); } +/* Based on fip_state enum from libfcoe.h */ +static char *fip_state_names[] = { + "FIP_ST_DISABLED", + "FIP_ST_LINK_WAIT", + "FIP_ST_AUTO", + "FIP_ST_NON_FIP", + "FIP_ST_ENABLED", + "FIP_ST_VNMP_START", + "FIP_ST_VNMP_PROBE1", + "FIP_ST_VNMP_PROBE2", + "FIP_ST_VNMP_CLAIM", + "FIP_ST_VNMP_UP", +}; + +/* Based on fc_rport_state enum from libfc.h */ +static char *fc_rport_state_names[] = { + "RPORT_ST_INIT", + "RPORT_ST_FLOGI", + "RPORT_ST_PLOGI_WAIT", + "RPORT_ST_PLOGI", + "RPORT_ST_PRLI", + "RPORT_ST_RTV", + "RPORT_ST_READY", + "RPORT_ST_ADISC", + "RPORT_ST_DELETE", +}; + static int qedf_driver_stats_show(struct seq_file *s, void *unused) { @@ -300,10 +327,28 @@ qedf_driver_stats_show(struct seq_file *s, void *unused) struct qedf_rport *fcport; struct fc_rport_priv *rdata; + seq_printf(s, "Host WWNN/WWPN: %016llx/%016llx\n", + qedf->wwnn, qedf->wwpn); + seq_printf(s, "Host NPortID: %06x\n", qedf->lport->port_id); + seq_printf(s, "Link State: %s\n", atomic_read(&qedf->link_state) ? + "Up" : "Down"); + seq_printf(s, "Logical Link State: %s\n", qedf->lport->link_up ? + "Up" : "Down"); + seq_printf(s, "FIP state: %s\n", fip_state_names[qedf->ctlr.state]); + seq_printf(s, "FIP VLAN ID: %d\n", qedf->vlan_id & 0xfff); + seq_printf(s, "FIP 802.1Q Priority: %d\n", qedf->prio); + if (qedf->ctlr.sel_fcf) { + seq_printf(s, "FCF WWPN: %016llx\n", + qedf->ctlr.sel_fcf->switch_name); + seq_printf(s, "FCF MAC: %pM\n", qedf->ctlr.sel_fcf->fcf_mac); + } else { + seq_puts(s, "FCF not selected\n"); + } + + seq_puts(s, "\nSGE stats:\n\n"); seq_printf(s, "cmg_mgr free io_reqs: %d\n", atomic_read(&qedf->cmd_mgr->free_list_cnt)); seq_printf(s, "slow SGEs: %d\n", qedf->slow_sge_ios); - seq_printf(s, "single SGEs: %d\n", qedf->single_sge_ios); seq_printf(s, "fast SGEs: %d\n\n", qedf->fast_sge_ios); seq_puts(s, "Offloaded ports:\n\n"); @@ -313,9 +358,12 @@ qedf_driver_stats_show(struct seq_file *s, void *unused) rdata = fcport->rdata; if (rdata == NULL) continue; - seq_printf(s, "%06x: free_sqes: %d, num_active_ios: %d\n", - rdata->ids.port_id, atomic_read(&fcport->free_sqes), - atomic_read(&fcport->num_active_ios)); + seq_printf(s, "%016llx/%016llx/%06x: state=%s, free_sqes=%d, num_active_ios=%d\n", + rdata->rport->node_name, rdata->rport->port_name, + rdata->ids.port_id, + fc_rport_state_names[rdata->rp_state], + atomic_read(&fcport->free_sqes), + atomic_read(&fcport->num_active_ios)); } rcu_read_unlock(); @@ -361,7 +409,6 @@ qedf_dbg_clear_stats_cmd_write(struct file *filp, /* Clear stat counters exposed by 'stats' node */ qedf->slow_sge_ios = 0; - qedf->single_sge_ios = 0; qedf->fast_sge_ios = 0; return count; diff --git a/drivers/scsi/qedf/qedf_els.c b/drivers/scsi/qedf/qedf_els.c index 04f0c4d2e256..d900c89e8049 100644 --- a/drivers/scsi/qedf/qedf_els.c +++ b/drivers/scsi/qedf/qedf_els.c @@ -23,8 +23,6 @@ static int qedf_initiate_els(struct qedf_rport *fcport, unsigned int op, int rc = 0; uint32_t did, sid; uint16_t xid; - uint32_t start_time = jiffies / HZ; - uint32_t current_time; struct fcoe_wqe *sqe; unsigned long flags; u16 sqe_idx; @@ -59,18 +57,12 @@ static int qedf_initiate_els(struct qedf_rport *fcport, unsigned int op, goto els_err; } -retry_els: els_req = qedf_alloc_cmd(fcport, QEDF_ELS); if (!els_req) { - current_time = jiffies / HZ; - if ((current_time - start_time) > 10) { - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, - "els: Failed els 0x%x\n", op); - rc = -ENOMEM; - goto els_err; - } - mdelay(20 * USEC_PER_MSEC); - goto retry_els; + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_ELS, + "Failed to alloc ELS request 0x%x\n", op); + rc = -ENOMEM; + goto els_err; } QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "initiate_els els_req = " @@ -143,6 +135,8 @@ retry_els: QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "Ringing doorbell for ELS " "req\n"); qedf_ring_doorbell(fcport); + set_bit(QEDF_CMD_OUTSTANDING, &els_req->flags); + spin_unlock_irqrestore(&fcport->rport_lock, flags); els_err: return rc; @@ -151,21 +145,16 @@ els_err: void qedf_process_els_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, struct qedf_ioreq *els_req) { - struct fcoe_task_context *task_ctx; - struct scsi_cmnd *sc_cmd; - uint16_t xid; struct fcoe_cqe_midpath_info *mp_info; QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "Entered with xid = 0x%x" " cmd_type = %d.\n", els_req->xid, els_req->cmd_type); + clear_bit(QEDF_CMD_OUTSTANDING, &els_req->flags); + /* Kill the ELS timer */ cancel_delayed_work(&els_req->timeout_work); - xid = els_req->xid; - task_ctx = qedf_get_task_mem(&qedf->tasks, xid); - sc_cmd = els_req->sc_cmd; - /* Get ELS response length from CQE */ mp_info = &cqe->cqe_info.midpath_info; els_req->mp_req.resp_len = mp_info->data_placement_size; @@ -205,8 +194,12 @@ static void qedf_rrq_compl(struct qedf_els_cb_arg *cb_arg) " orig xid = 0x%x, rrq_xid = 0x%x, refcount=%d\n", orig_io_req, orig_io_req->xid, rrq_req->xid, refcount); - /* This should return the aborted io_req to the command pool */ - if (orig_io_req) + /* + * This should return the aborted io_req to the command pool. Note that + * we need to check the refcound in case the original request was + * flushed but we get a completion on this xid. + */ + if (orig_io_req && refcount > 0) kref_put(&orig_io_req->refcount, qedf_release_cmd); out_free: @@ -233,6 +226,7 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req) uint32_t sid; uint32_t r_a_tov; int rc; + int refcount; if (!aborted_io_req) { QEDF_ERR(NULL, "abort_io_req is NULL.\n"); @@ -241,6 +235,15 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req) fcport = aborted_io_req->fcport; + if (!fcport) { + refcount = kref_read(&aborted_io_req->refcount); + QEDF_ERR(NULL, + "RRQ work was queued prior to a flush xid=0x%x, refcount=%d.\n", + aborted_io_req->xid, refcount); + kref_put(&aborted_io_req->refcount, qedf_release_cmd); + return -EINVAL; + } + /* Check that fcport is still offloaded */ if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { QEDF_ERR(NULL, "fcport is no longer offloaded.\n"); @@ -253,6 +256,19 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req) } qedf = fcport->qedf; + + /* + * Sanity check that we can send a RRQ to make sure that refcount isn't + * 0 + */ + refcount = kref_read(&aborted_io_req->refcount); + if (refcount != 1) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_ELS, + "refcount for xid=%x io_req=%p refcount=%d is not 1.\n", + aborted_io_req->xid, aborted_io_req, refcount); + return -EINVAL; + } + lport = qedf->lport; sid = fcport->sid; r_a_tov = lport->r_a_tov; @@ -335,32 +351,49 @@ void qedf_restart_rport(struct qedf_rport *fcport) struct fc_lport *lport; struct fc_rport_priv *rdata; u32 port_id; + unsigned long flags; if (!fcport) return; + spin_lock_irqsave(&fcport->rport_lock, flags); if (test_bit(QEDF_RPORT_IN_RESET, &fcport->flags) || !test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) || test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { QEDF_ERR(&(fcport->qedf->dbg_ctx), "fcport %p already in reset or not offloaded.\n", fcport); + spin_unlock_irqrestore(&fcport->rport_lock, flags); return; } /* Set that we are now in reset */ set_bit(QEDF_RPORT_IN_RESET, &fcport->flags); + spin_unlock_irqrestore(&fcport->rport_lock, flags); rdata = fcport->rdata; - if (rdata) { + if (rdata && !kref_get_unless_zero(&rdata->kref)) { + fcport->rdata = NULL; + rdata = NULL; + } + + if (rdata && rdata->rp_state == RPORT_ST_READY) { lport = fcport->qedf->lport; port_id = rdata->ids.port_id; QEDF_ERR(&(fcport->qedf->dbg_ctx), "LOGO port_id=%x.\n", port_id); fc_rport_logoff(rdata); + kref_put(&rdata->kref, fc_rport_destroy); + mutex_lock(&lport->disc.disc_mutex); /* Recreate the rport and log back in */ rdata = fc_rport_create(lport, port_id); - if (rdata) + if (rdata) { + mutex_unlock(&lport->disc.disc_mutex); fc_rport_login(rdata); + fcport->rdata = rdata; + } else { + mutex_unlock(&lport->disc.disc_mutex); + fcport->rdata = NULL; + } } clear_bit(QEDF_RPORT_IN_RESET, &fcport->flags); } @@ -569,7 +602,7 @@ static int qedf_send_srr(struct qedf_ioreq *orig_io_req, u32 offset, u8 r_ctl) struct qedf_rport *fcport; struct fc_lport *lport; struct qedf_els_cb_arg *cb_arg = NULL; - u32 sid, r_a_tov; + u32 r_a_tov; int rc; if (!orig_io_req) { @@ -595,7 +628,6 @@ static int qedf_send_srr(struct qedf_ioreq *orig_io_req, u32 offset, u8 r_ctl) qedf = fcport->qedf; lport = qedf->lport; - sid = fcport->sid; r_a_tov = lport->r_a_tov; QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "Sending SRR orig_io=%p, " diff --git a/drivers/scsi/qedf/qedf_fip.c b/drivers/scsi/qedf/qedf_fip.c index 3fd3af799b3d..d4741f8dcb41 100644 --- a/drivers/scsi/qedf/qedf_fip.c +++ b/drivers/scsi/qedf/qedf_fip.c @@ -19,17 +19,16 @@ void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf) { struct sk_buff *skb; char *eth_fr; - int fr_len; struct fip_vlan *vlan; #define MY_FIP_ALL_FCF_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 }) static u8 my_fcoe_all_fcfs[ETH_ALEN] = MY_FIP_ALL_FCF_MACS; unsigned long flags = 0; + int rc = -1; skb = dev_alloc_skb(sizeof(struct fip_vlan)); if (!skb) return; - fr_len = sizeof(*vlan); eth_fr = (char *)skb->data; vlan = (struct fip_vlan *)eth_fr; @@ -68,7 +67,13 @@ void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf) } set_bit(QED_LL2_XMIT_FLAGS_FIP_DISCOVERY, &flags); - qed_ops->ll2->start_xmit(qedf->cdev, skb, flags); + rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, flags); + if (rc) { + QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc); + kfree_skb(skb); + return; + } + } static void qedf_fcoe_process_vlan_resp(struct qedf_ctx *qedf, @@ -95,6 +100,12 @@ static void qedf_fcoe_process_vlan_resp(struct qedf_ctx *qedf, rlen -= dlen; } + if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Dropping VLAN response as link is down.\n"); + return; + } + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "VLAN response, " "vid=0x%x.\n", vid); @@ -114,6 +125,7 @@ void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) struct fip_header *fiph; u16 op, vlan_tci = 0; u8 sub; + int rc = -1; if (!test_bit(QEDF_LL2_STARTED, &qedf->flags)) { QEDF_WARN(&(qedf->dbg_ctx), "LL2 not started\n"); @@ -142,9 +154,16 @@ void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb->len, false); - qed_ops->ll2->start_xmit(qedf->cdev, skb, 0); + rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, 0); + if (rc) { + QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc); + kfree_skb(skb); + return; + } } +static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS; + /* Process incoming FIP frames. */ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) { @@ -157,20 +176,37 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) size_t rlen, dlen; u16 op; u8 sub; - bool do_reset = false; + bool fcf_valid = false; + /* Default is to handle CVL regardless of fabric id descriptor */ + bool fabric_id_valid = true; + bool fc_wwpn_valid = false; + u64 switch_name; + u16 vlan = 0; eth_hdr = (struct ethhdr *)skb_mac_header(skb); fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2); op = ntohs(fiph->fip_op); sub = fiph->fip_subcode; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "FIP frame received: " - "skb=%p fiph=%p source=%pM op=%x sub=%x", skb, fiph, - eth_hdr->h_source, op, sub); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2, + "FIP frame received: skb=%p fiph=%p source=%pM destn=%pM op=%x sub=%x vlan=%04x", + skb, fiph, eth_hdr->h_source, eth_hdr->h_dest, op, + sub, vlan); if (qedf_dump_frames) print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb->len, false); + if (!ether_addr_equal(eth_hdr->h_dest, qedf->mac) && + !ether_addr_equal(eth_hdr->h_dest, fcoe_all_enode) && + !ether_addr_equal(eth_hdr->h_dest, qedf->data_src_addr)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2, + "Dropping FIP type 0x%x pkt due to destination MAC mismatch dest_mac=%pM ctlr.dest_addr=%pM data_src_addr=%pM.\n", + op, eth_hdr->h_dest, qedf->mac, + qedf->data_src_addr); + kfree_skb(skb); + return; + } + /* Handle FIP VLAN resp in the driver */ if (op == FIP_OP_VLAN && sub == FIP_SC_VL_NOTE) { qedf_fcoe_process_vlan_resp(qedf, skb); @@ -199,25 +235,36 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) switch (desc->fip_dtype) { case FIP_DT_MAC: mp = (struct fip_mac_desc *)desc; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, - "fd_mac=%pM\n", mp->fd_mac); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Switch fd_mac=%pM.\n", mp->fd_mac); if (ether_addr_equal(mp->fd_mac, qedf->ctlr.sel_fcf->fcf_mac)) - do_reset = true; + fcf_valid = true; break; case FIP_DT_NAME: wp = (struct fip_wwn_desc *)desc; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, - "fc_wwpn=%016llx.\n", - get_unaligned_be64(&wp->fd_wwn)); + switch_name = get_unaligned_be64(&wp->fd_wwn); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Switch fd_wwn=%016llx fcf_switch_name=%016llx.\n", + switch_name, + qedf->ctlr.sel_fcf->switch_name); + if (switch_name == + qedf->ctlr.sel_fcf->switch_name) + fc_wwpn_valid = true; break; case FIP_DT_VN_ID: vp = (struct fip_vn_desc *)desc; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, - "fd_fc_id=%x.\n", ntoh24(vp->fd_fc_id)); - if (ntoh24(vp->fd_fc_id) == + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "vx_port fd_fc_id=%x fd_mac=%pM.\n", + ntoh24(vp->fd_fc_id), vp->fd_mac); + /* Check vx_port fabric ID */ + if (ntoh24(vp->fd_fc_id) != qedf->lport->port_id) - do_reset = true; + fabric_id_valid = false; + /* Check vx_port MAC */ + if (!ether_addr_equal(vp->fd_mac, + qedf->data_src_addr)) + fabric_id_valid = false; break; default: /* Ignore anything else */ @@ -227,13 +274,11 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) rlen -= dlen; } - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, - "do_reset=%d.\n", do_reset); - if (do_reset) { - fcoe_ctlr_link_down(&qedf->ctlr); - qedf_wait_for_upload(qedf); - fcoe_ctlr_link_up(&qedf->ctlr); - } + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "fcf_valid=%d fabric_id_valid=%d fc_wwpn_valid=%d.\n", + fcf_valid, fabric_id_valid, fc_wwpn_valid); + if (fcf_valid && fabric_id_valid && fc_wwpn_valid) + qedf_ctx_soft_reset(qedf->lport); kfree_skb(skb); } else { /* Everything else is handled by libfcoe */ diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index 6ca583bdde23..42f9f2a9d8ea 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -43,8 +43,9 @@ static void qedf_cmd_timeout(struct work_struct *work) switch (io_req->cmd_type) { case QEDF_ABTS: if (qedf == NULL) { - QEDF_INFO(NULL, QEDF_LOG_IO, "qedf is NULL for xid=0x%x.\n", - io_req->xid); + QEDF_INFO(NULL, QEDF_LOG_IO, + "qedf is NULL for ABTS xid=0x%x.\n", + io_req->xid); return; } @@ -61,6 +62,9 @@ static void qedf_cmd_timeout(struct work_struct *work) */ kref_put(&io_req->refcount, qedf_release_cmd); + /* Clear in abort bit now that we're done with the command */ + clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags); + /* * Now that the original I/O and the ABTS are complete see * if we need to reconnect to the target. @@ -68,6 +72,15 @@ static void qedf_cmd_timeout(struct work_struct *work) qedf_restart_rport(fcport); break; case QEDF_ELS: + if (!qedf) { + QEDF_INFO(NULL, QEDF_LOG_IO, + "qedf is NULL for ELS xid=0x%x.\n", + io_req->xid); + return; + } + /* ELS request no longer outstanding since it timed out */ + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + kref_get(&io_req->refcount); /* * Don't attempt to clean an ELS timeout as any subseqeunt @@ -103,7 +116,7 @@ void qedf_cmd_mgr_free(struct qedf_cmd_mgr *cmgr) struct io_bdt *bdt_info; struct qedf_ctx *qedf = cmgr->qedf; size_t bd_tbl_sz; - u16 min_xid = QEDF_MIN_XID; + u16 min_xid = 0; u16 max_xid = (FCOE_PARAMS_NUM_TASKS - 1); int num_ios; int i; @@ -157,6 +170,7 @@ static void qedf_handle_rrq(struct work_struct *work) struct qedf_ioreq *io_req = container_of(work, struct qedf_ioreq, rrq_work.work); + atomic_set(&io_req->state, QEDFC_CMD_ST_RRQ_ACTIVE); qedf_send_rrq(io_req); } @@ -169,7 +183,7 @@ struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf) u16 xid; int i; int num_ios; - u16 min_xid = QEDF_MIN_XID; + u16 min_xid = 0; u16 max_xid = (FCOE_PARAMS_NUM_TASKS - 1); /* Make sure num_queues is already set before calling this function */ @@ -201,7 +215,7 @@ struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf) /* * Initialize I/O request fields. */ - xid = QEDF_MIN_XID; + xid = 0; for (i = 0; i < num_ios; i++) { io_req = &cmgr->cmds[i]; @@ -329,7 +343,7 @@ struct qedf_ioreq *qedf_alloc_cmd(struct qedf_rport *fcport, u8 cmd_type) cmd_mgr->idx = 0; /* Check to make sure command was previously freed */ - if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags)) + if (!io_req->alloc) break; } @@ -338,7 +352,14 @@ struct qedf_ioreq *qedf_alloc_cmd(struct qedf_rport *fcport, u8 cmd_type) goto out_failed; } - set_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + if (test_bit(QEDF_CMD_DIRTY, &io_req->flags)) + QEDF_ERR(&qedf->dbg_ctx, + "io_req found to be dirty ox_id = 0x%x.\n", + io_req->xid); + + /* Clear any flags now that we've reallocated the xid */ + io_req->flags = 0; + io_req->alloc = 1; spin_unlock_irqrestore(&cmd_mgr->lock, flags); atomic_inc(&fcport->num_active_ios); @@ -349,8 +370,13 @@ struct qedf_ioreq *qedf_alloc_cmd(struct qedf_rport *fcport, u8 cmd_type) io_req->cmd_mgr = cmd_mgr; io_req->fcport = fcport; + /* Clear any stale sc_cmd back pointer */ + io_req->sc_cmd = NULL; + io_req->lun = -1; + /* Hold the io_req against deletion */ - kref_init(&io_req->refcount); + kref_init(&io_req->refcount); /* ID: 001 */ + atomic_set(&io_req->state, QEDFC_CMD_ST_IO_ACTIVE); /* Bind io_bdt for this io_req */ /* Have a static link between io_req and io_bdt_pool */ @@ -412,6 +438,10 @@ void qedf_release_cmd(struct kref *ref) container_of(ref, struct qedf_ioreq, refcount); struct qedf_cmd_mgr *cmd_mgr = io_req->cmd_mgr; struct qedf_rport *fcport = io_req->fcport; + unsigned long flags; + + if (io_req->cmd_type == QEDF_SCSI_CMD) + WARN_ON(io_req->sc_cmd); if (io_req->cmd_type == QEDF_ELS || io_req->cmd_type == QEDF_TASK_MGMT_CMD) @@ -419,36 +449,20 @@ void qedf_release_cmd(struct kref *ref) atomic_inc(&cmd_mgr->free_list_cnt); atomic_dec(&fcport->num_active_ios); + atomic_set(&io_req->state, QEDF_CMD_ST_INACTIVE); if (atomic_read(&fcport->num_active_ios) < 0) QEDF_WARN(&(fcport->qedf->dbg_ctx), "active_ios < 0.\n"); /* Increment task retry identifier now that the request is released */ io_req->task_retry_identifier++; + io_req->fcport = NULL; - clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); -} - -static int qedf_split_bd(struct qedf_ioreq *io_req, u64 addr, int sg_len, - int bd_index) -{ - struct scsi_sge *bd = io_req->bd_tbl->bd_tbl; - int frag_size, sg_frags; - - sg_frags = 0; - while (sg_len) { - if (sg_len > QEDF_BD_SPLIT_SZ) - frag_size = QEDF_BD_SPLIT_SZ; - else - frag_size = sg_len; - bd[bd_index + sg_frags].sge_addr.lo = U64_LO(addr); - bd[bd_index + sg_frags].sge_addr.hi = U64_HI(addr); - bd[bd_index + sg_frags].sge_len = (uint16_t)frag_size; - - addr += (u64)frag_size; - sg_frags++; - sg_len -= frag_size; - } - return sg_frags; + clear_bit(QEDF_CMD_DIRTY, &io_req->flags); + io_req->cpu = 0; + spin_lock_irqsave(&cmd_mgr->lock, flags); + io_req->fcport = NULL; + io_req->alloc = 0; + spin_unlock_irqrestore(&cmd_mgr->lock, flags); } static int qedf_map_sg(struct qedf_ioreq *io_req) @@ -462,75 +476,45 @@ static int qedf_map_sg(struct qedf_ioreq *io_req) int byte_count = 0; int sg_count = 0; int bd_count = 0; - int sg_frags; - unsigned int sg_len; + u32 sg_len; u64 addr, end_addr; - int i; + int i = 0; sg_count = dma_map_sg(&qedf->pdev->dev, scsi_sglist(sc), scsi_sg_count(sc), sc->sc_data_direction); - sg = scsi_sglist(sc); - /* - * New condition to send single SGE as cached-SGL with length less - * than 64k. - */ - if ((sg_count == 1) && (sg_dma_len(sg) <= - QEDF_MAX_SGLEN_FOR_CACHESGL)) { - sg_len = sg_dma_len(sg); - addr = (u64)sg_dma_address(sg); - - bd[bd_count].sge_addr.lo = (addr & 0xffffffff); - bd[bd_count].sge_addr.hi = (addr >> 32); - bd[bd_count].sge_len = (u16)sg_len; + io_req->sge_type = QEDF_IOREQ_UNKNOWN_SGE; - return ++bd_count; - } + if (sg_count <= 8 || io_req->io_req_flags == QEDF_READ) + io_req->sge_type = QEDF_IOREQ_FAST_SGE; scsi_for_each_sg(sc, sg, sg_count, i) { - sg_len = sg_dma_len(sg); + sg_len = (u32)sg_dma_len(sg); addr = (u64)sg_dma_address(sg); end_addr = (u64)(addr + sg_len); /* - * First s/g element in the list so check if the end_addr - * is paged aligned. Also check to make sure the length is - * at least page size. - */ - if ((i == 0) && (sg_count > 1) && - ((end_addr % QEDF_PAGE_SIZE) || - sg_len < QEDF_PAGE_SIZE)) - io_req->use_slowpath = true; - /* - * Last s/g element so check if the start address is paged - * aligned. - */ - else if ((i == (sg_count - 1)) && (sg_count > 1) && - (addr % QEDF_PAGE_SIZE)) - io_req->use_slowpath = true; - /* * Intermediate s/g element so check if start and end address - * is page aligned. + * is page aligned. Only required for writes and only if the + * number of scatter/gather elements is 8 or more. */ - else if ((i != 0) && (i != (sg_count - 1)) && - ((addr % QEDF_PAGE_SIZE) || (end_addr % QEDF_PAGE_SIZE))) - io_req->use_slowpath = true; + if (io_req->sge_type == QEDF_IOREQ_UNKNOWN_SGE && (i) && + (i != (sg_count - 1)) && sg_len < QEDF_PAGE_SIZE) + io_req->sge_type = QEDF_IOREQ_SLOW_SGE; - if (sg_len > QEDF_MAX_BD_LEN) { - sg_frags = qedf_split_bd(io_req, addr, sg_len, - bd_count); - } else { - sg_frags = 1; - bd[bd_count].sge_addr.lo = U64_LO(addr); - bd[bd_count].sge_addr.hi = U64_HI(addr); - bd[bd_count].sge_len = (uint16_t)sg_len; - } + bd[bd_count].sge_addr.lo = cpu_to_le32(U64_LO(addr)); + bd[bd_count].sge_addr.hi = cpu_to_le32(U64_HI(addr)); + bd[bd_count].sge_len = cpu_to_le32(sg_len); - bd_count += sg_frags; + bd_count++; byte_count += sg_len; } + /* To catch a case where FAST and SLOW nothing is set, set FAST */ + if (io_req->sge_type == QEDF_IOREQ_UNKNOWN_SGE) + io_req->sge_type = QEDF_IOREQ_FAST_SGE; + if (byte_count != scsi_bufflen(sc)) QEDF_ERR(&(qedf->dbg_ctx), "byte_count = %d != " "scsi_bufflen = %d, task_id = 0x%x.\n", byte_count, @@ -655,8 +639,10 @@ static void qedf_init_task(struct qedf_rport *fcport, struct fc_lport *lport, io_req->sgl_task_params->num_sges = bd_count; io_req->sgl_task_params->total_buffer_size = scsi_bufflen(io_req->sc_cmd); - io_req->sgl_task_params->small_mid_sge = - io_req->use_slowpath; + if (io_req->sge_type == QEDF_IOREQ_SLOW_SGE) + io_req->sgl_task_params->small_mid_sge = 1; + else + io_req->sgl_task_params->small_mid_sge = 0; } /* Fill in physical address of sense buffer */ @@ -679,16 +665,10 @@ static void qedf_init_task(struct qedf_rport *fcport, struct fc_lport *lport, io_req->task_retry_identifier, fcp_cmnd); /* Increment SGL type counters */ - if (bd_count == 1) { - qedf->single_sge_ios++; - io_req->sge_type = QEDF_IOREQ_SINGLE_SGE; - } else if (io_req->use_slowpath) { + if (io_req->sge_type == QEDF_IOREQ_SLOW_SGE) qedf->slow_sge_ios++; - io_req->sge_type = QEDF_IOREQ_SLOW_SGE; - } else { + else qedf->fast_sge_ios++; - io_req->sge_type = QEDF_IOREQ_FAST_SGE; - } } void qedf_init_mp_task(struct qedf_ioreq *io_req, @@ -770,9 +750,6 @@ void qedf_init_mp_task(struct qedf_ioreq *io_req, &task_fc_hdr, &tx_sgl_task_params, &rx_sgl_task_params, 0); - - /* Midpath requests always consume 1 SGE */ - qedf->single_sge_ios++; } /* Presumed that fcport->rport_lock is held */ @@ -804,10 +781,18 @@ void qedf_ring_doorbell(struct qedf_rport *fcport) FCOE_DB_DATA_AGG_VAL_SEL_SHIFT; dbell.sq_prod = fcport->fw_sq_prod_idx; + /* wmb makes sure that the BDs data is updated before updating the + * producer, otherwise FW may read old data from the BDs. + */ + wmb(); + barrier(); writel(*(u32 *)&dbell, fcport->p_doorbell); - /* Make sure SQ index is updated so f/w prcesses requests in order */ + /* + * Fence required to flush the write combined buffer, since another + * CPU may write to the same doorbell address and data may be lost + * due to relaxed order nature of write combined bar. + */ wmb(); - mmiowb(); } static void qedf_trace_io(struct qedf_rport *fcport, struct qedf_ioreq *io_req, @@ -872,7 +857,7 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) /* Initialize rest of io_req fileds */ io_req->data_xfer_len = scsi_bufflen(sc_cmd); sc_cmd->SCp.ptr = (char *)io_req; - io_req->use_slowpath = false; /* Assume fast SGL by default */ + io_req->sge_type = QEDF_IOREQ_FAST_SGE; /* Assume fast SGL by default */ /* Record which cpu this request is associated with */ io_req->cpu = smp_processor_id(); @@ -895,15 +880,24 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) /* Build buffer descriptor list for firmware from sg list */ if (qedf_build_bd_list_from_sg(io_req)) { QEDF_ERR(&(qedf->dbg_ctx), "BD list creation failed.\n"); + /* Release cmd will release io_req, but sc_cmd is assigned */ + io_req->sc_cmd = NULL; kref_put(&io_req->refcount, qedf_release_cmd); return -EAGAIN; } - if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { + if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) || + test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { QEDF_ERR(&(qedf->dbg_ctx), "Session not offloaded yet.\n"); + /* Release cmd will release io_req, but sc_cmd is assigned */ + io_req->sc_cmd = NULL; kref_put(&io_req->refcount, qedf_release_cmd); + return -EINVAL; } + /* Record LUN number for later use if we neeed them */ + io_req->lun = (int)sc_cmd->device->lun; + /* Obtain free SQE */ sqe_idx = qedf_get_sqe_idx(fcport); sqe = &fcport->sq[sqe_idx]; @@ -914,6 +908,8 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) if (!task_ctx) { QEDF_WARN(&(qedf->dbg_ctx), "task_ctx is NULL, xid=%d.\n", xid); + /* Release cmd will release io_req, but sc_cmd is assigned */ + io_req->sc_cmd = NULL; kref_put(&io_req->refcount, qedf_release_cmd); return -EINVAL; } @@ -923,6 +919,9 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) /* Ring doorbell */ qedf_ring_doorbell(fcport); + /* Set that command is with the firmware now */ + set_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + if (qedf_io_tracing && io_req->sc_cmd) qedf_trace_io(fcport, io_req, QEDF_IO_TRACE_REQ); @@ -941,7 +940,17 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) int rc = 0; int rval; unsigned long flags = 0; - + int num_sgs = 0; + + num_sgs = scsi_sg_count(sc_cmd); + if (scsi_sg_count(sc_cmd) > QEDF_MAX_BDS_PER_CMD) { + QEDF_ERR(&qedf->dbg_ctx, + "Number of SG elements %d exceeds what hardware limitation of %d.\n", + num_sgs, QEDF_MAX_BDS_PER_CMD); + sc_cmd->result = DID_ERROR; + sc_cmd->scsi_done(sc_cmd); + return 0; + } if (test_bit(QEDF_UNLOADING, &qedf->flags) || test_bit(QEDF_DBG_STOP_IO, &qedf->flags)) { @@ -981,7 +990,8 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) /* rport and tgt are allocated together, so tgt should be non-NULL */ fcport = (struct qedf_rport *)&rp[1]; - if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { + if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) || + test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { /* * Session is not offloaded yet. Let SCSI-ml retry * the command. @@ -989,12 +999,16 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) rc = SCSI_MLQUEUE_TARGET_BUSY; goto exit_qcmd; } + + atomic_inc(&fcport->ios_to_queue); + if (fcport->retry_delay_timestamp) { if (time_after(jiffies, fcport->retry_delay_timestamp)) { fcport->retry_delay_timestamp = 0; } else { /* If retry_delay timer is active, flow off the ML */ rc = SCSI_MLQUEUE_TARGET_BUSY; + atomic_dec(&fcport->ios_to_queue); goto exit_qcmd; } } @@ -1002,6 +1016,7 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) io_req = qedf_alloc_cmd(fcport, QEDF_SCSI_CMD); if (!io_req) { rc = SCSI_MLQUEUE_HOST_BUSY; + atomic_dec(&fcport->ios_to_queue); goto exit_qcmd; } @@ -1016,6 +1031,7 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) rc = SCSI_MLQUEUE_HOST_BUSY; } spin_unlock_irqrestore(&fcport->rport_lock, flags); + atomic_dec(&fcport->ios_to_queue); exit_qcmd: return rc; @@ -1092,7 +1108,7 @@ static void qedf_unmap_sg_list(struct qedf_ctx *qedf, struct qedf_ioreq *io_req) void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, struct qedf_ioreq *io_req) { - u16 xid, rval; + u16 xid; struct e4_fcoe_task_context *task_ctx; struct scsi_cmnd *sc_cmd; struct fcoe_cqe_rsp_info *fcp_rsp; @@ -1106,6 +1122,15 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, if (!cqe) return; + if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || + test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags) || + test_bit(QEDF_CMD_IN_ABORT, &io_req->flags)) { + QEDF_ERR(&qedf->dbg_ctx, + "io_req xid=0x%x already in cleanup or abort processing or already completed.\n", + io_req->xid); + return; + } + xid = io_req->xid; task_ctx = qedf_get_task_mem(&qedf->tasks, xid); sc_cmd = io_req->sc_cmd; @@ -1122,6 +1147,12 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, return; } + if (!sc_cmd->device) { + QEDF_ERR(&qedf->dbg_ctx, + "Device for sc_cmd %p is NULL.\n", sc_cmd); + return; + } + if (!sc_cmd->request) { QEDF_WARN(&(qedf->dbg_ctx), "sc_cmd->request is NULL, " "sc_cmd=%p.\n", sc_cmd); @@ -1136,6 +1167,19 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, fcport = io_req->fcport; + /* + * When flush is active, let the cmds be completed from the cleanup + * context + */ + if (test_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags) || + (test_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags) && + sc_cmd->device->lun == (u64)fcport->lun_reset_lun)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Dropping good completion xid=0x%x as fcport is flushing", + io_req->xid); + return; + } + qedf_parse_fcp_rsp(io_req, fcp_rsp); qedf_unmap_sg_list(qedf, io_req); @@ -1153,25 +1197,18 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, fw_residual_flag = GET_FIELD(cqe->cqe_info.rsp_info.fw_error_flags, FCOE_CQE_RSP_INFO_FW_UNDERRUN); if (fw_residual_flag) { - QEDF_ERR(&(qedf->dbg_ctx), - "Firmware detected underrun: xid=0x%x fcp_rsp.flags=0x%02x " - "fcp_resid=%d fw_residual=0x%x.\n", io_req->xid, - fcp_rsp->rsp_flags.flags, io_req->fcp_resid, - cqe->cqe_info.rsp_info.fw_residual); + QEDF_ERR(&qedf->dbg_ctx, + "Firmware detected underrun: xid=0x%x fcp_rsp.flags=0x%02x fcp_resid=%d fw_residual=0x%x lba=%02x%02x%02x%02x.\n", + io_req->xid, fcp_rsp->rsp_flags.flags, + io_req->fcp_resid, + cqe->cqe_info.rsp_info.fw_residual, sc_cmd->cmnd[2], + sc_cmd->cmnd[3], sc_cmd->cmnd[4], sc_cmd->cmnd[5]); if (io_req->cdb_status == 0) sc_cmd->result = (DID_ERROR << 16) | io_req->cdb_status; else sc_cmd->result = (DID_OK << 16) | io_req->cdb_status; - /* Abort the command since we did not get all the data */ - init_completion(&io_req->abts_done); - rval = qedf_initiate_abts(io_req, true); - if (rval) { - QEDF_ERR(&(qedf->dbg_ctx), "Failed to queue ABTS.\n"); - sc_cmd->result = (DID_ERROR << 16) | io_req->cdb_status; - } - /* * Set resid to the whole buffer length so we won't try to resue * any previously data. @@ -1243,6 +1280,12 @@ out: if (qedf_io_tracing) qedf_trace_io(fcport, io_req, QEDF_IO_TRACE_RSP); + /* + * We wait till the end of the function to clear the + * outstanding bit in case we need to send an abort + */ + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + io_req->sc_cmd = NULL; sc_cmd->SCp.ptr = NULL; sc_cmd->scsi_done(sc_cmd); @@ -1260,6 +1303,19 @@ void qedf_scsi_done(struct qedf_ctx *qedf, struct qedf_ioreq *io_req, if (!io_req) return; + if (test_and_set_bit(QEDF_CMD_ERR_SCSI_DONE, &io_req->flags)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "io_req:%p scsi_done handling already done\n", + io_req); + return; + } + + /* + * We will be done with this command after this call so clear the + * outstanding bit. + */ + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + xid = io_req->xid; sc_cmd = io_req->sc_cmd; @@ -1268,12 +1324,50 @@ void qedf_scsi_done(struct qedf_ctx *qedf, struct qedf_ioreq *io_req, return; } + if (!virt_addr_valid(sc_cmd)) { + QEDF_ERR(&qedf->dbg_ctx, "sc_cmd=%p is not valid.", sc_cmd); + goto bad_scsi_ptr; + } + if (!sc_cmd->SCp.ptr) { QEDF_WARN(&(qedf->dbg_ctx), "SCp.ptr is NULL, returned in " "another context.\n"); return; } + if (!sc_cmd->device) { + QEDF_ERR(&qedf->dbg_ctx, "Device for sc_cmd %p is NULL.\n", + sc_cmd); + goto bad_scsi_ptr; + } + + if (!virt_addr_valid(sc_cmd->device)) { + QEDF_ERR(&qedf->dbg_ctx, + "Device pointer for sc_cmd %p is bad.\n", sc_cmd); + goto bad_scsi_ptr; + } + + if (!sc_cmd->sense_buffer) { + QEDF_ERR(&qedf->dbg_ctx, + "sc_cmd->sense_buffer for sc_cmd %p is NULL.\n", + sc_cmd); + goto bad_scsi_ptr; + } + + if (!virt_addr_valid(sc_cmd->sense_buffer)) { + QEDF_ERR(&qedf->dbg_ctx, + "sc_cmd->sense_buffer for sc_cmd %p is bad.\n", + sc_cmd); + goto bad_scsi_ptr; + } + + if (!sc_cmd->scsi_done) { + QEDF_ERR(&qedf->dbg_ctx, + "sc_cmd->scsi_done for sc_cmd %p is NULL.\n", + sc_cmd); + goto bad_scsi_ptr; + } + qedf_unmap_sg_list(qedf, io_req); sc_cmd->result = result << 16; @@ -1300,6 +1394,15 @@ void qedf_scsi_done(struct qedf_ctx *qedf, struct qedf_ioreq *io_req, sc_cmd->SCp.ptr = NULL; sc_cmd->scsi_done(sc_cmd); kref_put(&io_req->refcount, qedf_release_cmd); + return; + +bad_scsi_ptr: + /* + * Clear the io_req->sc_cmd backpointer so we don't try to process + * this again + */ + io_req->sc_cmd = NULL; + kref_put(&io_req->refcount, qedf_release_cmd); /* ID: 001 */ } /* @@ -1438,6 +1541,10 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) struct qedf_ctx *qedf; struct qedf_cmd_mgr *cmd_mgr; int i, rc; + unsigned long flags; + int flush_cnt = 0; + int wait_cnt = 100; + int refcount = 0; if (!fcport) return; @@ -1449,18 +1556,102 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) } qedf = fcport->qedf; + + if (!qedf) { + QEDF_ERR(NULL, "qedf is NULL.\n"); + return; + } + + /* Only wait for all commands to be queued in the Upload context */ + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags) && + (lun == -1)) { + while (atomic_read(&fcport->ios_to_queue)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Waiting for %d I/Os to be queued\n", + atomic_read(&fcport->ios_to_queue)); + if (wait_cnt == 0) { + QEDF_ERR(NULL, + "%d IOs request could not be queued\n", + atomic_read(&fcport->ios_to_queue)); + } + msleep(20); + wait_cnt--; + } + } + cmd_mgr = qedf->cmd_mgr; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, "Flush active i/o's.\n"); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Flush active i/o's num=0x%x fcport=0x%p port_id=0x%06x scsi_id=%d.\n", + atomic_read(&fcport->num_active_ios), fcport, + fcport->rdata->ids.port_id, fcport->rport->scsi_target_id); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Locking flush mutex.\n"); + + mutex_lock(&qedf->flush_mutex); + if (lun == -1) { + set_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags); + } else { + set_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags); + fcport->lun_reset_lun = lun; + } for (i = 0; i < FCOE_PARAMS_NUM_TASKS; i++) { io_req = &cmd_mgr->cmds[i]; if (!io_req) continue; + if (!io_req->fcport) + continue; + + spin_lock_irqsave(&cmd_mgr->lock, flags); + + if (io_req->alloc) { + if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags)) { + if (io_req->cmd_type == QEDF_SCSI_CMD) + QEDF_ERR(&qedf->dbg_ctx, + "Allocated but not queued, xid=0x%x\n", + io_req->xid); + } + spin_unlock_irqrestore(&cmd_mgr->lock, flags); + } else { + spin_unlock_irqrestore(&cmd_mgr->lock, flags); + continue; + } + if (io_req->fcport != fcport) continue; - if (io_req->cmd_type == QEDF_ELS) { + + /* In case of ABTS, CMD_OUTSTANDING is cleared on ABTS response, + * but RRQ is still pending. + * Workaround: Within qedf_send_rrq, we check if the fcport is + * NULL, and we drop the ref on the io_req to clean it up. + */ + if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags)) { + refcount = kref_read(&io_req->refcount); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Not outstanding, xid=0x%x, cmd_type=%d refcount=%d.\n", + io_req->xid, io_req->cmd_type, refcount); + /* If RRQ work has been queue, try to cancel it and + * free the io_req + */ + if (atomic_read(&io_req->state) == + QEDFC_CMD_ST_RRQ_WAIT) { + if (cancel_delayed_work_sync + (&io_req->rrq_work)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Putting reference for pending RRQ work xid=0x%x.\n", + io_req->xid); + /* ID: 003 */ + kref_put(&io_req->refcount, + qedf_release_cmd); + } + } + continue; + } + + /* Only consider flushing ELS during target reset */ + if (io_req->cmd_type == QEDF_ELS && + lun == -1) { rc = kref_get_unless_zero(&io_req->refcount); if (!rc) { QEDF_ERR(&(qedf->dbg_ctx), @@ -1468,6 +1659,7 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) io_req, io_req->xid); continue; } + flush_cnt++; qedf_flush_els_req(qedf, io_req); /* * Release the kref and go back to the top of the @@ -1477,6 +1669,7 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) } if (io_req->cmd_type == QEDF_ABTS) { + /* ID: 004 */ rc = kref_get_unless_zero(&io_req->refcount); if (!rc) { QEDF_ERR(&(qedf->dbg_ctx), @@ -1484,28 +1677,50 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) io_req, io_req->xid); continue; } + if (lun != -1 && io_req->lun != lun) + goto free_cmd; + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Flushing abort xid=0x%x.\n", io_req->xid); - clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags); - - if (io_req->sc_cmd) { - if (io_req->return_scsi_cmd_on_abts) - qedf_scsi_done(qedf, io_req, DID_ERROR); + if (cancel_delayed_work_sync(&io_req->rrq_work)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Putting ref for cancelled RRQ work xid=0x%x.\n", + io_req->xid); + kref_put(&io_req->refcount, qedf_release_cmd); } - /* Notify eh_abort handler that ABTS is complete */ - complete(&io_req->abts_done); - kref_put(&io_req->refcount, qedf_release_cmd); - + if (cancel_delayed_work_sync(&io_req->timeout_work)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Putting ref for cancelled tmo work xid=0x%x.\n", + io_req->xid); + qedf_initiate_cleanup(io_req, true); + /* Notify eh_abort handler that ABTS is + * complete + */ + complete(&io_req->abts_done); + clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags); + /* ID: 002 */ + kref_put(&io_req->refcount, qedf_release_cmd); + } + flush_cnt++; goto free_cmd; } if (!io_req->sc_cmd) continue; - if (lun > 0) { - if (io_req->sc_cmd->device->lun != - (u64)lun) + if (!io_req->sc_cmd->device) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Device backpointer NULL for sc_cmd=%p.\n", + io_req->sc_cmd); + /* Put reference for non-existent scsi_cmnd */ + io_req->sc_cmd = NULL; + qedf_initiate_cleanup(io_req, false); + kref_put(&io_req->refcount, qedf_release_cmd); + continue; + } + if (lun > -1) { + if (io_req->lun != lun) continue; } @@ -1519,15 +1734,65 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) "io_req=0x%p xid=0x%x\n", io_req, io_req->xid); continue; } + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, "Cleanup xid=0x%x.\n", io_req->xid); + flush_cnt++; /* Cleanup task and return I/O mid-layer */ qedf_initiate_cleanup(io_req, true); free_cmd: - kref_put(&io_req->refcount, qedf_release_cmd); + kref_put(&io_req->refcount, qedf_release_cmd); /* ID: 004 */ + } + + wait_cnt = 60; + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Flushed 0x%x I/Os, active=0x%x.\n", + flush_cnt, atomic_read(&fcport->num_active_ios)); + /* Only wait for all commands to complete in the Upload context */ + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags) && + (lun == -1)) { + while (atomic_read(&fcport->num_active_ios)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Flushed 0x%x I/Os, active=0x%x cnt=%d.\n", + flush_cnt, + atomic_read(&fcport->num_active_ios), + wait_cnt); + if (wait_cnt == 0) { + QEDF_ERR(&qedf->dbg_ctx, + "Flushed %d I/Os, active=%d.\n", + flush_cnt, + atomic_read(&fcport->num_active_ios)); + for (i = 0; i < FCOE_PARAMS_NUM_TASKS; i++) { + io_req = &cmd_mgr->cmds[i]; + if (io_req->fcport && + io_req->fcport == fcport) { + refcount = + kref_read(&io_req->refcount); + set_bit(QEDF_CMD_DIRTY, + &io_req->flags); + QEDF_ERR(&qedf->dbg_ctx, + "Outstanding io_req =%p xid=0x%x flags=0x%lx, sc_cmd=%p refcount=%d cmd_type=%d.\n", + io_req, io_req->xid, + io_req->flags, + io_req->sc_cmd, + refcount, + io_req->cmd_type); + } + } + WARN_ON(1); + break; + } + msleep(500); + wait_cnt--; + } } + + clear_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags); + clear_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Unlocking flush mutex.\n"); + mutex_unlock(&qedf->flush_mutex); } /* @@ -1546,52 +1811,60 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) unsigned long flags; struct fcoe_wqe *sqe; u16 sqe_idx; + int refcount = 0; /* Sanity check qedf_rport before dereferencing any pointers */ if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { QEDF_ERR(NULL, "tgt not offloaded\n"); rc = 1; - goto abts_err; + goto out; } + qedf = fcport->qedf; rdata = fcport->rdata; + + if (!rdata || !kref_get_unless_zero(&rdata->kref)) { + QEDF_ERR(&qedf->dbg_ctx, "stale rport\n"); + rc = 1; + goto out; + } + r_a_tov = rdata->r_a_tov; - qedf = fcport->qedf; lport = qedf->lport; if (lport->state != LPORT_ST_READY || !(lport->link_up)) { QEDF_ERR(&(qedf->dbg_ctx), "link is not ready\n"); rc = 1; - goto abts_err; + goto drop_rdata_kref; } if (atomic_read(&qedf->link_down_tmo_valid) > 0) { QEDF_ERR(&(qedf->dbg_ctx), "link_down_tmo active.\n"); rc = 1; - goto abts_err; + goto drop_rdata_kref; } /* Ensure room on SQ */ if (!atomic_read(&fcport->free_sqes)) { QEDF_ERR(&(qedf->dbg_ctx), "No SQ entries available\n"); rc = 1; - goto abts_err; + goto drop_rdata_kref; } if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { QEDF_ERR(&qedf->dbg_ctx, "fcport is uploading.\n"); rc = 1; - goto out; + goto drop_rdata_kref; } if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags) || test_bit(QEDF_CMD_IN_ABORT, &io_req->flags)) { - QEDF_ERR(&(qedf->dbg_ctx), "io_req xid=0x%x already in " - "cleanup or abort processing or already " - "completed.\n", io_req->xid); + QEDF_ERR(&qedf->dbg_ctx, + "io_req xid=0x%x sc_cmd=%p already in cleanup or abort processing or already completed.\n", + io_req->xid, io_req->sc_cmd); rc = 1; - goto out; + goto drop_rdata_kref; } kref_get(&io_req->refcount); @@ -1600,18 +1873,17 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) qedf->control_requests++; qedf->packet_aborts++; - /* Set the return CPU to be the same as the request one */ - io_req->cpu = smp_processor_id(); - /* Set the command type to abort */ io_req->cmd_type = QEDF_ABTS; io_req->return_scsi_cmd_on_abts = return_scsi_cmd_on_abts; set_bit(QEDF_CMD_IN_ABORT, &io_req->flags); - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "ABTS io_req xid = " - "0x%x\n", xid); + refcount = kref_read(&io_req->refcount); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, + "ABTS io_req xid = 0x%x refcount=%d\n", + xid, refcount); - qedf_cmd_timer_set(qedf, io_req, QEDF_ABORT_TIMEOUT * HZ); + qedf_cmd_timer_set(qedf, io_req, QEDF_ABORT_TIMEOUT); spin_lock_irqsave(&fcport->rport_lock, flags); @@ -1625,13 +1897,8 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) spin_unlock_irqrestore(&fcport->rport_lock, flags); - return rc; -abts_err: - /* - * If the ABTS task fails to queue then we need to cleanup the - * task at the firmware. - */ - qedf_initiate_cleanup(io_req, return_scsi_cmd_on_abts); +drop_rdata_kref: + kref_put(&rdata->kref, fc_rport_destroy); out: return rc; } @@ -1641,27 +1908,62 @@ void qedf_process_abts_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, { uint32_t r_ctl; uint16_t xid; + int rc; + struct qedf_rport *fcport = io_req->fcport; QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "Entered with xid = " "0x%x cmd_type = %d\n", io_req->xid, io_req->cmd_type); - cancel_delayed_work(&io_req->timeout_work); - xid = io_req->xid; r_ctl = cqe->cqe_info.abts_info.r_ctl; + /* This was added at a point when we were scheduling abts_compl & + * cleanup_compl on different CPUs and there was a possibility of + * the io_req to be freed from the other context before we got here. + */ + if (!fcport) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Dropping ABTS completion xid=0x%x as fcport is NULL", + io_req->xid); + return; + } + + /* + * When flush is active, let the cmds be completed from the cleanup + * context + */ + if (test_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags) || + test_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Dropping ABTS completion xid=0x%x as fcport is flushing", + io_req->xid); + return; + } + + if (!cancel_delayed_work(&io_req->timeout_work)) { + QEDF_ERR(&qedf->dbg_ctx, + "Wasn't able to cancel abts timeout work.\n"); + } + switch (r_ctl) { case FC_RCTL_BA_ACC: QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "ABTS response - ACC Send RRQ after R_A_TOV\n"); io_req->event = QEDF_IOREQ_EV_ABORT_SUCCESS; + rc = kref_get_unless_zero(&io_req->refcount); /* ID: 003 */ + if (!rc) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, + "kref is already zero so ABTS was already completed or flushed xid=0x%x.\n", + io_req->xid); + return; + } /* * Dont release this cmd yet. It will be relesed * after we get RRQ response */ - kref_get(&io_req->refcount); queue_delayed_work(qedf->dpc_wq, &io_req->rrq_work, msecs_to_jiffies(qedf->lport->r_a_tov)); + atomic_set(&io_req->state, QEDFC_CMD_ST_RRQ_WAIT); break; /* For error cases let the cleanup return the command */ case FC_RCTL_BA_RJT: @@ -1803,6 +2105,7 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req, unsigned long flags; struct fcoe_wqe *sqe; u16 sqe_idx; + int refcount = 0; fcport = io_req->fcport; if (!fcport) { @@ -1824,36 +2127,45 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req, } if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || - test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags)) { + test_and_set_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags)) { QEDF_ERR(&(qedf->dbg_ctx), "io_req xid=0x%x already in " "cleanup processing or already completed.\n", io_req->xid); return SUCCESS; } + set_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); /* Ensure room on SQ */ if (!atomic_read(&fcport->free_sqes)) { QEDF_ERR(&(qedf->dbg_ctx), "No SQ entries available\n"); + /* Need to make sure we clear the flag since it was set */ + clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); return FAILED; } + if (io_req->cmd_type == QEDF_CLEANUP) { + QEDF_ERR(&qedf->dbg_ctx, + "io_req=0x%x is already a cleanup command cmd_type=%d.\n", + io_req->xid, io_req->cmd_type); + clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); + return SUCCESS; + } - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, "Entered xid=0x%x\n", - io_req->xid); + refcount = kref_read(&io_req->refcount); + + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Entered xid=0x%x sc_cmd=%p cmd_type=%d flags=0x%lx refcount=%d fcport=%p port_id=0x%06x\n", + io_req->xid, io_req->sc_cmd, io_req->cmd_type, io_req->flags, + refcount, fcport, fcport->rdata->ids.port_id); /* Cleanup cmds re-use the same TID as the original I/O */ xid = io_req->xid; io_req->cmd_type = QEDF_CLEANUP; io_req->return_scsi_cmd_on_abts = return_scsi_cmd_on_abts; - /* Set the return CPU to be the same as the request one */ - io_req->cpu = smp_processor_id(); - - set_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); - task = qedf_get_task_mem(&qedf->tasks, xid); - init_completion(&io_req->tm_done); + init_completion(&io_req->cleanup_done); spin_lock_irqsave(&fcport->rport_lock, flags); @@ -1867,8 +2179,8 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req, spin_unlock_irqrestore(&fcport->rport_lock, flags); - tmo = wait_for_completion_timeout(&io_req->tm_done, - QEDF_CLEANUP_TIMEOUT * HZ); + tmo = wait_for_completion_timeout(&io_req->cleanup_done, + QEDF_CLEANUP_TIMEOUT * HZ); if (!tmo) { rc = FAILED; @@ -1881,6 +2193,16 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req, qedf_drain_request(qedf); } + /* If it TASK MGMT handle it, reference will be decreased + * in qedf_execute_tmf + */ + if (io_req->tm_flags == FCP_TMF_LUN_RESET || + io_req->tm_flags == FCP_TMF_TGT_RESET) { + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + io_req->sc_cmd = NULL; + complete(&io_req->tm_done); + } + if (io_req->sc_cmd) { if (io_req->return_scsi_cmd_on_abts) qedf_scsi_done(qedf, io_req, DID_ERROR); @@ -1903,7 +2225,7 @@ void qedf_process_cleanup_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); /* Complete so we can finish cleaning up the I/O */ - complete(&io_req->tm_done); + complete(&io_req->cleanup_done); } static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, @@ -1916,6 +2238,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, int rc = 0; uint16_t xid; int tmo = 0; + int lun = 0; unsigned long flags; struct fcoe_wqe *sqe; u16 sqe_idx; @@ -1925,20 +2248,18 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, return FAILED; } + lun = (int)sc_cmd->device->lun; if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { QEDF_ERR(&(qedf->dbg_ctx), "fcport not offloaded\n"); rc = FAILED; - return FAILED; + goto no_flush; } - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "portid = 0x%x " - "tm_flags = %d\n", fcport->rdata->ids.port_id, tm_flags); - io_req = qedf_alloc_cmd(fcport, QEDF_TASK_MGMT_CMD); if (!io_req) { QEDF_ERR(&(qedf->dbg_ctx), "Failed TMF"); rc = -EAGAIN; - goto reset_tmf_err; + goto no_flush; } if (tm_flags == FCP_TMF_LUN_RESET) @@ -1951,7 +2272,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, io_req->fcport = fcport; io_req->cmd_type = QEDF_TASK_MGMT_CMD; - /* Set the return CPU to be the same as the request one */ + /* Record which cpu this request is associated with */ io_req->cpu = smp_processor_id(); /* Set TM flags */ @@ -1960,7 +2281,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, io_req->tm_flags = tm_flags; /* Default is to return a SCSI command when an error occurs */ - io_req->return_scsi_cmd_on_abts = true; + io_req->return_scsi_cmd_on_abts = false; /* Obtain exchange id */ xid = io_req->xid; @@ -1984,12 +2305,16 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, spin_unlock_irqrestore(&fcport->rport_lock, flags); + set_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); tmo = wait_for_completion_timeout(&io_req->tm_done, QEDF_TM_TIMEOUT * HZ); if (!tmo) { rc = FAILED; QEDF_ERR(&(qedf->dbg_ctx), "wait for tm_cmpl timeout!\n"); + /* Clear outstanding bit since command timed out */ + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + io_req->sc_cmd = NULL; } else { /* Check TMF response code */ if (io_req->fcp_rsp_code == 0) @@ -1997,14 +2322,25 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, else rc = FAILED; } + /* + * Double check that fcport has not gone into an uploading state before + * executing the command flush for the LUN/target. + */ + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { + QEDF_ERR(&qedf->dbg_ctx, + "fcport is uploading, not executing flush.\n"); + goto no_flush; + } + /* We do not need this io_req any more */ + kref_put(&io_req->refcount, qedf_release_cmd); + if (tm_flags == FCP_TMF_LUN_RESET) - qedf_flush_active_ios(fcport, (int)sc_cmd->device->lun); + qedf_flush_active_ios(fcport, lun); else qedf_flush_active_ios(fcport, -1); - kref_put(&io_req->refcount, qedf_release_cmd); - +no_flush: if (rc != SUCCESS) { QEDF_ERR(&(qedf->dbg_ctx), "task mgmt command failed...\n"); rc = FAILED; @@ -2012,7 +2348,6 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, QEDF_ERR(&(qedf->dbg_ctx), "task mgmt command success...\n"); rc = SUCCESS; } -reset_tmf_err: return rc; } @@ -2022,26 +2357,65 @@ int qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) struct fc_rport_libfc_priv *rp = rport->dd_data; struct qedf_rport *fcport = (struct qedf_rport *)&rp[1]; struct qedf_ctx *qedf; - struct fc_lport *lport; + struct fc_lport *lport = shost_priv(sc_cmd->device->host); int rc = SUCCESS; int rval; + struct qedf_ioreq *io_req = NULL; + int ref_cnt = 0; + struct fc_rport_priv *rdata = fcport->rdata; - rval = fc_remote_port_chkready(rport); + QEDF_ERR(NULL, + "tm_flags 0x%x sc_cmd %p op = 0x%02x target_id = 0x%x lun=%d\n", + tm_flags, sc_cmd, sc_cmd->cmnd[0], rport->scsi_target_id, + (int)sc_cmd->device->lun); + + if (!rdata || !kref_get_unless_zero(&rdata->kref)) { + QEDF_ERR(NULL, "stale rport\n"); + return FAILED; + } + + QEDF_ERR(NULL, "portid=%06x tm_flags =%s\n", rdata->ids.port_id, + (tm_flags == FCP_TMF_TGT_RESET) ? "TARGET RESET" : + "LUN RESET"); + + if (sc_cmd->SCp.ptr) { + io_req = (struct qedf_ioreq *)sc_cmd->SCp.ptr; + ref_cnt = kref_read(&io_req->refcount); + QEDF_ERR(NULL, + "orig io_req = %p xid = 0x%x ref_cnt = %d.\n", + io_req, io_req->xid, ref_cnt); + } + rval = fc_remote_port_chkready(rport); if (rval) { QEDF_ERR(NULL, "device_reset rport not ready\n"); rc = FAILED; goto tmf_err; } - if (fcport == NULL) { + rc = fc_block_scsi_eh(sc_cmd); + if (rc) + goto tmf_err; + + if (!fcport) { QEDF_ERR(NULL, "device_reset: rport is NULL\n"); rc = FAILED; goto tmf_err; } qedf = fcport->qedf; - lport = qedf->lport; + + if (!qedf) { + QEDF_ERR(NULL, "qedf is NULL.\n"); + rc = FAILED; + goto tmf_err; + } + + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { + QEDF_ERR(&qedf->dbg_ctx, "Connection is getting uploaded.\n"); + rc = SUCCESS; + goto tmf_err; + } if (test_bit(QEDF_UNLOADING, &qedf->flags) || test_bit(QEDF_DBG_STOP_IO, &qedf->flags)) { @@ -2055,9 +2429,22 @@ int qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) goto tmf_err; } + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { + if (!fcport->rdata) + QEDF_ERR(&qedf->dbg_ctx, "fcport %p is uploading.\n", + fcport); + else + QEDF_ERR(&qedf->dbg_ctx, + "fcport %p port_id=%06x is uploading.\n", + fcport, fcport->rdata->ids.port_id); + rc = FAILED; + goto tmf_err; + } + rc = qedf_execute_tmf(fcport, sc_cmd, tm_flags); tmf_err: + kref_put(&rdata->kref, fc_rport_destroy); return rc; } @@ -2066,6 +2453,8 @@ void qedf_process_tmf_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, { struct fcoe_cqe_rsp_info *fcp_rsp; + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + fcp_rsp = &cqe->cqe_info.rsp_info; qedf_parse_fcp_rsp(io_req, fcp_rsp); diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 9f9431a4cc0e..5b07235497c6 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -124,21 +124,24 @@ static bool qedf_initiate_fipvlan_req(struct qedf_ctx *qedf) { int rc; - if (atomic_read(&qedf->link_state) != QEDF_LINK_UP) { - QEDF_ERR(&(qedf->dbg_ctx), "Link not up.\n"); - return false; - } - while (qedf->fipvlan_retries--) { + /* This is to catch if link goes down during fipvlan retries */ + if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) { + QEDF_ERR(&qedf->dbg_ctx, "Link not up.\n"); + return false; + } + if (qedf->vlan_id > 0) return true; + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Retry %d.\n", qedf->fipvlan_retries); init_completion(&qedf->fipvlan_compl); qedf_fcoe_send_vlan_req(qedf); rc = wait_for_completion_timeout(&qedf->fipvlan_compl, 1 * HZ); - if (rc > 0) { + if (rc > 0 && + (atomic_read(&qedf->link_state) == QEDF_LINK_UP)) { fcoe_ctlr_link_up(&qedf->ctlr); return true; } @@ -153,12 +156,19 @@ static void qedf_handle_link_update(struct work_struct *work) container_of(work, struct qedf_ctx, link_update.work); int rc; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Entered.\n"); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Entered. link_state=%d.\n", + atomic_read(&qedf->link_state)); if (atomic_read(&qedf->link_state) == QEDF_LINK_UP) { rc = qedf_initiate_fipvlan_req(qedf); if (rc) return; + + if (atomic_read(&qedf->link_state) != QEDF_LINK_UP) { + qedf->vlan_id = 0; + return; + } + /* * If we get here then we never received a repsonse to our * fip vlan request so set the vlan_id to the default and @@ -185,7 +195,9 @@ static void qedf_handle_link_update(struct work_struct *work) QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Calling fcoe_ctlr_link_down().\n"); fcoe_ctlr_link_down(&qedf->ctlr); - qedf_wait_for_upload(qedf); + if (qedf_wait_for_upload(qedf) == false) + QEDF_ERR(&qedf->dbg_ctx, + "Could not upload all sessions.\n"); /* Reset the number of FIP VLAN retries */ qedf->fipvlan_retries = qedf_fipvlan_retries; } @@ -615,50 +627,113 @@ static struct scsi_transport_template *qedf_fc_vport_transport_template; static int qedf_eh_abort(struct scsi_cmnd *sc_cmd) { struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); - struct fc_rport_libfc_priv *rp = rport->dd_data; - struct qedf_rport *fcport; struct fc_lport *lport; struct qedf_ctx *qedf; struct qedf_ioreq *io_req; + struct fc_rport_libfc_priv *rp = rport->dd_data; + struct fc_rport_priv *rdata; + struct qedf_rport *fcport = NULL; int rc = FAILED; + int wait_count = 100; + int refcount = 0; int rval; - - if (fc_remote_port_chkready(rport)) { - QEDF_ERR(NULL, "rport not ready\n"); - goto out; - } + int got_ref = 0; lport = shost_priv(sc_cmd->device->host); qedf = (struct qedf_ctx *)lport_priv(lport); - if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) { - QEDF_ERR(&(qedf->dbg_ctx), "link not ready.\n"); + /* rport and tgt are allocated together, so tgt should be non-NULL */ + fcport = (struct qedf_rport *)&rp[1]; + rdata = fcport->rdata; + if (!rdata || !kref_get_unless_zero(&rdata->kref)) { + QEDF_ERR(&qedf->dbg_ctx, "stale rport, sc_cmd=%p\n", sc_cmd); + rc = 1; goto out; } - fcport = (struct qedf_rport *)&rp[1]; io_req = (struct qedf_ioreq *)sc_cmd->SCp.ptr; if (!io_req) { - QEDF_ERR(&(qedf->dbg_ctx), "io_req is NULL.\n"); + QEDF_ERR(&qedf->dbg_ctx, + "sc_cmd not queued with lld, sc_cmd=%p op=0x%02x, port_id=%06x\n", + sc_cmd, sc_cmd->cmnd[0], + rdata->ids.port_id); rc = SUCCESS; - goto out; + goto drop_rdata_kref; + } + + rval = kref_get_unless_zero(&io_req->refcount); /* ID: 005 */ + if (rval) + got_ref = 1; + + /* If we got a valid io_req, confirm it belongs to this sc_cmd. */ + if (!rval || io_req->sc_cmd != sc_cmd) { + QEDF_ERR(&qedf->dbg_ctx, + "Freed/Incorrect io_req, io_req->sc_cmd=%p, sc_cmd=%p, port_id=%06x, bailing out.\n", + io_req->sc_cmd, sc_cmd, rdata->ids.port_id); + + goto drop_rdata_kref; + } + + if (fc_remote_port_chkready(rport)) { + refcount = kref_read(&io_req->refcount); + QEDF_ERR(&qedf->dbg_ctx, + "rport not ready, io_req=%p, xid=0x%x sc_cmd=%p op=0x%02x, refcount=%d, port_id=%06x\n", + io_req, io_req->xid, sc_cmd, sc_cmd->cmnd[0], + refcount, rdata->ids.port_id); + + goto drop_rdata_kref; + } + + rc = fc_block_scsi_eh(sc_cmd); + if (rc) + goto drop_rdata_kref; + + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { + QEDF_ERR(&qedf->dbg_ctx, + "Connection uploading, xid=0x%x., port_id=%06x\n", + io_req->xid, rdata->ids.port_id); + while (io_req->sc_cmd && (wait_count != 0)) { + msleep(100); + wait_count--; + } + if (wait_count) { + QEDF_ERR(&qedf->dbg_ctx, "ABTS succeeded\n"); + rc = SUCCESS; + } else { + QEDF_ERR(&qedf->dbg_ctx, "ABTS failed\n"); + rc = FAILED; + } + goto drop_rdata_kref; } - QEDF_ERR(&(qedf->dbg_ctx), "Aborting io_req sc_cmd=%p xid=0x%x " - "fp_idx=%d.\n", sc_cmd, io_req->xid, io_req->fp_idx); + if (lport->state != LPORT_ST_READY || !(lport->link_up)) { + QEDF_ERR(&qedf->dbg_ctx, "link not ready.\n"); + goto drop_rdata_kref; + } + + QEDF_ERR(&qedf->dbg_ctx, + "Aborting io_req=%p sc_cmd=%p xid=0x%x fp_idx=%d, port_id=%06x.\n", + io_req, sc_cmd, io_req->xid, io_req->fp_idx, + rdata->ids.port_id); if (qedf->stop_io_on_error) { qedf_stop_all_io(qedf); rc = SUCCESS; - goto out; + goto drop_rdata_kref; } init_completion(&io_req->abts_done); rval = qedf_initiate_abts(io_req, true); if (rval) { QEDF_ERR(&(qedf->dbg_ctx), "Failed to queue ABTS.\n"); - goto out; + /* + * If we fail to queue the ABTS then return this command to + * the SCSI layer as it will own and free the xid + */ + rc = SUCCESS; + qedf_scsi_done(qedf, io_req, DID_ERROR); + goto drop_rdata_kref; } wait_for_completion(&io_req->abts_done); @@ -684,38 +759,68 @@ static int qedf_eh_abort(struct scsi_cmnd *sc_cmd) QEDF_ERR(&(qedf->dbg_ctx), "ABTS failed, xid=0x%x.\n", io_req->xid); +drop_rdata_kref: + kref_put(&rdata->kref, fc_rport_destroy); out: + if (got_ref) + kref_put(&io_req->refcount, qedf_release_cmd); return rc; } static int qedf_eh_target_reset(struct scsi_cmnd *sc_cmd) { - QEDF_ERR(NULL, "TARGET RESET Issued..."); + QEDF_ERR(NULL, "%d:0:%d:%lld: TARGET RESET Issued...", + sc_cmd->device->host->host_no, sc_cmd->device->id, + sc_cmd->device->lun); return qedf_initiate_tmf(sc_cmd, FCP_TMF_TGT_RESET); } static int qedf_eh_device_reset(struct scsi_cmnd *sc_cmd) { - QEDF_ERR(NULL, "LUN RESET Issued...\n"); + QEDF_ERR(NULL, "%d:0:%d:%lld: LUN RESET Issued... ", + sc_cmd->device->host->host_no, sc_cmd->device->id, + sc_cmd->device->lun); return qedf_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); } -void qedf_wait_for_upload(struct qedf_ctx *qedf) +bool qedf_wait_for_upload(struct qedf_ctx *qedf) { - while (1) { + struct qedf_rport *fcport = NULL; + int wait_cnt = 120; + + while (wait_cnt--) { if (atomic_read(&qedf->num_offloads)) - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, - "Waiting for all uploads to complete.\n"); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Waiting for all uploads to complete num_offloads = 0x%x.\n", + atomic_read(&qedf->num_offloads)); else - break; + return true; msleep(500); } + + rcu_read_lock(); + list_for_each_entry_rcu(fcport, &qedf->fcports, peers) { + if (fcport && test_bit(QEDF_RPORT_SESSION_READY, + &fcport->flags)) { + if (fcport->rdata) + QEDF_ERR(&qedf->dbg_ctx, + "Waiting for fcport %p portid=%06x.\n", + fcport, fcport->rdata->ids.port_id); + } else { + QEDF_ERR(&qedf->dbg_ctx, + "Waiting for fcport %p.\n", fcport); + } + } + rcu_read_unlock(); + return false; + } /* Performs soft reset of qedf_ctx by simulating a link down/up */ -static void qedf_ctx_soft_reset(struct fc_lport *lport) +void qedf_ctx_soft_reset(struct fc_lport *lport) { struct qedf_ctx *qedf; + struct qed_link_output if_link; if (lport->vport) { QEDF_ERR(NULL, "Cannot issue host reset on NPIV port.\n"); @@ -726,11 +831,32 @@ static void qedf_ctx_soft_reset(struct fc_lport *lport) /* For host reset, essentially do a soft link up/down */ atomic_set(&qedf->link_state, QEDF_LINK_DOWN); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Queuing link down work.\n"); queue_delayed_work(qedf->link_update_wq, &qedf->link_update, 0); - qedf_wait_for_upload(qedf); + + if (qedf_wait_for_upload(qedf) == false) { + QEDF_ERR(&qedf->dbg_ctx, "Could not upload all sessions.\n"); + WARN_ON(atomic_read(&qedf->num_offloads)); + } + + /* Before setting link up query physical link state */ + qed_ops->common->get_link(qedf->cdev, &if_link); + /* Bail if the physical link is not up */ + if (!if_link.link_up) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Physical link is not up.\n"); + return; + } + /* Flush and wait to make sure link down is processed */ + flush_delayed_work(&qedf->link_update); + msleep(500); + atomic_set(&qedf->link_state, QEDF_LINK_UP); qedf->vlan_id = 0; + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Queue link up work.\n"); queue_delayed_work(qedf->link_update_wq, &qedf->link_update, 0); } @@ -740,22 +866,6 @@ static int qedf_eh_host_reset(struct scsi_cmnd *sc_cmd) { struct fc_lport *lport; struct qedf_ctx *qedf; - struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); - struct fc_rport_libfc_priv *rp = rport->dd_data; - struct qedf_rport *fcport = (struct qedf_rport *)&rp[1]; - int rval; - - rval = fc_remote_port_chkready(rport); - - if (rval) { - QEDF_ERR(NULL, "device_reset rport not ready\n"); - return FAILED; - } - - if (fcport == NULL) { - QEDF_ERR(NULL, "device_reset: rport is NULL\n"); - return FAILED; - } lport = shost_priv(sc_cmd->device->host); qedf = lport_priv(lport); @@ -907,8 +1017,10 @@ static int qedf_xmit(struct fc_lport *lport, struct fc_frame *fp) "Dropping FCoE frame to %06x.\n", ntoh24(fh->fh_d_id)); kfree_skb(skb); rdata = fc_rport_lookup(lport, ntoh24(fh->fh_d_id)); - if (rdata) + if (rdata) { rdata->retries = lport->max_rport_retry_count; + kref_put(&rdata->kref, fc_rport_destroy); + } return -EINVAL; } /* End NPIV filtering */ @@ -1031,7 +1143,12 @@ static int qedf_xmit(struct fc_lport *lport, struct fc_frame *fp) if (qedf_dump_frames) print_hex_dump(KERN_WARNING, "fcoe: ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb->len, false); - qed_ops->ll2->start_xmit(qedf->cdev, skb, 0); + rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, 0); + if (rc) { + QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc); + kfree_skb(skb); + return rc; + } return 0; } @@ -1224,6 +1341,8 @@ static void qedf_upload_connection(struct qedf_ctx *qedf, static void qedf_cleanup_fcport(struct qedf_ctx *qedf, struct qedf_rport *fcport) { + struct fc_rport_priv *rdata = fcport->rdata; + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_CONN, "Cleaning up portid=%06x.\n", fcport->rdata->ids.port_id); @@ -1235,6 +1354,7 @@ static void qedf_cleanup_fcport(struct qedf_ctx *qedf, qedf_free_sq(qedf, fcport); fcport->rdata = NULL; fcport->qedf = NULL; + kref_put(&rdata->kref, fc_rport_destroy); } /** @@ -1310,6 +1430,8 @@ static void qedf_rport_event_handler(struct fc_lport *lport, break; } + /* Initial reference held on entry, so this can't fail */ + kref_get(&rdata->kref); fcport->rdata = rdata; fcport->rport = rport; @@ -1369,11 +1491,15 @@ static void qedf_rport_event_handler(struct fc_lport *lport, */ fcport = (struct qedf_rport *)&rp[1]; + spin_lock_irqsave(&fcport->rport_lock, flags); /* Only free this fcport if it is offloaded already */ - if (test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { - set_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags); + if (test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) && + !test_bit(QEDF_RPORT_UPLOADING_CONNECTION, + &fcport->flags)) { + set_bit(QEDF_RPORT_UPLOADING_CONNECTION, + &fcport->flags); + spin_unlock_irqrestore(&fcport->rport_lock, flags); qedf_cleanup_fcport(qedf, fcport); - /* * Remove fcport to list of qedf_ctx list of offloaded * ports @@ -1385,8 +1511,9 @@ static void qedf_rport_event_handler(struct fc_lport *lport, clear_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags); atomic_dec(&qedf->num_offloads); + } else { + spin_unlock_irqrestore(&fcport->rport_lock, flags); } - break; case RPORT_EV_NONE: @@ -1498,11 +1625,15 @@ static int qedf_lport_setup(struct qedf_ctx *qedf) fc_set_wwnn(lport, qedf->wwnn); fc_set_wwpn(lport, qedf->wwpn); - fcoe_libfc_config(lport, &qedf->ctlr, &qedf_lport_template, 0); + if (fcoe_libfc_config(lport, &qedf->ctlr, &qedf_lport_template, 0)) { + QEDF_ERR(&qedf->dbg_ctx, + "fcoe_libfc_config failed.\n"); + return -ENOMEM; + } /* Allocate the exchange manager */ - fc_exch_mgr_alloc(lport, FC_CLASS_3, qedf->max_scsi_xid + 1, - qedf->max_els_xid, NULL); + fc_exch_mgr_alloc(lport, FC_CLASS_3, FCOE_PARAMS_NUM_TASKS, + 0xfffe, NULL); if (fc_lport_init_stats(lport)) return -ENOMEM; @@ -1625,14 +1756,15 @@ static int qedf_vport_create(struct fc_vport *vport, bool disabled) vport_qedf->wwpn = vn_port->wwpn; vn_port->host->transportt = qedf_fc_vport_transport_template; - vn_port->host->can_queue = QEDF_MAX_ELS_XID; + vn_port->host->can_queue = FCOE_PARAMS_NUM_TASKS; vn_port->host->max_lun = qedf_max_lun; vn_port->host->sg_tablesize = QEDF_MAX_BDS_PER_CMD; vn_port->host->max_cmd_len = QEDF_MAX_CDB_LEN; rc = scsi_add_host(vn_port->host, &vport->dev); if (rc) { - QEDF_WARN(&(base_qedf->dbg_ctx), "Error adding Scsi_Host.\n"); + QEDF_WARN(&base_qedf->dbg_ctx, + "Error adding Scsi_Host rc=0x%x.\n", rc); goto err2; } @@ -2155,7 +2287,8 @@ static int qedf_setup_int(struct qedf_ctx *qedf) QEDF_SIMD_HANDLER_NUM, qedf_simd_int_handler); qedf->int_info.used_cnt = 1; - QEDF_ERR(&qedf->dbg_ctx, "Only MSI-X supported. Failing probe.\n"); + QEDF_ERR(&qedf->dbg_ctx, + "Cannot load driver due to a lack of MSI-X vectors.\n"); return -EINVAL; } @@ -2356,6 +2489,13 @@ static int qedf_ll2_rx(void *cookie, struct sk_buff *skb, struct qedf_ctx *qedf = (struct qedf_ctx *)cookie; struct qedf_skb_work *skb_work; + if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2, + "Dropping frame as link state is down.\n"); + kfree_skb(skb); + return 0; + } + skb_work = kzalloc(sizeof(struct qedf_skb_work), GFP_ATOMIC); if (!skb_work) { QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate skb_work so " @@ -2990,6 +3130,8 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) goto err0; } + fc_disc_init(lport); + /* Initialize qedf_ctx */ qedf = lport_priv(lport); qedf->lport = lport; @@ -3005,6 +3147,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) pci_set_drvdata(pdev, qedf); init_completion(&qedf->fipvlan_compl); mutex_init(&qedf->stats_mutex); + mutex_init(&qedf->flush_mutex); QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_INFO, "QLogic FastLinQ FCoE Module qedf %s, " @@ -3181,11 +3324,6 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) sprintf(host_buf, "host_%d", host->host_no); qed_ops->common->set_name(qedf->cdev, host_buf); - - /* Set xid max values */ - qedf->max_scsi_xid = QEDF_MAX_SCSI_XID; - qedf->max_els_xid = QEDF_MAX_ELS_XID; - /* Allocate cmd mgr */ qedf->cmd_mgr = qedf_cmd_mgr_alloc(qedf); if (!qedf->cmd_mgr) { @@ -3196,12 +3334,15 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) if (mode != QEDF_MODE_RECOVERY) { host->transportt = qedf_fc_transport_template; - host->can_queue = QEDF_MAX_ELS_XID; host->max_lun = qedf_max_lun; host->max_cmd_len = QEDF_MAX_CDB_LEN; + host->can_queue = FCOE_PARAMS_NUM_TASKS; rc = scsi_add_host(host, &pdev->dev); - if (rc) + if (rc) { + QEDF_WARN(&qedf->dbg_ctx, + "Error adding Scsi_Host rc=0x%x.\n", rc); goto err6; + } } memset(¶ms, 0, sizeof(params)); @@ -3377,7 +3518,9 @@ static void __qedf_remove(struct pci_dev *pdev, int mode) fcoe_ctlr_link_down(&qedf->ctlr); else fc_fabric_logoff(qedf->lport); - qedf_wait_for_upload(qedf); + + if (qedf_wait_for_upload(qedf) == false) + QEDF_ERR(&qedf->dbg_ctx, "Could not upload all sessions.\n"); #ifdef CONFIG_DEBUG_FS qedf_dbg_host_exit(&(qedf->dbg_ctx)); diff --git a/drivers/scsi/qedf/qedf_version.h b/drivers/scsi/qedf/qedf_version.h index 9455faacd5de..334a9cdf346a 100644 --- a/drivers/scsi/qedf/qedf_version.h +++ b/drivers/scsi/qedf/qedf_version.h @@ -7,9 +7,9 @@ * this source tree. */ -#define QEDF_VERSION "8.33.16.20" +#define QEDF_VERSION "8.37.25.20" #define QEDF_DRIVER_MAJOR_VER 8 -#define QEDF_DRIVER_MINOR_VER 33 -#define QEDF_DRIVER_REV_VER 16 +#define QEDF_DRIVER_MINOR_VER 37 +#define QEDF_DRIVER_REV_VER 25 #define QEDF_DRIVER_ENG_VER 20 |