/**************************************************************************** * * * Copyright 2004-2011 NetApp Inc. All rights reserved. This file is * * confidential and a trade secret of NetApp Inc. The receipt or * * possession of this file does not convey any rights to reproduce or * * disclose its contents or to manufacture, use, or sell anything it may * * describe, in whole, or in part, without the specific written consent of * * NetApp Inc. * * * ****************************************************************************/ /**************************************************************************** * * * NAME sasphychk.c * * SUMMARY * * VERSION %version: % * * UPDATE DATE %date_modified: % * * PROGRAMMER %created_by: Merck Hung % * * * * Copyright 2002-2011 NetApp Inc. All Rights Reserved. * * * * DESCRIPTION: * * * ****************************************************************************/ #include #include #include #include #include #include #include #include #include "hddMgr.h" #define SASPHY_PATH "/sys/class/sas_phy" #define MAX_BUF_SZ 512 #define COLUMN 70 #define PASS_SIGN "OK" #define FAIL_SIGN "FAIL" enum { SCSI_HOST_SAS0 = 0, SCSI_HOST_SAS1, SCSI_HOST_SAS2, SCSI_HOST_SAS3, SCSI_HOST_SAS4, }; // Jerry : base on Arapaho assignment enum { SAS0_SAS_NUM = 0, SAS1_SAS_NUM = 1, SAS2_SAS_NUM = 2, }; static char hostNoMatchWithQuatHicTbl[] = { SAS0_SAS_NUM, SAS1_SAS_NUM, SAS2_SAS_NUM, }; static int cellHostNoMatchWithQuatHicTbl = ARRAY_SIZE( hostNoMatchWithQuatHicTbl ); static char hostNoMatchWithoutHicTbl[] = { SAS0_SAS_NUM, SAS1_SAS_NUM, }; static int cellHostNoMatchWithoutHicTbl = ARRAY_SIZE( hostNoMatchWithoutHicTbl ); // void printResult( char *str, int pass ) { int len, i; char buf[ COLUMN * 2 ]; len = strlen( str ) + 1; snprintf( buf, sizeof( buf ), "%s ", str ); for( i = len ; i < (COLUMN - strlen( FAIL_SIGN )) ; i++ ) buf[ i ] = '.'; buf[ i ] = 0; if( pass ) strcat( buf, PASS_SIGN "\n" ); else strcat( buf, FAIL_SIGN "\n" ); printf( "%s", buf ); } int findSasNum(int hostNo, int hicType ) { FILE *fp = NULL; char result[255]; char *tbl; int cell,i,index = 0; fp = popen("lsscsi -H | grep mpt | awk -F']' '{print $1}' | tr -d '[' ", "r");// get SAS host number if (fp == NULL) { printf("Failed to run command\n"); return -1; } while (fgets(result, sizeof(result), fp) != NULL) { if (atoi(result) == hostNo) break; index++; } if (hicType == CASCADE) { tbl = hostNoMatchWithQuatHicTbl; cell = cellHostNoMatchWithQuatHicTbl; } else { tbl = hostNoMatchWithoutHicTbl; cell = cellHostNoMatchWithoutHicTbl; } for (i = 0 ; i < cell ; i++) { if (i == index) { pclose(fp); return tbl[i]; } } pclose(fp); return -1; } //20121004 Luap : Add int getExpanderPath(int host_no, int exp_no) { DIR *top = NULL; struct dirent *dir = NULL; int scan_host_no, scan_exp_no; char buf[ MAX_BUF_SZ ]; sprintf(buf, "/sys/class/sas_phy/phy-%d:4/device/port", host_no); top = opendir( buf ); if( !top ) goto remote_expander_check; for( dir = readdir( top ) ; dir ; dir = readdir( top ) ) { if( strncmp( dir->d_name, EXPANDER_PREFIX, strlen( EXPANDER_PREFIX ) ) ) { //printf("cmp dir : %s\n", dir->d_name); continue; } sscanf( dir->d_name, EXPANDER_PREFIX "%d:%d", &scan_host_no, &scan_exp_no); if (scan_exp_no == exp_no){ closedir( top ); return CTL_SLOT_A; // Local Expander } } closedir( top ); remote_expander_check: sprintf(buf, "/sys/class/sas_phy/phy-%d:0/device/port", host_no); top = opendir( buf ); if( !top ){ return -1; // Unknow Path } for( dir = readdir( top ) ; dir ; dir = readdir( top ) ) { if( strncmp( dir->d_name, EXPANDER_PREFIX, strlen( EXPANDER_PREFIX ) ) ) continue; sscanf( dir->d_name, EXPANDER_PREFIX "%d:%d", &scan_host_no, &scan_exp_no); if (scan_exp_no == exp_no){ closedir( top ); return CTL_SLOT_B; // Remote Expander } } closedir( top ); return -1; } //20121004 Luap : Add int getExpanderDCMPath(int host_no, int exp_no) { DIR *top = NULL, *second = NULL; struct dirent *dir, *dir1; int scan_host_no, scan_exp_no, drawer_exp_no, swap = -1; char buf[ MAX_BUF_SZ ], str[ MAX_BUF_SZ ]; FILE *fp = NULL; int ret_code; sprintf(buf, "/sys/class/sas_phy/phy-%d:4/device/port", host_no); top = opendir( buf ); if( !top ) goto remote_expander_check; for( dir = readdir( top ) ; dir ; dir = readdir( top ) ) { if( strncmp( dir->d_name, EXPANDER_PREFIX, strlen( EXPANDER_PREFIX ) ) ) { continue; } sscanf( dir->d_name, EXPANDER_PREFIX "%d:%d", &scan_host_no, &scan_exp_no); system("rm -f /tmp/expander_dcm"); sprintf(buf,"/usr/bin/find /sys/class/sas_expander/expander-%d:%d/device/port* -maxdepth 1 | cut -d'/' -f8 | grep expander >> /tmp/expander_dcm",scan_host_no, scan_exp_no); system(buf); fp = fopen("/tmp/expander_dcm","r"); if (!fp) { printf("Open /tmp/expander_dcm failed on check local path!\n"); goto remote_expander_check; } while(!feof(fp)) { if (fgets(str, 50, fp) != NULL) { sscanf(str, EXPANDER_PREFIX "%d:%d", &scan_host_no, &drawer_exp_no); if (drawer_exp_no == exp_no) { swap = CTL_SLOT_A; if (fp) fclose(fp); goto exit_get_path; } } } if (fp) fclose(fp); break; } remote_expander_check: sprintf(buf, "/sys/class/sas_phy/phy-%d:0/device/port", host_no); second = opendir( buf ); if( !second ){ goto exit_get_path; } for( dir1 = readdir( second ) ; dir1 ; dir1 = readdir( second ) ) { if( strncmp( dir1->d_name, EXPANDER_PREFIX, strlen( EXPANDER_PREFIX ) ) ) continue; sscanf( dir1->d_name, EXPANDER_PREFIX "%d:%d", &scan_host_no, &scan_exp_no); system("rm -f /tmp/expander_dcm"); sprintf(buf,"/usr/bin/find /sys/class/sas_expander/expander-%d:%d/device/port* -maxdepth 1 | cut -d'/' -f8 | grep expander >> /tmp/expander_dcm",scan_host_no, scan_exp_no); system(buf); fp = fopen("/tmp/expander_dcm","r"); if (!fp){ printf("Open /tmp/expander_dcm failed on check remote path!\n"); goto exit_get_path; } while(!feof(fp)) { if (fgets(str, 100, fp) != NULL) { sscanf(str, EXPANDER_PREFIX "%d:%d", &scan_host_no, &drawer_exp_no); if (drawer_exp_no == exp_no) { swap = CTL_SLOT_B; if (fp) fclose(fp); goto exit_get_path; } } } if (fp) fclose(fp); break; } exit_get_path: if (top) closedir( top ); if (second) closedir( second ); return swap; } // int main( int argc, char **argv ) { sasPhyAttr_t devNode; DIR *top = NULL, *testdir = NULL; struct dirent *dir = NULL; char path[ MAX_BUF_SZ ]; char buf[ MAX_BUF_SZ ]; char *pInvDw = NULL, *pDispErr = NULL, *pLossCnt = NULL, *pRstProbCnt = NULL; unsigned int InvDw, DispErr, LossCnt, RstProbCnt; int failed = 0, drawer_no; char *str = NULL; int drv, cnt, swp, hic, encl, slot; FILE *fp = NULL, *fp1 = NULL, *fp2 = NULL; char result[255], tempAddress[255]; if( argc >= 2 ) str = argv[ 1 ]; // Get HIC type hic = findHicId(); encl = findEnclosure(); slot = findCtlSlot(); // Open the top directory top = opendir( SASPHY_PATH ); if( !top ) goto FailExit; if(encl == ENCLOSURE_TSAS || encl == ENCLOSURE_WSAS) // Expander DCM only for Trafford and Wembley { fp = fopen("/tmp/drawer_exp_wwn", "r"); if (fp == NULL) { // assign drawer number to specific Expander DCM system("diag -d sasexpander -p sasexpander -t phyinfo > /tmp/phyinfo"); // assign drawer number to specific Expander DCM if ( slot == CTL_SLOT_A) { system("cat /tmp/phyinfo |grep \"04 EXP\" |awk '{print $6}' | sed s/_//g > /tmp/drawer_exp_wwn; \ cat /tmp/phyinfo |grep \"28 EXP\" |awk '{print $6}' | sed s/_//g >> /tmp/drawer_exp_wwn; \ cat /tmp/phyinfo |grep \"36 EXP\" |awk '{print $6}' | sed s/_//g >> /tmp/drawer_exp_wwn; \ cat /tmp/phyinfo |grep \"24 EXP\" |awk '{print $6}' | sed s/_//g >> /tmp/drawer_exp_wwn; \ cat /tmp/phyinfo |grep \"32 EXP\" |awk '{print $6}' | sed s/_//g >> /tmp/drawer_exp_wwn"); } else { system("cat /tmp/phyinfo |grep \"28 EXP\" |awk '{print $6}' | sed s/_//g > /tmp/drawer_exp_wwn; \ cat /tmp/phyinfo |grep \"04 EXP\" |awk '{print $6}' | sed s/_//g >> /tmp/drawer_exp_wwn; \ cat /tmp/phyinfo |grep \"36 EXP\" |awk '{print $6}' | sed s/_//g >> /tmp/drawer_exp_wwn; \ cat /tmp/phyinfo |grep \"32 EXP\" |awk '{print $6}' | sed s/_//g >> /tmp/drawer_exp_wwn; \ cat /tmp/phyinfo |grep \"24 EXP\" |awk '{print $6}' | sed s/_//g >> /tmp/drawer_exp_wwn"); } system("rm /tmp/phyinfo"); fp = fopen("/tmp/drawer_exp_wwn", "r"); if (fp == NULL) { printf("Failed to get Expander DCM SAS Address\n"); goto FailExit; } } } // Walk through all SAS PHYs for( dir = readdir( top ) ; dir ; dir = readdir( top ) ) { // Skip "." & ".." if( !strcmp( dir->d_name, "." ) || !strcmp( dir->d_name, ".." ) ) continue; // Invalid dword count snprintf( buf, sizeof( buf ), SASPHY_PATH "/%s/invalid_dword_count", dir->d_name ); pInvDw = readFileToNewBuffer( buf ); snprintf( buf, sizeof( buf ), SASPHY_PATH "/%s/loss_of_dword_sync_count", dir->d_name ); pLossCnt = readFileToNewBuffer( buf ); snprintf( buf, sizeof( buf ), SASPHY_PATH "/%s/phy_reset_problem_count", dir->d_name ); pRstProbCnt = readFileToNewBuffer( buf ); snprintf( buf, sizeof( buf ), SASPHY_PATH "/%s/running_disparity_error_count", dir->d_name ); pDispErr = readFileToNewBuffer( buf ); // Sanity check if( !pInvDw || !pLossCnt || !pRstProbCnt || !pDispErr ) { // support on board Fury currently //printf( "Failed to obtain SAS PHY(%s) status\n", dir->d_name ); //failed = 1; goto FreeRes; } // Human readable // Clear Buffer memset( &devNode, 0, sizeof( sasPhyAttr_t ) ); strncpy( devNode.phyName, dir->d_name, MAX_BLKNAME_SIZE ); // "phy-?:?" if( sscanf( dir->d_name, PHY_PREFIX "%d:%d:%d", &devNode.hostNo, &devNode.tgtNo, &devNode.numNo ) == 3 ) { // EXP or EXPDCM devNode.phyType = SASPHY_TYPE_EXPDCM; devNode.sasNo = findSasNum( devNode.hostNo, hic ); // Test for EXP type snprintf( path, MAX_BUF_SIZE, SASPHY_PATH "/" PHY_PREFIX "%d:%d:37", devNode.hostNo, devNode.tgtNo ); testdir = opendir( path ); if( testdir ) { devNode.phyType = SASPHY_TYPE_EXP; closedir( testdir ); } //20121004 Luap : Add if (devNode.phyType == SASPHY_TYPE_EXP) { if (devNode.sasNo != -1) { if ((swp = getExpanderPath(devNode.hostNo, devNode.tgtNo)) == -1) { printf( "Failed to obtain Expander(%s) path\n", dir->d_name ); failed = 1; goto FreeRes; } } else { printf( "Failed to obtain Expander(%s) path type(%d)\n", dir->d_name, devNode.phyType); failed = 1; goto FreeRes; } } else { if (devNode.sasNo != -1) { if ((swp = getExpanderDCMPath(devNode.hostNo, devNode.tgtNo)) == -1) { printf( "Failed to obtain ExpanderDCM(%s) path\n", dir->d_name ); failed = 1; goto FreeRes; } if (swp == CTL_SLOT_A) { drawer_no = 1; snprintf( path, MAX_BUF_SIZE, "cat " SASPHY_PATH "/" PHY_PREFIX "%d:%d:0/sas_address | sed 's/..//'" , devNode.hostNo, devNode.tgtNo ); while (fgets(result, sizeof(result), fp) != NULL) { if (result[strlen(result)-1] == '\n') result[strlen(result)-1] = '\0'; fp1 = popen(path, "r"); if (fgets(tempAddress, sizeof(tempAddress), fp1) != NULL) { if (tempAddress[strlen(tempAddress)-1] == '\n') tempAddress[strlen(tempAddress)-1] = '\0'; if (strcasecmp(result, tempAddress) == 0) { if (fp1) pclose(fp1); break; } } if (fp1) pclose(fp1); drawer_no++; } } } else { printf( "Failed to obtain ExpanderDCM(%s) path type(%d)\n", dir->d_name, devNode.phyType); failed = 1; goto FreeRes; } } } else if( sscanf( dir->d_name, PHY_PREFIX "%d:%d", &devNode.hostNo, &devNode.numNo ) == 2 ) { // SAS PHY devNode.phyType = SASPHY_TYPE_IOC; devNode.sasNo = findSasNum( devNode.hostNo, hic ); } // Convert InvDw = strtol( pInvDw, NULL, 10 ); LossCnt = strtol( pLossCnt, NULL, 10 ); RstProbCnt = strtol( pRstProbCnt, NULL, 10 ); DispErr = strtol( pDispErr, NULL, 10 ); if( InvDw || LossCnt || RstProbCnt || DispErr ) { if( devNode.sasNo == 2) snprintf( buf, sizeof( buf ), "/tmp/sasHICStressPHYError.log", devNode.sasNo ); else snprintf( buf, sizeof( buf ), "/tmp/sas%dStressPHYError.log", devNode.sasNo ); fp2 = fopen( buf , "a+"); if (fp2 == NULL) { printf("Failed to write to log file\n"); goto FailExit; } printf( "===== SAS PHY has error counts =====\n" ); fprintf( fp2, "===== SAS PHY has error counts =====\n" ); if( devNode.phyType == SASPHY_TYPE_EXP ) { if (swp == CTL_SLOT_A) { printf( "SAS%d Onboard Local Expander PHY%d\n", devNode.sasNo, devNode.numNo ); fprintf( fp2, "SAS%d Onboard Local Expander PHY%d\n", devNode.sasNo, devNode.numNo ); } else { printf( "SAS%d Onboard Remote Expander PHY%d\n", devNode.sasNo, devNode.numNo ); fprintf( fp2, "SAS%d Onboard Remote Expander PHY%d\n", devNode.sasNo, devNode.numNo ); } /* if( encl != ENCLOSURE_WSAS ) { drv = findSasDrvByPhy( encl, swp, devNode.numNo ); if( drv >= 0 ) printf( "HDD Slot : %d\n", drv ); else printf( "PHY Conn : Expander to SAS Controller \n" ); }*/ } else if( devNode.phyType == SASPHY_TYPE_EXPDCM ) { if (swp == CTL_SLOT_A) { printf( "SAS%d Local DCM Expander PHY%d Drawer %d\n", devNode.sasNo, devNode.numNo, drawer_no ); fprintf( fp2, "SAS%d Local DCM Expander PHY%d Drawer %d\n", devNode.sasNo, devNode.numNo, drawer_no ); } else { printf( "SAS%d Remote DCM Expander PHY%d\n", devNode.sasNo, devNode.numNo ); fprintf( fp2, "SAS%d Remote DCM Expander PHY%d\n", devNode.sasNo, devNode.numNo ); } /* // Print HDD slot cnt = getOrderNumOfExp( EXPANDER_PATH, devNode.hostNo, devNode.tgtNo ); if( cnt >= 0 && encl == ENCLOSURE_WSAS ) { drv = findWsasDrvByExpAndPhy( swp, cnt - 1, devNode.numNo ); if( drv >= 0 ) printf( "HDD Slot : %d\n", drv ); else printf( "PHY Conn : DCM Expander to Onboard Expander\n" ); }*/ } else if( devNode.phyType == SASPHY_TYPE_IOC ) { if( devNode.sasNo == SAS0_SAS_NUM || devNode.sasNo == SAS1_SAS_NUM) { printf( "SAS%d Onboard IOC PHY%d\n", devNode.sasNo, devNode.numNo ); fprintf( fp2, "SAS%d Onboard IOC PHY%d\n", devNode.sasNo, devNode.numNo ); } else { printf( "SAS HIC IOC PHY%d\n", devNode.numNo ); fprintf( fp2, "SAS HIC IOC PHY%d\n", devNode.numNo ); } } else { printf( "SAS Unknown PHY: " SASPHY_PATH "/%s\n", dir->d_name ); fprintf( fp2, "SAS Unknown PHY: " SASPHY_PATH "/%s\n", dir->d_name ); } printf( "InvDw : %d\n", InvDw ); printf( "DispErr : %d\n", DispErr ); printf( "LossCnt : %d\n", LossCnt ); printf( "RstProbCnt: %d\n", RstProbCnt ); fprintf( fp2, "InvDw : %d\n", InvDw ); fprintf( fp2, "DispErr : %d\n", DispErr ); fprintf( fp2, "LossCnt : %d\n", LossCnt ); fprintf( fp2, "RstProbCnt: %d\n", RstProbCnt ); failed = 1; } FreeRes: // Free resource if( pInvDw ) free( pInvDw ); if( pDispErr ) free( pDispErr ); if( pLossCnt ) free( pLossCnt ); if( pRstProbCnt ) free( pRstProbCnt ); if(encl == ENCLOSURE_TSAS || encl == ENCLOSURE_WSAS) rewind(fp); } if (fp) fclose(fp); if (fp2) fclose(fp2); // Close dir closedir( top ); if( failed ) goto FailExit; if( str ) printResult( str, 1 ); else printf( PASS_SIGN "\n" ); return 0; FailExit: if( str ) printResult( str, 0 ); else printf( FAIL_SIGN "\n" ); return 1; }