#include #include #include #include #include #include #include #include #include #include #include #include #include "../mpi/mpi2_type.h" #include "../mpt3sas_base.h" #include "../mpi/mpi2_sas.h" #include "../mpt3sas_base.h" #include "inc/sasdiag.h" #include "inc/diag_mpt.h" #include "inc/diag_debug.h" #include "inc/diag_platform.h" /* * Extern Declaration */ extern int _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc); extern void sasdiag_proc_entry_remove(void); extern bool isIocNumValid(U8 ioc_num); extern void sasdiag_unlockIocDiagnosticsRegs(struct MPT3SAS_ADAPTER *ioc); extern int mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz); extern int mpt3sas_config_set_iounit_pg3(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page); extern int g_bring_up_ioc[]; extern U8 g_numIocOnboard; struct MPT3SAS_ADAPTER *mpt_softc[NUM_IOC_TOTAL] = {NULL}; #define MAX_FURY_SENSOR 1 #define MAX_THRESHOLD 1 U8 iocLogicalId(struct pci_dev *pdev) { //U8 i; if (!pdev) return -1; /* for (i = 0; i < g_numIocOnboard; i++) { // assume busnum is unique enough to identify an IOC if (g_sasHicPresent) { // if there's HIC on board if ((pdev->device == infoWithHic[i].devId)) { if (pdev->bus->number == infoWithHic[i].busNum) return i; } else return i; } } */ if (pdev->bus->number == 0x3b) // onboard SAS bus number return 0; else return 1; printk(KERN_ERR "iocLogicalId: Found NO match for PCI device 0x%p " "pdev->device=0x%04x pdev->bus->number=0x%02x!!!", pdev, pdev->device, pdev->bus->number); return -1; } void sasdiag_exit_ioc_driver(void) { U8 i; sasdiag_proc_entry_remove(); for (i = 0; i < g_numIocOnboard; i++) g_bring_up_ioc[i] = 0; } /** * * scsih_get_ioc_address - Get IOC Address. * @ioc_id: the number of IOC * * Return: Pointer to IOC */ struct MPT3SAS_ADAPTER *_scsih_get_ioc_address(int ioc_id) { if (isIocNumValid(ioc_id)) { if (mpt_softc[ioc_id] != NULL) return mpt_softc[ioc_id]; else{ printk("IOC:[%d] Get IOC Address Failed! 1\n", ioc_id); return NULL; } }else { printk("IOC:[%d] Get IOC Address Failed! 2\n", ioc_id); return NULL; } } /* * Return number of phy linked up */ int sasdiag_countIocPhyLinkUp(U8 ioc_num) { U8 i, count = 0; U16 sz, ioc_status; Mpi2ConfigReply_t mpi_reply; Mpi2SasIOUnitPage0_t *sasIoUnitPg0 = NULL; struct MPT3SAS_ADAPTER *ioc; if ((ioc = _scsih_get_ioc_address(ioc_num)) == NULL) { DBG_PRINT(DBG_ERR, "countIocPhyLinkUp: ioc %d invalid ioc addr!\n", ioc_num); return -1; } // Get config page sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * sizeof(Mpi2SasIOUnit0PhyData_t)); if ((sasIoUnitPg0 = kzalloc(sz, GFP_KERNEL)) == NULL) { DBG_PRINT(DBG_ERR, "countIocPhyLinkUp: ioc %d fail get mem to read mpi page\n", ioc_num); return -1; } if (!(mpt3sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, sasIoUnitPg0, sz))) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS){ DBG_PRINT(DBG_ERR, "countIocPhyLinkUp: ioc %d IOCStatus !ok when get " "SASIOUnitPage0\n", ioc_num); kfree(sasIoUnitPg0); return -1; } } else { DBG_PRINT(DBG_ERR, "ioc %d failed sasIoUnitPage0 read\n", ioc_num); kfree(sasIoUnitPg0); return -1; } for (i = 0; i < sasIoUnitPg0->NumPhys; ++i) { if ((sasIoUnitPg0->PhyData[i].NegotiatedLinkRate != MPT_IOC_LINK_RATE_DISABLED) && (sasIoUnitPg0->PhyData[i].NegotiatedLinkRate != 0x0)) count++; else DBG_PRINT(DBG_ERR, "IOC %d phy %d link disabled or unplugged (rate=0x%02x)\n", ioc_num, i, sasIoUnitPg0->PhyData[i].NegotiatedLinkRate); } kfree(sasIoUnitPg0); return count; } // Fill out PhyData field in SASIOUnitPage1 int sasdiag_setPhyDataInPage(struct MPT3SAS_ADAPTER *ioc, ioc_port *port, U8 phy, Mpi2SasIOUnitPage0_t *p0, Mpi2SasIOUnitPage1_t *p1) { U32 devInfo = 0; U8 phy_flag = 0, i = 0; if (!port || !p0 || !p1 || !ioc || phy >= MAX_IOC_PHYS) { DBG_PRINT(DBG_ERR, "setPhyDataInPage: Invalid param ioc %p, port %p, phy %d", ioc, port, phy); return -1; } p1->PhyData[phy].PortFlags = 0; // auto-port config p1->PhyData[phy].MaxMinLinkRate = (MPI2_SASIOUNIT1_MAX_RATE_6_0 | MPI2_SASIOUNIT1_MIN_RATE_1_5); phy_flag = p0->PhyData[phy].PhyFlags; if (port->port_stat == PORT_STAT_ENABLED) phy_flag &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; else phy_flag |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; p1->PhyData[phy].PhyFlags = phy_flag; if (port->port_func & FUNC_INITIATOR) { if (port->port_func & FUNC_PORT_LOOPBACK) { //p1->ControlFlags |= MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST; p1->PhyData[phy].Port = phy; // narrow port loop back } else { // Clear the self-test bit b/c this is for normal traffic p1->ControlFlags &= ~MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST; if (port->con_desc == PORT_IOC_CON_LOOP) p1->PhyData[phy].Port = phy; // narrow initiator port else p1->PhyData[phy].Port = port->port_num; // wide port number } // PHY to be set as initiator devInfo = MPI2_SAS_DEVICE_INFO_SSP_INITIATOR | MPI2_SAS_DEVICE_INFO_STP_INITIATOR | MPI2_SAS_DEVICE_INFO_SMP_INITIATOR | MPI2_SAS_DEVICE_INFO_END_DEVICE; DBG_PRINT(DBG_DUMP, " Set Initator Port - Port 0x%02x", p1->PhyData[phy].Port); } else if (port->port_func & FUNC_TARGET) { if (port->port_func & FUNC_PORT_LOOPBACK) { //p1->ControlFlags |= MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST; p1->PhyData[phy].Port = phy; // narrow port loop back } else { // Clear the self-test bit b/c this is for normal traffic p1->ControlFlags &= ~MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST; if (port->con_desc == PORT_IOC_CON_LOOP) p1->PhyData[phy].Port = phy; // narrow target port else p1->PhyData[phy].Port = port->port_num; // wide port number } // PHY to be set as target devInfo = MPI2_SAS_DEVICE_INFO_SSP_TARGET | MPI2_SAS_DEVICE_INFO_END_DEVICE; DBG_PRINT(DBG_DUMP, " Set Target Port - Port 0x%02x", p1->PhyData[phy].Port); } else if (port->port_func & FUNC_IOC_LOOPBACK) { // Set the self-test bit p1->ControlFlags |= MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST; // default PHY to be set as initiator devInfo = MPI2_SAS_DEVICE_INFO_SSP_INITIATOR | MPI2_SAS_DEVICE_INFO_STP_INITIATOR | MPI2_SAS_DEVICE_INFO_SMP_INITIATOR | MPI2_SAS_DEVICE_INFO_END_DEVICE; // // The input phy to be set as initiator, one other phys will be target phy // the caller is supposed to call this setup funct for each initiator phy. // This means when all phys takes turn to be initiator, we have tested // these init-tgt pairs: 0-1, 1-0, 2-3, 3-2, 4-5, 5-4, 6-7, 7-6 // for (i = 0; i < p0->NumPhys; i++) { if (i == phy) { p1->PhyData[i].PhyFlags &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; DBG_PRINT(DBG_DUMP, "\n\t\t iter %d set Init phy 0x%02x - Enbl - " "portnum 0x%02x inf 0x%08x\n", i, phy, p1->PhyData[i].Port, devInfo); } else if ((phy ^ i) == 0x1 ) { // PHY to be set as target devInfo = MPI2_SAS_DEVICE_INFO_SSP_TARGET | MPI2_SAS_DEVICE_INFO_END_DEVICE; p1->PhyData[i].PhyFlags &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; DBG_PRINT(DBG_DUMP, "\n\t\t iter %d set Tgt phy 0x%02x - Enbl - " "Portnum 0x%02x inf 0x%08x\n", i, i, p1->PhyData[i].Port, devInfo); } else { // disable phys that's not a part of the loopback narrow path? p1->PhyData[i].PhyFlags |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; DBG_PRINT(DBG_DUMP, "\n\t\t iter %d - set phy 0%02x Disbl " "Portnum 0x%02x inf 0x%08x\n", i, i, p1->PhyData[i].Port, devInfo); } p1->PhyData[i].Port = i; p1->PhyData[i].ControllerPhyDeviceInfo = devInfo; p1->PhyData[i].PortFlags = 0; // not auto-port config p1->PhyData[i].MaxMinLinkRate = (MPI2_SASIOUNIT1_MAX_RATE_6_0 | MPI2_SASIOUNIT1_MIN_RATE_1_5); } // for - phy loop } else { DBG_PRINT(DBG_ERR, "setPhyDataInPage: unsupported port func x%02x\n", port->port_func); return -1; } p1->PhyData[phy].ControllerPhyDeviceInfo = devInfo; DBG_PRINT(DBG_DUMP, " devInfo 0x%08x\n", p1->PhyData[phy].ControllerPhyDeviceInfo); return 0; } /* * Get exp SAS Address */ int sasdiag_iocGetExpSasAddr(struct MPT3SAS_ADAPTER *ioc, U64 *addr, int iocPhy) { int failCnt = 0, attachedExpPhy = -1; Mpi2ConfigReply_t mpi_reply; Mpi2SasPhyPage0_t phy_pg0; Mpi2SasDevicePage0_t sas_device_pg0; u16 ioc_status; u16 attDevHandle = 0; if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, iocPhy))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } attDevHandle = phy_pg0.AttachedDevHandle; attachedExpPhy = phy_pg0.AttachedPhyIdentifier; if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, attDevHandle))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } out: *addr=0; if ( !failCnt ) *addr=sas_device_pg0.SASAddress; if ( failCnt ) return -1; else return attachedExpPhy; } /** * sasdiag_iocGetAttachedTgtDevH() - Retrieves the devhandle of the first target device * detected as connected to a given phy. * * @ioc: per adapter object * @phy: the number of IOC's phy * @devhandle: target handle * * Returns 0 success, anything else error. */ // old: _scsih_dgIocGetSasDevTgtInfo() int sasdiag_iocGetAttachedTgtDevH(struct MPT3SAS_ADAPTER *ioc, int phy, u16 *devhandle) { Mpi2ConfigReply_t mpi_reply; Mpi2SasPhyPage0_t phy_pg0; Mpi2SasDevicePage0_t sas_device_pg0; Mpi2ExpanderPage0_t expander_pg0; Mpi2ExpanderPage1_t expander_pg1; u16 ioc_status; u16 attDevHandle = 0; u32 devInfo = 0; int failCnt = 0; int i; int find_target = 0; if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, phy))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } attDevHandle = phy_pg0.AttachedDevHandle; if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, attDevHandle))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } devInfo = sas_device_pg0.DeviceInfo; *devhandle = 0; // Here means board has on-board exp, check end device but not expander // This takes care of loopback device (IOC target phys) for cross-ioc loop test if(!MPT_IOC_IS_EXPANDER(devInfo)) { *devhandle = attDevHandle; DBG_PRINT(DBG_PORT, "GetAttachedTgtDevH: direct attached devHandle 0x%04x\n", *devhandle); return 0; } if(MPT_IOC_IS_EXPANDER(devInfo)){ if ((mpt3sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, MPI2_SAS_EXPAND_PGAD_FORM_HNDL, attDevHandle))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } for ( i = 0; !failCnt && i < (expander_pg0.NumPhys) - 1; ++i ){ if ((mpt3sas_config_get_expander_pg1(ioc, &mpi_reply, &expander_pg1, i, attDevHandle))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } if ( MPT_IOC_IS_TARGET(expander_pg1.AttachedDeviceInfo) ){ find_target = 1; *devhandle = expander_pg1.AttachedDevHandle; // printk("IOC[%d]: Target Dev Page on Expander Phy %d\n", ioc->id, i); break; } } if (find_target != 1) failCnt++; } else { failCnt++; } //if (find_target == 1) //printk("IOC[%d]: Getting target info for devHandle=%x\n", ioc->id, *devhandle); out: if (failCnt ||(find_target == 0)) return -1; else return 0; } /** * sasdiag_iocGetAttachedTgtDevH() - Retrieves the device info of the device * detected as connected to a given phy. * * @ioc: per adapter object * @phy: the number of IOC's phy * @devhandle: target handle * * Returns 0 success, anything else error. */ // old: _scsih_dgIocGetSasDevTgtInfo() //Added by Sean P. int sasdiag_iocGetAttachedDevInfo(ioc_phy_att_dev_info* att_dev_info) { // Local Variables for extracting phy page and sas device page struct MPT3SAS_ADAPTER *ioc = NULL; Mpi2ConfigReply_t mpi_reply; Mpi2SasPhyPage0_t phy_pg0; Mpi2SasDevicePage0_t sas_device_pg0; u16 ioc_status; u16 attDevHandle = 0; //Verify IOC number if (!isIocNumValid(att_dev_info->ioc_num)) { DBG_PRINT(DBG_ERR, "getIocPhyStatus: FAILED - Invalid IOC %d\n", att_dev_info->ioc_num); return IOC_NUM_INVALID; } // Fetch adapter ioc = mpt_softc[att_dev_info->ioc_num]; //Get phy page 0 if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, att_dev_info->phy_num))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); return -1;// Fail to get phy page 0 } //Extract the IOC status ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); return -1; } //Extract the attDevHandle attDevHandle = phy_pg0.AttachedDevHandle; //Get sas device page 0 if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, attDevHandle))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); return -1; //Fail to get sas device page 0 } //Extract the device info att_dev_info->att_dev_info = sas_device_pg0.DeviceInfo; return 0; } /* * Enable ReadWrite access to IOC internal registers * IMPORTANT: Must not execute this function when I/O is running */ inline void sasdiag_enableIocRegReadWrite(struct MPT3SAS_ADAPTER *ioc) { U32 regVal; // Unlock Diag reg and enable Diag read/write sasdiag_unlockIocDiagnosticsRegs(ioc); regVal = readl_sdk(&ioc->chip->HostDiagnostic); regVal |= MPI2_DIAG_DIAG_RW_ENABLE; writel_sdk(regVal, &ioc->chip->HostDiagnostic); } inline void sasdiag_regReadWrite(struct MPT3SAS_ADAPTER *ioc, U8 ctrl, U32 regOffset, U32 *val) { // // This is how to access internal reg: // - Setup the ADDRESS register for the register group (i.e. SDMegaWrapper): // a- Write SDMegaWrapper address reg to Diag R/W addr reg // b- Write the offset of the particular SDMegaWrapper reg to Diag R/W data reg // - Setup DATA register for the register group via Diag R/W Data reg: // a- Write the SDMegaWrapper data reg to Diag R/W addr reg // b- Read/Write the value from/to Diag R/W data reg // - Read or Write from/to the register the base register via Diag R/W Data reg // writel_sdk(SAS_IOC_BASE_ADDR_REG, &ioc->chip->DiagRWAddressLow); writel_sdk(0, &ioc->chip->DiagRWAddressHigh); writel_sdk(regOffset, &ioc->chip->DiagRWData); writel_sdk(SAS_IOC_BASE_DATA_REG, &ioc->chip->DiagRWAddressLow); writel_sdk(0, &ioc->chip->DiagRWAddressHigh); if (ctrl == REG_CTRL_READ) *val = readl_sdk(&ioc->chip->DiagRWData); else writel_sdk(*val, &ioc->chip->DiagRWData); } /* * Access IOC internal registers * IMPORTANT: Must not execute this function when I/O is running */ int sasdiag_iocRegReadWrite(U8 ioc_num, U8 regCtrl, U32 regOffset, U32 *val) { struct MPT3SAS_ADAPTER *ioc; if ((ioc = _scsih_get_ioc_address(ioc_num)) == NULL) { DBG_PRINT(DBG_ERR, "iocRegReadWrite: ioc %d failed get ioc addr!\n", ioc_num); return -1; } DBG_PRINT(DBG_REG, "iocRegReadWrite: IOC [%d] Enable Diag Read/Write\n", ioc_num); sasdiag_enableIocRegReadWrite(ioc); DBG_PRINT(DBG_REG, "iocRegReadWrite: IOC [%d] Setup Reg via Diag R/W and Diag Data\n", ioc_num); sasdiag_regReadWrite(ioc, regCtrl, regOffset, val); return 0; } /* * Access GPIO lines using IOUnitPage 3 */ int sasdiag_gpioReadWrite(U8 action, U8 ioc_num, U8 gpio_num, U16 *val) { int i, ret, doReadWrite = 0; U16 sz, ioc_status, readVal; Mpi2ConfigReply_t mpi_reply; Mpi2IOUnitPage3_t *ioUnitPg3 = NULL; struct MPT3SAS_ADAPTER *ioc; if ((ioc = _scsih_get_ioc_address(ioc_num)) == NULL) { DBG_PRINT(DBG_ERR, "gpioReadWrite: ioc %d invalid ioc addr!\n", ioc_num); return IOC_NUM_INVALID; } if ((gpio_num >= MAX_IOC_GPIO_NUM) || (val == NULL)) { DBG_PRINT(DBG_ERR, "gpioReadWrite: ioc %d invalid param\n", gpio_num); return -1; } // Get config page sz = sizeof(Mpi2IOUnitPage3_t); if ((ioUnitPg3 = kzalloc(sz, GFP_KERNEL)) == NULL) { DBG_PRINT(DBG_ERR, "gpioReadWrite: ioc %d fail get mem for MPI page\n", ioc_num); return -1; } if (action == GPIO_WRITE) doReadWrite = 1; if ((action == GPIO_READ) || doReadWrite) { DBG_PRINT(DBG_GPIO, "gpioReadWrite: ioc %d Read gpio 0x%02x\n", ioc_num, gpio_num); if ((ret = mpt3sas_config_get_iounit_pg3(ioc, &mpi_reply, ioUnitPg3, sz)) == 0) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS){ DBG_PRINT(DBG_ERR, "gpioReadWrite: ioc %d IOCStatus !ok\n", ioc_num); kfree(ioUnitPg3); return -1; } } else { DBG_PRINT(DBG_ERR, "ioc %d failed sasIoUnitPage3 read\n", ioc_num); kfree(ioUnitPg3); return -1; } DBG_PRINT(DBG_GPIO, "\nRead IOUnitPage3:\nGPIOCount=0x%02x\n", ioUnitPg3->GPIOCount); for (i = 0; i < ioUnitPg3->GPIOCount; i++) DBG_PRINT(DBG_GPIO, "\tGPIOVal[%d]=0x%04x\n", i, ioUnitPg3->GPIOVal[i]); readVal = ioUnitPg3->GPIOVal[gpio_num]; if (!doReadWrite) { *val = readVal; kfree(ioUnitPg3); return 0; } } if (action == GPIO_WRITE) { DBG_PRINT(DBG_ERR, "gpioReadWrite: ioc %d Write gpio 0x%02x val 0x%04x\n", ioc_num, gpio_num, *val); ioUnitPg3->GPIOVal[gpio_num] = *val; DBG_PRINT(DBG_GPIO, "\nWrite IOUnitControlPage3:\n\tGPIOCount=%d\n", ioUnitPg3->GPIOCount); for (i = 0; i < ioUnitPg3->GPIOCount ; i++) DBG_PRINT(DBG_GPIO, "\tGPIOVal[%d]=0x%04x\n", i, ioUnitPg3->GPIOVal[i]); if ((ret = mpt3sas_config_set_iounit_pg3(ioc, &mpi_reply, ioUnitPg3)) == 0) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS){ DBG_PRINT(DBG_ERR, "gpioReadWrite: ioc %d IOCStatus !ok\n", ioc_num); kfree(ioUnitPg3); return -1; } } else { DBG_PRINT(DBG_ERR, "ioc %d failed sasIoUnitPage3 write\n", ioc_num); kfree(ioUnitPg3); return -1; } } return 0; } /** * * sasdiag_iocGetAttachedDevAddr - Get SAS addr from the device attached to a * given PHY. * * @ioc: per adapter object * @addr:sas address * @phy: the number of IOC's phy * * Returns 0 success, anything else error. */ // diep - name chagne to avoid confusion int sasdiag_iocGetAttachedDevAddr(struct MPT3SAS_ADAPTER *ioc, U64 *addr, int phy) { int failCnt = 0; Mpi2ConfigReply_t mpi_reply; Mpi2SasPhyPage0_t phy_pg0; Mpi2SasDevicePage0_t sas_device_pg0; u16 ioc_status; u16 attDevHandle = 0; if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, phy))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } attDevHandle = phy_pg0.AttachedDevHandle; if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, attDevHandle))) { printk(MPT3SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); failCnt++; goto out; } out: *addr=0; if ( !failCnt ){ *addr = cpu_to_le64(sas_device_pg0.SASAddress); memcpy(&addr,&(sas_device_pg0.SASAddress), sizeof(U64)); //printk("iocGetAttachedDevAddr: IOC %d phy %d SASAddress = 0x%llx\n", // ioc->id, phy, sas_device_pg0.SASAddress); } if ( failCnt ) return -1; else return 0; } /** * For MAPI mfgSASIocPhyStatusSummaryShow */ int sasdiag_getIocPhyStatus(U8 iocNum, U8 phy) { struct MPT3SAS_ADAPTER *ioc = NULL; Mpi2SasPhyPage0_t phy_pg0; Mpi2SasPhyPage1_t phy_pg1; Mpi2ConfigReply_t mpi_reply; struct file *fp; mm_segment_t fs; U8 linkRate[8]; U8 rateVal = 0; U8 buf[64]; U8 i, numPhysToGet; DBG_PRINT(DBG_GET, "getIocPhyStatus: IOC %d phy x%02x\n", iocNum, phy); if (!isIocNumValid(iocNum)) { DBG_PRINT(DBG_ERR, "getIocPhyStatus: FAILED - Invalid IOC %d\n", iocNum); return IOC_NUM_INVALID; } ioc = mpt_softc[iocNum]; if (!ioc) { DBG_PRINT(DBG_ERR, "getIocPhyStatus: FAILED - can't get ioc %d struct\n", iocNum); return 1; } DBG_PRINT(DBG_GET, "getIocPhyStatus: create file to write status\n"); fp = filp_open("/tmp/SAS/sasIocPhyStatus", O_RDWR | O_CREAT, S_IRUSR); if(IS_ERR(fp)) { DBG_PRINT(DBG_ERR, "getIocPhyStatus: FAILED open file to write stat\n"); return 1; } DBG_PRINT(DBG_GET, "getIocPhyStatus: Write status to file\n"); fs = get_fs(); set_fs(KERNEL_DS); snprintf(buf, sizeof(buf), "%s\n", "Phy Rate InvDw DispErr LossCnt RstProbCnt"); fp->f_op->write(fp, buf, strlen(buf), &fp->f_pos); SERVER_PRINT("%s\n", buf); if (phy == PHY_NUM_ALL) { i = 0; numPhysToGet = MAX_IOC_PHYS; } else { i = phy; numPhysToGet = 1; } do { DBG_PRINT(DBG_GET, "getIocPhyStatus: get status for phy %d \n", i); if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, i))) { DBG_PRINT(DBG_ERR, "getIocPhyStatus: FAILED get phy page0 for phy %d \n", i); return 1; } rateVal = phy_pg0.NegotiatedLinkRate >> NEGOTIATED_LOGICAL_LINK_RATE_SHIFT; switch(rateVal) { case 0x0: memcpy(linkRate, "Unknown ", sizeof("Unknown ")); break; case 0x1: memcpy(linkRate, "Disabled", sizeof("Disabled")); break; case 0x2: memcpy(linkRate, "NegoFail", sizeof("NegoFail")); break; case 0x8: memcpy(linkRate, "1.5 ", sizeof("1.5 ")); break; case 0x9: memcpy(linkRate, "3.0 ", sizeof("3.0 ")); break; case 0xA: memcpy(linkRate, "6.0 ", sizeof("6.0 ")); break; case 0xB: memcpy(linkRate, "12.0 ", sizeof("12.0 ")); break; default: memcpy(linkRate, "N/A ", sizeof("N/A ")); } if ((mpt3sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, i))) { DBG_PRINT(DBG_ERR, "getIocPhyStatus: FAILED get phy page1 for phy %d \n", i); return 1; } snprintf(buf, sizeof(buf), "%3d %s 0x%08x 0x%08x 0x%08x 0x%08x\n", i, linkRate, le32_to_cpu(phy_pg1.InvalidDwordCount), le32_to_cpu(phy_pg1.RunningDisparityErrorCount), le32_to_cpu(phy_pg1.LossDwordSynchCount), le32_to_cpu(phy_pg1.PhyResetProblemCount)); fp->f_op->write(fp, buf, strlen(buf), &fp->f_pos); SERVER_PRINT("%s\n", buf); i++; // next phy } while ((--numPhysToGet) > 0); set_fs(fs); filp_close(fp,NULL); return 0; } /** * sasdiag_getIocPhyStatus * * This function read sas phy page 0 to retrive the phy speed * Added by Sean P. */ // Code derived from sasdiag_getIocPhyStatus(U8 iocNum, U8 phy) int sasdiag_getIocPhyLinkSpeed(ioc_phy_speed* phy_speed) { // Local variables struct MPT3SAS_ADAPTER *ioc = NULL; Mpi2SasPhyPage0_t phy_pg0; Mpi2ConfigReply_t mpi_reply; //mm_segment_t fs; //U8 buf[64]; DBG_PRINT(DBG_GET, "getIocPhyStatus: IOC %d phy x%02x\n", phy_speed->ioc_num, phy_speed->phy_num); //Verify IOC number if (!isIocNumValid(phy_speed->ioc_num)) { DBG_PRINT(DBG_ERR, "getIocPhyStatus: FAILED - Invalid IOC %d\n", phy_speed->ioc_num); return IOC_NUM_INVALID; } // Fetch adapter ioc = mpt_softc[phy_speed->ioc_num]; if (!ioc) { DBG_PRINT(DBG_ERR, "getIocPhyStatus: FAILED - can't get ioc %d struct\n", phy_speed->ioc_num); return 1; } DBG_PRINT(DBG_GET, "getIocPhyStatus: get status for phy %d \n", phy_speed->phy_num); // Fetch sas phy page0, if it fails output warning. if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, phy_speed->phy_num))) { DBG_PRINT(DBG_ERR, "getIocPhyStatus: FAILED get phy page0 for phy %d \n", phy_speed->phy_num); return 1; } // Assign logical phy speed phy_speed->logical_link_speed = phy_pg0.NegotiatedLinkRate &NEGOTIATED_LOGICAL_LINK_RATE_MASK; phy_speed->logical_link_speed = phy_speed->logical_link_speed >> NEGOTIATED_LOGICAL_LINK_RATE_SHIFT; // Assign physical phy speed phy_speed->physical_link_speed = phy_pg0.NegotiatedLinkRate & NEGOTIATED_PHYSICAL_LINK_RATE_MASK; return 0; } int sasdiag_getIocTemperature(ioc_temp_info* tempInfo) { struct MPT3SAS_ADAPTER *ioc; Mpi2IOUnitPage7_t *iounitPage7 = NULL; Mpi2ConfigReply_t mpi_reply; U16 sz; if (!isIocNumValid(tempInfo->ioc_num)) return IOC_NUM_INVALID; if ((ioc = _scsih_get_ioc_address(tempInfo->ioc_num)) == NULL) { DBG_PRINT(DBG_ERR, "ioUnitPage7: IOC %d FAILED to get ioc addr!\n", tempInfo->ioc_num); return -1; } sz = sizeof(Mpi2IOUnitPage7_t); iounitPage7 = kzalloc(sz, GFP_KERNEL); if (mpt3sas_config_get_iounit_pg7(ioc, &mpi_reply, iounitPage7)){ DBG_PRINT(DBG_ERR, "Get ioUnitPage7 Fail\n"); return -1; } tempInfo->temperature = iounitPage7->IOCTemperature; kfree(iounitPage7); return 0; } int sasdiag_getFuryTemperature(U8 ioc_num, U16 *temp) { struct MPT3SAS_ADAPTER *ioc; Mpi2IOUnitPage9_t *iounitPage9 = NULL; Mpi2ConfigReply_t mpi_reply; U16 sz; U8 pageNum1; U8 flags, pageType; if (!isIocNumValid(ioc_num)) return IOC_NUM_INVALID; if ((ioc = _scsih_get_ioc_address(ioc_num)) == NULL) { DBG_PRINT(DBG_ERR, "ioUnitPage9: IOC %d FAILED to get ioc addr!\n", ioc_num); return -1; } sz = offsetof(Mpi2IOUnitPage9_t, Sensor) + (MAX_THRESHOLD * sizeof(MPI2_IOUNIT9_SENSOR)); iounitPage9 = kzalloc(sz, GFP_KERNEL); if (mpt3sas_config_get_iounit_pg9(ioc, &mpi_reply, iounitPage9, sz)){ DBG_PRINT(DBG_ERR, "Get ioUnitPage9 Fail\n"); return -1; } pageNum1 = 0xff; pageType = iounitPage9->Header.PageType; pageNum1 = iounitPage9->Header.PageNumber; printk("Page9 Type:%x\n",pageType); printk("Page9 num:%x\n",pageNum1); flags = iounitPage9->Sensor[0].Flags; if (!(flags & MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID)) { DBG_PRINT(DBG_ERR, "The CurrentTemperature field does not contain a valid value\n"); return -1; } else { *temp = iounitPage9->Sensor[0].CurrentTemperature; // internal sensor threshold printk("threshold:%x\n",*temp); } kfree(iounitPage9); return 0; } // Setup Temperature Monitor using IO Unit Page 8 int sasdiag_TempMonitorIntervalReadWrite(U8 action, U8 ioc_num, U8 *interval) { struct MPT3SAS_ADAPTER *ioc; Mpi2ConfigReply_t mpi_reply; U16 ioc_status = 0; int ret; U8 sensorNum; if (!isIocNumValid(ioc_num)) return IOC_NUM_INVALID; if ((ioc = _scsih_get_ioc_address(ioc_num)) == NULL) { DBG_PRINT(DBG_ERR, "ioUnitPage8: IOC %d FAILED to get ioc addr!\n", ioc_num); return -1; } if (mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8)) { DBG_PRINT(DBG_ERR, "Get ioUnitPage8 Fail\n"); return -1; } sensorNum = ioc->iounit_pg8.NumSensors; if (!sensorNum) // if sensor number is zero set NumSensors to 1 { // enable threshold ioc->iounit_pg8.NumSensors = 1; if ((ret = mpt3sas_config_set_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8, sizeof(ioc->iounit_pg8))) == 0) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { DBG_PRINT(DBG_ERR, "Set Sensor number failed: IOC %d IOCStatus !ok\n", ioc_num); return -1; } } } if (action == GET_TEMP_POLLINGINTERVAL) { DBG_PRINT(DBG_IOCTL, "TempIntervalReadWrite: ioc %d Read interval 0x%x\n", ioc_num, (unsigned int)interval); if ((ret = mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8)) == 0) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { DBG_PRINT(DBG_ERR, "TempIntervalReadWrite: ioc %d IOCStatus !ok\n", ioc_num); return -1; } } else { DBG_PRINT(DBG_ERR, "ioc %d failed sasIoUnitPage8 read\n", ioc_num); return -1; } *interval = ioc->iounit_pg8.PollingInterval; //DBG_PRINT(DBG_ERR,"INT Page8 Get Interval :%d\n",*interval); return 0; } if(action == SET_TEMP_POLLINGINTERVAL) { ioc->iounit_pg8.PollingInterval = *interval; if ((ret = mpt3sas_config_set_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8, sizeof(ioc->iounit_pg8))) == 0) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { DBG_PRINT(DBG_ERR, "Temp Monitor interval SetWrite: ioc %d IOCStatus !ok\n", ioc_num); return -1; } } else { DBG_PRINT(DBG_ERR, "IOC %d failed sasIoUnitPage8 write\n", ioc_num); return -1; } } return 0; } // Read Write Temperature Threshold using IO Unit Page 8 int sasdiag_ThresholdReadWrite(U8 action, U8 ioc_num, U8 sensor_num, U16 *threshold) { struct MPT3SAS_ADAPTER *ioc; Mpi2ConfigReply_t mpi_reply; U16 ioc_status = 0, flags; int ret; //U8 sensorNum,interval; if (!isIocNumValid(ioc_num)) return IOC_NUM_INVALID; if ((ioc = _scsih_get_ioc_address(ioc_num)) == NULL) { DBG_PRINT(DBG_ERR, "IoUnitPage8: IOC %d FAILED to get ioc addr!\n", ioc_num); return -1; } if (mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8)) { DBG_PRINT(DBG_ERR, "Get ioUnitPage8 Fail\n"); return -1; } flags = ioc->iounit_pg8.Sensor[0].Flags; // check threshold is enabling if (!(flags & MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE)) // check threshold 0 is enabling { // enable threshold ioc->iounit_pg8.Sensor[0].Flags = flags | 0x0001; if ((ret = mpt3sas_config_set_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8, sizeof(ioc->iounit_pg8))) == 0) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { DBG_PRINT(DBG_ERR, "Set Threshold enable failed: IOC %d IOCStatus !ok\n", ioc_num); return -1; } } if (mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8)) { flags = ioc->iounit_pg8.Sensor[0].Flags; if (!(flags & MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE)) { DBG_PRINT(DBG_ERR, "Set Threshold 0 enable failed\n"); return -1; } } } if (action == GET_IOC_TEMP_THRESHOLD) { DBG_PRINT(DBG_IOCTL, "ThresholdReadWrite: IOC %d Read sensor 0x%02x\n", ioc_num, sensor_num); if ((ret = mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8)) == 0) { flags = ioc->iounit_pg8.Sensor[sensor_num].Flags; //DBG_PRINT(DBG_ERR,"Page8 sensor 0 flags:0x%x\n",flags); ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { DBG_PRINT(DBG_ERR, "Threshold Read: ioc %d IOCStatus !ok\n", ioc_num); return -1; } } else { DBG_PRINT(DBG_ERR, "IOC %d failed sasIoUnitPage8 read\n", ioc_num); return -1; } *threshold = ioc->iounit_pg8.Sensor[sensor_num].Threshold[0]; return 0; } if(action == SET_IOC_TEMP_THRESHOLD) { ioc->iounit_pg8.Sensor[0].Threshold[0] = *threshold; if ((ret = mpt3sas_config_set_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8, sizeof(ioc->iounit_pg8))) == 0) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { DBG_PRINT(DBG_ERR, "Threshold Write: ioc %d IOCStatus !ok\n", ioc_num); return -1; } } else { DBG_PRINT(DBG_ERR, "ioc %d failed sasIoUnitPage8 write\n", ioc_num); return -1; } } return 0; } // Get information using IOC Page 7 int sasdiag_EventMasksInfo(U8 ioc_num, U32 *eventMasks) { struct MPT3SAS_ADAPTER *ioc; Mpi2IOCPage7_t *iocPage7 = NULL; Mpi2ConfigReply_t mpi_reply; U16 sz; if (!isIocNumValid(ioc_num)) return IOC_NUM_INVALID; if ((ioc = _scsih_get_ioc_address(ioc_num)) == NULL) { DBG_PRINT(DBG_ERR, "ioUnitPage7: IOC %d FAILED to get ioc addr!\n", ioc_num); return -1; } sz = sizeof(Mpi2IOCPage7_t); iocPage7 = kzalloc(sz, GFP_KERNEL); if (mpt3sas_config_get_ioc_pg7(ioc, &mpi_reply, iocPage7)){ DBG_PRINT(DBG_ERR, "Get iocPage7 Fail\n"); return -1; } eventMasks = (U32 *)&iocPage7->EventMasks; kfree(iocPage7); return 0; } // setting PHY configuration via SAS IO UINT PAGE 1 int sasdiag_doPhyCfg(U8 ioc_num, U8 action, phy_ctrl* phyctrl) { struct MPT3SAS_ADAPTER *ioc; Mpi2SasIOUnitPage0_t *sasIoUnitPg0 = NULL; Mpi2SasIOUnitPage1_t *sasIoUnitPg1 = NULL; Mpi2ConfigReply_t mpi_reply; U16 sz0, sz1, ioc_status; U8 fail = 0, i = 0; if (!isIocNumValid(ioc_num)) { DBG_PRINT(DBG_IOCTL, "doPhyCfg: FAILED invalid ioc num %d\n", ioc_num); return IOC_NUM_INVALID; } if ((ioc = _scsih_get_ioc_address(ioc_num)) == NULL) { DBG_PRINT(DBG_ERR, "doPhyCfg: IOC %d FAILED to get ioc addr!\n", ioc_num); return -1; } // Get the IOC PHY configuration sz0 = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * sizeof(Mpi2SasIOUnit0PhyData_t)); sz1 = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * sizeof(Mpi2SasIOUnit1PhyData_t)); if (((sasIoUnitPg0 = kzalloc(sz0, GFP_KERNEL)) == NULL) || (sasIoUnitPg1 = kzalloc(sz1, GFP_KERNEL)) == NULL) { DBG_PRINT(DBG_ERR, "doPhyCfg: IOC %d fail get mem for mpi page\n", ioc_num); return -1; } switch (action) { case PHY_CTRL_GET_PHY_STATUS: // Read Page 0 if (!(mpt3sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, sasIoUnitPg0, sz0))) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS){ DBG_PRINT(DBG_ERR, "doPhyCfg: IOC %d IOCStatus !ok when get " "SASIOUnitPage\n", ioc_num); kfree(sasIoUnitPg0); return -1; } } else { DBG_PRINT(DBG_ERR, "doPhyCfg: IOC %d failed sas iounit page 0 read\n", ioc_num); kfree(sasIoUnitPg0); return -1; } phyctrl->phy_flag = sasIoUnitPg0->PhyData[phyctrl->phy_num].PhyFlags; kfree(sasIoUnitPg0); break; case PHY_CTRL_SET_LINK_SPEED: case PHY_CTRL_SET_DISABLE: case PHY_CTRL_SET_ENABLE: // Read Page 1 if (!(mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, sasIoUnitPg1, sz1))) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS){ DBG_PRINT(DBG_ERR, "doPhyCfg: IOC %d IOCStatus !ok when get " "SASIOUnitPage\n", ioc_num); kfree(sasIoUnitPg1); return -1; } } else { DBG_PRINT(DBG_ERR, "doPhyCfg: IOC %d failed mpi cfg page read\n", ioc_num); kfree(sasIoUnitPg1); return -1; } // change all phys in the port if (phyctrl->phy_num == PHY_NUM_ALL) { for (i = 0 ; i < sasIoUnitPg1->NumPhys ; i++) { if (action == PHY_CTRL_SET_LINK_SPEED) sasIoUnitPg1->PhyData[i].MaxMinLinkRate = phyctrl->max_min_link_rate; else if (action == PHY_CTRL_SET_ENABLE) // set PHY enable sasIoUnitPg1->PhyData[i].PhyFlags &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; else sasIoUnitPg1->PhyData[i].PhyFlags |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; } // change one phy } else { if (action == PHY_CTRL_SET_LINK_SPEED) sasIoUnitPg1->PhyData[phyctrl->phy_num].MaxMinLinkRate = phyctrl->max_min_link_rate; else if (action == PHY_CTRL_SET_ENABLE) sasIoUnitPg1->PhyData[phyctrl->phy_num].PhyFlags &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; else sasIoUnitPg1->PhyData[phyctrl->phy_num].PhyFlags |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; } // Write the page down to chip memory DBG_PRINT(DBG_PORT, "Write SASIOUnitPage1 down to IOC %d\n", ioc_num); if((mpt3sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sasIoUnitPg1, sz1))) { DBG_PRINT(DBG_ERR, "Write SASIOUnitPage1 to chip failed\n"); kfree(sasIoUnitPg1); return -1; } // Check mpi reply here? // DBG_PRINT(DBG_ERR, "SASIOUnitPage1 is written, Read back to verify\n"); // Read the page back to verify ioc phy setting if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, sasIoUnitPg1, sz1))) { DBG_PRINT(DBG_ERR, "Verify/Read SASIOUnitPage1 failed\n"); kfree(sasIoUnitPg1); return -1; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { DBG_PRINT(DBG_ERR, "Verify/Read SASIOUnitPage1, IOCStatus not success\n"); kfree(sasIoUnitPg1); return -1; } kfree(sasIoUnitPg1); // initiate port enable so IOC re-discover its SAS domain DBG_PRINT(DBG_PORT, "doPhyCfg: IOC %d sends PortEnable\n", ioc_num); if (_base_send_port_enable(ioc) != 0) { DBG_PRINT(DBG_ERR, "doPhyCfg: IOC %d failed port enable\n", ioc_num); return -1; } DBG_PRINT(DBG_ERR, "doPhyCfg: set PHY successful\n"); break; } return 0; } int sasdiag_getIocWWID(U8 iocNum, U32* wwid) { struct MPT3SAS_ADAPTER *ioc; Mpi2ManufacturingPage5_t *manuf_page5 = NULL; Mpi2ConfigReply_t mpi_reply; U16 sz; U64 SASAddress; if (!isIocNumValid(iocNum)) return IOC_NUM_INVALID; if ((ioc = _scsih_get_ioc_address(iocNum)) == NULL) { DBG_PRINT(DBG_ERR, "ioUnitPage7: IOC %d FAILED to get ioc addr!\n", iocNum); return -1; } sz = offsetof(Mpi2ManufacturingPage5_t, Phy) + (MAX_IOC_PHYS * sizeof(Mpi2Manufacturing5Entry_t)); manuf_page5 = kzalloc(sz, GFP_KERNEL); if (config_get_manufacturing_pg5(ioc, &mpi_reply, manuf_page5, sz, MPI2_CONFIG_ACTION_PAGE_READ_CURRENT)){ DBG_PRINT(DBG_ERR, "Get manufacturing_pg5 Fail\n"); return -1; } SASAddress = manuf_page5->Phy[0].WWID; wwid[0] = (U32)(SASAddress >> 32); wwid[1] = (U32)(SASAddress & 0xffffffffLL); kfree(manuf_page5); return 0; } int sasdiag_getIocNvdataVersionDefault(U8 iocNum, U32* nvdataVersion) { struct MPT3SAS_ADAPTER *ioc; if (!isIocNumValid(iocNum)) return IOC_NUM_INVALID; if ((ioc = _scsih_get_ioc_address(iocNum)) == NULL) { DBG_PRINT(DBG_ERR, "ioUnitPage0: IOC %d FAILED to get ioc addr!\n", iocNum); return -1; } *nvdataVersion = ioc->iounit_pg0.NvdataVersionDefault.Word; return 0; } int sasdiag_getIocVPD(U8 iocNum, U8* VPDdata) { struct MPT3SAS_ADAPTER *ioc; int i; if (!isIocNumValid(iocNum)) return IOC_NUM_INVALID; if ((ioc = _scsih_get_ioc_address(iocNum)) == NULL) { DBG_PRINT(DBG_ERR, "get IOC VPD: IOC %d FAILED to get ioc addr!\n", iocNum); return -1; } /* for (i=0; i<256 ; i++) { if (i == 0 || (i % 16) == 0 ) { printk("%04x: ", i); } printk("%02x ", ioc->manu_pg1.VPD[i]); if (((i+1) % 16) == 0 && i != (256-1)) { printk("\n"); } } */ memcpy(VPDdata, ioc->manu_pg1.VPD, sizeof(ioc->manu_pg1.VPD)); return 0; }