#include "lpfc_compat.h"
#include "lpfc_crtn.h"
+#define LPFC_DEF_DEVLOSS_TMO 30
+#define LPFC_MIN_DEVLOSS_TMO 1
+#define LPFC_MAX_DEVLOSS_TMO 255
static void
lpfc_jedec_to_ascii(int incr, char hdw[])
return -ENOMEM;
memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
- lpfc_init_link(phba, pmboxq, phba->cfg_topology, phba->cfg_link_speed);
- mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+ pmboxq->mb.mbxCommand = MBX_DOWN_LINK;
+ pmboxq->mb.mbxOwner = OWN_HOST;
+
+ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2);
+
+ if ((mbxstatus == MBX_SUCCESS) && (pmboxq->mb.mbxStatus == 0)) {
+ memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
+ lpfc_init_link(phba, pmboxq, phba->cfg_topology,
+ phba->cfg_link_speed);
+ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq,
+ phba->fc_ratov * 2);
+ }
if (mbxstatus == MBX_TIMEOUT)
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
return 0;
}
-static ssize_t
-lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
+static int
+lpfc_selective_reset(struct lpfc_hba *phba)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
+ struct completion online_compl;
+ int status = 0;
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_OFFLINE);
+ wait_for_completion(&online_compl);
+
+ if (status != 0)
+ return -EIO;
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_ONLINE);
+ wait_for_completion(&online_compl);
+
+ if (status != 0)
+ return -EIO;
+
+ return 0;
}
static ssize_t
-lpfc_board_online_show(struct class_device *cdev, char *buf)
+lpfc_issue_reset(struct class_device *cdev, const char *buf, size_t count)
{
struct Scsi_Host *host = class_to_shost(cdev);
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ int status = -EINVAL;
- if (phba->fc_flag & FC_OFFLINE_MODE)
- return snprintf(buf, PAGE_SIZE, "0\n");
+ if (strncmp(buf, "selective", sizeof("selective") - 1) == 0)
+ status = lpfc_selective_reset(phba);
+
+ if (status == 0)
+ return strlen(buf);
else
- return snprintf(buf, PAGE_SIZE, "1\n");
+ return status;
}
static ssize_t
-lpfc_board_online_store(struct class_device *cdev, const char *buf,
- size_t count)
+lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- struct completion online_compl;
- int val=0, status=0;
-
- if (sscanf(buf, "%d", &val) != 1)
- return -EINVAL;
-
- init_completion(&online_compl);
-
- if (val)
- lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_ONLINE);
- else
- lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_OFFLINE);
- wait_for_completion(&online_compl);
- if (!status)
- return strlen(buf);
- else
- return -EIO;
+ return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
}
static ssize_t
NULL);
static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show,
NULL);
-static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR,
- lpfc_board_online_show, lpfc_board_online_store);
static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
lpfc_board_mode_show, lpfc_board_mode_store);
+static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
+
+
+static char *lpfc_soft_wwpn_key = "C99G71SL8032A";
+
+static ssize_t
+lpfc_soft_wwpn_enable_store(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ unsigned int cnt = count;
+
+ /*
+ * We're doing a simple sanity check for soft_wwpn setting.
+ * We require that the user write a specific key to enable
+ * the soft_wwpn attribute to be settable. Once the attribute
+ * is written, the enable key resets. If further updates are
+ * desired, the key must be written again to re-enable the
+ * attribute.
+ *
+ * The "key" is not secret - it is a hardcoded string shown
+ * here. The intent is to protect against the random user or
+ * application that is just writing attributes.
+ */
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ if ((cnt != strlen(lpfc_soft_wwpn_key)) ||
+ (strncmp(buf, lpfc_soft_wwpn_key, strlen(lpfc_soft_wwpn_key)) != 0))
+ return -EINVAL;
+
+ phba->soft_wwpn_enable = 1;
+ return count;
+}
+static CLASS_DEVICE_ATTR(lpfc_soft_wwpn_enable, S_IWUSR, NULL,
+ lpfc_soft_wwpn_enable_store);
+
+static ssize_t
+lpfc_soft_wwpn_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+ (unsigned long long)phba->cfg_soft_wwpn);
+}
+
+
+static ssize_t
+lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct completion online_compl;
+ int stat1=0, stat2=0;
+ unsigned int i, j, cnt=count;
+ u8 wwpn[8];
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ if (!phba->soft_wwpn_enable || (cnt < 16) || (cnt > 18) ||
+ ((cnt == 17) && (*buf++ != 'x')) ||
+ ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
+ return -EINVAL;
+
+ phba->soft_wwpn_enable = 0;
+
+ memset(wwpn, 0, sizeof(wwpn));
+
+ /* Validate and store the new name */
+ for (i=0, j=0; i < 16; i++) {
+ if ((*buf >= 'a') && (*buf <= 'f'))
+ j = ((j << 4) | ((*buf++ -'a') + 10));
+ else if ((*buf >= 'A') && (*buf <= 'F'))
+ j = ((j << 4) | ((*buf++ -'A') + 10));
+ else if ((*buf >= '0') && (*buf <= '9'))
+ j = ((j << 4) | (*buf++ -'0'));
+ else
+ return -EINVAL;
+ if (i % 2) {
+ wwpn[i/2] = j & 0xff;
+ j = 0;
+ }
+ }
+ phba->cfg_soft_wwpn = wwn_to_u64(wwpn);
+ fc_host_port_name(host) = phba->cfg_soft_wwpn;
+
+ dev_printk(KERN_NOTICE, &phba->pcidev->dev,
+ "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &stat1, &online_compl, LPFC_EVT_OFFLINE);
+ wait_for_completion(&online_compl);
+ if (stat1)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0463 lpfc_soft_wwpn attribute set failed to reinit "
+ "adapter - %d\n", phba->brd_no, stat1);
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &stat2, &online_compl, LPFC_EVT_ONLINE);
+ wait_for_completion(&online_compl);
+ if (stat2)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0464 lpfc_soft_wwpn attribute set failed to reinit "
+ "adapter - %d\n", phba->brd_no, stat2);
+
+ return (stat1 || stat2) ? -EIO : count;
+}
+static CLASS_DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\
+ lpfc_soft_wwpn_show, lpfc_soft_wwpn_store);
+
static int lpfc_poll = 0;
module_param(lpfc_poll, int, 0);
static CLASS_DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR,
lpfc_poll_show, lpfc_poll_store);
+/*
+# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
+# until the timer expires. Value range is [0,255]. Default value is 30.
+*/
+static int lpfc_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
+static int lpfc_devloss_tmo = LPFC_DEF_DEVLOSS_TMO;
+module_param(lpfc_nodev_tmo, int, 0);
+MODULE_PARM_DESC(lpfc_nodev_tmo,
+ "Seconds driver will hold I/O waiting "
+ "for a device to come back");
+static ssize_t
+lpfc_nodev_tmo_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ int val = 0;
+ val = phba->cfg_devloss_tmo;
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->cfg_devloss_tmo);
+}
+
+static int
+lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
+{
+ static int warned;
+ if (phba->cfg_devloss_tmo != LPFC_DEF_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = phba->cfg_devloss_tmo;
+ if (!warned && val != LPFC_DEF_DEVLOSS_TMO) {
+ warned = 1;
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0402 Ignoring nodev_tmo module "
+ "parameter because devloss_tmo is"
+ " set.\n",
+ phba->brd_no);
+ }
+ return 0;
+ }
+
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ return 0;
+ }
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0400 lpfc_nodev_tmo attribute cannot be set to %d, "
+ "allowed range is [%d, %d]\n",
+ phba->brd_no, val,
+ LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
+ phba->cfg_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
+ return -EINVAL;
+}
+
+static int
+lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
+{
+ if (phba->dev_loss_tmo_changed ||
+ (lpfc_devloss_tmo != LPFC_DEF_DEVLOSS_TMO)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0401 Ignoring change to nodev_tmo "
+ "because devloss_tmo is set.\n",
+ phba->brd_no);
+ return 0;
+ }
+
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ return 0;
+ }
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0403 lpfc_nodev_tmo attribute cannot be set to %d, "
+ "allowed range is [%d, %d]\n",
+ phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
+ LPFC_MAX_DEVLOSS_TMO);
+ return -EINVAL;
+}
+
+lpfc_param_store(nodev_tmo)
+
+static CLASS_DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR,
+ lpfc_nodev_tmo_show, lpfc_nodev_tmo_store);
+
+/*
+# lpfc_devloss_tmo: If set, it will hold all I/O errors on devices that
+# disappear until the timer expires. Value range is [0,255]. Default
+# value is 30.
+*/
+module_param(lpfc_devloss_tmo, int, 0);
+MODULE_PARM_DESC(lpfc_devloss_tmo,
+ "Seconds driver will hold I/O waiting "
+ "for a device to come back");
+lpfc_param_init(devloss_tmo, LPFC_DEF_DEVLOSS_TMO,
+ LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO)
+lpfc_param_show(devloss_tmo)
+static int
+lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
+{
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ phba->dev_loss_tmo_changed = 1;
+ return 0;
+ }
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0404 lpfc_devloss_tmo attribute cannot be set to"
+ " %d, allowed range is [%d, %d]\n",
+ phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
+ LPFC_MAX_DEVLOSS_TMO);
+ return -EINVAL;
+}
+
+lpfc_param_store(devloss_tmo)
+static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
+ lpfc_devloss_tmo_show, lpfc_devloss_tmo_store);
+
/*
# lpfc_log_verbose: Only turn this flag on if you are willing to risk being
# deluged with LOTS of information.
# LOG_MBOX 0x4 Mailbox events
# LOG_INIT 0x8 Initialization events
# LOG_LINK_EVENT 0x10 Link events
-# LOG_IP 0x20 IP traffic history
# LOG_FCP 0x40 FCP traffic history
# LOG_NODE 0x80 Node table events
# LOG_MISC 0x400 Miscellaneous events
# LOG_SLI 0x800 SLI events
-# LOG_CHK_COND 0x1000 FCP Check condition flag
+# LOG_FCP_ERROR 0x1000 Only log FCP errors
# LOG_LIBDFC 0x2000 LIBDFC events
# LOG_ALL_MSG 0xffff LOG all messages
*/
LPFC_ATTR_R(scan_down, 1, 0, 1,
"Start scanning for devices from highest ALPA to lowest");
-/*
-# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
-# until the timer expires. Value range is [0,255]. Default value is 30.
-# NOTE: this MUST be less then the SCSI Layer command timeout - 1.
-*/
-LPFC_ATTR_RW(nodev_tmo, 30, 0, 255,
- "Seconds driver will hold I/O waiting for a device to come back");
-
/*
# lpfc_topology: link topology for init link
# 0x0 = attempt loop mode then point-to-point
LPFC_ATTR_R(multi_ring_support, 1, 1, 2, "Determines number of primary "
"SLI rings to spread IOCB entries across");
+/*
+# lpfc_multi_ring_rctl: If lpfc_multi_ring_support is enabled, this
+# 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,
+ 255, "Identifies RCTL for additional ring configuration");
+
+/*
+# lpfc_multi_ring_type: If lpfc_multi_ring_support is enabled, this
+# 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,
+ 255, "Identifies TYPE for additional ring configuration");
+
/*
# lpfc_fdmi_on: controls FDMI support.
# 0 = no FDMI support
"during discovery");
/*
-# lpfc_max_luns: maximum number of LUNs per target driver will support
-# Value range is [1,32768]. Default value is 256.
-# NOTE: The SCSI layer will scan each target for this many luns
+# lpfc_max_luns: maximum allowed LUN.
+# Value range is [0,65535]. Default value is 255.
+# NOTE: The SCSI layer might probe all allowed LUN on some old targets.
*/
-LPFC_ATTR_R(max_luns, 256, 1, 32768,
- "Maximum number of LUNs per target driver will support");
+LPFC_ATTR_R(max_luns, 255, 0, 65535,
+ "Maximum allowed LUN");
/*
# lpfc_poll_tmo: .Milliseconds driver will wait between polling FCP ring.
LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
"Milliseconds driver will wait between polling FCP ring");
+/*
+# lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that
+# support this feature
+# 0 = MSI disabled (default)
+# 1 = MSI enabled
+# Value range is [0,1]. Default value is 0.
+*/
+LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible");
+
+
struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_info,
&class_device_attr_serialnum,
&class_device_attr_lpfc_lun_queue_depth,
&class_device_attr_lpfc_hba_queue_depth,
&class_device_attr_lpfc_nodev_tmo,
+ &class_device_attr_lpfc_devloss_tmo,
&class_device_attr_lpfc_fcp_class,
&class_device_attr_lpfc_use_adisc,
&class_device_attr_lpfc_ack0,
&class_device_attr_lpfc_cr_delay,
&class_device_attr_lpfc_cr_count,
&class_device_attr_lpfc_multi_ring_support,
+ &class_device_attr_lpfc_multi_ring_rctl,
+ &class_device_attr_lpfc_multi_ring_type,
&class_device_attr_lpfc_fdmi_on,
&class_device_attr_lpfc_max_luns,
&class_device_attr_nport_evt_cnt,
&class_device_attr_management_version,
- &class_device_attr_board_online,
&class_device_attr_board_mode,
+ &class_device_attr_issue_reset,
&class_device_attr_lpfc_poll,
&class_device_attr_lpfc_poll_tmo,
+ &class_device_attr_lpfc_use_msi,
+ &class_device_attr_lpfc_soft_wwpn,
+ &class_device_attr_lpfc_soft_wwpn_enable,
NULL,
};
phba->sysfs_mbox.mbox == NULL ) {
sysfs_mbox_idle(phba);
spin_unlock_irq(host->host_lock);
- return -EINVAL;
+ return -EAGAIN;
}
}
spin_unlock_irq(phba->host->host_lock);
rc = lpfc_sli_issue_mbox_wait (phba,
phba->sysfs_mbox.mbox,
- phba->fc_ratov * 2);
+ lpfc_mbox_tmo_val(phba,
+ phba->sysfs_mbox.mbox->mb.mbxCommand) * HZ);
spin_lock_irq(phba->host->host_lock);
}
if (rc != MBX_SUCCESS) {
sysfs_mbox_idle(phba);
spin_unlock_irq(host->host_lock);
- return -ENODEV;
+ return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
}
phba->sysfs_mbox.state = SMBOX_READING;
}
printk(KERN_WARNING "mbox_read: Bad State\n");
sysfs_mbox_idle(phba);
spin_unlock_irq(host->host_lock);
- return -EINVAL;
+ return -EAGAIN;
}
memcpy(buf, (uint8_t *) & phba->sysfs_mbox.mbox->mb + off, count);
fc_host_fabric_name(shost) = node_name;
}
+static void
+lpfc_get_host_symbolic_name (struct Scsi_Host *shost)
+{
+ struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+
+ spin_lock_irq(shost->host_lock);
+ lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
+ spin_unlock_irq(shost->host_lock);
+}
static struct fc_host_statistics *
lpfc_get_stats(struct Scsi_Host *shost)
struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
struct lpfc_sli *psli = &phba->sli;
struct fc_host_statistics *hs = &phba->link_stats;
+ struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets;
LPFC_MBOXQ_t *pmboxq;
MAILBOX_t *pmb;
+ unsigned long seconds;
int rc = 0;
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
hs->invalid_crc_count = pmb->un.varRdLnk.crcCnt;
hs->error_frames = pmb->un.varRdLnk.crcCnt;
+ hs->link_failure_count -= lso->link_failure_count;
+ hs->loss_of_sync_count -= lso->loss_of_sync_count;
+ hs->loss_of_signal_count -= lso->loss_of_signal_count;
+ hs->prim_seq_protocol_err_count -= lso->prim_seq_protocol_err_count;
+ hs->invalid_tx_word_count -= lso->invalid_tx_word_count;
+ hs->invalid_crc_count -= lso->invalid_crc_count;
+ hs->error_frames -= lso->error_frames;
+
if (phba->fc_topology == TOPOLOGY_LOOP) {
hs->lip_count = (phba->fc_eventTag >> 1);
+ hs->lip_count -= lso->link_events;
hs->nos_count = -1;
} else {
hs->lip_count = -1;
hs->nos_count = (phba->fc_eventTag >> 1);
+ hs->nos_count -= lso->link_events;
}
hs->dumped_frames = -1;
-/* FIX ME */
- /*hs->SecondsSinceLastReset = (jiffies - lpfc_loadtime) / HZ;*/
+ seconds = get_seconds();
+ if (seconds < psli->stats_start)
+ hs->seconds_since_last_reset = seconds +
+ ((unsigned long)-1 - psli->stats_start);
+ else
+ hs->seconds_since_last_reset = seconds - psli->stats_start;
return hs;
}
+static void
+lpfc_reset_stats(struct Scsi_Host *shost)
+{
+ struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets;
+ LPFC_MBOXQ_t *pmboxq;
+ MAILBOX_t *pmb;
+ int rc = 0;
+
+ pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmboxq)
+ return;
+ memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
+
+ pmb = &pmboxq->mb;
+ pmb->mbxCommand = MBX_READ_STATUS;
+ pmb->mbxOwner = OWN_HOST;
+ pmb->un.varWords[0] = 0x1; /* reset request */
+ pmboxq->context1 = NULL;
+
+ if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+ rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+ else
+ rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+
+ if (rc != MBX_SUCCESS) {
+ if (rc == MBX_TIMEOUT)
+ pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ else
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ return;
+ }
+
+ memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
+ pmb->mbxCommand = MBX_READ_LNK_STAT;
+ pmb->mbxOwner = OWN_HOST;
+ pmboxq->context1 = NULL;
+
+ if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+ rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+ else
+ rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+
+ if (rc != MBX_SUCCESS) {
+ if (rc == MBX_TIMEOUT)
+ pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ else
+ mempool_free( pmboxq, phba->mbox_mem_pool);
+ return;
+ }
+
+ lso->link_failure_count = pmb->un.varRdLnk.linkFailureCnt;
+ lso->loss_of_sync_count = pmb->un.varRdLnk.lossSyncCnt;
+ lso->loss_of_signal_count = pmb->un.varRdLnk.lossSignalCnt;
+ lso->prim_seq_protocol_err_count = pmb->un.varRdLnk.primSeqErrCnt;
+ 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);
+
+ psli->stats_start = get_seconds();
+
+ return;
+}
/*
* The LPFC driver treats linkdown handling as target loss events so there
fc_starget_port_name(starget) = port_name;
}
-static void
-lpfc_get_rport_loss_tmo(struct fc_rport *rport)
-{
- /*
- * Return the driver's global value for device loss timeout plus
- * five seconds to allow the driver's nodev timer to run.
- */
- rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
-}
-
static void
lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
{
- /*
- * The driver doesn't have a per-target timeout setting. Set
- * this value globally. lpfc_nodev_tmo should be greater then 0.
- */
if (timeout)
- lpfc_nodev_tmo = timeout;
+ rport->dev_loss_tmo = timeout;
else
- lpfc_nodev_tmo = 1;
- rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
+ rport->dev_loss_tmo = 1;
}
.show_host_port_name = 1,
.show_host_supported_classes = 1,
.show_host_supported_fc4s = 1,
- .show_host_symbolic_name = 1,
.show_host_supported_speeds = 1,
.show_host_maxframe_size = 1,
.get_host_fabric_name = lpfc_get_host_fabric_name,
.show_host_fabric_name = 1,
+ .get_host_symbolic_name = lpfc_get_host_symbolic_name,
+ .show_host_symbolic_name = 1,
+
/*
* The LPFC driver treats linkdown handling as target loss events
* so there are no sysfs handlers for link_down_tmo.
*/
.get_fc_host_stats = lpfc_get_stats,
-
- /* the LPFC driver doesn't support resetting stats yet */
+ .reset_fc_host_stats = lpfc_reset_stats,
.dd_fcrport_size = sizeof(struct lpfc_rport_data),
.show_rport_maxframe_size = 1,
.show_rport_supported_classes = 1,
- .get_rport_dev_loss_tmo = lpfc_get_rport_loss_tmo,
.set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo,
.show_rport_dev_loss_tmo = 1,
.show_starget_port_name = 1,
.issue_fc_host_lip = lpfc_issue_lip,
+ .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
+ .terminate_rport_io = lpfc_terminate_rport_io,
};
void
lpfc_cr_delay_init(phba, lpfc_cr_delay);
lpfc_cr_count_init(phba, lpfc_cr_count);
lpfc_multi_ring_support_init(phba, lpfc_multi_ring_support);
+ lpfc_multi_ring_rctl_init(phba, lpfc_multi_ring_rctl);
+ lpfc_multi_ring_type_init(phba, lpfc_multi_ring_type);
lpfc_lun_queue_depth_init(phba, lpfc_lun_queue_depth);
lpfc_fcp_class_init(phba, lpfc_fcp_class);
lpfc_use_adisc_init(phba, lpfc_use_adisc);
lpfc_ack0_init(phba, lpfc_ack0);
lpfc_topology_init(phba, lpfc_topology);
lpfc_scan_down_init(phba, lpfc_scan_down);
- lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
lpfc_link_speed_init(phba, lpfc_link_speed);
lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
lpfc_discovery_threads_init(phba, lpfc_discovery_threads);
lpfc_max_luns_init(phba, lpfc_max_luns);
lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
-
+ lpfc_use_msi_init(phba, lpfc_use_msi);
+ lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
+ lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
phba->cfg_poll = lpfc_poll;
+ phba->cfg_soft_wwpn = 0L;
/*
* The total number of segments is the configuration value plus 2