Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: lpfc: Expand FPIN and RDF receive logging

Expand FPIN logging:

- Display Attached Port Names for Link Integrity and Peer Congestion
events

- Log Delivery, Peer Congestion, and Congestion events

- Sanity check FPIN descriptor lengths when processing FPIN descriptors.

Log RDF events when congestion logging is enabled.

Link: https://lore.kernel.org/r/20210816162901.121235-5-jsmart2021@gmail.com
Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

James Smart and committed by
Martin K. Petersen
428569e6 c6a5c747

+322 -41
+308 -41
drivers/scsi/lpfc/lpfc_els.c
··· 3260 3260 irsp->ulpStatus, irsp->un.ulpWord[4], 3261 3261 irsp->un.elsreq64.remoteID); 3262 3262 /* ELS cmd tag <ulpIoTag> completes */ 3263 - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, 3263 + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, 3264 3264 "0217 ELS cmd tag x%x completes Data: x%x x%x x%x " 3265 3265 "x%x\n", 3266 3266 irsp->ulpIoTag, irsp->ulpStatus, ··· 3319 3319 3320 3320 for (i = 0; i < ELS_RDF_REG_TAG_CNT && 3321 3321 i < be32_to_cpu(prdf->reg_d1.reg_desc.count); i++) 3322 - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, 3323 - "4677 Fabric RDF Notification Grant Data: " 3324 - "0x%08x\n", 3325 - be32_to_cpu( 3326 - prdf->reg_d1.desc_tags[i])); 3322 + lpfc_printf_vlog(vport, KERN_INFO, 3323 + LOG_ELS | LOG_CGN_MGMT, 3324 + "4677 Fabric RDF Notification Grant " 3325 + "Data: 0x%08x\n", 3326 + be32_to_cpu( 3327 + prdf->reg_d1.desc_tags[i])); 3327 3328 } 3328 3329 3329 3330 out: ··· 3690 3689 prdf->reg_d1.desc_tags[2] = cpu_to_be32(ELS_DTAG_PEER_CONGEST); 3691 3690 prdf->reg_d1.desc_tags[3] = cpu_to_be32(ELS_DTAG_CONGESTION); 3692 3691 3693 - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, 3692 + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, 3694 3693 "6444 Xmit RDF to remote NPORT x%x\n", 3695 3694 ndlp->nlp_DID); 3696 3695 ··· 3734 3733 { 3735 3734 /* Send LS_ACC */ 3736 3735 if (lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL)) { 3737 - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, 3736 + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, 3738 3737 "1623 Failed to RDF_ACC from x%x for x%x\n", 3739 3738 ndlp->nlp_DID, vport->fc_myDID); 3740 3739 return -EIO; ··· 3742 3741 3743 3742 /* Issue new RDF for reregistering */ 3744 3743 if (lpfc_issue_els_rdf(vport, 0)) { 3745 - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, 3744 + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, 3746 3745 "2623 Failed to re register RDF for x%x\n", 3747 3746 vport->fc_myDID); 3748 3747 return -EIO; ··· 8694 8693 DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_li_event_nm, fc_fpin_li_event_types, 8695 8694 FC_FPIN_LI_EVT_TYPES_INIT); 8696 8695 8696 + DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_deli_event_nm, fc_fpin_deli_event_types, 8697 + FC_FPIN_DELI_EVT_TYPES_INIT); 8698 + 8699 + DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_congn_event_nm, fc_fpin_congn_event_types, 8700 + FC_FPIN_CONGN_EVT_TYPES_INIT); 8701 + 8702 + DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_congn_severity_nm, 8703 + fc_fpin_congn_severity_types, 8704 + FC_FPIN_CONGN_SEVERITY_INIT); 8705 + 8706 + 8707 + /** 8708 + * lpfc_display_fpin_wwpn - Display WWPNs accessible by the attached port 8709 + * @phba: Pointer to phba object. 8710 + * @wwnlist: Pointer to list of WWPNs in FPIN payload 8711 + * @cnt: count of WWPNs in FPIN payload 8712 + * 8713 + * This routine is called by LI and PC descriptors. 8714 + * Limit the number of WWPNs displayed to 6 log messages, 6 per log message 8715 + */ 8716 + static void 8717 + lpfc_display_fpin_wwpn(struct lpfc_hba *phba, __be64 *wwnlist, u32 cnt) 8718 + { 8719 + char buf[LPFC_FPIN_WWPN_LINE_SZ]; 8720 + __be64 wwn; 8721 + u64 wwpn; 8722 + int i, len; 8723 + int line = 0; 8724 + int wcnt = 0; 8725 + bool endit = false; 8726 + 8727 + len = scnprintf(buf, LPFC_FPIN_WWPN_LINE_SZ, "Accessible WWPNs:"); 8728 + for (i = 0; i < cnt; i++) { 8729 + /* Are we on the last WWPN */ 8730 + if (i == (cnt - 1)) 8731 + endit = true; 8732 + 8733 + /* Extract the next WWPN from the payload */ 8734 + wwn = *wwnlist++; 8735 + wwpn = be64_to_cpu(wwn); 8736 + len += scnprintf(buf + len, LPFC_FPIN_WWPN_LINE_SZ, 8737 + " %016llx", wwpn); 8738 + 8739 + /* Log a message if we are on the last WWPN 8740 + * or if we hit the max allowed per message. 8741 + */ 8742 + wcnt++; 8743 + if (wcnt == LPFC_FPIN_WWPN_LINE_CNT || endit) { 8744 + buf[len] = 0; 8745 + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, 8746 + "4686 %s\n", buf); 8747 + 8748 + /* Check if we reached the last WWPN */ 8749 + if (endit) 8750 + return; 8751 + 8752 + /* Limit the number of log message displayed per FPIN */ 8753 + line++; 8754 + if (line == LPFC_FPIN_WWPN_NUM_LINE) { 8755 + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, 8756 + "4687 %d WWPNs Truncated\n", 8757 + cnt - i - 1); 8758 + return; 8759 + } 8760 + 8761 + /* Start over with next log message */ 8762 + wcnt = 0; 8763 + len = scnprintf(buf, LPFC_FPIN_WWPN_LINE_SZ, 8764 + "Additional WWPNs:"); 8765 + } 8766 + } 8767 + } 8768 + 8697 8769 /** 8698 8770 * lpfc_els_rcv_fpin_li - Process an FPIN Link Integrity Event. 8699 - * @vport: Pointer to vport object. 8771 + * @phba: Pointer to phba object. 8700 8772 * @tlv: Pointer to the Link Integrity Notification Descriptor. 8701 8773 * 8702 - * This function processes a link integrity FPIN event by 8703 - * logging a message 8774 + * This function processes a Link Integrity FPIN event by logging a message. 8704 8775 **/ 8705 8776 static void 8706 - lpfc_els_rcv_fpin_li(struct lpfc_vport *vport, struct fc_tlv_desc *tlv) 8777 + lpfc_els_rcv_fpin_li(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) 8707 8778 { 8708 8779 struct fc_fn_li_desc *li = (struct fc_fn_li_desc *)tlv; 8709 8780 const char *li_evt_str; 8710 - u32 li_evt; 8781 + u32 li_evt, cnt; 8711 8782 8712 8783 li_evt = be16_to_cpu(li->event_type); 8713 8784 li_evt_str = lpfc_get_fpin_li_event_nm(li_evt); 8785 + cnt = be32_to_cpu(li->pname_count); 8714 8786 8715 - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, 8716 - "4680 FPIN Link Integrity %s (x%x) " 8717 - "Detecting PN x%016llx Attached PN x%016llx " 8718 - "Duration %d mSecs Count %d Port Cnt %d\n", 8719 - li_evt_str, li_evt, 8720 - be64_to_cpu(li->detecting_wwpn), 8721 - be64_to_cpu(li->attached_wwpn), 8722 - be32_to_cpu(li->event_threshold), 8723 - be32_to_cpu(li->event_count), 8724 - be32_to_cpu(li->pname_count)); 8787 + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, 8788 + "4680 FPIN Link Integrity %s (x%x) " 8789 + "Detecting PN x%016llx Attached PN x%016llx " 8790 + "Duration %d mSecs Count %d Port Cnt %d\n", 8791 + li_evt_str, li_evt, 8792 + be64_to_cpu(li->detecting_wwpn), 8793 + be64_to_cpu(li->attached_wwpn), 8794 + be32_to_cpu(li->event_threshold), 8795 + be32_to_cpu(li->event_count), cnt); 8796 + 8797 + lpfc_display_fpin_wwpn(phba, (__be64 *)&li->pname_list, cnt); 8798 + } 8799 + 8800 + /** 8801 + * lpfc_els_rcv_fpin_del - Process an FPIN Delivery Event. 8802 + * @phba: Pointer to hba object. 8803 + * @tlv: Pointer to the Delivery Notification Descriptor TLV 8804 + * 8805 + * This function processes a Delivery FPIN event by logging a message. 8806 + **/ 8807 + static void 8808 + lpfc_els_rcv_fpin_del(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) 8809 + { 8810 + struct fc_fn_deli_desc *del = (struct fc_fn_deli_desc *)tlv; 8811 + const char *del_rsn_str; 8812 + u32 del_rsn; 8813 + __be32 *frame; 8814 + 8815 + del_rsn = be16_to_cpu(del->deli_reason_code); 8816 + del_rsn_str = lpfc_get_fpin_deli_event_nm(del_rsn); 8817 + 8818 + /* Skip over desc_tag/desc_len header to payload */ 8819 + frame = (__be32 *)(del + 1); 8820 + 8821 + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, 8822 + "4681 FPIN Delivery %s (x%x) " 8823 + "Detecting PN x%016llx Attached PN x%016llx " 8824 + "DiscHdr0 x%08x " 8825 + "DiscHdr1 x%08x DiscHdr2 x%08x DiscHdr3 x%08x " 8826 + "DiscHdr4 x%08x DiscHdr5 x%08x\n", 8827 + del_rsn_str, del_rsn, 8828 + be64_to_cpu(del->detecting_wwpn), 8829 + be64_to_cpu(del->attached_wwpn), 8830 + be32_to_cpu(frame[0]), 8831 + be32_to_cpu(frame[1]), 8832 + be32_to_cpu(frame[2]), 8833 + be32_to_cpu(frame[3]), 8834 + be32_to_cpu(frame[4]), 8835 + be32_to_cpu(frame[5])); 8836 + } 8837 + 8838 + /** 8839 + * lpfc_els_rcv_fpin_peer_cgn - Process a FPIN Peer Congestion Event. 8840 + * @phba: Pointer to hba object. 8841 + * @tlv: Pointer to the Peer Congestion Notification Descriptor TLV 8842 + * 8843 + * This function processes a Peer Congestion FPIN event by logging a message. 8844 + **/ 8845 + static void 8846 + lpfc_els_rcv_fpin_peer_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) 8847 + { 8848 + struct fc_fn_peer_congn_desc *pc = (struct fc_fn_peer_congn_desc *)tlv; 8849 + const char *pc_evt_str; 8850 + u32 pc_evt, cnt; 8851 + 8852 + pc_evt = be16_to_cpu(pc->event_type); 8853 + pc_evt_str = lpfc_get_fpin_congn_event_nm(pc_evt); 8854 + cnt = be32_to_cpu(pc->pname_count); 8855 + 8856 + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_ELS, 8857 + "4684 FPIN Peer Congestion %s (x%x) " 8858 + "Duration %d mSecs " 8859 + "Detecting PN x%016llx Attached PN x%016llx " 8860 + "Impacted Port Cnt %d\n", 8861 + pc_evt_str, pc_evt, 8862 + be32_to_cpu(pc->event_period), 8863 + be64_to_cpu(pc->detecting_wwpn), 8864 + be64_to_cpu(pc->attached_wwpn), 8865 + cnt); 8866 + 8867 + lpfc_display_fpin_wwpn(phba, (__be64 *)&pc->pname_list, cnt); 8868 + } 8869 + 8870 + /** 8871 + * lpfc_els_rcv_fpin_cgn - Process an FPIN Congestion notification 8872 + * @phba: Pointer to hba object. 8873 + * @tlv: Pointer to the Congestion Notification Descriptor TLV 8874 + * 8875 + * This function processes an FPIN Congestion Notifiction. The notification 8876 + * could be an Alarm or Warning. This routine feeds that data into driver's 8877 + * running congestion algorithm. It also processes the FPIN by 8878 + * logging a message. It returns 1 to indicate deliver this message 8879 + * to the upper layer or 0 to indicate don't deliver it. 8880 + **/ 8881 + static int 8882 + lpfc_els_rcv_fpin_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) 8883 + { 8884 + struct fc_fn_congn_desc *cgn = (struct fc_fn_congn_desc *)tlv; 8885 + const char *cgn_evt_str; 8886 + u32 cgn_evt; 8887 + const char *cgn_sev_str; 8888 + u32 cgn_sev; 8889 + bool nm_log = false; 8890 + int rc = 1; 8891 + 8892 + cgn_evt = be16_to_cpu(cgn->event_type); 8893 + cgn_evt_str = lpfc_get_fpin_congn_event_nm(cgn_evt); 8894 + cgn_sev = cgn->severity; 8895 + cgn_sev_str = lpfc_get_fpin_congn_severity_nm(cgn_sev); 8896 + 8897 + /* The driver only takes action on a Credit Stall or Oversubscription 8898 + * event type to engage the IO algorithm. The driver prints an 8899 + * unmaskable message only for Lost Credit and Credit Stall. 8900 + * TODO: Still need to have definition of host action on clear, 8901 + * lost credit and device specific event types. 8902 + */ 8903 + switch (cgn_evt) { 8904 + case FPIN_CONGN_LOST_CREDIT: 8905 + nm_log = true; 8906 + break; 8907 + case FPIN_CONGN_CREDIT_STALL: 8908 + nm_log = true; 8909 + fallthrough; 8910 + case FPIN_CONGN_OVERSUBSCRIPTION: 8911 + if (cgn_evt == FPIN_CONGN_OVERSUBSCRIPTION) 8912 + nm_log = false; 8913 + switch (cgn_sev) { 8914 + case FPIN_CONGN_SEVERITY_ERROR: 8915 + /* Take action here for an Alarm event */ 8916 + break; 8917 + case FPIN_CONGN_SEVERITY_WARNING: 8918 + /* Take action here for a Warning event */ 8919 + break; 8920 + } 8921 + break; 8922 + } 8923 + 8924 + /* Change the log level to unmaskable for the following event types. */ 8925 + lpfc_printf_log(phba, (nm_log ? KERN_WARNING : KERN_INFO), 8926 + LOG_CGN_MGMT | LOG_ELS, 8927 + "4683 FPIN CONGESTION %s type %s (x%x) Event " 8928 + "Duration %d mSecs\n", 8929 + cgn_sev_str, cgn_evt_str, cgn_evt, 8930 + be32_to_cpu(cgn->event_period)); 8931 + return rc; 8725 8932 } 8726 8933 8727 8934 static void 8728 - lpfc_els_rcv_fpin(struct lpfc_vport *vport, struct fc_els_fpin *fpin, 8729 - u32 fpin_length) 8935 + lpfc_els_rcv_fpin(struct lpfc_vport *vport, void *p, u32 fpin_length) 8730 8936 { 8731 - struct fc_tlv_desc *tlv; 8937 + struct lpfc_hba *phba = vport->phba; 8938 + struct fc_els_fpin *fpin = (struct fc_els_fpin *)p; 8939 + struct fc_tlv_desc *tlv, *first_tlv, *current_tlv; 8732 8940 const char *dtag_nm; 8733 - uint32_t desc_cnt = 0, bytes_remain; 8734 - u32 dtag; 8941 + int desc_cnt = 0, bytes_remain, cnt; 8942 + u32 dtag, deliver = 0; 8943 + int len; 8735 8944 8736 8945 /* FPINs handled only if we are in the right discovery state */ 8737 8946 if (vport->port_state < LPFC_DISC_AUTH) ··· 8951 8740 if (fpin_length < sizeof(struct fc_els_fpin)) 8952 8741 return; 8953 8742 8743 + /* Sanity check descriptor length. The desc_len value does not 8744 + * include space for the ELS command and the desc_len fields. 8745 + */ 8746 + len = be32_to_cpu(fpin->desc_len); 8747 + if (fpin_length < len + sizeof(struct fc_els_fpin)) { 8748 + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, 8749 + "4671 Bad ELS FPIN length %d: %d\n", 8750 + len, fpin_length); 8751 + return; 8752 + } 8753 + 8954 8754 tlv = (struct fc_tlv_desc *)&fpin->fpin_desc[0]; 8755 + first_tlv = tlv; 8955 8756 bytes_remain = fpin_length - offsetof(struct fc_els_fpin, fpin_desc); 8956 8757 bytes_remain = min_t(u32, bytes_remain, be32_to_cpu(fpin->desc_len)); 8957 8758 8958 - /* process each descriptor */ 8759 + /* process each descriptor separately */ 8959 8760 while (bytes_remain >= FC_TLV_DESC_HDR_SZ && 8960 8761 bytes_remain >= FC_TLV_DESC_SZ_FROM_LENGTH(tlv)) { 8961 - 8962 8762 dtag = be32_to_cpu(tlv->desc_tag); 8963 8763 switch (dtag) { 8964 8764 case ELS_DTAG_LNK_INTEGRITY: 8965 - lpfc_els_rcv_fpin_li(vport, tlv); 8765 + lpfc_els_rcv_fpin_li(phba, tlv); 8766 + deliver = 1; 8767 + break; 8768 + case ELS_DTAG_DELIVERY: 8769 + lpfc_els_rcv_fpin_del(phba, tlv); 8770 + deliver = 1; 8771 + break; 8772 + case ELS_DTAG_PEER_CONGEST: 8773 + lpfc_els_rcv_fpin_peer_cgn(phba, tlv); 8774 + deliver = 1; 8775 + break; 8776 + case ELS_DTAG_CONGESTION: 8777 + deliver = lpfc_els_rcv_fpin_cgn(phba, tlv); 8966 8778 break; 8967 8779 default: 8968 8780 dtag_nm = lpfc_get_tlv_dtag_nm(dtag); 8969 - lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 8970 - "4678 skipped FPIN descriptor[%d]: " 8971 - "tag x%x (%s)\n", 8972 - desc_cnt, dtag, dtag_nm); 8973 - break; 8781 + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, 8782 + "4678 unknown FPIN descriptor[%d]: " 8783 + "tag x%x (%s)\n", 8784 + desc_cnt, dtag, dtag_nm); 8785 + 8786 + /* If descriptor is bad, drop the rest of the data */ 8787 + return; 8788 + } 8789 + cnt = be32_to_cpu(tlv->desc_len); 8790 + 8791 + /* Sanity check descriptor length. The desc_len value does not 8792 + * include space for the desc_tag and the desc_len fields. 8793 + */ 8794 + len -= (cnt + sizeof(struct fc_tlv_desc)); 8795 + if (len < 0) { 8796 + dtag_nm = lpfc_get_tlv_dtag_nm(dtag); 8797 + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, 8798 + "4672 Bad FPIN descriptor TLV length " 8799 + "%d: %d %d %s\n", 8800 + cnt, len, fpin_length, dtag_nm); 8801 + return; 8974 8802 } 8975 8803 8976 - desc_cnt++; 8804 + current_tlv = tlv; 8977 8805 bytes_remain -= FC_TLV_DESC_SZ_FROM_LENGTH(tlv); 8978 8806 tlv = fc_tlv_next_desc(tlv); 8979 - } 8980 8807 8981 - fc_host_fpin_rcv(lpfc_shost_from_vport(vport), fpin_length, 8982 - (char *)fpin); 8808 + /* Format payload such that the FPIN delivered to the 8809 + * upper layer is a single descriptor FPIN. 8810 + */ 8811 + if (desc_cnt) 8812 + memcpy(first_tlv, current_tlv, 8813 + (cnt + sizeof(struct fc_els_fpin))); 8814 + 8815 + /* Adjust the length so that it only reflects a 8816 + * single descriptor FPIN. 8817 + */ 8818 + fpin_length = cnt + sizeof(struct fc_els_fpin); 8819 + fpin->desc_len = cpu_to_be32(fpin_length); 8820 + fpin_length += sizeof(struct fc_els_fpin); /* the entire FPIN */ 8821 + 8822 + /* Send every descriptor individually to the upper layer */ 8823 + if (deliver) 8824 + fc_host_fpin_rcv(lpfc_shost_from_vport(vport), 8825 + fpin_length, (char *)fpin); 8826 + desc_cnt++; 8827 + } 8983 8828 } 8984 8829 8985 8830 /**
+14
drivers/scsi/lpfc/lpfc_hw4.h
··· 20 20 * included with this package. * 21 21 *******************************************************************/ 22 22 23 + #include <uapi/scsi/fc/fc_fs.h> 23 24 #include <uapi/scsi/fc/fc_els.h> 24 25 25 26 /* Macros to deal with bit fields. Each bit field must have 3 #defines ··· 4814 4813 #define LPFC_FW_DUMP 1 4815 4814 #define LPFC_FW_RESET 2 4816 4815 #define LPFC_DV_RESET 3 4816 + 4817 + /* 4818 + * Initializer useful for decoding FPIN string table. 4819 + */ 4820 + #define FC_FPIN_CONGN_SEVERITY_INIT { \ 4821 + { FPIN_CONGN_SEVERITY_WARNING, "Warning" }, \ 4822 + { FPIN_CONGN_SEVERITY_ERROR, "Alarm" }, \ 4823 + } 4824 + 4825 + /* Used for logging FPIN messages */ 4826 + #define LPFC_FPIN_WWPN_LINE_SZ 128 4827 + #define LPFC_FPIN_WWPN_LINE_CNT 6 4828 + #define LPFC_FPIN_WWPN_NUM_LINE 6