Commit 19ca7609 authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc 8.3.19: Added support for ELS RRQ command

Added support for ELS RRQ command

- Add new routine lpfc_set_rrq_active() to track XRI qualifier state.
- Add new module parameter lpfc_enable_rrq to control RRQ operation.
- Add logic to ELS RRQ completion handler and xri qualifier timeout
  to clear XRI qualifier state.
- Use OX_ID from XRI_ABORTED_CQE for RRQ payload.
- Tie abort and XRI_ABORTED_CQE andler to RRQ generation.
Signed-off-by: default avatarAlex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 76a95d75
......@@ -486,7 +486,7 @@ struct lpfc_hba {
int (*lpfc_new_scsi_buf)
(struct lpfc_vport *, int);
struct lpfc_scsi_buf * (*lpfc_get_scsi_buf)
(struct lpfc_hba *);
(struct lpfc_hba *, struct lpfc_nodelist *);
int (*lpfc_scsi_prep_dma_buf)
(struct lpfc_hba *, struct lpfc_scsi_buf *);
void (*lpfc_scsi_unprep_dma_buf)
......@@ -574,6 +574,7 @@ struct lpfc_hba {
#define HBA_FIP_SUPPORT 0x800 /* FIP support in HBA */
#define HBA_AER_ENABLED 0x1000 /* AER enabled with HBA */
#define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */
#define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */
uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
struct lpfc_dmabuf slim2p;
......@@ -623,6 +624,7 @@ struct lpfc_hba {
/* HBA Config Parameters */
uint32_t cfg_ack0;
uint32_t cfg_enable_npiv;
uint32_t cfg_enable_rrq;
uint32_t cfg_topology;
uint32_t cfg_link_speed;
uint32_t cfg_cr_delay;
......@@ -733,6 +735,7 @@ struct lpfc_hba {
uint32_t total_scsi_bufs;
struct list_head lpfc_iocb_list;
uint32_t total_iocbq_bufs;
struct list_head active_rrq_list;
spinlock_t hbalock;
/* pci_mem_pools */
......@@ -745,6 +748,7 @@ struct lpfc_hba {
mempool_t *mbox_mem_pool;
mempool_t *nlp_mem_pool;
mempool_t *rrq_pool;
struct fc_host_statistics link_stats;
enum intr_type_t intr_type;
......@@ -801,6 +805,7 @@ struct lpfc_hba {
unsigned long skipped_hb;
struct timer_list hb_tmofunc;
uint8_t hb_outstanding;
struct timer_list rrq_tmr;
enum hba_temp_state over_temp_state;
/* ndlp reference management */
spinlock_t ndlp_lock;
......
......@@ -1977,6 +1977,13 @@ lpfc_param_show(enable_npiv);
lpfc_param_init(enable_npiv, 1, 0, 1);
static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
int lpfc_enable_rrq;
module_param(lpfc_enable_rrq, int, 0);
MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality");
lpfc_param_show(enable_rrq);
lpfc_param_init(enable_rrq, 0, 0, 1);
static DEVICE_ATTR(lpfc_enable_rrq, S_IRUGO, lpfc_enable_rrq_show, NULL);
/*
# lpfc_suppress_link_up: Bring link up at initialization
# 0x0 = bring link up (issue MBX_INIT_LINK)
......@@ -3394,6 +3401,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_fdmi_on,
&dev_attr_lpfc_max_luns,
&dev_attr_lpfc_enable_npiv,
&dev_attr_lpfc_enable_rrq,
&dev_attr_nport_evt_cnt,
&dev_attr_board_mode,
&dev_attr_max_vpi,
......@@ -4610,6 +4618,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_link_speed_init(phba, lpfc_link_speed);
lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count);
......
......@@ -416,5 +416,13 @@ struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *,
int __lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
struct lpfc_iocbq *, uint32_t);
uint32_t lpfc_drain_txq(struct lpfc_hba *);
void lpfc_clr_rrq_active(struct lpfc_hba *, uint16_t, struct lpfc_node_rrq *);
int lpfc_test_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *, uint16_t);
void lpfc_handle_rrq_active(struct lpfc_hba *);
int lpfc_send_rrq(struct lpfc_hba *, struct lpfc_node_rrq *);
int lpfc_set_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *,
uint16_t, uint16_t, uint16_t);
void lpfc_cleanup_wt_rrqs(struct lpfc_hba *);
void lpfc_cleanup_vports_rrqs(struct lpfc_vport *);
struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t,
uint32_t);
......@@ -68,6 +68,12 @@ struct lpfc_fast_path_event {
} un;
};
#define LPFC_SLI4_MAX_XRI 1024 /* Used to make the ndlp's xri_bitmap */
#define XRI_BITMAP_ULONGS (LPFC_SLI4_MAX_XRI / BITS_PER_LONG)
struct lpfc_node_rrqs {
unsigned long xri_bitmap[XRI_BITMAP_ULONGS];
};
struct lpfc_nodelist {
struct list_head nlp_listp;
struct lpfc_name nlp_portname;
......@@ -110,8 +116,19 @@ struct lpfc_nodelist {
atomic_t cmd_pending;
uint32_t cmd_qdepth;
unsigned long last_change_time;
struct lpfc_node_rrqs active_rrqs;
struct lpfc_scsicmd_bkt *lat_data; /* Latency data */
};
struct lpfc_node_rrq {
struct list_head list;
uint16_t xritag;
uint16_t send_rrq;
uint16_t rxid;
uint32_t nlp_DID; /* FC D_ID of entry */
struct lpfc_vport *vport;
struct lpfc_nodelist *ndlp;
unsigned long rrq_stop_time;
};
/* Defines for nlp_flag (uint32) */
#define NLP_IGNR_REG_CMPL 0x00000001 /* Rcvd rscn before we cmpl reg login */
......
This diff is collapsed.
......@@ -607,6 +607,8 @@ lpfc_work_done(struct lpfc_hba *phba)
/* Process SLI4 events */
if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
if (phba->hba_flag & HBA_RRQ_ACTIVE)
lpfc_handle_rrq_active(phba);
if (phba->hba_flag & FCP_XRI_ABORT_EVENT)
lpfc_sli4_fcp_xri_abort_event_proc(phba);
if (phba->hba_flag & ELS_XRI_ABORT_EVENT)
......@@ -966,6 +968,7 @@ lpfc_linkup(struct lpfc_hba *phba)
struct lpfc_vport **vports;
int i;
lpfc_cleanup_wt_rrqs(phba);
phba->link_state = LPFC_LINK_UP;
/* Unblock fabric iocbs if they are blocked */
......@@ -3161,6 +3164,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
spin_unlock_irq(shost->host_lock);
vport->unreg_vpi_cmpl = VPORT_OK;
mempool_free(pmb, phba->mbox_mem_pool);
lpfc_cleanup_vports_rrqs(vport);
/*
* This shost reference might have been taken at the beginning of
* lpfc_vport_delete()
......
......@@ -880,6 +880,24 @@ struct RLS_RSP { /* Structure is in Big Endian format */
uint32_t crcCnt;
};
struct RRQ { /* Structure is in Big Endian format */
uint32_t rrq;
#define rrq_rsvd_SHIFT 24
#define rrq_rsvd_MASK 0x000000ff
#define rrq_rsvd_WORD rrq
#define rrq_did_SHIFT 0
#define rrq_did_MASK 0x00ffffff
#define rrq_did_WORD rrq
uint32_t rrq_exchg;
#define rrq_oxid_SHIFT 16
#define rrq_oxid_MASK 0xffff
#define rrq_oxid_WORD rrq_exchg
#define rrq_rxid_SHIFT 0
#define rrq_rxid_MASK 0xffff
#define rrq_rxid_WORD rrq_exchg
};
struct RTV_RSP { /* Structure is in Big Endian format */
uint32_t ratov;
uint32_t edtov;
......
......@@ -929,6 +929,35 @@ lpfc_hb_timeout(unsigned long ptr)
return;
}
/**
* lpfc_rrq_timeout - The RRQ-timer timeout handler
* @ptr: unsigned long holds the pointer to lpfc hba data structure.
*
* This is the RRQ-timer timeout handler registered to the lpfc driver. When
* this timer fires, a RRQ timeout event shall be posted to the lpfc driver
* work-port-events bitmap and the worker thread is notified. This timeout
* event will be used by the worker thread to invoke the actual timeout
* handler routine, lpfc_rrq_handler. Any periodical operations will
* be performed in the timeout handler and the RRQ timeout event bit shall
* be cleared by the worker thread after it has taken the event bitmap out.
**/
static void
lpfc_rrq_timeout(unsigned long ptr)
{
struct lpfc_hba *phba;
uint32_t tmo_posted;
unsigned long iflag;
phba = (struct lpfc_hba *)ptr;
spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
tmo_posted = phba->hba_flag & HBA_RRQ_ACTIVE;
if (!tmo_posted)
phba->hba_flag |= HBA_RRQ_ACTIVE;
spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
if (!tmo_posted)
lpfc_worker_wake_up(phba);
}
/**
* lpfc_hb_mbox_cmpl - The lpfc heart-beat mailbox command callback function
* @phba: pointer to lpfc hba data structure.
......@@ -3990,6 +4019,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
init_timer(&phba->hb_tmofunc);
phba->hb_tmofunc.function = lpfc_hb_timeout;
phba->hb_tmofunc.data = (unsigned long)phba;
init_timer(&phba->rrq_tmr);
phba->rrq_tmr.function = lpfc_rrq_timeout;
phba->rrq_tmr.data = (unsigned long)phba;
psli = &phba->sli;
/* MBOX heartbeat timer */
......@@ -8192,6 +8224,8 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_unset_driver_resource_s4;
}
INIT_LIST_HEAD(&phba->active_rrq_list);
/* Set up common device driver resources */
error = lpfc_setup_driver_resource_phase2(phba);
if (error) {
......
......@@ -113,11 +113,16 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align)
goto fail_free_mbox_pool;
if (phba->sli_rev == LPFC_SLI_REV4) {
phba->rrq_pool =
mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE,
sizeof(struct lpfc_node_rrq));
if (!phba->rrq_pool)
goto fail_free_nlp_mem_pool;
phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool",
phba->pcidev,
LPFC_HDR_BUF_SIZE, align, 0);
if (!phba->lpfc_hrb_pool)
goto fail_free_nlp_mem_pool;
goto fail_free_rrq_mem_pool;
phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool",
phba->pcidev,
......@@ -147,6 +152,9 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align)
fail_free_hrb_pool:
pci_pool_destroy(phba->lpfc_hrb_pool);
phba->lpfc_hrb_pool = NULL;
fail_free_rrq_mem_pool:
mempool_destroy(phba->rrq_pool);
phba->rrq_pool = NULL;
fail_free_nlp_mem_pool:
mempool_destroy(phba->nlp_mem_pool);
phba->nlp_mem_pool = NULL;
......
......@@ -621,10 +621,13 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
struct sli4_wcqe_xri_aborted *axri)
{
uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
struct lpfc_scsi_buf *psb, *next_psb;
unsigned long iflag = 0;
struct lpfc_iocbq *iocbq;
int i;
struct lpfc_nodelist *ndlp;
int rrq_empty = 0;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irqsave(&phba->hbalock, iflag);
......@@ -637,8 +640,14 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
psb->status = IOSTAT_SUCCESS;
spin_unlock(
&phba->sli4_hba.abts_scsi_buf_list_lock);
ndlp = psb->rdata->pnode;
rrq_empty = list_empty(&phba->active_rrq_list);
spin_unlock_irqrestore(&phba->hbalock, iflag);
if (ndlp)
lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1);
lpfc_release_scsi_buf_s4(phba, psb);
if (rrq_empty)
lpfc_worker_wake_up(phba);
return;
}
}
......@@ -914,7 +923,7 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport, int num_to_alloc)
}
/**
* lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
* lpfc_get_scsi_buf_s3 - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
* @phba: The HBA for which this call is being executed.
*
* This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list
......@@ -925,7 +934,7 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport, int num_to_alloc)
* Pointer to lpfc_scsi_buf - Success
**/
static struct lpfc_scsi_buf*
lpfc_get_scsi_buf(struct lpfc_hba * phba)
lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
struct lpfc_scsi_buf * lpfc_cmd = NULL;
struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
......@@ -941,6 +950,67 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)
spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
return lpfc_cmd;
}
/**
* lpfc_get_scsi_buf_s4 - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
* @phba: The HBA for which this call is being executed.
*
* This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list
* and returns to caller.
*
* Return codes:
* NULL - Error
* Pointer to lpfc_scsi_buf - Success
**/
static struct lpfc_scsi_buf*
lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
struct lpfc_scsi_buf *lpfc_cmd = NULL;
struct lpfc_scsi_buf *start_lpfc_cmd = NULL;
struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
unsigned long iflag = 0;
int found = 0;
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
while (!found && lpfc_cmd) {
if (lpfc_test_rrq_active(phba, ndlp,
lpfc_cmd->cur_iocbq.sli4_xritag)) {
lpfc_release_scsi_buf_s4(phba, lpfc_cmd);
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
list_remove_head(scsi_buf_list, lpfc_cmd,
struct lpfc_scsi_buf, list);
spin_unlock_irqrestore(&phba->scsi_buf_list_lock,
iflag);
if (lpfc_cmd == start_lpfc_cmd) {
lpfc_cmd = NULL;
break;
} else
continue;
}
found = 1;
lpfc_cmd->seg_cnt = 0;
lpfc_cmd->nonsg_phys = 0;
lpfc_cmd->prot_seg_cnt = 0;
}
return lpfc_cmd;
}
/**
* lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
* @phba: The HBA for which this call is being executed.
*
* This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list
* and returns to caller.
*
* Return codes:
* NULL - Error
* Pointer to lpfc_scsi_buf - Success
**/
static struct lpfc_scsi_buf*
lpfc_get_scsi_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
return phba->lpfc_get_scsi_buf(phba, ndlp);
}
/**
* lpfc_release_scsi_buf - Return a scsi buffer back to hba scsi buf list
......@@ -2744,18 +2814,19 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf;
phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd;
phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf;
switch (dev_grp) {
case LPFC_PCI_DEV_LP:
phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s3;
phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s3;
phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3;
phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s3;
break;
case LPFC_PCI_DEV_OC:
phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s4;
phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4;
phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4;
phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s4;
break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
......@@ -2764,7 +2835,6 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
return -ENODEV;
break;
}
phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf;
phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth;
phba->lpfc_scsi_cmd_iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl;
return 0;
......@@ -2940,7 +3010,7 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
goto out_host_busy;
lpfc_cmd = lpfc_get_scsi_buf(phba);
lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp);
if (lpfc_cmd == NULL) {
lpfc_rampdown_queue_depth(phba);
......@@ -3239,7 +3309,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
if (!pnode || !NLP_CHK_NODE_ACT(pnode))
return FAILED;
lpfc_cmd = lpfc_get_scsi_buf(phba);
lpfc_cmd = lpfc_get_scsi_buf(phba, rdata->pnode);
if (lpfc_cmd == NULL)
return FAILED;
lpfc_cmd->timeout = 60;
......
This diff is collapsed.
......@@ -82,6 +82,7 @@ struct lpfc_iocbq {
struct lpfc_iocbq *rsp_iocb;
struct lpfcMboxq *mbox;
struct lpfc_nodelist *ndlp;
struct lpfc_node_rrq *rrq;
} context_un;
void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
......
......@@ -466,6 +466,7 @@ struct lpfc_sglq {
struct list_head clist;
enum lpfc_sge_type buff_type; /* is this a scsi sgl */
enum lpfc_sgl_state state;
struct lpfc_nodelist *ndlp; /* ndlp associated with IO */
uint16_t iotag; /* pre-assigned IO tag */
uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */
struct sli4_sge *sgl; /* pre-assigned SGL */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment