#include #include #include #include #include #include #include #include #include #include #include #include #include #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) #include #endif #include "../mpi/mpi2_type.h" #include "../mpi/mpi2_sas.h" #include "../mpt3sas_base.h" #include "inc/sasdiag.h" #include "inc/diag_mpt.h" #include "inc/diag_debug.h" /* * Extern Declaration */ extern struct MPT3SAS_ADAPTER *_scsih_get_ioc_address(int ioc_id); extern int sasdiag_iocResetToDefault(struct MPT3SAS_ADAPTER *ioc, enum reset_type type); extern int sasdiag_printIocPhyErr(int ioc_id); extern int sasIocPhyErrLogClear(int ioc_num, int mapi); extern int sasdiag_gpioReadWrite(U8 action, U8 ioc_num, U8 gpio_num, U16 *val); extern int sasdiag_hicGpioLedCtrl(U8 action, U8 hicPortNum, char *led); extern int sasdiag_showManPage2(U8 ioc_num, U8 action); extern int sasdiag_getIocPhyStatus(U8 iocNum, U8 phy); extern int _scsih_dgIocShowSasIoUnitPage0(int ioc_id); extern int _scsih_dgIocShowSasIoUnitPage1(int ioc_id); extern int sasdiag_changeFirmware(U8 new_config_id, U8 ioc_num, U8 fwIdx); extern struct MPT3SAS_ADAPTER *mpt_softc[]; /* * Global */ unsigned int g_expander_phy_error; EXPORT_SYMBOL(g_expander_phy_error); unsigned int g_ioc_phy_error=0; EXPORT_SYMBOL(g_ioc_phy_error); unsigned int g_board_ioc_stress_err=0; EXPORT_SYMBOL(g_board_ioc_stress_err); unsigned int g_last_stress_type=10; EXPORT_SYMBOL(g_last_stress_type); unsigned int g_hd_io_error; unsigned int g_sas_hic_stress_err=0; EXPORT_SYMBOL(g_sas_hic_stress_err); unsigned int g_sas_stress_pattern; unsigned int g_peer_stress_failure_hd_num; EXPORT_SYMBOL(g_peer_stress_failure_hd_num); unsigned int g_expansion_port_linked; unsigned int g_sas_stress_soe; unsigned int g_sas_start_socket_srv; struct proc_dir_entry *g_mpt_proc = NULL; int g_MPTIocPatterns_count = 4; /* Num IOC patterns to be tested */ int WRITE_TO_NVSRAM = 0; /* Debug only */ int g_stop_expander_loopback_test = 0; U8 g_front_end_io_cable_ok; U8 g_sasdiag_skip_device_event = 0; U32 g_component_test_flag = 0; int g_bring_up_ioc[NUM_IOC_TOTAL] = { 0 , 0}; /* Indicate SAS Driver loaded/insmod */ bool g_sasHicPresent = FALSE; U8 g_numIocOnboard = NUM_IOC_TOTAL; U8 g_sasEnclType = 0; int g_sasdiag_dbg_flag = (DBG_DUMP); //(DBG_TEST); /* Memory test patterns, Defined IOC testing patterns */ u32 g_MPTIocPatterns[4] = { 0xFFFFFFFF, 0x00000000, 0xAAAAAAAA, //FXIME? 0x55555555 }; U16 BYTE_SWAP_16(U16 Data) { U8 temp; U8 *ptrTemp = (U8 *)&Data; temp = ptrTemp[1]; ptrTemp[1] = ptrTemp[0]; ptrTemp[0] = temp; return Data; } U32 BYTE_SWAP_32(U32 Data) { U8 temp; U8 *ptrTemp = (U8 *)&Data; temp = ptrTemp[3]; ptrTemp[3] = ptrTemp[0]; ptrTemp[0] = temp; temp = ptrTemp[2]; ptrTemp[2] = ptrTemp[1]; ptrTemp[1] = temp; return Data; } /** * * sasDiag_DisplayAttachedDevices - Show all AttachedDevices * * @@ioc_id: the id of ioc * * Returns 0 success, anything else error. */ int sasDiag_DisplayAttachedDevices(int ioc_id) { struct MPT3SAS_ADAPTER *ioc = NULL; Mpi2SasDevicePage0_t sas_device_pg0; Mpi2ConfigReply_t mpi_reply; u16 ioc_status; u16 handle; u32 device_info; u64 SASAddress; int flags; int type; char info[80]; ioc = _scsih_get_ioc_address(ioc_id); if (!ioc) return -1; // Get all Device info printk(" B___T SASAddress PhyNum Handle Parent Type\n"); handle = 0xFFFF; while (!(mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) break; handle = le16_to_cpu(sas_device_pg0.DevHandle); device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); flags = le16_to_cpu(sas_device_pg0.Flags); memcpy(&SASAddress, &sas_device_pg0.SASAddress, sizeof(sas_device_pg0.SASAddress)); le64_to_cpus(&SASAddress); info[0] = 0; type = device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE; if (type == MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER) memcpy(info, ", Edge Expander", sizeof(", Edge Expander")); if (type == MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) memcpy(info, ", FanOut Expander", sizeof(", FanOut Expander")); if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR) if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) memcpy(info,", SAS Initiator and Target" , sizeof(", SAS Initiator and Target")); else memcpy(info,", SAS Initiator" , sizeof(", SAS Initiator")); else if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) memcpy(info, ", SAS Target", sizeof(", SAS Target")); if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST) if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) memcpy(info, ", SATA Initiator and Target", sizeof(", SATA Initiator and Target")); else memcpy(info, ", SATA Initiator", sizeof(", SATA Initiator")); else if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) memcpy(info,", SATA Target" , sizeof(", SATA Target")); if (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) memcpy(info,", ATAPI" , sizeof(", ATAPI")); if (!(flags & MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) memcpy(info, ", not present", sizeof(", not present")); if (le16_to_cpu(sas_device_pg0.ParentDevHandle) == 0){ printk(" %08x%08x %04x %s\n", (u32)(SASAddress >> 32), (u32)(SASAddress & 0xffffffffLL), handle, info + 2); }else{ printk(" %08x%08x %2d %04x %04x %s\n", (u32)(SASAddress >> 32), (u32)(SASAddress & 0xffffffffLL), sas_device_pg0.PhyNum, handle, sas_device_pg0.ParentDevHandle, info + 2); } } return 0; } ssize_t sasdiag_procEntryWrite(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char *buffer, *p; U8 i, numIoc; if (!buf || count > PAGE_SIZE) return -EINVAL; if (!(buffer = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; if (copy_from_user(buffer, buf, count)){ free_page((unsigned long)buffer); return -EFAULT; } if (count < PAGE_SIZE) buffer[count] = '\0'; else if (buffer[PAGE_SIZE-1]){ free_page((unsigned long)buffer); return -EINVAL; } if (!strncmp("2", buffer, 1)) { int ioc_id; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); printk("sasDiag_DisplayAttachedDevices:ioc_id=[%d]!\n",ioc_id); sasDiag_DisplayAttachedDevices(ioc_id); } else if (!strncmp("3", buffer, 1)) { int ioc_id; struct MPT3SAS_ADAPTER *ioc; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); ioc = _scsih_get_ioc_address(ioc_id); printk("sasdiag_iocResetToDefault - FORCE_BIG_HAMMER:ioc_id=[%d] ioc:[%p]!\n",ioc_id, ioc); sasdiag_iocResetToDefault(ioc, FORCE_BIG_HAMMER); } else if (!strncmp("4", buffer, 1)) { int ioc_id; struct MPT3SAS_ADAPTER *ioc; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); ioc = _scsih_get_ioc_address(ioc_id); printk("sasdiag_iocResetToDefault - SOFT_RESET:ioc_id=[%d] ioc:[%p]!\n",ioc_id, ioc); sasdiag_iocResetToDefault(ioc, SOFT_RESET); } else if (!strncmp("5", buffer, 1)) { int ioc_id; struct MPT3SAS_ADAPTER *ioc; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); ioc = _scsih_get_ioc_address(ioc_id); printk("_scsih_dgIocShowSasIoUnitPage0!\n"); _scsih_dgIocShowSasIoUnitPage0(ioc_id); } else if (!strncmp("7", buffer, 1)) { int ioc_id; //struct MPT3SAS_ADAPTER *ioc; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); printk("_scsih_dgIocShowSasIoUnitPage1!\n"); _scsih_dgIocShowSasIoUnitPage1(ioc_id); } else if (!strncmp("9", buffer, 1)) { int ioc_id; //struct MPT3SAS_ADAPTER *ioc; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); //old: scsih_Getlinkerrors(ioc_id); sasdiag_printIocPhyErr(ioc_id); } else if (!strncmp("d", buffer, 1)) { int ioc_id, err = 0; struct MPT3SAS_ADAPTER *ioc; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); printk("IOC Reset:ioc_id=[%d]!\n",ioc_id); ioc = _scsih_get_ioc_address(ioc_id); err = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); printk(MPT3SAS_INFO_FMT "host reset: %s\n", ioc->name, ((!err) ? "SUCCESS" : "FAILED")); if (err != 0) printk("[Debug] IOC Reset Failed!\n"); else printk("[Debug] IOC Reset Success!\n"); } else if (!strncmp("e", buffer, 1)) { int ioc_id, err = 0; //struct MPT3SAS_ADAPTER *ioc; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); printk("IOC Phy Error Log clear:ioc_id=[%d]!\n",ioc_id); //ioc = _scsih_get_ioc_address(ioc_id); err = sasIocPhyErrLogClear(ioc_id, FALSE); if (err != 0) printk("[Debug] Clear PHY error log Failed!\n"); else printk("[Debug] Clear PHY error log Success!\n"); } else if (!strncmp("l", buffer, 1)) { int ioc_id, err = 0; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); printk("sasdiag_showManPage2 :ioc_id=[%d]!\n",ioc_id); err = sasdiag_showManPage2(ioc_id, MPI2_CONFIG_ACTION_PAGE_READ_CURRENT); if (err != 0) printk("[Debug] Failed!\n"); else printk("[Debug] Success!\n"); } else if (!strncmp("m", buffer, 1)) { int ioc_id, err = 0; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); printk("sasdiag_getIocPhyStatus :ioc_id=[%d]!\n",ioc_id); err = sasdiag_getIocPhyStatus(ioc_id, PHY_NUM_ALL); if (err != 0) printk("[Debug] Failed!\n"); else printk("[Debug] Success!\n"); } else if (!strncmp("o", buffer, 1)) { int ioc_id, err = 0, mode; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); p++; mode = simple_strtoul(p, &p, 0); printk("_scsih_dgIocShowSasIoUnitPageX :ioc_id=[%d] mode:[%d]!\n",ioc_id, mode); if (mode == 0) err = _scsih_dgIocShowSasIoUnitPage0(ioc_id); else err = _scsih_dgIocShowSasIoUnitPage1(ioc_id); if (err != 0) printk("[Debug] Failed!\n"); else printk("[Debug] Success!\n"); } else if (!strncmp("r", buffer, 1)) { int ioc_id, err = 0, fwIdx; p = buffer + 2; ioc_id=simple_strtoul(p, &p, 0); p++; fwIdx = simple_strtoul(p, &p, 0); printk("sasdiag_changeFirmware ioc_id=[%d] fwIdx:[0x%x]!\n",ioc_id,fwIdx); err = sasdiag_changeFirmware(CFG_ID_IOC_SPECIFIC, ioc_id, fwIdx); if (err != 0) printk("[Debug] Failed!\n"); else printk("[Debug] Success!\n"); } free_page((unsigned long)buffer); return count; } static struct file_operations SasProcFops = { .write = sasdiag_procEntryWrite, }; void sasdiag_procEntryInitwithoutIoc(void) { printk("[SAS MESSAGE] IOC:Create proc entry\n"); if (g_mpt_proc) return; g_mpt_proc = proc_create_data("lsi", 0644, NULL, &SasProcFops, NULL); if (!g_mpt_proc) printk("PROC_ERROR Can't create proc entry\n"); } // Revisit: should remove or not? If not, rmmod/insmod causes kernel crash // because the "lsi" entry already exist at insmod (the second time) // to do: check if "lsi" entry exit, then not create it and not remove at rmmod void sasdiag_proc_entry_remove(void) { if (g_mpt_proc) { remove_proc_entry("lsi", 0); g_mpt_proc = NULL; } }