#include #include #include #include #include #include #include #include "../mpi/mpi2_type.h" #include "../mpt3sas_base.h" #include "inc/sasdiag.h" #include "inc/diag_debug.h" extern struct MPT3SAS_ADAPTER *_scsih_get_ioc_address(int ioc_id); extern bool isIocNumValid(U8 ioc_num); extern struct MPT3SAS_ADAPTER *mpt_softc[]; /** * For MAPI Returns 0 for success, non-zero for failure. * Added by Sean P. for implementing single phy error count reset */ int sasIocSinglePhyErrLogClear(int ioc_num, int phy_num) { // Local Variables struct MPT3SAS_ADAPTER *ioc; Mpi2SasIoUnitControlReply_t mpi_reply; Mpi2SasIoUnitControlRequest_t mpi_request; int ret; // Validate the ioc number if (!isIocNumValid(ioc_num)) { return IOC_NUM_INVALID; } // Extract the adapter struct ioc = mpt_softc[ioc_num]; if (!ioc) { return 1; } // Initialization memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; mpi_request.Operation = MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG; mpi_request.PhyNum = phy_num; mpi_request.VF_ID = 0; // Send out the request to the IOC ret = mpt3sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request); if(ret != 0) { return ret; } // Sucessful result return 0; } /** * For MAPI Returns 0 for success, non-zero for failure. * Actual implementation is moved to sasIocSinglePhyErrLogClear */ int sasIocPhyErrLogClear(int ioc_num, int mapi) { int ret; int PhyNum; for(PhyNum = 0; PhyNum < MAX_IOC_PHYS; PhyNum++) { ret =sasIocSinglePhyErrLogClear( ioc_num, PhyNum ); if(ret != 0) { return ret; } } return 0; } /** * scsih_ClearPhyLinkerError - This function is used to clear link error of Falcon. * * @ioc_id: the id of ioc * * Returns 0 success, anything else error. */ int sasdiag_clearIocPhyLinkError(int ioc_id) { struct MPT3SAS_ADAPTER *ioc; Mpi2SasIoUnitControlReply_t mpi_reply; Mpi2SasIoUnitControlRequest_t mpi_request; u8 ii; //mptsas_init_ioc(); ioc = _scsih_get_ioc_address(ioc_id); if (ioc == NULL){ printk("[Driver] ioc:[%d] is NULL !\n", ioc_id); return -1; } for (ii = 0 ; ii < MAX_IOC_PHYS ; ii++){ memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; mpi_request.Operation = MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG; mpi_request.PhyNum = ii; mpi_request.VF_ID = 0; if ((mpt3sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request)) != 0) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); return -1; } } return 0; } /** * sasdiag_printIocPhyErr - Get Falcon Phy error count * * @ioc_id: the id of ioc * * Returns 0 success, anything else error. */ // old: int scsih_Getlinkerrors(int ioc_id) // diep - just a name cange to avoid confusion int sasdiag_printIocPhyErr(int ioc_id) { struct MPT3SAS_ADAPTER *ioc; Mpi2ConfigReply_t mpi_reply; Mpi2SasPhyPage1_t phy_pg1; int i; ioc = _scsih_get_ioc_address(ioc_id); if (ioc == NULL) { DBG_PRINT(DBG_ERR, "printIocPhyErr: ioc %d can't get ioc mpt address!\n", ioc_id); return -1; } printk("\n\nLink Error For IOC [%d]:\n\n", ioc_id); // Fill in information for each phy. for (i = 0; i < MAX_IOC_PHYS; i++) { printk("Phy :[%d] ====================================================\n",i); if ((mpt3sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, i))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); return -1; } if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) printk(MPT3SAS_INFO_FMT "phy(%d), ioc_status" "(0x%04x), loginfo(0x%08x)\n", ioc->name, i, le16_to_cpu(mpi_reply.IOCStatus), le32_to_cpu(mpi_reply.IOCLogInfo)); // dump PHY Page 1 data printk("Invalid Dword Count=0x%x\n", le32_to_cpu(phy_pg1.InvalidDwordCount)); printk("Running Disparity Error Count=0x%x\n", le32_to_cpu(phy_pg1.RunningDisparityErrorCount)); printk("Loss Dword Synch Count=0x%x\n", le32_to_cpu(phy_pg1.LossDwordSynchCount)); printk("PHY Reset Problem Count=0x%x\n", le32_to_cpu(phy_pg1.PhyResetProblemCount)); if(le32_to_cpu(phy_pg1.InvalidDwordCount) != 0 || le32_to_cpu(phy_pg1.RunningDisparityErrorCount) != 0 || le32_to_cpu(phy_pg1.LossDwordSynchCount) != 0 || le32_to_cpu(phy_pg1.PhyResetProblemCount)!= 0 ){ } } // for - phy loop return 0; } /* * Get IOC PHY error info for either all phys in the IOC or a specific phy */ int sasdiag_getIocPhyErrInfo(U8 ioc_num, U8 phy_num, ioc_phy_err *err) { struct MPT3SAS_ADAPTER *ioc; Mpi2ConfigReply_t mpi_reply; Mpi2SasPhyPage1_t phy_pg1; U8 i; ioc = _scsih_get_ioc_address(ioc_num); if (ioc == NULL) { DBG_PRINT(DBG_ERR, "GetIocPhyErr: ioc %d can't get ioc mpt address!!!\n", ioc_num); return -1; } // Go thru all phys. for (i = 0; i < MAX_IOC_PHYS; i++) { // Check if the caller means specific phy if ((phy_num != PHY_NUM_ALL) && (phy_num != i)) continue; if ((mpt3sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, i))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); return -1; } if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) printk(MPT3SAS_INFO_FMT "getIocPhyErr: phy(%d), ioc_status" "(0x%04x), loginfo(0x%08x)\n", ioc->name, i, le16_to_cpu(mpi_reply.IOCStatus), le32_to_cpu(mpi_reply.IOCLogInfo)); err->InvalidDwordCount += le32_to_cpu(phy_pg1.InvalidDwordCount); err->RunningDisparityErrorCount += le32_to_cpu(phy_pg1.RunningDisparityErrorCount); err->LossDwordSynchCount += le32_to_cpu(phy_pg1.LossDwordSynchCount); err->PhyResetProblemCount += le32_to_cpu(phy_pg1.PhyResetProblemCount); } // for - phy loop return 0; }