aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-04 15:15:15 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-04 15:15:15 -0700
commit03da30986793385af57eeca3296253c887b742e6 (patch)
tree9c46dbe51c9d0856990649dd917ab45474b7be87 /drivers/scsi/lpfc
parentMerge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6 (diff)
parent[SCSI] zfcp: Trigger logging in the FCP channel on qdio error conditions (diff)
downloadlinux-dev-03da30986793385af57eeca3296253c887b742e6.tar.xz
linux-dev-03da30986793385af57eeca3296253c887b742e6.zip
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (276 commits) [SCSI] zfcp: Trigger logging in the FCP channel on qdio error conditions [SCSI] zfcp: Introduce experimental support for DIF/DIX [SCSI] zfcp: Enable data division support for FCP devices [SCSI] zfcp: Prevent access on uninitialized memory. [SCSI] zfcp: Post events through FC transport class [SCSI] zfcp: Cleanup QDIO attachment and improve processing. [SCSI] zfcp: Cleanup function parameters for sbal value. [SCSI] zfcp: Use correct width for timer_interval field [SCSI] zfcp: Remove SCSI device when removing unit [SCSI] zfcp: Use memdup_user and kstrdup [SCSI] zfcp: Fix retry after failed "open port" erp action [SCSI] zfcp: Fail erp after timeout [SCSI] zfcp: Use forced_reopen in terminate_rport_io callback [SCSI] zfcp: Register SCSI devices after successful fc_remote_port_add [SCSI] zfcp: Do not try "forced close" when port is already closed [SCSI] zfcp: Do not unblock rport from REOPEN_PORT_FORCED [SCSI] sd: add support for runtime PM [SCSI] implement runtime Power Management [SCSI] convert to the new PM framework [SCSI] Unify SAM_ and SAM_STAT_ macros ...
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r--drivers/scsi/lpfc/lpfc.h17
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c96
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c36
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h11
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c112
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c220
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h17
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c279
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c23
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c31
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c86
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c345
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h8
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c2
17 files changed, 1073 insertions, 216 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index e35a4c71eb9a..3482d5a5aed2 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -20,7 +20,6 @@
*******************************************************************/
#include <scsi/scsi_host.h>
-
struct lpfc_sli2_slim;
#define LPFC_PCI_DEV_LP 0x1
@@ -49,7 +48,7 @@ struct lpfc_sli2_slim;
#define LPFC_TGTQ_INTERVAL 40000 /* Min amount of time between tgt
queue depth change in millisecs */
#define LPFC_TGTQ_RAMPUP_PCENT 5 /* Target queue rampup in percentage */
-#define LPFC_MIN_TGT_QDEPTH 100
+#define LPFC_MIN_TGT_QDEPTH 10
#define LPFC_MAX_TGT_QDEPTH 0xFFFF
#define LPFC_MAX_BUCKET_COUNT 20 /* Maximum no. of buckets for stat data
@@ -376,6 +375,7 @@ struct lpfc_vport {
#define WORKER_FABRIC_BLOCK_TMO 0x400 /* hba: fabric block timeout */
#define WORKER_RAMP_DOWN_QUEUE 0x800 /* hba: Decrease Q depth */
#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */
+#define WORKER_SERVICE_TXQ 0x2000 /* hba: IOCBs on the txq */
struct timer_list fc_fdmitmo;
struct timer_list els_tmofunc;
@@ -400,6 +400,7 @@ struct lpfc_vport {
uint32_t cfg_max_luns;
uint32_t cfg_enable_da_id;
uint32_t cfg_max_scsicmpl_time;
+ uint32_t cfg_tgt_queue_depth;
uint32_t dev_loss_tmo_changed;
@@ -510,9 +511,9 @@ struct lpfc_hba {
void (*lpfc_stop_port)
(struct lpfc_hba *);
int (*lpfc_hba_init_link)
- (struct lpfc_hba *);
+ (struct lpfc_hba *, uint32_t);
int (*lpfc_hba_down_link)
- (struct lpfc_hba *);
+ (struct lpfc_hba *, uint32_t);
/* SLI4 specific HBA data structure */
struct lpfc_sli4_hba sli4_hba;
@@ -525,7 +526,6 @@ struct lpfc_hba {
#define LPFC_SLI3_NPIV_ENABLED 0x02
#define LPFC_SLI3_VPORT_TEARDOWN 0x04
#define LPFC_SLI3_CRP_ENABLED 0x08
-#define LPFC_SLI3_INB_ENABLED 0x10
#define LPFC_SLI3_BG_ENABLED 0x20
#define LPFC_SLI3_DSS_ENABLED 0x40
uint32_t iocb_cmd_size;
@@ -557,9 +557,6 @@ struct lpfc_hba {
MAILBOX_t *mbox;
uint32_t *mbox_ext;
- uint32_t *inb_ha_copy;
- uint32_t *inb_counter;
- uint32_t inb_last_counter;
uint32_t ha_copy;
struct _PCB *pcb;
struct _IOCB *IOCBs;
@@ -628,6 +625,7 @@ struct lpfc_hba {
uint32_t cfg_hostmem_hgp;
uint32_t cfg_log_verbose;
uint32_t cfg_aer_support;
+ uint32_t cfg_iocb_cnt;
uint32_t cfg_suppress_link_up;
#define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */
#define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */
@@ -816,6 +814,9 @@ struct lpfc_hba {
uint8_t menlo_flag; /* menlo generic flags */
#define HBA_MENLO_SUPPORT 0x1 /* HBA supports menlo commands */
+ uint32_t iocb_cnt;
+ uint32_t iocb_max;
+ atomic_t sdev_cnt;
};
static inline struct Scsi_Host *
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index bf33b315f93e..868874c28f99 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -506,10 +506,10 @@ lpfc_link_state_store(struct device *dev, struct device_attribute *attr,
if ((strncmp(buf, "up", sizeof("up") - 1) == 0) &&
(phba->link_state == LPFC_LINK_DOWN))
- status = phba->lpfc_hba_init_link(phba);
+ status = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
else if ((strncmp(buf, "down", sizeof("down") - 1) == 0) &&
(phba->link_state >= LPFC_LINK_UP))
- status = phba->lpfc_hba_down_link(phba);
+ status = phba->lpfc_hba_down_link(phba, MBX_NOWAIT);
if (status == 0)
return strlen(buf);
@@ -864,7 +864,6 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
uint32_t *mrpi, uint32_t *arpi,
uint32_t *mvpi, uint32_t *avpi)
{
- struct lpfc_sli *psli = &phba->sli;
struct lpfc_mbx_read_config *rd_config;
LPFC_MBOXQ_t *pmboxq;
MAILBOX_t *pmb;
@@ -893,8 +892,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
pmb->mbxOwner = OWN_HOST;
pmboxq->context1 = NULL;
- if ((phba->pport->fc_flag & FC_OFFLINE_MODE) ||
- (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+ if (phba->pport->fc_flag & FC_OFFLINE_MODE)
rc = MBX_NOT_FINISHED;
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -1949,6 +1947,59 @@ static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
LPFC_ATTR_R(suppress_link_up, LPFC_INITIALIZE_LINK, LPFC_INITIALIZE_LINK,
LPFC_DELAY_INIT_LINK_INDEFINITELY,
"Suppress Link Up at initialization");
+/*
+# lpfc_cnt: Number of IOCBs allocated for ELS, CT, and ABTS
+# 1 - (1024)
+# 2 - (2048)
+# 3 - (3072)
+# 4 - (4096)
+# 5 - (5120)
+*/
+static ssize_t
+lpfc_iocb_hw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", phba->iocb_max);
+}
+
+static DEVICE_ATTR(iocb_hw, S_IRUGO,
+ lpfc_iocb_hw_show, NULL);
+static ssize_t
+lpfc_txq_hw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->sli.ring[LPFC_ELS_RING].txq_max);
+}
+
+static DEVICE_ATTR(txq_hw, S_IRUGO,
+ lpfc_txq_hw_show, NULL);
+static ssize_t
+lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->sli.ring[LPFC_ELS_RING].txcmplq_max);
+}
+
+static DEVICE_ATTR(txcmplq_hw, S_IRUGO,
+ lpfc_txcmplq_hw_show, NULL);
+
+int lpfc_iocb_cnt = 2;
+module_param(lpfc_iocb_cnt, int, 1);
+MODULE_PARM_DESC(lpfc_iocb_cnt,
+ "Number of IOCBs alloc for ELS, CT, and ABTS: 1k to 5k IOCBs");
+lpfc_param_show(iocb_cnt);
+lpfc_param_init(iocb_cnt, 2, 1, 5);
+static DEVICE_ATTR(lpfc_iocb_cnt, S_IRUGO,
+ lpfc_iocb_cnt_show, NULL);
/*
# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -2157,6 +2208,13 @@ LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 128,
"Max number of FCP commands we can queue to a specific LUN");
/*
+# tgt_queue_depth: This parameter is used to limit the number of outstanding
+# commands per target port. Value range is [10,65535]. Default value is 65535.
+*/
+LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535,
+ "Max number of FCP commands we can queue to a specific target port");
+
+/*
# hba_queue_depth: This parameter is used to limit the number of outstanding
# commands per lpfc HBA. Value range is [32,8192]. If this parameter
# value is greater than the maximum number of exchanges supported by the HBA,
@@ -2890,9 +2948,6 @@ lpfc_aer_support_store(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
int val = 0, rc = -EINVAL;
- /* AER not supported on OC devices yet */
- if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
- return -EPERM;
if (!isdigit(buf[0]))
return -EINVAL;
if (sscanf(buf, "%i", &val) != 1)
@@ -2965,12 +3020,6 @@ lpfc_param_show(aer_support)
static int
lpfc_aer_support_init(struct lpfc_hba *phba, int val)
{
- /* AER not supported on OC devices yet */
- if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
- phba->cfg_aer_support = 0;
- return -EPERM;
- }
-
if (val == 0 || val == 1) {
phba->cfg_aer_support = val;
return 0;
@@ -3015,9 +3064,6 @@ lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
int val, rc = -1;
- /* AER not supported on OC devices yet */
- if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
- return -EPERM;
if (!isdigit(buf[0]))
return -EINVAL;
if (sscanf(buf, "%i", &val) != 1)
@@ -3083,7 +3129,7 @@ lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val)
continue;
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
continue;
- ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
+ ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
}
spin_unlock_irq(shost->host_lock);
return 0;
@@ -3287,6 +3333,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_temp_sensor,
&dev_attr_lpfc_log_verbose,
&dev_attr_lpfc_lun_queue_depth,
+ &dev_attr_lpfc_tgt_queue_depth,
&dev_attr_lpfc_hba_queue_depth,
&dev_attr_lpfc_peer_port_login,
&dev_attr_lpfc_nodev_tmo,
@@ -3334,6 +3381,10 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_aer_support,
&dev_attr_lpfc_aer_state_cleanup,
&dev_attr_lpfc_suppress_link_up,
+ &dev_attr_lpfc_iocb_cnt,
+ &dev_attr_iocb_hw,
+ &dev_attr_txq_hw,
+ &dev_attr_txcmplq_hw,
NULL,
};
@@ -3344,6 +3395,7 @@ struct device_attribute *lpfc_vport_attrs[] = {
&dev_attr_lpfc_drvr_version,
&dev_attr_lpfc_log_verbose,
&dev_attr_lpfc_lun_queue_depth,
+ &dev_attr_lpfc_tgt_queue_depth,
&dev_attr_lpfc_nodev_tmo,
&dev_attr_lpfc_devloss_tmo,
&dev_attr_lpfc_hba_queue_depth,
@@ -4042,8 +4094,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
pmboxq->context1 = NULL;
pmboxq->vport = vport;
- if ((vport->fc_flag & FC_OFFLINE_MODE) ||
- (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+ if (vport->fc_flag & FC_OFFLINE_MODE)
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -4067,8 +4118,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
pmboxq->context1 = NULL;
pmboxq->vport = vport;
- if ((vport->fc_flag & FC_OFFLINE_MODE) ||
- (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+ if (vport->fc_flag & FC_OFFLINE_MODE)
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -4521,6 +4571,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
lpfc_aer_support_init(phba, lpfc_aer_support);
lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
+ lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt);
return;
}
@@ -4533,6 +4584,7 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
{
lpfc_log_verbose_init(vport, lpfc_log_verbose);
lpfc_lun_queue_depth_init(vport, lpfc_lun_queue_depth);
+ lpfc_tgt_queue_depth_init(vport, lpfc_tgt_queue_depth);
lpfc_devloss_tmo_init(vport, lpfc_devloss_tmo);
lpfc_nodev_tmo_init(vport, lpfc_nodev_tmo);
lpfc_peer_port_login_init(vport, lpfc_peer_port_login);
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index dcf088262b20..d521569e6620 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -377,6 +377,11 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
+ else if (rc == IOCB_BUSY)
+ rc = EAGAIN;
+ else
+ rc = EIO;
+
/* iocb failed so cleanup */
pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
@@ -625,6 +630,10 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
lpfc_nlp_put(ndlp);
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
+ else if (rc == IOCB_BUSY)
+ rc = EAGAIN;
+ else
+ rc = EIO;
pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
job->request_payload.sg_cnt, DMA_TO_DEVICE);
@@ -953,10 +962,22 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (phba->sli_rev == LPFC_SLI_REV4) {
evt_dat->immed_dat = phba->ctx_idx;
phba->ctx_idx = (phba->ctx_idx + 1) % 64;
+ /* Provide warning for over-run of the ct_ctx array */
+ if (phba->ct_ctx[evt_dat->immed_dat].flags &
+ UNSOL_VALID)
+ lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
+ "2717 CT context array entry "
+ "[%d] over-run: oxid:x%x, "
+ "sid:x%x\n", phba->ctx_idx,
+ phba->ct_ctx[
+ evt_dat->immed_dat].oxid,
+ phba->ct_ctx[
+ evt_dat->immed_dat].SID);
phba->ct_ctx[evt_dat->immed_dat].oxid =
piocbq->iocb.ulpContext;
phba->ct_ctx[evt_dat->immed_dat].SID =
piocbq->iocb.un.rcvels.remoteID;
+ phba->ct_ctx[evt_dat->immed_dat].flags = UNSOL_VALID;
} else
evt_dat->immed_dat = piocbq->iocb.ulpContext;
@@ -1314,6 +1335,21 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
rc = IOCB_ERROR;
goto issue_ct_rsp_exit;
}
+
+ /* Check if the ndlp is active */
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
+ rc = -IOCB_ERROR;
+ goto issue_ct_rsp_exit;
+ }
+
+ /* get a refernece count so the ndlp doesn't go away while
+ * we respond
+ */
+ if (!lpfc_nlp_get(ndlp)) {
+ rc = -IOCB_ERROR;
+ goto issue_ct_rsp_exit;
+ }
+
icmd->un.ulpWord[3] = ndlp->nlp_rpi;
/* The exchange is done, mark the entry as invalid */
phba->ct_ctx[tag].flags &= ~UNSOL_VALID;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index fbc9baeb6048..03f4ddc18572 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -41,6 +41,7 @@ void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
LPFC_MBOXQ_t *, uint32_t);
+void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *);
@@ -190,6 +191,7 @@ irqreturn_t lpfc_sli4_sp_intr_handler(int, void *);
irqreturn_t lpfc_sli4_fp_intr_handler(int, void *);
void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_sli4_swap_str(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -402,3 +404,12 @@ int lpfc_bsg_request(struct fc_bsg_job *);
int lpfc_bsg_timeout(struct fc_bsg_job *);
int lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
+void __lpfc_sli_ringtx_put(struct lpfc_hba *, struct lpfc_sli_ring *,
+ struct lpfc_iocbq *);
+struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *,
+ struct lpfc_sli_ring *);
+int __lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
+ struct lpfc_iocbq *, uint32_t);
+uint32_t lpfc_drain_txq(struct lpfc_hba *);
+
+
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 36257a685509..7cae69de36f7 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -114,6 +114,8 @@ struct lpfc_nodelist {
};
/* Defines for nlp_flag (uint32) */
+#define NLP_IGNR_REG_CMPL 0x00000001 /* Rcvd rscn before we cmpl reg login */
+#define NLP_REG_LOGIN_SEND 0x00000002 /* sent reglogin to adapter */
#define NLP_PLOGI_SND 0x00000020 /* sent PLOGI request for this entry */
#define NLP_PRLI_SND 0x00000040 /* sent PRLI request for this entry */
#define NLP_ADISC_SND 0x00000080 /* sent ADISC request for this entry */
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index c4c7f0ad7468..afbed6bc31f0 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -796,7 +796,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* due to new FCF discovery
*/
if ((phba->hba_flag & HBA_FIP_SUPPORT) &&
- (phba->fcf.fcf_flag & FCF_DISCOVERY)) {
+ (phba->fcf.fcf_flag & FCF_DISCOVERY) &&
+ (irsp->ulpStatus != IOSTAT_LOCAL_REJECT) &&
+ (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
"2611 FLOGI failed on registered "
"FCF record fcf_index:%d, trying "
@@ -811,18 +813,21 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
lpfc_printf_log(phba, KERN_WARNING,
LOG_FIP | LOG_ELS,
- "2760 FLOGI exhausted FCF "
- "round robin failover list, "
- "retry FLOGI on the current "
- "registered FCF index:%d\n",
+ "2760 Completed one round "
+ "of FLOGI FCF round robin "
+ "failover list, retry FLOGI "
+ "on currently registered "
+ "FCF index:%d\n",
phba->fcf.current_rec.fcf_indx);
- spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
- spin_unlock_irq(&phba->hbalock);
} else {
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_FIP | LOG_ELS,
+ "2794 FLOGI FCF round robin "
+ "failover to FCF index x%x\n",
+ fcf_index);
rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba,
fcf_index);
- if (rc) {
+ if (rc)
lpfc_printf_log(phba, KERN_WARNING,
LOG_FIP | LOG_ELS,
"2761 FLOGI round "
@@ -831,10 +836,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
"rc:x%x, fcf_index:"
"%d\n", rc,
phba->fcf.current_rec.fcf_indx);
- spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
- spin_unlock_irq(&phba->hbalock);
- } else
+ else
goto out;
}
}
@@ -890,9 +892,39 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
if (sp->cmn.fPort)
rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
- else
+ else if (!(phba->hba_flag & HBA_FCOE_SUPPORT))
rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
-
+ else {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_FIP | LOG_ELS,
+ "2831 FLOGI response with cleared Fabric "
+ "bit fcf_index 0x%x "
+ "Switch Name %02x%02x%02x%02x%02x%02x%02x%02x "
+ "Fabric Name "
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ phba->fcf.current_rec.fcf_indx,
+ phba->fcf.current_rec.switch_name[0],
+ phba->fcf.current_rec.switch_name[1],
+ phba->fcf.current_rec.switch_name[2],
+ phba->fcf.current_rec.switch_name[3],
+ phba->fcf.current_rec.switch_name[4],
+ phba->fcf.current_rec.switch_name[5],
+ phba->fcf.current_rec.switch_name[6],
+ phba->fcf.current_rec.switch_name[7],
+ phba->fcf.current_rec.fabric_name[0],
+ phba->fcf.current_rec.fabric_name[1],
+ phba->fcf.current_rec.fabric_name[2],
+ phba->fcf.current_rec.fabric_name[3],
+ phba->fcf.current_rec.fabric_name[4],
+ phba->fcf.current_rec.fabric_name[5],
+ phba->fcf.current_rec.fabric_name[6],
+ phba->fcf.current_rec.fabric_name[7]);
+ lpfc_nlp_put(ndlp);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ spin_unlock_irq(&phba->hbalock);
+ goto out;
+ }
if (!rc) {
/* Mark the FCF discovery process done */
if (phba->hba_flag & HBA_FIP_SUPPORT)
@@ -1472,8 +1504,12 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
goto out;
}
- /* PLOGI failed */
- lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ /* PLOGI failed Don't print the vport to vport rjts */
+ if (irsp->ulpStatus != IOSTAT_LS_RJT ||
+ (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) &&
+ ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) ||
+ (phba)->pport->cfg_log_verbose & LOG_ELS)
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"2753 PLOGI failure DID:%06X Status:x%x/x%x\n",
ndlp->nlp_DID, irsp->ulpStatus,
irsp->un.ulpWord[4]);
@@ -2740,6 +2776,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
retry = 1;
break;
}
+ if (stat.un.b.lsRjtRsnCodeExp ==
+ LSEXP_CANT_GIVE_DATA) {
+ if (cmd == ELS_CMD_PLOGI) {
+ delay = 1000;
+ maxretry = 48;
+ }
+ retry = 1;
+ break;
+ }
if (cmd == ELS_CMD_PLOGI) {
delay = 1000;
maxretry = lpfc_max_els_tries + 1;
@@ -5135,6 +5180,7 @@ lpfc_els_timeout(unsigned long ptr)
return;
}
+
/**
* lpfc_els_timeout_handler - Process an els timeout event
* @vport: pointer to a virtual N_Port data structure.
@@ -5155,13 +5201,19 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
uint32_t els_command = 0;
uint32_t timeout;
uint32_t remote_ID = 0xffffffff;
+ LIST_HEAD(txcmplq_completions);
+ LIST_HEAD(abort_list);
+
- spin_lock_irq(&phba->hbalock);
timeout = (uint32_t)(phba->fc_ratov << 1);
pring = &phba->sli.ring[LPFC_ELS_RING];
- list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
+ spin_lock_irq(&phba->hbalock);
+ list_splice_init(&pring->txcmplq, &txcmplq_completions);
+ spin_unlock_irq(&phba->hbalock);
+
+ list_for_each_entry_safe(piocb, tmp_iocb, &txcmplq_completions, list) {
cmd = &piocb->iocb;
if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
@@ -5198,13 +5250,22 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
if (ndlp && NLP_CHK_NODE_ACT(ndlp))
remote_ID = ndlp->nlp_DID;
}
+ list_add_tail(&piocb->dlist, &abort_list);
+ }
+ spin_lock_irq(&phba->hbalock);
+ list_splice(&txcmplq_completions, &pring->txcmplq);
+ spin_unlock_irq(&phba->hbalock);
+
+ list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
- "0127 ELS timeout Data: x%x x%x x%x "
- "x%x\n", els_command,
- remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
+ "0127 ELS timeout Data: x%x x%x x%x "
+ "x%x\n", els_command,
+ remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&piocb->dlist);
lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+ spin_unlock_irq(&phba->hbalock);
}
- spin_unlock_irq(&phba->hbalock);
if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
@@ -6901,6 +6962,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
unsigned long iflag = 0;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irqsave(&phba->hbalock, iflag);
spin_lock(&phba->sli4_hba.abts_sgl_list_lock);
@@ -6913,6 +6975,10 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
sglq_entry->state = SGL_FREED;
spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
+
+ /* Check if TXQ queue needs to be serviced */
+ if (pring->txq_cnt)
+ lpfc_worker_wake_up(phba);
return;
}
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 1f87b4fb8b50..0639c994349c 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -275,7 +275,9 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
if (!(vport->load_flag & FC_UNLOADING) &&
!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
!(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
- (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
+ (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+ (ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) &&
+ (ndlp->nlp_state != NLP_STE_PRLI_ISSUE))
lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
lpfc_unregister_unused_fcf(phba);
@@ -586,6 +588,8 @@ lpfc_work_done(struct lpfc_hba *phba)
(status &
HA_RXMASK));
}
+ if (pring->txq_cnt)
+ lpfc_drain_txq(phba);
/*
* Turn on Ring interrupts
*/
@@ -1297,7 +1301,7 @@ lpfc_register_fcf(struct lpfc_hba *phba)
* used for this FCF when the function returns.
* If the FCF record need to be used with a particular vlan id, the vlan is
* set in the vlan_id on return of the function. If not VLAN tagging need to
- * be used with the FCF vlan_id will be set to 0xFFFF;
+ * be used with the FCF vlan_id will be set to LPFC_FCOE_NULL_VID;
**/
static int
lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
@@ -1333,7 +1337,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
if (phba->valid_vlan)
*vlan_id = phba->vlan_id;
else
- *vlan_id = 0xFFFF;
+ *vlan_id = LPFC_FCOE_NULL_VID;
return 1;
}
@@ -1357,7 +1361,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
if (fcf_vlan_id)
*vlan_id = fcf_vlan_id;
else
- *vlan_id = 0xFFFF;
+ *vlan_id = LPFC_FCOE_NULL_VID;
return 1;
}
@@ -1466,7 +1470,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
else if (fcf_vlan_id)
*vlan_id = fcf_vlan_id;
else
- *vlan_id = 0xFFFF;
+ *vlan_id = LPFC_FCOE_NULL_VID;
return 1;
}
@@ -1518,6 +1522,9 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
* Do not continue FCF discovery and clear FCF_DISC_INPROGRESS
* flag
*/
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+ "2833 Stop FCF discovery process due to link "
+ "state change (x%x)\n", phba->link_state);
spin_lock_irq(&phba->hbalock);
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY);
@@ -1565,7 +1572,7 @@ lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt)
}
/**
- * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.
+ * lpfc_sli4_fcf_rec_mbox_parse - Parse read_fcf mbox command.
* @phba: pointer to lpfc hba data structure.
* @mboxq: pointer to mailbox object.
* @next_fcf_index: pointer to holder of next fcf index.
@@ -1693,6 +1700,37 @@ lpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba,
}
/**
+ lpfc_sli4_fcf_record_match - testing new FCF record for matching existing FCF
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_rec: pointer to an existing FCF record.
+ * @new_fcf_record: pointer to a new FCF record.
+ * @new_vlan_id: vlan id from the new FCF record.
+ *
+ * This function performs matching test of a new FCF record against an existing
+ * FCF record. If the new_vlan_id passed in is LPFC_FCOE_IGNORE_VID, vlan id
+ * will not be used as part of the FCF record matching criteria.
+ *
+ * Returns true if all the fields matching, otherwise returns false.
+ */
+static bool
+lpfc_sli4_fcf_record_match(struct lpfc_hba *phba,
+ struct lpfc_fcf_rec *fcf_rec,
+ struct fcf_record *new_fcf_record,
+ uint16_t new_vlan_id)
+{
+ if (new_vlan_id != LPFC_FCOE_IGNORE_VID)
+ if (!lpfc_vlan_id_match(fcf_rec->vlan_id, new_vlan_id))
+ return false;
+ if (!lpfc_mac_addr_match(fcf_rec->mac_addr, new_fcf_record))
+ return false;
+ if (!lpfc_sw_name_match(fcf_rec->switch_name, new_fcf_record))
+ return false;
+ if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record))
+ return false;
+ return true;
+}
+
+/**
* lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.
* @phba: pointer to lpfc hba data structure.
* @mboxq: pointer to mailbox object.
@@ -1755,7 +1793,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
if (!rc) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
- "2781 FCF record fcf_index:x%x failed FCF "
+ "2781 FCF record (x%x) failed FCF "
"connection list check, fcf_avail:x%x, "
"fcf_valid:x%x\n",
bf_get(lpfc_fcf_record_fcf_index,
@@ -1764,6 +1802,32 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
new_fcf_record),
bf_get(lpfc_fcf_record_fcf_valid,
new_fcf_record));
+ if ((phba->fcf.fcf_flag & FCF_IN_USE) &&
+ lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
+ new_fcf_record, LPFC_FCOE_IGNORE_VID)) {
+ /*
+ * In case the current in-use FCF record becomes
+ * invalid/unavailable during FCF discovery that
+ * was not triggered by fast FCF failover process,
+ * treat it as fast FCF failover.
+ */
+ if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND) &&
+ !(phba->fcf.fcf_flag & FCF_REDISC_FOV)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+ "2835 Invalid in-use FCF "
+ "record (x%x) reported, "
+ "entering fast FCF failover "
+ "mode scanning.\n",
+ phba->fcf.current_rec.fcf_indx);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag |= FCF_REDISC_FOV;
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_sli4_mbox_cmd_free(phba, mboxq);
+ lpfc_sli4_fcf_scan_read_fcf_rec(phba,
+ LPFC_FCOE_FCF_GET_FIRST);
+ return;
+ }
+ }
goto read_next_fcf;
} else {
fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
@@ -1780,14 +1844,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
spin_lock_irq(&phba->hbalock);
if (phba->fcf.fcf_flag & FCF_IN_USE) {
- if (lpfc_fab_name_match(phba->fcf.current_rec.fabric_name,
- new_fcf_record) &&
- lpfc_sw_name_match(phba->fcf.current_rec.switch_name,
- new_fcf_record) &&
- lpfc_mac_addr_match(phba->fcf.current_rec.mac_addr,
- new_fcf_record) &&
- lpfc_vlan_id_match(phba->fcf.current_rec.vlan_id,
- vlan_id)) {
+ if (lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
+ new_fcf_record, vlan_id)) {
phba->fcf.fcf_flag |= FCF_AVAILABLE;
if (phba->fcf.fcf_flag & FCF_REDISC_PEND)
/* Stop FCF redisc wait timer if pending */
@@ -1797,6 +1855,13 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV |
FCF_DISCOVERY);
spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2836 The new FCF record (x%x) "
+ "matches the in-use FCF record "
+ "(x%x)\n",
+ phba->fcf.current_rec.fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
goto out;
}
/*
@@ -1828,6 +1893,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
if (boot_flag && !(fcf_rec->flag & BOOT_ENABLE)) {
/* Choose this FCF record */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2837 Update current FCF record "
+ "(x%x) with new FCF record (x%x)\n",
+ fcf_rec->fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
addr_mode, vlan_id, BOOT_ENABLE);
spin_unlock_irq(&phba->hbalock);
@@ -1848,6 +1919,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
if (new_fcf_record->fip_priority < fcf_rec->priority) {
/* Choose the new FCF record with lower priority */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2838 Update current FCF record "
+ "(x%x) with new FCF record (x%x)\n",
+ fcf_rec->fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
addr_mode, vlan_id, 0);
/* Reset running random FCF selection count */
@@ -1857,11 +1934,18 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->fcf.eligible_fcf_cnt++;
select_new_fcf = lpfc_sli4_new_fcf_random_select(phba,
phba->fcf.eligible_fcf_cnt);
- if (select_new_fcf)
+ if (select_new_fcf) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2839 Update current FCF record "
+ "(x%x) with new FCF record (x%x)\n",
+ fcf_rec->fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
/* Choose the new FCF by random selection */
__lpfc_update_fcf_record(phba, fcf_rec,
new_fcf_record,
addr_mode, vlan_id, 0);
+ }
}
spin_unlock_irq(&phba->hbalock);
goto read_next_fcf;
@@ -1871,6 +1955,11 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
* initial best-fit FCF.
*/
if (fcf_rec) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2840 Update current FCF record "
+ "with initial FCF record (x%x)\n",
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
addr_mode, vlan_id, (boot_flag ?
BOOT_ENABLE : 0));
@@ -1928,12 +2017,23 @@ read_next_fcf:
lpfc_unregister_fcf(phba);
/* Replace in-use record with the new record */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2842 Replace the current in-use "
+ "FCF record (x%x) with failover FCF "
+ "record (x%x)\n",
+ phba->fcf.current_rec.fcf_indx,
+ phba->fcf.failover_rec.fcf_indx);
memcpy(&phba->fcf.current_rec,
&phba->fcf.failover_rec,
sizeof(struct lpfc_fcf_rec));
- /* mark the FCF fast failover completed */
+ /*
+ * Mark the fast FCF failover rediscovery completed
+ * and the start of the first round of the roundrobin
+ * FCF failover.
+ */
spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
+ phba->fcf.fcf_flag &=
+ ~(FCF_REDISC_FOV | FCF_REDISC_RRU);
spin_unlock_irq(&phba->hbalock);
/*
* Set up the initial registered FCF index for FLOGI
@@ -1951,15 +2051,42 @@ read_next_fcf:
if ((phba->fcf.fcf_flag & FCF_REDISC_EVT) ||
(phba->fcf.fcf_flag & FCF_REDISC_PEND))
return;
+
+ if (phba->fcf.fcf_flag & FCF_IN_USE) {
+ /*
+ * In case the current in-use FCF record no
+ * longer existed during FCF discovery that
+ * was not triggered by fast FCF failover
+ * process, treat it as fast FCF failover.
+ */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2841 In-use FCF record (x%x) "
+ "not reported, entering fast "
+ "FCF failover mode scanning.\n",
+ phba->fcf.current_rec.fcf_indx);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag |= FCF_REDISC_FOV;
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_sli4_mbox_cmd_free(phba, mboxq);
+ lpfc_sli4_fcf_scan_read_fcf_rec(phba,
+ LPFC_FCOE_FCF_GET_FIRST);
+ return;
+ }
+
/*
* Otherwise, initial scan or post linkdown rescan,
* register with the best FCF record found so far
* through the FCF scanning process.
*/
- /* mark the initial FCF discovery completed */
+ /*
+ * Mark the initial FCF discovery completed and
+ * the start of the first round of the roundrobin
+ * FCF failover.
+ */
spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~FCF_INIT_DISC;
+ phba->fcf.fcf_flag &=
+ ~(FCF_INIT_DISC | FCF_REDISC_RRU);
spin_unlock_irq(&phba->hbalock);
/*
* Set up the initial registered FCF index for FLOGI
@@ -2033,6 +2160,11 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
next_fcf_index);
/* Upload new FCF record to the failover FCF record */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2834 Update the current FCF record (x%x) "
+ "with the next FCF record (x%x)\n",
+ phba->fcf.failover_rec.fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
spin_lock_irq(&phba->hbalock);
__lpfc_update_fcf_record(phba, &phba->fcf.failover_rec,
new_fcf_record, addr_mode, vlan_id,
@@ -2050,7 +2182,7 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
"2783 FLOGI round robin FCF failover from FCF "
- "(index:x%x) to FCF (index:x%x).\n",
+ "(x%x) to FCF (x%x).\n",
current_fcf_index,
bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
@@ -2084,7 +2216,7 @@ lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
goto out;
/* If FCF discovery period is over, no need to proceed */
- if (phba->fcf.fcf_flag & FCF_DISCOVERY)
+ if (!(phba->fcf.fcf_flag & FCF_DISCOVERY))
goto out;
/* Parse the FCF record from the non-embedded mailbox command */
@@ -2715,11 +2847,35 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
struct lpfc_vport *vport = pmb->vport;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
pmb->context1 = NULL;
- /* Good status, call state machine */
- lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
+ if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
+ ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
+
+ if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL ||
+ ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) {
+ /* We rcvd a rscn after issuing this
+ * mbox reg login, we may have cycled
+ * back through the state and be
+ * back at reg login state so this
+ * mbox needs to be ignored becase
+ * there is another reg login in
+ * proccess.
+ */
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+ spin_unlock_irq(shost->host_lock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba,
+ pmb->u.mb.un.varRegLogin.rpi);
+
+ } else
+ /* Good status, call state machine */
+ lpfc_disc_state_machine(vport, ndlp, pmb,
+ NLP_EVT_CMPL_REG_LOGIN);
+
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
@@ -3427,7 +3583,7 @@ lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
kref_init(&ndlp->kref);
NLP_INT_NODE_ACT(ndlp);
atomic_set(&ndlp->cmd_pending, 0);
- ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
+ ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
}
struct lpfc_nodelist *
@@ -3700,6 +3856,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
mempool_free(mbox, phba->mbox_mem_pool);
}
lpfc_no_rpi(phba, ndlp);
+
ndlp->nlp_rpi = 0;
ndlp->nlp_flag &= ~NLP_RPI_VALID;
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
@@ -3842,6 +3999,9 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
kfree(mp);
}
list_del(&mb->list);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba,
+ mb->u.mb.un.varRegLogin.rpi);
mempool_free(mb, phba->mbox_mem_pool);
/* We shall not invoke the lpfc_nlp_put to decrement
* the ndlp reference count as we are in the process
@@ -3883,6 +4043,7 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
lpfc_cancel_retry_delay_tmo(vport, ndlp);
if ((ndlp->nlp_flag & NLP_DEFER_RM) &&
+ !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) &&
!(ndlp->nlp_flag & NLP_RPI_VALID)) {
/* For this case we need to cleanup the default rpi
* allocated by the firmware.
@@ -5180,13 +5341,16 @@ void
lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
{
/*
- * If HBA is not running in FIP mode or if HBA does not support
- * FCoE or if FCF is not registered, do nothing.
+ * If HBA is not running in FIP mode, if HBA does not support
+ * FCoE, if FCF discovery is ongoing, or if FCF has not been
+ * registered, do nothing.
*/
spin_lock_irq(&phba->hbalock);
if (!(phba->hba_flag & HBA_FCOE_SUPPORT) ||
!(phba->fcf.fcf_flag & FCF_REGISTERED) ||
- !(phba->hba_flag & HBA_FIP_SUPPORT)) {
+ !(phba->hba_flag & HBA_FIP_SUPPORT) ||
+ (phba->fcf.fcf_flag & FCF_DISCOVERY) ||
+ (phba->pport->port_state == LPFC_FLOGI)) {
spin_unlock_irq(&phba->hbalock);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index e654d01dad24..f5dbf2be3eab 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1170,6 +1170,7 @@ typedef struct {
#define PCI_DEVICE_ID_TIGERSHARK 0x0704
#define PCI_DEVICE_ID_TOMCAT 0x0714
#define PCI_DEVICE_ID_FALCON 0xf180
+#define PCI_DEVICE_ID_BALIUS 0xe131
#define JEDEC_ID_ADDRESS 0x0080001c
#define FIREFLY_JEDEC_ID 0x1ACC
@@ -3014,18 +3015,10 @@ struct sli3_pgp {
uint32_t hbq_get[16];
};
-struct sli3_inb_pgp {
- uint32_t ha_copy;
- uint32_t counter;
- struct lpfc_pgp port[MAX_RINGS];
- uint32_t hbq_get[16];
-};
-
union sli_var {
struct sli2_desc s2;
struct sli3_desc s3;
struct sli3_pgp s3_pgp;
- struct sli3_inb_pgp s3_inb_pgp;
};
typedef struct {
@@ -3132,6 +3125,14 @@ typedef struct {
#define IOERR_BUFFER_SHORTAGE 0x28
#define IOERR_DEFAULT 0x29
#define IOERR_CNT 0x2A
+#define IOERR_SLER_FAILURE 0x46
+#define IOERR_SLER_CMD_RCV_FAILURE 0x47
+#define IOERR_SLER_REC_RJT_ERR 0x48
+#define IOERR_SLER_REC_SRR_RETRY_ERR 0x49
+#define IOERR_SLER_SRR_RJT_ERR 0x4A
+#define IOERR_SLER_RRQ_RJT_ERR 0x4C
+#define IOERR_SLER_RRQ_RETRY_ERR 0x4D
+#define IOERR_SLER_ABTS_ERR 0x4E
#define IOERR_DRVR_MASK 0x100
#define IOERR_SLI_DOWN 0x101 /* ulpStatus - Driver defined */
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index cd9697edf860..2786ee3b605d 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -621,6 +621,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
/**
* lpfc_hba_init_link - Initialize the FC link
* @phba: pointer to lpfc hba data structure.
+ * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT
*
* This routine will issue the INIT_LINK mailbox command call.
* It is available to other drivers through the lpfc_hba data
@@ -632,7 +633,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
* Any other value - error
**/
int
-lpfc_hba_init_link(struct lpfc_hba *phba)
+lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag)
{
struct lpfc_vport *vport = phba->pport;
LPFC_MBOXQ_t *pmb;
@@ -651,7 +652,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba)
phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
lpfc_set_loopback_flag(phba);
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ rc = lpfc_sli_issue_mbox(phba, pmb, flag);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0498 Adapter failed to init, mbxCmd x%x "
@@ -664,17 +665,21 @@ lpfc_hba_init_link(struct lpfc_hba *phba)
writel(0xffffffff, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
phba->link_state = LPFC_HBA_ERROR;
- if (rc != MBX_BUSY)
+ if (rc != MBX_BUSY || flag == MBX_POLL)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
phba->cfg_suppress_link_up = LPFC_INITIALIZE_LINK;
+ if (flag == MBX_POLL)
+ mempool_free(pmb, phba->mbox_mem_pool);
return 0;
}
/**
* lpfc_hba_down_link - this routine downs the FC link
+ * @phba: pointer to lpfc hba data structure.
+ * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT
*
* This routine will issue the DOWN_LINK mailbox command call.
* It is available to other drivers through the lpfc_hba data
@@ -685,7 +690,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba)
* Any other value - error
**/
int
-lpfc_hba_down_link(struct lpfc_hba *phba)
+lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag)
{
LPFC_MBOXQ_t *pmb;
int rc;
@@ -701,7 +706,7 @@ lpfc_hba_down_link(struct lpfc_hba *phba)
"0491 Adapter Link is disabled.\n");
lpfc_down_link(phba, pmb);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ rc = lpfc_sli_issue_mbox(phba, pmb, flag);
if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
lpfc_printf_log(phba,
KERN_ERR, LOG_INIT,
@@ -711,6 +716,9 @@ lpfc_hba_down_link(struct lpfc_hba *phba)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
+ if (flag == MBX_POLL)
+ mempool_free(pmb, phba->mbox_mem_pool);
+
return 0;
}
@@ -1818,6 +1826,10 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
m = (typeof(m)){"LPSe12002-ML1-E", "PCIe",
"EmulexSecure Fibre"};
break;
+ case PCI_DEVICE_ID_BALIUS:
+ m = (typeof(m)){"LPVe12002", "PCIe Shared I/O",
+ "Fibre Channel Adapter"};
+ break;
default:
m = (typeof(m)){"Unknown", "", ""};
break;
@@ -2279,10 +2291,32 @@ static void
lpfc_block_mgmt_io(struct lpfc_hba * phba)
{
unsigned long iflag;
+ uint8_t actcmd = MBX_HEARTBEAT;
+ unsigned long timeout;
+
spin_lock_irqsave(&phba->hbalock, iflag);
phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
+ if (phba->sli.mbox_active)
+ actcmd = phba->sli.mbox_active->u.mb.mbxCommand;
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ /* Determine how long we might wait for the active mailbox
+ * command to be gracefully completed by firmware.
+ */
+ timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, actcmd) * 1000) +
+ jiffies;
+ /* Wait for the outstnading mailbox command to complete */
+ while (phba->sli.mbox_active) {
+ /* Check active mailbox complete status every 2ms */
+ msleep(2);
+ if (time_after(jiffies, timeout)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2813 Mgmt IO is Blocked %x "
+ "- mbox cmd %x still active\n",
+ phba->sli.sli_flag, actcmd);
+ break;
+ }
+ }
}
/**
@@ -3323,22 +3357,14 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
"evt_tag:x%x, fcf_index:x%x\n",
acqe_fcoe->event_tag,
acqe_fcoe->index);
+ /* If the FCF discovery is in progress, do nothing. */
spin_lock_irq(&phba->hbalock);
- if ((phba->fcf.fcf_flag & FCF_SCAN_DONE) ||
- (phba->hba_flag & FCF_DISC_INPROGRESS)) {
- /*
- * If the current FCF is in discovered state or
- * FCF discovery is in progress, do nothing.
- */
+ if (phba->hba_flag & FCF_DISC_INPROGRESS) {
spin_unlock_irq(&phba->hbalock);
break;
}
-
+ /* If fast FCF failover rescan event is pending, do nothing */
if (phba->fcf.fcf_flag & FCF_REDISC_EVT) {
- /*
- * If fast FCF failover rescan event is pending,
- * do nothing.
- */
spin_unlock_irq(&phba->hbalock);
break;
}
@@ -3359,7 +3385,13 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
acqe_fcoe->index);
rc = lpfc_sli4_read_fcf_rec(phba, acqe_fcoe->index);
}
-
+ /* If the FCF has been in discovered state, do nothing. */
+ spin_lock_irq(&phba->hbalock);
+ if (phba->fcf.fcf_flag & FCF_SCAN_DONE) {
+ spin_unlock_irq(&phba->hbalock);
+ break;
+ }
+ spin_unlock_irq(&phba->hbalock);
/* Otherwise, scan the entire FCF table and re-discover SAN */
lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
"2770 Start FCF table scan due to new FCF "
@@ -4885,6 +4917,7 @@ lpfc_create_shost(struct lpfc_hba *phba)
phba->fc_altov = FF_DEF_ALTOV;
phba->fc_arbtov = FF_DEF_ARBTOV;
+ atomic_set(&phba->sdev_cnt, 0);
vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
if (!vport)
return -ENODEV;
@@ -5533,9 +5566,12 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
mempool_free(pmb, phba->mbox_mem_pool);
/* Reset the DFT_HBA_Q_DEPTH to the max xri */
- if (phba->cfg_hba_queue_depth > (phba->sli4_hba.max_cfg_param.max_xri))
+ if (phba->cfg_hba_queue_depth >
+ (phba->sli4_hba.max_cfg_param.max_xri -
+ lpfc_sli4_get_els_iocb_cnt(phba)))
phba->cfg_hba_queue_depth =
- phba->sli4_hba.max_cfg_param.max_xri;
+ phba->sli4_hba.max_cfg_param.max_xri -
+ lpfc_sli4_get_els_iocb_cnt(phba);
return rc;
}
@@ -6993,22 +7029,28 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba)
static int
lpfc_sli4_enable_msix(struct lpfc_hba *phba)
{
- int rc, index;
+ int vectors, rc, index;
/* Set up MSI-X multi-message vectors */
for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
phba->sli4_hba.msix_entries[index].entry = index;
/* Configure MSI-X capability structure */
+ vectors = phba->sli4_hba.cfg_eqn;
+enable_msix_vectors:
rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries,
- phba->sli4_hba.cfg_eqn);
- if (rc) {
+ vectors);
+ if (rc > 1) {
+ vectors = rc;
+ goto enable_msix_vectors;
+ } else if (rc) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"0484 PCI enable MSI-X failed (%d)\n", rc);
goto msi_fail_out;
}
+
/* Log MSI-X vector assignment */
- for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
+ for (index = 0; index < vectors; index++)
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"0489 MSI-X entry[%d]: vector=x%x "
"message=%d\n", index,
@@ -7030,7 +7072,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
}
/* The rest of the vector(s) are associated to fast-path handler(s) */
- for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) {
+ for (index = 1; index < vectors; index++) {
phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1;
phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba;
rc = request_irq(phba->sli4_hba.msix_entries[index].vector,
@@ -7044,6 +7086,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
goto cfg_fail_out;
}
}
+ phba->sli4_hba.msix_vec_nr = vectors;
return rc;
@@ -7077,9 +7120,10 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)
/* Free up MSI-X multi-message vectors */
free_irq(phba->sli4_hba.msix_entries[0].vector, phba);
- for (index = 1; index < phba->sli4_hba.cfg_eqn; index++)
+ for (index = 1; index < phba->sli4_hba.msix_vec_nr; index++)
free_irq(phba->sli4_hba.msix_entries[index].vector,
&phba->sli4_hba.fcp_eq_hdl[index - 1]);
+
/* Disable MSI-X */
pci_disable_msix(phba->pcidev);
@@ -7121,6 +7165,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
pci_disable_msi(phba->pcidev);
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
"0490 MSI request_irq failed (%d)\n", rc);
+ return rc;
}
for (index = 0; index < phba->cfg_fcp_eq_count; index++) {
@@ -7128,7 +7173,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
}
- return rc;
+ return 0;
}
/**
@@ -7839,6 +7884,9 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2710 PCI channel disable preparing for reset\n");
+ /* Block any management I/Os to the device */
+ lpfc_block_mgmt_io(phba);
+
/* Block all SCSI devices' I/Os on the host */
lpfc_scsi_dev_block(phba);
@@ -7848,6 +7896,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
/* Disable interrupt and pci device */
lpfc_sli_disable_intr(phba);
pci_disable_device(phba->pcidev);
+
/* Flush all driver's outstanding SCSI I/Os as we are to reset */
lpfc_sli_flush_fcp_rings(phba);
}
@@ -7861,7 +7910,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
* pending I/Os.
**/
static void
-lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba)
+lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba)
{
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2711 PCI channel permanent disable for failure\n");
@@ -7910,7 +7959,7 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state)
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
/* Permanent failure, prepare for device down */
- lpfc_prep_dev_for_perm_failure(phba);
+ lpfc_sli_prep_dev_for_perm_failure(phba);
return PCI_ERS_RESULT_DISCONNECT;
default:
/* Unknown state, prepare and request slot reset */
@@ -7979,7 +8028,8 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev)
} else
phba->intr_mode = intr_mode;
- /* Take device offline; this will perform cleanup */
+ /* Take device offline, it will perform cleanup */
+ lpfc_offline_prep(phba);
lpfc_offline(phba);
lpfc_sli_brdrestart(phba);
@@ -8110,8 +8160,12 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
}
/* Initialize and populate the iocb list per host */
- error = lpfc_init_iocb_list(phba,
- phba->sli4_hba.max_cfg_param.max_xri);
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2821 initialize iocb list %d.\n",
+ phba->cfg_iocb_cnt*1024);
+ error = lpfc_init_iocb_list(phba, phba->cfg_iocb_cnt*1024);
+
if (error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"1413 Failed to initialize iocb list.\n");
@@ -8160,6 +8214,8 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
/* Default to single FCP EQ for non-MSI-X */
if (phba->intr_type != MSIX)
phba->cfg_fcp_eq_count = 1;
+ else if (phba->sli4_hba.msix_vec_nr < phba->cfg_fcp_eq_count)
+ phba->cfg_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1;
/* Set up SLI-4 HBA */
if (lpfc_sli4_hba_setup(phba)) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -8321,7 +8377,7 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg)
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "0298 PCI device Power Management suspend.\n");
+ "2843 PCI device Power Management suspend.\n");
/* Bring down the device */
lpfc_offline_prep(phba);
@@ -8412,6 +8468,84 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev)
}
/**
+ * lpfc_sli4_prep_dev_for_recover - Prepare SLI4 device for pci slot recover
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot recover. It
+ * aborts all the outstanding SCSI I/Os to the pci device.
+ **/
+static void
+lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba)
+{
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring;
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2828 PCI channel I/O abort preparing for recovery\n");
+ /*
+ * There may be errored I/Os through HBA, abort all I/Os on txcmplq
+ * and let the SCSI mid-layer to retry them to recover.
+ */
+ pring = &psli->ring[psli->fcp_ring];
+ lpfc_sli_abort_iocb_ring(phba, pring);
+}
+
+/**
+ * lpfc_sli4_prep_dev_for_reset - Prepare SLI4 device for pci slot reset
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot reset. It
+ * disables the device interrupt and pci device, and aborts the internal FCP
+ * pending I/Os.
+ **/
+static void
+lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba)
+{
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2826 PCI channel disable preparing for reset\n");
+
+ /* Block any management I/Os to the device */
+ lpfc_block_mgmt_io(phba);
+
+ /* Block all SCSI devices' I/Os on the host */
+ lpfc_scsi_dev_block(phba);
+
+ /* stop all timers */
+ lpfc_stop_hba_timers(phba);
+
+ /* Disable interrupt and pci device */
+ lpfc_sli4_disable_intr(phba);
+ pci_disable_device(phba->pcidev);
+
+ /* Flush all driver's outstanding SCSI I/Os as we are to reset */
+ lpfc_sli_flush_fcp_rings(phba);
+}
+
+/**
+ * lpfc_sli4_prep_dev_for_perm_failure - Prepare SLI4 dev for pci slot disable
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot permanently
+ * disabling. It blocks the SCSI transport layer traffic and flushes the FCP
+ * pending I/Os.
+ **/
+static void
+lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba)
+{
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2827 PCI channel permanent disable for failure\n");
+
+ /* Block all SCSI devices' I/Os on the host */
+ lpfc_scsi_dev_block(phba);
+
+ /* stop all timers */
+ lpfc_stop_hba_timers(phba);
+
+ /* Clean up all driver's outstanding SCSI I/Os */
+ lpfc_sli_flush_fcp_rings(phba);
+}
+
+/**
* lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device
* @pdev: pointer to PCI device.
* @state: the current PCI connection state.
@@ -8430,7 +8564,29 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev)
static pci_ers_result_t
lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state)
{
- return PCI_ERS_RESULT_NEED_RESET;
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ switch (state) {
+ case pci_channel_io_normal:
+ /* Non-fatal error, prepare for recovery */
+ lpfc_sli4_prep_dev_for_recover(phba);
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ /* Fatal error, prepare for slot reset */
+ lpfc_sli4_prep_dev_for_reset(phba);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ /* Permanent failure, prepare for device down */
+ lpfc_sli4_prep_dev_for_perm_failure(phba);
+ return PCI_ERS_RESULT_DISCONNECT;
+ default:
+ /* Unknown state, prepare and request slot reset */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2825 Unknown PCI error state: x%x\n", state);
+ lpfc_sli4_prep_dev_for_reset(phba);
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
}
/**
@@ -8454,6 +8610,39 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state)
static pci_ers_result_t
lpfc_io_slot_reset_s4(struct pci_dev *pdev)
{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ struct lpfc_sli *psli = &phba->sli;
+ uint32_t intr_mode;
+
+ dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
+ if (pci_enable_device_mem(pdev)) {
+ printk(KERN_ERR "lpfc: Cannot re-enable "
+ "PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ pci_restore_state(pdev);
+ if (pdev->is_busmaster)
+ pci_set_master(pdev);
+
+ spin_lock_irq(&phba->hbalock);
+ psli->sli_flag &= ~LPFC_SLI_ACTIVE;
+ spin_unlock_irq(&phba->hbalock);
+
+ /* Configure and enable interrupt */
+ intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode);
+ if (intr_mode == LPFC_INTR_ERROR) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2824 Cannot re-enable interrupt after "
+ "slot reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ } else
+ phba->intr_mode = intr_mode;
+
+ /* Log the current active interrupt mode */
+ lpfc_log_intr_mode(phba, phba->intr_mode);
+
return PCI_ERS_RESULT_RECOVERED;
}
@@ -8470,7 +8659,27 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev)
static void
lpfc_io_resume_s4(struct pci_dev *pdev)
{
- return;
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ /*
+ * In case of slot reset, as function reset is performed through
+ * mailbox command which needs DMA to be enabled, this operation
+ * has to be moved to the io resume phase. Taking device offline
+ * will perform the necessary cleanup.
+ */
+ if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) {
+ /* Perform device reset */
+ lpfc_offline_prep(phba);
+ lpfc_offline(phba);
+ lpfc_sli_brdrestart(phba);
+ /* Bring the device back online */
+ lpfc_online(phba);
+ }
+
+ /* Clean up Advanced Error Reporting (AER) if needed */
+ if (phba->hba_flag & HBA_AER_ENABLED)
+ pci_cleanup_aer_uncorrect_error_status(pdev);
}
/**
@@ -8802,6 +9011,8 @@ static struct pci_device_id lpfc_id_table[] = {
PCI_ANY_ID, PCI_ANY_ID, },
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON,
PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS,
+ PCI_ANY_ID, PCI_ANY_ID, },
{ 0 }
};
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index e84dc33ca201..9c2c7c7140c7 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -955,6 +955,26 @@ lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
return;
}
+void
+lpfc_sli4_swap_str(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb = &pmb->u.mb;
+ struct lpfc_mqe *mqe;
+
+ switch (mb->mbxCommand) {
+ case MBX_READ_REV:
+ mqe = &pmb->u.mqe;
+ lpfc_sli_pcimem_bcopy(mqe->un.read_rev.fw_name,
+ mqe->un.read_rev.fw_name, 16);
+ lpfc_sli_pcimem_bcopy(mqe->un.read_rev.ulp_fw_name,
+ mqe->un.read_rev.ulp_fw_name, 16);
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
/**
* lpfc_build_hbq_profile2 - Set up the HBQ Selection Profile 2
* @hbqmb: pointer to the HBQ configuration data structure in mailbox command.
@@ -1199,7 +1219,6 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
mb->un.varCfgPort.cdss = 1; /* Configure Security */
mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */
- mb->un.varCfgPort.cinb = 1; /* Interrupt Notification Block */
mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
if (phba->max_vpi && phba->cfg_enable_npiv &&
phba->vpd.sli3Feat.cmv) {
@@ -2026,7 +2045,7 @@ lpfc_reg_fcfi(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
phba->fcf.current_rec.fcf_indx);
/* reg_fcf addr mode is bit wise inverted value of fcf addr_mode */
bf_set(lpfc_reg_fcfi_mam, reg_fcfi, (~phba->fcf.addr_mode) & 0x3);
- if (phba->fcf.current_rec.vlan_id != 0xFFFF) {
+ if (phba->fcf.current_rec.vlan_id != LPFC_FCOE_NULL_VID) {
bf_set(lpfc_reg_fcfi_vv, reg_fcfi, 1);
bf_set(lpfc_reg_fcfi_vlan_tag, reg_fcfi,
phba->fcf.current_rec.vlan_id);
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index b90820a699fd..bccc9c66fa37 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -190,6 +190,7 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
+
/*
* Free resources / clean up outstanding I/Os
* associated with a LPFC_NODELIST entry. This
@@ -199,13 +200,15 @@ int
lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
LIST_HEAD(completions);
+ LIST_HEAD(txcmplq_completions);
+ LIST_HEAD(abort_list);
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
struct lpfc_iocbq *iocb, *next_iocb;
/* Abort outstanding I/O on NPort <nlp_DID> */
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_DISCOVERY,
- "0205 Abort outstanding I/O on NPort x%x "
+ "2819 Abort outstanding I/O on NPort x%x "
"Data: x%x x%x x%x\n",
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi);
@@ -224,14 +227,25 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
}
/* Next check the txcmplq */
- list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+ list_splice_init(&pring->txcmplq, &txcmplq_completions);
+ spin_unlock_irq(&phba->hbalock);
+
+ list_for_each_entry_safe(iocb, next_iocb, &txcmplq_completions, list) {
/* Check to see if iocb matches the nport we are looking for */
- if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
- lpfc_sli_issue_abort_iotag(phba, pring, iocb);
- }
+ if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
+ list_add_tail(&iocb->dlist, &abort_list);
}
+ spin_lock_irq(&phba->hbalock);
+ list_splice(&txcmplq_completions, &pring->txcmplq);
spin_unlock_irq(&phba->hbalock);
+ list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) {
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&iocb->dlist);
+ lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+ spin_unlock_irq(&phba->hbalock);
+ }
+
/* Cancel all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
IOERR_SLI_ABORTED);
@@ -626,7 +640,8 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
if (!(vport->fc_flag & FC_PT2PT)) {
/* Check config parameter use-adisc or FCP-2 */
if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
- ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
+ ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) &&
+ (ndlp->nlp_type & NLP_FCP_TARGET))) {
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_ADISC;
spin_unlock_irq(shost->host_lock);
@@ -962,6 +977,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
break;
default:
+ ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
}
mbox->context2 = lpfc_nlp_get(ndlp);
@@ -972,6 +988,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
NLP_STE_REG_LOGIN_ISSUE);
return ndlp->nlp_state;
}
+ if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
+ ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
/* decrement node reference count to the failed mbox
* command
*/
@@ -1458,6 +1476,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport,
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_IGNR_REG_CMPL;
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(shost->host_lock);
lpfc_disc_set_adisc(vport, ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index f4a3b2e79eea..c818a7255962 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -623,6 +623,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
unsigned long iflag = 0;
struct lpfc_iocbq *iocbq;
int i;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irqsave(&phba->hbalock, iflag);
spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock);
@@ -651,6 +652,8 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
psb = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
psb->exch_busy = 0;
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ if (pring->txq_cnt)
+ lpfc_worker_wake_up(phba);
return;
}
@@ -747,7 +750,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
int status = 0, index;
int bcnt;
int non_sequential_xri = 0;
- int rc = 0;
LIST_HEAD(sblist);
for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
@@ -774,6 +776,8 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
/* Allocate iotag for psb->cur_iocbq. */
iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
if (iotag == 0) {
+ pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
+ psb->data, psb->dma_handle);
kfree(psb);
break;
}
@@ -858,7 +862,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
if (status) {
/* Put this back on the abort scsi list */
psb->exch_busy = 1;
- rc++;
} else {
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
@@ -877,7 +880,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
if (status) {
/* Put this back on the abort scsi list */
psb->exch_busy = 1;
- rc++;
} else {
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
@@ -887,7 +889,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
}
}
- return bcnt + non_sequential_xri - rc;
+ return bcnt + non_sequential_xri;
}
/**
@@ -1323,6 +1325,10 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
pde5->reftag = reftag;
+ /* Endian convertion if necessary for PDE5 */
+ pde5->word0 = cpu_to_le32(pde5->word0);
+ pde5->reftag = cpu_to_le32(pde5->reftag);
+
/* advance bpl and increment bde count */
num_bde++;
bpl++;
@@ -1341,6 +1347,11 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
bf_set(pde6_ai, pde6, 1);
bf_set(pde6_apptagval, pde6, apptagval);
+ /* Endian convertion if necessary for PDE6 */
+ pde6->word0 = cpu_to_le32(pde6->word0);
+ pde6->word1 = cpu_to_le32(pde6->word1);
+ pde6->word2 = cpu_to_le32(pde6->word2);
+
/* advance bpl and increment bde count */
num_bde++;
bpl++;
@@ -1448,6 +1459,10 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
pde5->reftag = reftag;
+ /* Endian convertion if necessary for PDE5 */
+ pde5->word0 = cpu_to_le32(pde5->word0);
+ pde5->reftag = cpu_to_le32(pde5->reftag);
+
/* advance bpl and increment bde count */
num_bde++;
bpl++;
@@ -1464,6 +1479,11 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
bf_set(pde6_ai, pde6, 1);
bf_set(pde6_apptagval, pde6, apptagval);
+ /* Endian convertion if necessary for PDE6 */
+ pde6->word0 = cpu_to_le32(pde6->word0);
+ pde6->word1 = cpu_to_le32(pde6->word1);
+ pde6->word2 = cpu_to_le32(pde6->word2);
+
/* advance bpl and increment bde count */
num_bde++;
bpl++;
@@ -1475,7 +1495,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
protgroup_len = sg_dma_len(sgpe);
-
/* must be integer multiple of the DIF block length */
BUG_ON(protgroup_len % 8);
@@ -2293,15 +2312,21 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
struct lpfc_vport *vport = pIocbIn->vport;
struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
struct lpfc_nodelist *pnode = rdata->pnode;
- struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
+ struct scsi_cmnd *cmd;
int result;
struct scsi_device *tmp_sdev;
int depth;
unsigned long flags;
struct lpfc_fast_path_event *fast_path_evt;
- struct Scsi_Host *shost = cmd->device->host;
+ struct Scsi_Host *shost;
uint32_t queue_depth, scsi_id;
+ /* Sanity check on return of outstanding command */
+ if (!(lpfc_cmd->pCmd))
+ return;
+ cmd = lpfc_cmd->pCmd;
+ shost = cmd->device->host;
+
lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
/* pick up SLI4 exhange busy status from HBA */
@@ -2363,7 +2388,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
case IOSTAT_LOCAL_REJECT:
if (lpfc_cmd->result == IOERR_INVALID_RPI ||
lpfc_cmd->result == IOERR_NO_RESOURCES ||
- lpfc_cmd->result == IOERR_ABORT_REQUESTED) {
+ lpfc_cmd->result == IOERR_ABORT_REQUESTED ||
+ lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) {
cmd->result = ScsiResult(DID_REQUEUE, 0);
break;
}
@@ -2432,14 +2458,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
}
spin_unlock_irqrestore(shost->host_lock, flags);
} else if (pnode && NLP_CHK_NODE_ACT(pnode)) {
- if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) &&
+ if ((pnode->cmd_qdepth < vport->cfg_tgt_queue_depth) &&
time_after(jiffies, pnode->last_change_time +
msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) {
spin_lock_irqsave(shost->host_lock, flags);
- pnode->cmd_qdepth += pnode->cmd_qdepth *
- LPFC_TGTQ_RAMPUP_PCENT / 100;
- if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH)
- pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
+ depth = pnode->cmd_qdepth * LPFC_TGTQ_RAMPUP_PCENT
+ / 100;
+ depth = depth ? depth : 1;
+ pnode->cmd_qdepth += depth;
+ if (pnode->cmd_qdepth > vport->cfg_tgt_queue_depth)
+ pnode->cmd_qdepth = vport->cfg_tgt_queue_depth;
pnode->last_change_time = jiffies;
spin_unlock_irqrestore(shost->host_lock, flags);
}
@@ -2894,8 +2922,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0);
goto out_fail_command;
}
- if (vport->cfg_max_scsicmpl_time &&
- (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth))
+ if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
goto out_host_busy;
lpfc_cmd = lpfc_get_scsi_buf(phba);
@@ -3041,7 +3068,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
int ret = SUCCESS;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
- fc_block_scsi_eh(cmnd);
+ ret = fc_block_scsi_eh(cmnd);
+ if (ret)
+ return ret;
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
BUG_ON(!lpfc_cmd);
@@ -3225,7 +3254,9 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
lpfc_taskmgmt_name(task_mgmt_cmd),
tgt_id, lun_id, iocbqrsp->iocb.ulpStatus,
iocbqrsp->iocb.un.ulpWord[4]);
- } else
+ } else if (status == IOCB_BUSY)
+ ret = FAILED;
+ else
ret = SUCCESS;
lpfc_sli_release_iocbq(phba, iocbqrsp);
@@ -3357,7 +3388,9 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
return FAILED;
}
pnode = rdata->pnode;
- fc_block_scsi_eh(cmnd);
+ status = fc_block_scsi_eh(cmnd);
+ if (status)
+ return status;
status = lpfc_chk_tgt_mapped(vport, cmnd);
if (status == FAILED) {
@@ -3422,7 +3455,9 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
return FAILED;
}
pnode = rdata->pnode;
- fc_block_scsi_eh(cmnd);
+ status = fc_block_scsi_eh(cmnd);
+ if (status)
+ return status;
status = lpfc_chk_tgt_mapped(vport, cmnd);
if (status == FAILED) {
@@ -3488,7 +3523,9 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID);
- fc_block_scsi_eh(cmnd);
+ ret = fc_block_scsi_eh(cmnd);
+ if (ret)
+ return ret;
/*
* Since the driver manages a single bus device, reset all
@@ -3561,11 +3598,13 @@ lpfc_slave_alloc(struct scsi_device *sdev)
uint32_t total = 0;
uint32_t num_to_alloc = 0;
int num_allocated = 0;
+ uint32_t sdev_cnt;
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
sdev->hostdata = rport->dd_data;
+ sdev_cnt = atomic_inc_return(&phba->sdev_cnt);
/*
* Populate the cmds_per_lun count scsi_bufs into this host's globally
@@ -3577,6 +3616,10 @@ lpfc_slave_alloc(struct scsi_device *sdev)
total = phba->total_scsi_bufs;
num_to_alloc = vport->cfg_lun_queue_depth + 2;
+ /* If allocated buffers are enough do nothing */
+ if ((sdev_cnt * (vport->cfg_lun_queue_depth + 2)) < total)
+ return 0;
+
/* Allow some exchanges to be available always to complete discovery */
if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
@@ -3658,6 +3701,9 @@ lpfc_slave_configure(struct scsi_device *sdev)
static void
lpfc_slave_destroy(struct scsi_device *sdev)
{
+ struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ atomic_dec(&phba->sdev_cnt);
sdev->hostdata = NULL;
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 7a61455140b6..e758eae0d0fd 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -455,6 +455,11 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba)
struct lpfc_iocbq * iocbq = NULL;
list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list);
+
+ if (iocbq)
+ phba->iocb_cnt++;
+ if (phba->iocb_cnt > phba->iocb_max)
+ phba->iocb_max = phba->iocb_cnt;
return iocbq;
}
@@ -575,7 +580,8 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
struct lpfc_sglq *sglq;
size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
- unsigned long iflag;
+ unsigned long iflag = 0;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
if (iocbq->sli4_xritag == NO_XRI)
sglq = NULL;
@@ -593,6 +599,10 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
} else {
sglq->state = SGL_FREED;
list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list);
+
+ /* Check if TXQ queue needs to be serviced */
+ if (pring->txq_cnt)
+ lpfc_worker_wake_up(phba);
}
}
@@ -605,6 +615,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
}
+
/**
* __lpfc_sli_release_iocbq_s3 - Release iocb to the iocb pool
* @phba: Pointer to HBA context object.
@@ -642,6 +653,7 @@ static void
__lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
phba->__lpfc_sli_release_iocbq(phba, iocbq);
+ phba->iocb_cnt--;
}
/**
@@ -872,7 +884,11 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
list_add_tail(&piocb->list, &pring->txcmplq);
+ piocb->iocb_flag |= LPFC_IO_ON_Q;
pring->txcmplq_cnt++;
+ if (pring->txcmplq_cnt > pring->txcmplq_max)
+ pring->txcmplq_max = pring->txcmplq_cnt;
+
if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
(piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
(piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
@@ -897,7 +913,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* the txq, the function returns first iocb in the list after
* removing the iocb from the list, else it returns NULL.
**/
-static struct lpfc_iocbq *
+struct lpfc_iocbq *
lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
struct lpfc_iocbq *cmd_iocb;
@@ -2150,7 +2166,10 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
list_del_init(&cmd_iocb->list);
- pring->txcmplq_cnt--;
+ if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
+ pring->txcmplq_cnt--;
+ cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ }
return cmd_iocb;
}
@@ -2183,7 +2202,10 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
list_del_init(&cmd_iocb->list);
- pring->txcmplq_cnt--;
+ if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
+ cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ pring->txcmplq_cnt--;
+ }
return cmd_iocb;
}
@@ -3564,13 +3586,16 @@ static int
lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
-
+ uint32_t hba_aer_enabled;
/* Restart HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"0296 Restart HBA Data: x%x x%x\n",
phba->pport->port_state, psli->sli_flag);
+ /* Take PCIe device Advanced Error Reporting (AER) state */
+ hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED;
+
lpfc_sli4_brdreset(phba);
spin_lock_irq(&phba->hbalock);
@@ -3582,6 +3607,10 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
psli->stats_start = get_seconds();
+ /* Reset HBA AER if it was enabled, note hba_flag was reset above */
+ if (hba_aer_enabled)
+ pci_disable_pcie_error_reporting(phba->pcidev);
+
lpfc_hba_down_post(phba);
return 0;
@@ -3794,7 +3823,7 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba)
phba->link_state = LPFC_HBA_ERROR;
mempool_free(pmb, phba->mbox_mem_pool);
- return ENXIO;
+ return -ENXIO;
}
}
phba->hbq_count = hbq_count;
@@ -3885,7 +3914,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
phba->sli3_options &= ~(LPFC_SLI3_NPIV_ENABLED |
LPFC_SLI3_HBQ_ENABLED |
LPFC_SLI3_CRP_ENABLED |
- LPFC_SLI3_INB_ENABLED |
LPFC_SLI3_BG_ENABLED);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -3927,20 +3955,9 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
if (pmb->u.mb.un.varCfgPort.gcrp)
phba->sli3_options |= LPFC_SLI3_CRP_ENABLED;
- if (pmb->u.mb.un.varCfgPort.ginb) {
- phba->sli3_options |= LPFC_SLI3_INB_ENABLED;
- phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get;
- phba->port_gp = phba->mbox->us.s3_inb_pgp.port;
- phba->inb_ha_copy = &phba->mbox->us.s3_inb_pgp.ha_copy;
- phba->inb_counter = &phba->mbox->us.s3_inb_pgp.counter;
- phba->inb_last_counter =
- phba->mbox->us.s3_inb_pgp.counter;
- } else {
- phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
- phba->port_gp = phba->mbox->us.s3_pgp.port;
- phba->inb_ha_copy = NULL;
- phba->inb_counter = NULL;
- }
+
+ phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
+ phba->port_gp = phba->mbox->us.s3_pgp.port;
if (phba->cfg_enable_bg) {
if (pmb->u.mb.un.varCfgPort.gbg)
@@ -3953,8 +3970,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
} else {
phba->hbq_get = NULL;
phba->port_gp = phba->mbox->us.s2.port;
- phba->inb_ha_copy = NULL;
- phba->inb_counter = NULL;
phba->max_vpi = 0;
}
do_prep_failed:
@@ -4214,7 +4229,8 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
if (mqe->un.read_rev.avail_vpd_len < *vpd_size)
*vpd_size = mqe->un.read_rev.avail_vpd_len;
- lpfc_sli_pcimem_bcopy(dmabuf->virt, vpd, *vpd_size);
+ memcpy(vpd, dmabuf->virt, *vpd_size);
+
dma_free_coherent(&phba->pcidev->dev, dma_size,
dmabuf->virt, dmabuf->phys);
kfree(dmabuf);
@@ -4539,6 +4555,24 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
/* Start error attention (ERATT) polling timer */
mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL);
+ /* Enable PCIe device Advanced Error Reporting (AER) if configured */
+ if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) {
+ rc = pci_enable_pcie_error_reporting(phba->pcidev);
+ if (!rc) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2829 This device supports "
+ "Advanced Error Reporting (AER)\n");
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag |= HBA_AER_ENABLED;
+ spin_unlock_irq(&phba->hbalock);
+ } else {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2830 This device does not support "
+ "Advanced Error Reporting (AER)\n");
+ phba->cfg_aer_support = 0;
+ }
+ }
+
/*
* The port is ready, set the host's link state to LINK_DOWN
* in preparation for link interrupts.
@@ -5265,7 +5299,8 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
if (mcqe_status != MB_CQE_STATUS_SUCCESS) {
bf_set(lpfc_mqe_status, mb, LPFC_MBX_ERROR_RANGE | mcqe_status);
rc = MBXERR_ERROR;
- }
+ } else
+ lpfc_sli4_swap_str(phba, mboxq);
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
"(%d):0356 Mailbox cmd x%x (x%x) Status x%x "
@@ -5592,7 +5627,7 @@ lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
* iocb to the txq when SLI layer cannot submit the command iocb
* to the ring.
**/
-static void
+void
__lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
@@ -6209,7 +6244,6 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_iocbq *piocb, uint32_t flag)
{
struct lpfc_sglq *sglq;
- uint16_t xritag;
union lpfc_wqe wqe;
struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
@@ -6218,10 +6252,26 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
sglq = NULL;
else {
+ if (pring->txq_cnt) {
+ if (!(flag & SLI_IOCB_RET_IOCB)) {
+ __lpfc_sli_ringtx_put(phba,
+ pring, piocb);
+ return IOCB_SUCCESS;
+ } else {
+ return IOCB_BUSY;
+ }
+ } else {
sglq = __lpfc_sli_get_sglq(phba);
- if (!sglq)
- return IOCB_ERROR;
- piocb->sli4_xritag = sglq->sli4_xritag;
+ if (!sglq) {
+ if (!(flag & SLI_IOCB_RET_IOCB)) {
+ __lpfc_sli_ringtx_put(phba,
+ pring,
+ piocb);
+ return IOCB_SUCCESS;
+ } else
+ return IOCB_BUSY;
+ }
+ }
}
} else if (piocb->iocb_flag & LPFC_IO_FCP) {
sglq = NULL; /* These IO's already have an XRI and
@@ -6237,8 +6287,9 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
}
if (sglq) {
- xritag = lpfc_sli4_bpl2sgl(phba, piocb, sglq);
- if (xritag != sglq->sli4_xritag)
+ piocb->sli4_xritag = sglq->sli4_xritag;
+
+ if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocb, sglq))
return IOCB_ERROR;
}
@@ -6278,7 +6329,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
* IOCB_SUCCESS - Success
* IOCB_BUSY - Busy
**/
-static inline int
+int
__lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_iocbq *piocb, uint32_t flag)
{
@@ -7095,13 +7146,6 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
abort_iocb = phba->sli.iocbq_lookup[abort_context];
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI,
- "0327 Cannot abort els iocb %p "
- "with tag %x context %x, abort status %x, "
- "abort code %x\n",
- abort_iocb, abort_iotag, abort_context,
- irsp->ulpStatus, irsp->un.ulpWord[4]);
-
/*
* If the iocb is not found in Firmware queue the iocb
* might have completed already. Do not free it again.
@@ -7120,6 +7164,13 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (abort_iocb && phba->sli_rev == LPFC_SLI_REV4)
abort_context = abort_iocb->iocb.ulpContext;
}
+
+ lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_SLI,
+ "0327 Cannot abort els iocb %p "
+ "with tag %x context %x, abort status %x, "
+ "abort code %x\n",
+ abort_iocb, abort_iotag, abort_context,
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
/*
* make sure we have the right iocbq before taking it
* off the txcmplq and try to call completion routine.
@@ -7137,7 +7188,10 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* following abort XRI from the HBA.
*/
list_del_init(&abort_iocb->list);
- pring->txcmplq_cnt--;
+ if (abort_iocb->iocb_flag & LPFC_IO_ON_Q) {
+ abort_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ pring->txcmplq_cnt--;
+ }
/* Firmware could still be in progress of DMAing
* payload, so don't free data buffer till after
@@ -7269,8 +7323,9 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
"0339 Abort xri x%x, original iotag x%x, "
"abort cmd iotag x%x\n",
+ iabt->un.acxri.abortIoTag,
iabt->un.acxri.abortContextTag,
- iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
+ abtsiocbp->iotag);
retval = __lpfc_sli_issue_iocb(phba, pring->ringno, abtsiocbp, 0);
if (retval)
@@ -7600,7 +7655,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
long timeleft, timeout_req = 0;
int retval = IOCB_SUCCESS;
uint32_t creg_val;
-
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
/*
* If the caller has provided a response iocbq buffer, then context2
* is NULL or its an error.
@@ -7622,7 +7677,8 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
readl(phba->HCregaddr); /* flush */
}
- retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, 0);
+ retval = lpfc_sli_issue_iocb(phba, ring_number, piocb,
+ SLI_IOCB_RET_IOCB);
if (retval == IOCB_SUCCESS) {
timeout_req = timeout * HZ;
timeleft = wait_event_timeout(done_q,
@@ -7644,6 +7700,11 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
timeout, (timeleft / jiffies));
retval = IOCB_TIMEDOUT;
}
+ } else if (retval == IOCB_BUSY) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n",
+ phba->iocb_cnt, pring->txq_cnt, pring->txcmplq_cnt);
+ return retval;
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"0332 IOCB wait issue failed, Data x%x\n",
@@ -7724,9 +7785,10 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
* if LPFC_MBX_WAKE flag is set the mailbox is completed
* else do not free the resources.
*/
- if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
+ if (pmboxq->mbox_flag & LPFC_MBX_WAKE) {
retval = MBX_SUCCESS;
- else {
+ lpfc_sli4_swap_str(phba, pmboxq);
+ } else {
retval = MBX_TIMEOUT;
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
}
@@ -8789,12 +8851,17 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba,
{
struct lpfc_iocbq *irspiocbq;
unsigned long iflags;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING];
/* Get an irspiocbq for later ELS response processing use */
irspiocbq = lpfc_sli_get_iocbq(phba);
if (!irspiocbq) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0387 Failed to allocate an iocbq\n");
+ "0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d "
+ "fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n",
+ pring->txq_cnt, phba->iocb_cnt,
+ phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt,
+ phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt);
return false;
}
@@ -9043,9 +9110,10 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
}
}
if (unlikely(!cq)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0365 Slow-path CQ identifier (%d) does "
- "not exist\n", cqid);
+ if (phba->sli.sli_flag & LPFC_SLI_ACTIVE)
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "0365 Slow-path CQ identifier "
+ "(%d) does not exist\n", cqid);
return;
}
@@ -9208,6 +9276,7 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
{
struct lpfc_wcqe_release wcqe;
bool workposted = false;
+ unsigned long iflag;
/* Copy the work queue CQE and convert endian order if needed */
lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe));
@@ -9216,6 +9285,9 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
switch (bf_get(lpfc_wcqe_c_code, &wcqe)) {
case CQE_CODE_COMPL_WQE:
/* Process the WQ complete event */
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ phba->last_completion_time = jiffies;
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
lpfc_sli4_fp_handle_fcp_wcqe(phba,
(struct lpfc_wcqe_complete *)&wcqe);
break;
@@ -9271,9 +9343,10 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
cq = phba->sli4_hba.fcp_cq[fcp_cqidx];
if (unlikely(!cq)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0367 Fast-path completion queue does not "
- "exist\n");
+ if (phba->sli.sli_flag & LPFC_SLI_ACTIVE)
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "0367 Fast-path completion queue "
+ "does not exist\n");
return;
}
@@ -11898,12 +11971,26 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
* available rpis maintained by the driver.
**/
void
+__lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
+{
+ if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) {
+ phba->sli4_hba.rpi_count--;
+ phba->sli4_hba.max_cfg_param.rpi_used--;
+ }
+}
+
+/**
+ * lpfc_sli4_free_rpi - Release an rpi for reuse.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release an rpi to the pool of
+ * available rpis maintained by the driver.
+ **/
+void
lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
{
spin_lock_irq(&phba->hbalock);
- clear_bit(rpi, phba->sli4_hba.rpi_bmask);
- phba->sli4_hba.rpi_count--;
- phba->sli4_hba.max_cfg_param.rpi_used--;
+ __lpfc_sli4_free_rpi(phba, rpi);
spin_unlock_irq(&phba->hbalock);
}
@@ -12318,18 +12405,47 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
{
uint16_t next_fcf_index;
- /* Search from the currently registered FCF index */
+ /* Search start from next bit of currently registered FCF index */
+ next_fcf_index = (phba->fcf.current_rec.fcf_indx + 1) %
+ LPFC_SLI4_FCF_TBL_INDX_MAX;
next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
LPFC_SLI4_FCF_TBL_INDX_MAX,
- phba->fcf.current_rec.fcf_indx);
+ next_fcf_index);
+
/* Wrap around condition on phba->fcf.fcf_rr_bmask */
if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)
next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
LPFC_SLI4_FCF_TBL_INDX_MAX, 0);
- /* Round robin failover stop condition */
- if (next_fcf_index == phba->fcf.fcf_rr_init_indx)
+
+ /* Check roundrobin failover list empty condition */
+ if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+ "2844 No roundrobin failover FCF available\n");
return LPFC_FCOE_FCF_NEXT_NONE;
+ }
+
+ /* Check roundrobin failover index bmask stop condition */
+ if (next_fcf_index == phba->fcf.fcf_rr_init_indx) {
+ if (!(phba->fcf.fcf_flag & FCF_REDISC_RRU)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+ "2847 Round robin failover FCF index "
+ "search hit stop condition:x%x\n",
+ next_fcf_index);
+ return LPFC_FCOE_FCF_NEXT_NONE;
+ }
+ /* The roundrobin failover index bmask updated, start over */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2848 Round robin failover FCF index bmask "
+ "updated, start over\n");
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_REDISC_RRU;
+ spin_unlock_irq(&phba->hbalock);
+ return phba->fcf.fcf_rr_init_indx;
+ }
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2845 Get next round robin failover "
+ "FCF index x%x\n", next_fcf_index);
return next_fcf_index;
}
@@ -12359,11 +12475,20 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
/* Set the eligible FCF record index bmask */
set_bit(fcf_index, phba->fcf.fcf_rr_bmask);
+ /* Set the roundrobin index bmask updated */
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag |= FCF_REDISC_RRU;
+ spin_unlock_irq(&phba->hbalock);
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2790 Set FCF index x%x to round robin failover "
+ "bmask\n", fcf_index);
+
return 0;
}
/**
- * lpfc_sli4_fcf_rr_index_set - Clear bmask from eligible fcf record index
+ * lpfc_sli4_fcf_rr_index_clear - Clear bmask from eligible fcf record index
* @phba: pointer to lpfc hba data structure.
*
* This routine clears the FCF record index from the eligible bmask for
@@ -12384,6 +12509,10 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
}
/* Clear the eligible FCF record index bmask */
clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2791 Clear FCF index x%x from round robin failover "
+ "bmask\n", fcf_index);
}
/**
@@ -12446,7 +12575,7 @@ lpfc_mbx_cmpl_redisc_fcf_table(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
}
/**
- * lpfc_sli4_redisc_all_fcf - Request to rediscover entire FCF table by port.
+ * lpfc_sli4_redisc_fcf_table - Request to rediscover entire FCF table by port.
* @phba: pointer to lpfc hba data structure.
*
* This routine is invoked to request for rediscovery of the entire FCF table
@@ -12662,6 +12791,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
LPFC_MBOXQ_t *mb, *nextmb;
struct lpfc_dmabuf *mp;
struct lpfc_nodelist *ndlp;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
@@ -12673,6 +12803,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
continue;
if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ __lpfc_sli4_free_rpi(phba,
+ mb->u.mb.un.varRegLogin.rpi);
mp = (struct lpfc_dmabuf *) (mb->context1);
if (mp) {
__lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -12680,6 +12813,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
}
ndlp = (struct lpfc_nodelist *) mb->context2;
if (ndlp) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+ spin_unlock_irq(shost->host_lock);
lpfc_nlp_put(ndlp);
mb->context2 = NULL;
}
@@ -12695,6 +12831,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
ndlp = (struct lpfc_nodelist *) mb->context2;
if (ndlp) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+ spin_unlock_irq(shost->host_lock);
lpfc_nlp_put(ndlp);
mb->context2 = NULL;
}
@@ -12705,3 +12844,85 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
spin_unlock_irq(&phba->hbalock);
}
+/**
+ * lpfc_drain_txq - Drain the txq
+ * @phba: Pointer to HBA context object.
+ *
+ * This function attempt to submit IOCBs on the txq
+ * to the adapter. For SLI4 adapters, the txq contains
+ * ELS IOCBs that have been deferred because the there
+ * are no SGLs. This congestion can occur with large
+ * vport counts during node discovery.
+ **/
+
+uint32_t
+lpfc_drain_txq(struct lpfc_hba *phba)
+{
+ LIST_HEAD(completions);
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ struct lpfc_iocbq *piocbq = 0;
+ unsigned long iflags = 0;
+ char *fail_msg = NULL;
+ struct lpfc_sglq *sglq;
+ union lpfc_wqe wqe;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ if (pring->txq_cnt > pring->txq_max)
+ pring->txq_max = pring->txq_cnt;
+
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+ while (pring->txq_cnt) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
+
+ sglq = __lpfc_sli_get_sglq(phba);
+ if (!sglq) {
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ break;
+ } else {
+ piocbq = lpfc_sli_ringtx_get(phba, pring);
+ if (!piocbq) {
+ /* The txq_cnt out of sync. This should
+ * never happen
+ */
+ sglq = __lpfc_clear_active_sglq(phba,
+ sglq->sli4_xritag);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2823 txq empty and txq_cnt is %d\n ",
+ pring->txq_cnt);
+ break;
+ }
+ }
+
+ /* The xri and iocb resources secured,
+ * attempt to issue request
+ */
+ piocbq->sli4_xritag = sglq->sli4_xritag;
+ if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq))
+ fail_msg = "to convert bpl to sgl";
+ else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe))
+ fail_msg = "to convert iocb to wqe";
+ else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe))
+ fail_msg = " - Wq is full";
+ else
+ lpfc_sli_ringtxcmpl_put(phba, pring, piocbq);
+
+ if (fail_msg) {
+ /* Failed means we can't issue and need to cancel */
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2822 IOCB failed %s iotag 0x%x "
+ "xri 0x%x\n",
+ fail_msg,
+ piocbq->iotag, piocbq->sli4_xritag);
+ list_add_tail(&piocbq->list, &completions);
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ }
+
+ /* Cancel all the IOCBs that cannot be issued */
+ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
+ IOERR_SLI_ABORTED);
+
+ return pring->txq_cnt;
+}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index e3792151ca06..cd56d6cce6c3 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -48,6 +48,7 @@ struct lpfc_iocbq {
/* lpfc_iocbqs are used in double linked lists */
struct list_head list;
struct list_head clist;
+ struct list_head dlist;
uint16_t iotag; /* pre-assigned IO tag */
uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */
struct lpfc_cq_event cq_event;
@@ -64,6 +65,7 @@ struct lpfc_iocbq {
#define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */
#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */
#define DSS_SECURITY_OP 0x100 /* security IO */
+#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */
#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
#define LPFC_FIP_ELS_ID_SHIFT 14
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 58bb4c81b54e..a3b24d99a2a7 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -51,6 +51,9 @@
#define LPFC_FCOE_FCF_GET_FIRST 0xFFFF
#define LPFC_FCOE_FCF_NEXT_NONE 0xFFFF
+#define LPFC_FCOE_NULL_VID 0xFFF
+#define LPFC_FCOE_IGNORE_VID 0xFFFF
+
/* First 3 bytes of default FCF MAC is specified by FC_MAP */
#define LPFC_FCOE_FCF_MAC3 0xFF
#define LPFC_FCOE_FCF_MAC4 0xFF
@@ -58,7 +61,7 @@
#define LPFC_FCOE_FCF_MAP0 0x0E
#define LPFC_FCOE_FCF_MAP1 0xFC
#define LPFC_FCOE_FCF_MAP2 0x00
-#define LPFC_FCOE_MAX_RCV_SIZE 0x5AC
+#define LPFC_FCOE_MAX_RCV_SIZE 0x800
#define LPFC_FCOE_FKA_ADV_PER 0
#define LPFC_FCOE_FIP_PRIORITY 0x80
@@ -160,6 +163,7 @@ struct lpfc_fcf {
#define FCF_REDISC_PEND 0x80 /* FCF rediscovery pending */
#define FCF_REDISC_EVT 0x100 /* FCF rediscovery event to worker thread */
#define FCF_REDISC_FOV 0x200 /* Post FCF rediscovery fast failover */
+#define FCF_REDISC_RRU 0x400 /* Roundrobin bitmap updated */
uint32_t addr_mode;
uint16_t fcf_rr_init_indx;
uint32_t eligible_fcf_cnt;
@@ -382,6 +386,7 @@ struct lpfc_sli4_hba {
struct lpfc_pc_sli4_params pc_sli4_params;
struct msix_entry *msix_entries;
uint32_t cfg_eqn;
+ uint32_t msix_vec_nr;
struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */
/* Pointers to the constructed SLI4 queues */
struct lpfc_queue **fp_eq; /* Fast-path event queue */
@@ -524,6 +529,7 @@ int lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *);
struct lpfc_rpi_hdr *lpfc_sli4_create_rpi_hdr(struct lpfc_hba *);
void lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *);
int lpfc_sli4_alloc_rpi(struct lpfc_hba *);
+void __lpfc_sli4_free_rpi(struct lpfc_hba *, int);
void lpfc_sli4_free_rpi(struct lpfc_hba *, int);
void lpfc_sli4_remove_rpis(struct lpfc_hba *);
void lpfc_sli4_async_event_proc(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 5294c3a515a1..d28830af71d8 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.12"
+#define LPFC_DRIVER_VERSION "8.3.15"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index ab91359bde20..1655507a682c 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -782,7 +782,7 @@ lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports)
int i;
if (vports == NULL)
return;
- for (i = 0; vports[i] != NULL && i <= phba->max_vports; i++)
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
scsi_host_put(lpfc_shost_from_vport(vports[i]));
kfree(vports);
}