@@ -347,6 +347,7 @@ struct lpfc_vport {
#define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */
struct list_head fc_nodes;
+ uint32_t throttle_cnt;
/* Keep counters for the number of entries in each list. */
uint16_t fc_plogi_cnt;
@@ -443,6 +444,7 @@ struct lpfc_vport {
unsigned long rcv_buffer_time_stamp;
uint32_t vport_flag;
#define STATIC_VPORT 1
+ struct throttle_history log; /* Throttle log history for phba */
};
struct hbq_s {
@@ -750,6 +752,9 @@ struct lpfc_hba {
uint32_t cfg_request_firmware_upgrade;
uint32_t cfg_iocb_cnt;
uint32_t cfg_suppress_link_up;
+ uint32_t cfg_throttle_log_cnt;
+ uint32_t cfg_throttle_log_time;
+ struct throttle_history log; /* Throttle log history for phba */
uint32_t cfg_rrq_xri_bitmap_sz;
#define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */
#define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */
@@ -4773,6 +4773,20 @@ LPFC_ATTR_R(prot_sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT,
LPFC_DEFAULT_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT,
"Max Protection Scatter Gather Segment Count");
+#define THROTTLE_CNT_MIN 1
+#define THROTTLE_CNT_MAX 1000
+#define THROTTLE_CNT_DEF 10
+LPFC_ATTR_RW(throttle_log_cnt, THROTTLE_CNT_DEF, THROTTLE_CNT_MIN,
+ THROTTLE_CNT_MAX, "Do not exceed this number of messages "
+ "logged within throttle_log_time");
+
+#define THROTTLE_TIME_MIN 1
+#define THROTTLE_TIME_MAX 60
+#define THROTTLE_TIME_DEF 1
+LPFC_ATTR_RW(throttle_log_time, THROTTLE_TIME_DEF, THROTTLE_TIME_MIN,
+ THROTTLE_TIME_MAX, "Do not exceed throttle_log_cnt within "
+ "this limit (seconds)");
+
struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_bg_info,
&dev_attr_bg_guard_err,
@@ -4868,6 +4882,8 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_sriov_hw_max_virtfn,
&dev_attr_protocol,
&dev_attr_lpfc_xlane_supported,
+ &dev_attr_lpfc_throttle_log_cnt,
+ &dev_attr_lpfc_throttle_log_time,
NULL,
};
@@ -5858,6 +5874,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt);
phba->cfg_enable_dss = 1;
+ lpfc_throttle_log_cnt_init(phba, lpfc_throttle_log_cnt);
+ lpfc_throttle_log_time_init(phba, lpfc_throttle_log_time);
return;
}
@@ -21,6 +21,7 @@
typedef int (*node_filter)(struct lpfc_nodelist *, void *);
struct fc_rport;
+bool lpfc_throttler(struct lpfc_vport *, struct throttle_history *);
void lpfc_down_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_sli_read_link_ste(struct lpfc_hba *);
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t, uint16_t);
@@ -74,8 +74,19 @@ struct lpfc_node_rrqs {
unsigned long xri_bitmap[XRI_BITMAP_ULONGS];
};
+struct throttle_history {
+ /* Throttle log defaults if more than 10 messages per second */
+ #define ONE_SEC 1000000 /* one second */
+ bool logit; /* True means throttle logging on */
+ uint32_t log_messages_lost; /* Messages discarded due to throttle */
+ uint32_t log_messages; /* Log messages count within second */
+ uint64_t log_start; /* start of message burst in usec */
+ char announcement[16]; /* announcement string */
+};
+
struct lpfc_nodelist {
struct list_head nlp_listp;
+ struct throttle_history log; /* used to record throttle */
struct lpfc_name nlp_portname;
struct lpfc_name nlp_nodename;
uint32_t nlp_flag; /* entry flags */
@@ -3959,6 +3959,29 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
(rport->scsi_target_id < LPFC_MAX_TARGET)) {
ndlp->nlp_sid = rport->scsi_target_id;
}
+
+ lpfc_throttle_vlog(ndlp->vport, &ndlp->log, LOG_NODE,
+ "3237 SCSI ID %d "
+ " WWNN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, "
+ " WWPN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ ndlp->nlp_sid,
+ ndlp->nlp_nodename.u.wwn[0],
+ ndlp->nlp_nodename.u.wwn[1],
+ ndlp->nlp_nodename.u.wwn[2],
+ ndlp->nlp_nodename.u.wwn[3],
+ ndlp->nlp_nodename.u.wwn[4],
+ ndlp->nlp_nodename.u.wwn[5],
+ ndlp->nlp_nodename.u.wwn[6],
+ ndlp->nlp_nodename.u.wwn[7],
+ ndlp->nlp_portname.u.wwn[0],
+ ndlp->nlp_portname.u.wwn[1],
+ ndlp->nlp_portname.u.wwn[2],
+ ndlp->nlp_portname.u.wwn[3],
+ ndlp->nlp_portname.u.wwn[4],
+ ndlp->nlp_portname.u.wwn[5],
+ ndlp->nlp_portname.u.wwn[6],
+ ndlp->nlp_portname.u.wwn[7]);
+
return;
}
@@ -9543,6 +9543,9 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid)
if (error)
goto out_disable_pci_dev;
+ phba->log.logit = true; /* Turn on throttle logs for Adapter */
+ sprintf(phba->log.announcement, "adapter");
+
/* Set up SLI-3 specific device PCI memory space */
error = lpfc_sli_pci_mem_setup(phba);
if (error) {
@@ -10313,6 +10316,9 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
if (error)
goto out_disable_pci_dev;
+ phba->log.logit = true; /* Turn on throttle logs for Adapter */
+ sprintf(phba->log.announcement, "adapter");
+
/* Set up SLI-4 specific device PCI memory space */
error = lpfc_sli4_pci_mem_setup(phba);
if (error) {
@@ -11270,6 +11276,70 @@ lpfc_fof_queue_destroy(struct lpfc_hba *phba)
return 0;
}
+/**
+ * lpfc_throttler - lpfc log throttling function
+ * @phba : the adapter instance.
+ *
+ * This routine is to be invoked by lpfc_throttle_log and lpfc_throttle_vlog.
+ * It is controlled using two module parameters.
+ * lpfc_throttle_log_time: The number of seconds to monitor the log count
+ * lpfc_throttle_log_cnt: The number of logs that cannot be exceeded within
+ * the throttle log time.
+ *
+ * This function acts as a gate to the logger. It monitors the the lpfc log
+ * load. If the log load exceeds the threshold, it return false which is a
+ * hint to the caller not to send the log.
+ *
+ * Return codes
+ * true - Okay to log
+ * false - Do not log
+ */
+bool
+lpfc_throttler(struct lpfc_vport *vport, struct throttle_history *tlog)
+{
+ /* All times in microseconds */
+ uint64_t now = (jiffies * ONE_SEC) / HZ;
+ struct lpfc_hba *phba = vport->phba;
+
+ if (tlog->logit) {
+ /* Currently Logging */
+ if (now > (tlog->log_start +
+ (phba->cfg_throttle_log_time * ONE_SEC))) {
+ /* Last Log more than one second ago */
+ tlog->log_messages_lost = 0;
+ tlog->log_messages = 1;
+ tlog->log_start = now;
+ } else if (++tlog->log_messages > phba->cfg_throttle_log_cnt) {
+ /* Transition to throttling */
+ lpfc_printf_log(phba, KERN_INFO, LOG_EVENT,
+ "0040 Log compression on %s starting."
+ "\n", tlog->announcement);
+ tlog->log_messages_lost++;
+ tlog->log_messages = 0;
+ tlog->log_start = now;
+ tlog->logit = false;
+ }
+
+ } else if (now > (tlog->log_start +
+ (300 * ONE_SEC))) {
+ /* Transition to logging if quiesced for five minutes */
+ lpfc_printf_log(phba, KERN_INFO, LOG_EVENT,
+ "0041 Log compression %s ending, messages "
+ "have been quiesced with %d compressed.\n",
+ tlog->announcement, tlog->log_messages_lost);
+
+
+ tlog->log_start = now;
+ tlog->log_messages_lost = 0;
+ tlog->log_messages = 0;
+ tlog->logit = true;
+ } else {
+ /* Currently throttling */
+ tlog->log_messages_lost++;
+ }
+ return tlog->logit;
+}
+
static struct pci_device_id lpfc_id_table[] = {
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
PCI_ANY_ID, PCI_ANY_ID, },
@@ -57,3 +57,43 @@ do { \
fmt, phba->brd_no, ##arg); \
} \
} while (0)
+
+#define lpfc_throttle_vlog(vport, hist, log, fmt, arg...) \
+do { \
+ { if (!lpfc_throttler(vport, (hist))) \
+ break; \
+ lpfc_printf_vlog(vport, KERN_INFO, log, \
+ fmt, arg); \
+ } \
+} while (0)
+
+#define lpfc_throttle_log(phba, hist, log, fmt, arg...) \
+do { \
+ { if (!lpfc_throttler((phba->pport), (hist))) \
+ break; \
+ lpfc_printf_log(phba, KERN_INFO, log, \
+ fmt, arg); \
+ } \
+} while (0)
+
+#define lpfc_optioned_vlog(vport, hist, level, mask, fmt, arg...) \
+do { \
+ { if (!lpfc_throttler(vport, (hist))) \
+ { lpfc_printf_vlog(vport, level, mask, fmt, ##arg); \
+ break; \
+ } \
+ dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \
+ fmt, (vport)->phba->brd_no, vport->vpi, ##arg); \
+ } \
+} while (0)
+
+#define lpfc_optioned_log(phba, hist, level, mask, fmt, arg...) \
+do { \
+ { if (!lpfc_throttler((phba->pport), (hist))) \
+ { lpfc_printf_log(phba, level, mask, fmt, ##arg); \
+ break; \
+ } \
+ dev_printk(level, &((phba)->pcidev)->dev, "%d:" \
+ fmt, phba->brd_no, ##arg); \
+ } \
+} while (0)
@@ -4621,14 +4621,34 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
&lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
if (err) {
atomic_dec(&ndlp->cmd_pending);
- lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
- "3376 FCP could not issue IOCB err %x"
+ lpfc_throttle_vlog(vport, &vport->log, LOG_FCP,
+ "3376 FCP could not issue IOCB err %x "
+ "FCP cmd x%x <%d/%llu> "
+ "sid: x%x did: x%x oxid: x%x "
+ "Data: x%x x%x x%x x%x\n",
+ err, cmnd->cmnd[0],
+ cmnd->device ? cmnd->device->id : 0xffff,
+ cmnd->device ? cmnd->device->lun : (u64) -1,
+ vport->fc_myDID, ndlp->nlp_DID,
+ phba->sli_rev == LPFC_SLI_REV4 ?
+ lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff,
+ lpfc_cmd->cur_iocbq.iocb.ulpContext,
+ lpfc_cmd->cur_iocbq.iocb.ulpIoTag,
+ lpfc_cmd->cur_iocbq.iocb.ulpTimeout,
+ (uint32_t)
+ (cmnd->request->timeout / 1000));
+
+
+ goto out_host_busy_free_buf;
+ } else
+ lpfc_throttle_vlog(vport, &vport->log, LOG_FCP,
+ "0019 FCP IOCB issued"
"FCP cmd x%x <%d/%llu> "
"sid: x%x did: x%x oxid: x%x "
"Data: x%x x%x x%x x%x\n",
- err, cmnd->cmnd[0],
+ cmnd->cmnd[0],
cmnd->device ? cmnd->device->id : 0xffff,
- cmnd->device ? cmnd->device->lun : (u64) -1,
+ cmnd->device ? cmnd->device->lun : 0xffff,
vport->fc_myDID, ndlp->nlp_DID,
phba->sli_rev == LPFC_SLI_REV4 ?
lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff,
@@ -4638,9 +4658,6 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
(uint32_t)
(cmnd->request->timeout / 1000));
-
- goto out_host_busy_free_buf;
- }
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
lpfc_sli_handle_fast_ring_event(phba,
&phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ);
@@ -4900,8 +4917,8 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd)
rsp_info_code = fcprsp->rspInfo3;
- lpfc_printf_vlog(vport, KERN_INFO,
- LOG_FCP,
+ lpfc_optioned_vlog(vport, &vport->log,
+ KERN_INFO, LOG_FCP,
"0706 fcp_rsp valid 0x%x,"
" rsp len=%d code 0x%x\n",
rsp_info,
@@ -4910,8 +4927,10 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd)
if ((fcprsp->rspStatus2&RSP_LEN_VALID) && (rsp_len == 8)) {
switch (rsp_info_code) {
case RSP_NO_FAILURE:
- lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
- "0715 Task Mgmt No Failure\n");
+ lpfc_optioned_vlog(vport, &vport->log,
+ KERN_INFO, LOG_FCP,
+ "0715 Task Mgmt No "
+ "Failure\n");
ret = SUCCESS;
break;
case RSP_TM_NOT_SUPPORTED: /* TM rejected */
@@ -108,9 +108,16 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
/* If the host has not yet processed the next entry then we are done */
idx = ((q->host_index + 1) % q->entry_count);
if (idx == q->hba_index) {
+ lpfc_throttle_log(q->phba, &q->phba->pport->log, LOG_SLI,
+ "9998 WQ failure. WQ Full. "
+ "q_id x%x, host x%x, hba x%x\n",
+ q->queue_id, idx, q->hba_index);
q->WQ_overflow++;
return -ENOMEM;
}
+ lpfc_throttle_log(q->phba, &q->phba->pport->log, LOG_SLI,
+ "0039 WQ Posted. q_id x%x, host x%x, hba x%x\n",
+ q->queue_id, idx, q->hba_index);
q->WQ_posted++;
/* set consumption flag every once in a while */
if (!((q->host_index + 1) % q->entry_repost))