aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/lpfc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r--drivers/scsi/lpfc/lpfc.h17
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c262
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c5
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h14
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c53
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c10
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c76
-rwxr-xr-x[-rw-r--r--]drivers/scsi/lpfc/lpfc_hbadisc.c129
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h34
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h131
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c515
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c35
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c7
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c394
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c1240
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h27
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h34
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c4
20 files changed, 1999 insertions, 995 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index aa10f795163..1cc23a69db5 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -109,7 +109,8 @@ struct hbq_dmabuf {
struct lpfc_dmabuf dbuf;
uint32_t size;
uint32_t tag;
- struct lpfc_rcqe rcqe;
+ struct lpfc_cq_event cq_event;
+ unsigned long time_stamp;
};
/* Priority bit. Set value to exceed low water mark in lpfc_mem. */
@@ -201,6 +202,7 @@ struct lpfc_stats {
uint32_t elsRcvLIRR;
uint32_t elsRcvRPS;
uint32_t elsRcvRPL;
+ uint32_t elsRcvRRQ;
uint32_t elsXmitFLOGI;
uint32_t elsXmitFDISC;
uint32_t elsXmitPLOGI;
@@ -289,8 +291,8 @@ struct lpfc_vport {
uint16_t vpi;
uint16_t vfi;
- uint8_t vfi_state;
-#define LPFC_VFI_REGISTERED 0x1
+ uint8_t vpi_state;
+#define LPFC_VPI_REGISTERED 0x1
uint32_t fc_flag; /* FC flags */
/* Several of these flags are HBA centric and should be moved to
@@ -405,6 +407,7 @@ struct lpfc_vport {
uint8_t stat_data_enabled;
uint8_t stat_data_blocked;
struct list_head rcv_buffer_list;
+ unsigned long rcv_buffer_time_stamp;
uint32_t vport_flag;
#define STATIC_VPORT 1
};
@@ -527,13 +530,16 @@ struct lpfc_hba {
#define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */
#define DEFER_ERATT 0x2 /* Deferred error attention in progress */
#define HBA_FCOE_SUPPORT 0x4 /* HBA function supports FCOE */
-#define HBA_RECEIVE_BUFFER 0x8 /* Rcv buffer posted to worker thread */
+#define HBA_SP_QUEUE_EVT 0x8 /* Slow-path qevt posted to worker thread*/
#define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */
#define FCP_XRI_ABORT_EVENT 0x20
#define ELS_XRI_ABORT_EVENT 0x40
#define ASYNC_EVENT 0x80
#define LINK_DISABLED 0x100 /* Link disabled by user */
#define FCF_DISC_INPROGRESS 0x200 /* FCF discovery in progress */
+#define HBA_FIP_SUPPORT 0x400 /* FIP support in HBA */
+#define HBA_AER_ENABLED 0x800 /* AER enabled with HBA */
+ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
struct lpfc_dmabuf slim2p;
MAILBOX_t *mbox;
@@ -551,6 +557,7 @@ struct lpfc_hba {
uint8_t fc_linkspeed; /* Link speed after last READ_LA */
uint32_t fc_eventTag; /* event tag for link attention */
+ uint32_t link_events;
/* These fields used to be binfo */
uint32_t fc_pref_DID; /* preferred D_ID */
@@ -604,8 +611,8 @@ struct lpfc_hba {
uint32_t cfg_enable_hba_reset;
uint32_t cfg_enable_hba_heartbeat;
uint32_t cfg_enable_bg;
- uint32_t cfg_enable_fip;
uint32_t cfg_log_verbose;
+ uint32_t cfg_aer_support;
lpfc_vpd_t vpd; /* vital product data */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index e1a30a16a9f..75523603b91 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -23,12 +23,14 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/aer.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport_fc.h>
+#include <scsi/fc/fc_fs.h>
#include "lpfc_hw4.h"
#include "lpfc_hw.h"
@@ -98,6 +100,28 @@ lpfc_drvr_version_show(struct device *dev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n");
}
+/**
+ * lpfc_enable_fip_show - Return the fip mode of the HBA
+ * @dev: class unused variable.
+ * @attr: device attribute, not used.
+ * @buf: on return contains the module description text.
+ *
+ * Returns: size of formatted string.
+ **/
+static ssize_t
+lpfc_enable_fip_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
+ if (phba->hba_flag & HBA_FIP_SUPPORT)
+ return snprintf(buf, PAGE_SIZE, "1\n");
+ else
+ return snprintf(buf, PAGE_SIZE, "0\n");
+}
+
static ssize_t
lpfc_bg_info_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -762,9 +786,15 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr,
} else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0)
- status = lpfc_do_offline(phba, LPFC_EVT_WARM_START);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ return -EINVAL;
+ else
+ status = lpfc_do_offline(phba, LPFC_EVT_WARM_START);
else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
- status = lpfc_do_offline(phba, LPFC_EVT_KILL);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ return -EINVAL;
+ else
+ status = lpfc_do_offline(phba, LPFC_EVT_KILL);
else
return -EINVAL;
@@ -1126,6 +1156,9 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr,
if ((val & 0x3) != val)
return -EINVAL;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ val = 0;
+
spin_lock_irq(&phba->hbalock);
old_val = phba->cfg_poll;
@@ -1589,6 +1622,7 @@ static DEVICE_ATTR(num_discovered_ports, S_IRUGO,
static DEVICE_ATTR(menlo_mgmt_mode, S_IRUGO, lpfc_mlomgmt_show, NULL);
static DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL);
static DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show, NULL);
+static DEVICE_ATTR(lpfc_enable_fip, S_IRUGO, lpfc_enable_fip_show, NULL);
static DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
lpfc_board_mode_show, lpfc_board_mode_store);
static DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
@@ -2759,6 +2793,196 @@ static DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR,
lpfc_link_speed_show, lpfc_link_speed_store);
/*
+# lpfc_aer_support: Support PCIe device Advanced Error Reporting (AER)
+# 0 = aer disabled or not supported
+# 1 = aer supported and enabled (default)
+# Value range is [0,1]. Default value is 1.
+*/
+
+/**
+ * lpfc_aer_support_store - Set the adapter for aer support
+ *
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: containing the string "selective".
+ * @count: unused variable.
+ *
+ * Description:
+ * If the val is 1 and currently the device's AER capability was not
+ * enabled, invoke the kernel's enable AER helper routine, trying to
+ * enable the device's AER capability. If the helper routine enabling
+ * AER returns success, update the device's cfg_aer_support flag to
+ * indicate AER is supported by the device; otherwise, if the device
+ * AER capability is already enabled to support AER, then do nothing.
+ *
+ * If the val is 0 and currently the device's AER support was enabled,
+ * invoke the kernel's disable AER helper routine. After that, update
+ * the device's cfg_aer_support flag to indicate AER is not supported
+ * by the device; otherwise, if the device AER capability is already
+ * disabled from supporting AER, then do nothing.
+ *
+ * Returns:
+ * length of the buf on success if val is in range the intended mode
+ * is supported.
+ * -EINVAL if val out of range or intended mode is not supported.
+ **/
+static ssize_t
+lpfc_aer_support_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+ 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)
+ return -EINVAL;
+
+ switch (val) {
+ case 0:
+ if (phba->hba_flag & HBA_AER_ENABLED) {
+ rc = pci_disable_pcie_error_reporting(phba->pcidev);
+ if (!rc) {
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag &= ~HBA_AER_ENABLED;
+ spin_unlock_irq(&phba->hbalock);
+ phba->cfg_aer_support = 0;
+ rc = strlen(buf);
+ } else
+ rc = -EPERM;
+ } else {
+ phba->cfg_aer_support = 0;
+ rc = strlen(buf);
+ }
+ break;
+ case 1:
+ if (!(phba->hba_flag & HBA_AER_ENABLED)) {
+ rc = pci_enable_pcie_error_reporting(phba->pcidev);
+ if (!rc) {
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag |= HBA_AER_ENABLED;
+ spin_unlock_irq(&phba->hbalock);
+ phba->cfg_aer_support = 1;
+ rc = strlen(buf);
+ } else
+ rc = -EPERM;
+ } else {
+ phba->cfg_aer_support = 1;
+ rc = strlen(buf);
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static int lpfc_aer_support = 1;
+module_param(lpfc_aer_support, int, 1);
+MODULE_PARM_DESC(lpfc_aer_support, "Enable PCIe device AER support");
+lpfc_param_show(aer_support)
+
+/**
+ * lpfc_aer_support_init - Set the initial adapters aer support flag
+ * @phba: lpfc_hba pointer.
+ * @val: link speed value.
+ *
+ * Description:
+ * If val is in a valid range [0,1], then set the adapter's initial
+ * cfg_aer_support field. It will be up to the driver's probe_one
+ * routine to determine whether the device's AER support can be set
+ * or not.
+ *
+ * Notes:
+ * If the value is not in range log a kernel error message, and
+ * choose the default value of setting AER support and return.
+ *
+ * Returns:
+ * zero if val saved.
+ * -EINVAL val out of range
+ **/
+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;
+ }
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2712 lpfc_aer_support attribute value %d out "
+ "of range, allowed values are 0|1, setting it "
+ "to default value of 1\n", val);
+ /* By default, try to enable AER on a device */
+ phba->cfg_aer_support = 1;
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(lpfc_aer_support, S_IRUGO | S_IWUSR,
+ lpfc_aer_support_show, lpfc_aer_support_store);
+
+/**
+ * lpfc_aer_cleanup_state - Clean up aer state to the aer enabled device
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: containing the string "selective".
+ * @count: unused variable.
+ *
+ * Description:
+ * If the @buf contains 1 and the device currently has the AER support
+ * enabled, then invokes the kernel AER helper routine
+ * pci_cleanup_aer_uncorrect_error_status to clean up the uncorrectable
+ * error status register.
+ *
+ * Notes:
+ *
+ * Returns:
+ * -EINVAL if the buf does not contain the 1 or the device is not currently
+ * enabled with the AER support.
+ **/
+static ssize_t
+lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ 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)
+ return -EINVAL;
+ if (val != 1)
+ return -EINVAL;
+
+ if (phba->hba_flag & HBA_AER_ENABLED)
+ rc = pci_cleanup_aer_uncorrect_error_status(phba->pcidev);
+
+ if (rc == 0)
+ return strlen(buf);
+ else
+ return -EPERM;
+}
+
+static DEVICE_ATTR(lpfc_aer_state_cleanup, S_IWUSR, NULL,
+ lpfc_aer_cleanup_state);
+
+/*
# lpfc_fcp_class: Determines FC class to use for the FCP protocol.
# Value range is [2,3]. Default value is 3.
*/
@@ -2846,7 +3070,7 @@ LPFC_ATTR_R(multi_ring_support, 1, 1, 2, "Determines number of primary "
# identifies what rctl value to configure the additional ring for.
# Value range is [1,0xff]. Default value is 4 (Unsolicated Data).
*/
-LPFC_ATTR_R(multi_ring_rctl, FC_UNSOL_DATA, 1,
+LPFC_ATTR_R(multi_ring_rctl, FC_RCTL_DD_UNSOL_DATA, 1,
255, "Identifies RCTL for additional ring configuration");
/*
@@ -2854,7 +3078,7 @@ LPFC_ATTR_R(multi_ring_rctl, FC_UNSOL_DATA, 1,
# identifies what type value to configure the additional ring for.
# Value range is [1,0xff]. Default value is 5 (LLC/SNAP).
*/
-LPFC_ATTR_R(multi_ring_type, FC_LLC_SNAP, 1,
+LPFC_ATTR_R(multi_ring_type, FC_TYPE_IP, 1,
255, "Identifies TYPE for additional ring configuration");
/*
@@ -2947,15 +3171,6 @@ LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat.");
LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support");
/*
-# lpfc_enable_fip: When set, FIP is required to start discovery. If not
-# set, the driver will add an FCF record manually if the port has no
-# FCF records available and start discovery.
-# Value range is [0,1]. Default value is 1 (enabled)
-*/
-LPFC_ATTR_RW(enable_fip, 0, 0, 1, "Enable FIP Discovery");
-
-
-/*
# lpfc_prot_mask: i
# - Bit mask of host protection capabilities used to register with the
# SCSI mid-layer
@@ -3013,6 +3228,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_num_discovered_ports,
&dev_attr_menlo_mgmt_mode,
&dev_attr_lpfc_drvr_version,
+ &dev_attr_lpfc_enable_fip,
&dev_attr_lpfc_temp_sensor,
&dev_attr_lpfc_log_verbose,
&dev_attr_lpfc_lun_queue_depth,
@@ -3020,7 +3236,6 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_peer_port_login,
&dev_attr_lpfc_nodev_tmo,
&dev_attr_lpfc_devloss_tmo,
- &dev_attr_lpfc_enable_fip,
&dev_attr_lpfc_fcp_class,
&dev_attr_lpfc_use_adisc,
&dev_attr_lpfc_ack0,
@@ -3061,6 +3276,8 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_max_scsicmpl_time,
&dev_attr_lpfc_stat_data_ctrl,
&dev_attr_lpfc_prot_sg_seg_cnt,
+ &dev_attr_lpfc_aer_support,
+ &dev_attr_lpfc_aer_state_cleanup,
NULL,
};
@@ -3073,7 +3290,6 @@ struct device_attribute *lpfc_vport_attrs[] = {
&dev_attr_lpfc_lun_queue_depth,
&dev_attr_lpfc_nodev_tmo,
&dev_attr_lpfc_devloss_tmo,
- &dev_attr_lpfc_enable_fip,
&dev_attr_lpfc_hba_queue_depth,
&dev_attr_lpfc_peer_port_login,
&dev_attr_lpfc_restrict_login,
@@ -3815,7 +4031,11 @@ lpfc_get_stats(struct Scsi_Host *shost)
hs->invalid_crc_count -= lso->invalid_crc_count;
hs->error_frames -= lso->error_frames;
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->hba_flag & HBA_FCOE_SUPPORT) {
+ hs->lip_count = -1;
+ hs->nos_count = (phba->link_events >> 1);
+ hs->nos_count -= lso->link_events;
+ } else if (phba->fc_topology == TOPOLOGY_LOOP) {
hs->lip_count = (phba->fc_eventTag >> 1);
hs->lip_count -= lso->link_events;
hs->nos_count = -1;
@@ -3906,7 +4126,10 @@ lpfc_reset_stats(struct Scsi_Host *shost)
lso->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord;
lso->invalid_crc_count = pmb->un.varRdLnk.crcCnt;
lso->error_frames = pmb->un.varRdLnk.crcCnt;
- lso->link_events = (phba->fc_eventTag >> 1);
+ if (phba->hba_flag & HBA_FCOE_SUPPORT)
+ lso->link_events = (phba->link_events >> 1);
+ else
+ lso->link_events = (phba->fc_eventTag >> 1);
psli->stats_start = get_seconds();
@@ -4222,14 +4445,17 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
lpfc_enable_bg_init(phba, lpfc_enable_bg);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ phba->cfg_poll = 0;
+ else
phba->cfg_poll = lpfc_poll;
phba->cfg_soft_wwnn = 0L;
phba->cfg_soft_wwpn = 0L;
lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
lpfc_prot_sg_seg_cnt_init(phba, lpfc_prot_sg_seg_cnt);
lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
- lpfc_enable_fip_init(phba, lpfc_enable_fip);
lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
+ lpfc_aer_support_init(phba, lpfc_aer_support);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index da6bf5aac9d..a5d9048235d 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -26,6 +26,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_bsg_fc.h>
+#include <scsi/fc/fc_fs.h>
#include "lpfc_hw4.h"
#include "lpfc_hw.h"
@@ -148,8 +149,8 @@ lpfc_bsg_rport_ct(struct fc_bsg_job *job)
cmd->ulpCommand = CMD_GEN_REQUEST64_CR;
cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
cmd->un.genreq64.w5.hcsw.Dfctl = 0;
- cmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL;
- cmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP;
+ cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
+ cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT;
cmd->ulpBdeCount = 1;
cmd->ulpLe = 1;
cmd->ulpClass = CLASS3;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 0830f37409a..650494d622c 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -49,6 +49,8 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *);
struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
+void lpfc_cleanup_rcv_buffers(struct lpfc_vport *);
+void lpfc_rcv_seq_check_edtov(struct lpfc_vport *);
void lpfc_cleanup_rpis(struct lpfc_vport *, int);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_linkdown_port(struct lpfc_vport *);
@@ -144,6 +146,8 @@ void lpfc_hb_timeout_handler(struct lpfc_hba *);
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
+void lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
+ struct lpfc_iocbq *);
int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
void lpfc_fdmi_tmo(unsigned long);
@@ -188,7 +192,7 @@ int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
void lpfc_init_vfi(struct lpfcMboxq *, struct lpfc_vport *);
void lpfc_reg_vfi(struct lpfcMboxq *, struct lpfc_vport *, dma_addr_t);
void lpfc_init_vpi(struct lpfc_hba *, struct lpfcMboxq *, uint16_t);
-void lpfc_unreg_vfi(struct lpfcMboxq *, uint16_t);
+void lpfc_unreg_vfi(struct lpfcMboxq *, struct lpfc_vport *);
void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *);
void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t);
void lpfc_resume_rpi(struct lpfcMboxq *, struct lpfc_nodelist *);
@@ -212,7 +216,10 @@ void lpfc_stop_vport_timers(struct lpfc_vport *);
void lpfc_poll_timeout(unsigned long ptr);
void lpfc_poll_start_timer(struct lpfc_hba *);
void lpfc_poll_eratt(unsigned long);
-void lpfc_sli_poll_fcp_ring(struct lpfc_hba *);
+int
+lpfc_sli_handle_fast_ring_event(struct lpfc_hba *,
+ struct lpfc_sli_ring *, uint32_t);
+
struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *);
uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *);
@@ -235,7 +242,7 @@ void lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *);
int lpfc_sli_check_eratt(struct lpfc_hba *);
void lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
struct lpfc_sli_ring *, uint32_t);
-int lpfc_sli4_handle_received_buffer(struct lpfc_hba *);
+void lpfc_sli4_handle_received_buffer(struct lpfc_hba *, struct hbq_dmabuf *);
void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
struct lpfc_iocbq *, uint32_t);
@@ -361,6 +368,7 @@ void lpfc_stop_port(struct lpfc_hba *);
void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t);
int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
void lpfc_start_fdiscs(struct lpfc_hba *phba);
+struct lpfc_vport *lpfc_find_vport_by_vpid(struct lpfc_hba *, uint16_t);
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
#define HBA_EVENT_RSCN 5
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 9a1bd9534d7..0ebcd9baca7 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -31,6 +31,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
+#include <scsi/fc/fc_fs.h>
#include "lpfc_hw4.h"
#include "lpfc_hw.h"
@@ -87,7 +88,6 @@ void
lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocbq)
{
-
struct lpfc_dmabuf *mp = NULL;
IOCB_t *icmd = &piocbq->iocb;
int i;
@@ -160,6 +160,39 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
}
+/**
+ * lpfc_sli4_ct_abort_unsol_event - Default handle for sli4 unsol abort
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to the driver internal I/O ring.
+ * @piocbq: Pointer to the IOCBQ.
+ *
+ * This function serves as the default handler for the sli4 unsolicited
+ * abort event. It shall be invoked when there is no application interface
+ * registered unsolicited abort handler. This handler does nothing but
+ * just simply releases the dma buffer used by the unsol abort event.
+ **/
+void
+lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocbq)
+{
+ IOCB_t *icmd = &piocbq->iocb;
+ struct lpfc_dmabuf *bdeBuf;
+ uint32_t size;
+
+ /* Forward abort event to any process registered to receive ct event */
+ lpfc_bsg_ct_unsol_event(phba, pring, piocbq);
+
+ /* If there is no BDE associated with IOCB, there is nothing to do */
+ if (icmd->ulpBdeCount == 0)
+ return;
+ bdeBuf = piocbq->context2;
+ piocbq->context2 = NULL;
+ size = icmd->un.cont64[0].tus.f.bdeSize;
+ lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
+ lpfc_in_buf_free(phba, bdeBuf);
+}
+
static void
lpfc_free_ct_rsp(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist)
{
@@ -304,8 +337,8 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
/* Fill in rest of iocb */
icmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
icmd->un.genreq64.w5.hcsw.Dfctl = 0;
- icmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL;
- icmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP;
+ icmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
+ icmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT;
if (!tmo) {
/* FC spec states we need 3 * ratov for CT requests */
@@ -363,9 +396,14 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
outmp = lpfc_alloc_ct_rsp(phba, cmdcode, bpl, rsp_size, &cnt);
if (!outmp)
return -ENOMEM;
-
+ /*
+ * Form the CT IOCB. The total number of BDEs in this IOCB
+ * is the single command plus response count from
+ * lpfc_alloc_ct_rsp.
+ */
+ cnt += 1;
status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0,
- cnt+1, 0, retry);
+ cnt, 0, retry);
if (status) {
lpfc_free_ct_rsp(phba, outmp);
return -ENOMEM;
@@ -501,6 +539,9 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
SLI_CTNS_GFF_ID,
0, Did) == 0)
vport->num_disc_nodes++;
+ else
+ lpfc_setup_disc_node
+ (vport, Did);
}
else {
lpfc_debugfs_disc_trc(vport,
@@ -1209,7 +1250,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
be16_to_cpu(SLI_CTNS_RFF_ID);
CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);
CtReq->un.rff.fbits = FC4_FEATURE_INIT;
- CtReq->un.rff.type_code = FC_FCP_DATA;
+ CtReq->un.rff.type_code = FC_TYPE_FCP;
cmpl = lpfc_cmpl_ct_cmd_rff_id;
break;
}
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 8d0f0de76b6..391584183d8 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -926,7 +926,7 @@ lpfc_debugfs_dumpData_open(struct inode *inode, struct file *file)
goto out;
/* Round to page boundry */
- printk(KERN_ERR "BLKGRD %s: _dump_buf_data=0x%p\n",
+ printk(KERN_ERR "9059 BLKGRD: %s: _dump_buf_data=0x%p\n",
__func__, _dump_buf_data);
debug->buffer = _dump_buf_data;
if (!debug->buffer) {
@@ -956,8 +956,8 @@ lpfc_debugfs_dumpDif_open(struct inode *inode, struct file *file)
goto out;
/* Round to page boundry */
- printk(KERN_ERR "BLKGRD %s: _dump_buf_dif=0x%p file=%s\n", __func__,
- _dump_buf_dif, file->f_dentry->d_name.name);
+ printk(KERN_ERR "9060 BLKGRD: %s: _dump_buf_dif=0x%p file=%s\n",
+ __func__, _dump_buf_dif, file->f_dentry->d_name.name);
debug->buffer = _dump_buf_dif;
if (!debug->buffer) {
kfree(debug);
@@ -1377,7 +1377,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
debugfs_create_dir(name, phba->hba_debugfs_root);
if (!vport->vport_debugfs_root) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
- "0417 Cant create debugfs");
+ "0417 Cant create debugfs\n");
goto debug_failed;
}
atomic_inc(&phba->debugfs_vport_count);
@@ -1430,7 +1430,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
vport, &lpfc_debugfs_op_nodelist);
if (!vport->debug_nodelist) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
- "0409 Cant create debugfs nodelist");
+ "0409 Cant create debugfs nodelist\n");
goto debug_failed;
}
debug_failed:
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 1142070e948..2851d75ffc6 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -19,7 +19,7 @@
*******************************************************************/
#define FC_MAX_HOLD_RSCN 32 /* max number of deferred RSCNs */
-#define FC_MAX_NS_RSP 65536 /* max size NameServer rsp */
+#define FC_MAX_NS_RSP 64512 /* max size NameServer rsp */
#define FC_MAXLOOP 126 /* max devices supported on a fc loop */
#define LPFC_DISC_FLOGI_TMO 10 /* Discovery FLOGI ratov */
@@ -105,8 +105,6 @@ struct lpfc_nodelist {
struct lpfc_vport *vport;
struct lpfc_work_evt els_retry_evt;
struct lpfc_work_evt dev_loss_evt;
- unsigned long last_ramp_up_time; /* jiffy of last ramp up */
- unsigned long last_q_full_time; /* jiffy of last queue full */
struct kref kref;
atomic_t cmd_pending;
uint32_t cmd_qdepth;
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 45337cd23fe..a079bbc03cf 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -173,13 +173,26 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
* in FIP mode send FLOGI, FDISC and LOGO as FIP frames.
*/
if ((did == Fabric_DID) &&
- bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags) &&
+ (phba->hba_flag & HBA_FIP_SUPPORT) &&
((elscmd == ELS_CMD_FLOGI) ||
(elscmd == ELS_CMD_FDISC) ||
(elscmd == ELS_CMD_LOGO)))
- elsiocb->iocb_flag |= LPFC_FIP_ELS;
+ switch (elscmd) {
+ case ELS_CMD_FLOGI:
+ elsiocb->iocb_flag |= ((ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT)
+ & LPFC_FIP_ELS_ID_MASK);
+ break;
+ case ELS_CMD_FDISC:
+ elsiocb->iocb_flag |= ((ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT)
+ & LPFC_FIP_ELS_ID_MASK);
+ break;
+ case ELS_CMD_LOGO:
+ elsiocb->iocb_flag |= ((ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT)
+ & LPFC_FIP_ELS_ID_MASK);
+ break;
+ }
else
- elsiocb->iocb_flag &= ~LPFC_FIP_ELS;
+ elsiocb->iocb_flag &= ~LPFC_FIP_ELS_ID_MASK;
icmd = &elsiocb->iocb;
@@ -591,7 +604,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
} else {
ndlp->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
- if (vport->vfi_state & LPFC_VFI_REGISTERED) {
+ if (vport->vpi_state & LPFC_VPI_REGISTERED) {
lpfc_start_fdiscs(phba);
lpfc_do_scr_ns_plogi(phba, vport);
} else
@@ -2452,6 +2465,7 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
*/
del_timer_sync(&ndlp->nlp_delayfunc);
retry = ndlp->nlp_retry;
+ ndlp->nlp_retry = 0;
switch (cmd) {
case ELS_CMD_FLOGI:
@@ -2711,12 +2725,16 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
!lpfc_error_lost_link(irsp)) {
/* FLOGI retry policy */
retry = 1;
- maxretry = 48;
- if (cmdiocb->retry >= 32)
+ /* retry forever */
+ maxretry = 0;
+ if (cmdiocb->retry >= 100)
+ delay = 5000;
+ else if (cmdiocb->retry >= 32)
delay = 1000;
}
- if ((++cmdiocb->retry) >= maxretry) {
+ cmdiocb->retry++;
+ if (maxretry && (cmdiocb->retry >= maxretry)) {
phba->fc_stat.elsRetryExceeded++;
retry = 0;
}
@@ -4503,6 +4521,29 @@ lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
}
/**
+ * lpfc_els_rcv_rrq - Process an unsolicited rrq iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * This routine processes a Reinstate Recovery Qualifier (RRQ) IOCB
+ * received as an ELS unsolicited event. A request to RRQ shall only
+ * be accepted if the Originator Nx_Port N_Port_ID or the Responder
+ * Nx_Port N_Port_ID of the target Exchange is the same as the
+ * N_Port_ID of the Nx_Port that makes the request. If the RRQ is
+ * not accepted, an LS_RJT with reason code "Unable to perform
+ * command request" and reason code explanation "Invalid Originator
+ * S_ID" shall be returned. For now, we just unconditionally accept
+ * RRQ from the target.
+ **/
+static void
+lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
+{
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+}
+
+/**
* lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd
* @phba: pointer to lpfc hba data structure.
* @pmb: pointer to the driver internal queue element for mailbox command.
@@ -5396,7 +5437,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (lpfc_els_chk_latt(vport))
goto dropit;
- /* Ignore traffic recevied during vport shutdown. */
+ /* Ignore traffic received during vport shutdown. */
if (vport->load_flag & FC_UNLOADING)
goto dropit;
@@ -5618,6 +5659,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (newnode)
lpfc_nlp_put(ndlp);
break;
+ case ELS_CMD_RRQ:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RRQ: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
+ phba->fc_stat.elsRcvRRQ++;
+ lpfc_els_rcv_rrq(vport, elsiocb, ndlp);
+ if (newnode)
+ lpfc_nlp_put(ndlp);
+ break;
default:
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
"RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
@@ -5670,7 +5721,7 @@ dropit:
* NULL - No vport with the matching @vpi found
* Otherwise - Address to the vport with the matching @vpi.
**/
-static struct lpfc_vport *
+struct lpfc_vport *
lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
{
struct lpfc_vport *vport;
@@ -6024,11 +6075,6 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
irsp->ulpStatus, irsp->un.ulpWord[4]);
goto fdisc_failed;
}
- if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
- lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_nlp_put(ndlp