diff options
Diffstat (limited to 'util')
91 files changed, 79279 insertions, 0 deletions
diff --git a/util/AnsiTerm.cpp b/util/AnsiTerm.cpp new file mode 100644 index 0000000..be94465 --- /dev/null +++ b/util/AnsiTerm.cpp @@ -0,0 +1,1892 @@ +/* + * AnsiTerm.cpp + * Windows ANSI Terminal Emulation + * + * Author: Robert Nelson robertnelson at users.sourceforge.net + * Copyright (c) 2009 Robert Nelson + * + * 10/07/09 Robert Nelson - Created + * 10/08/09 Robert Nelson + * - Fixed bug with resetting attribute to Black on Black on exit + * - Fixed setting of attribute when erasing + * - Added automatic handling of buffer resize events + * - Added display of unrecognized escape sequences + * 10/15/09 Robert Nelson + * - Fixed display problems caused by custom ColorTable used by cmd.exe + * - Fixed cursor positioning problems with OriginMode. + * - Changed to use block cursor because I think its more terminal like :-) + * - Added Reset handling + * - Added Cursor Show / Hide + * 10/16/09 Robert Nelson + * - Better handling of ColorTable. + * 10/17/09 Robert Nelson + * - Use GetProcAddress for (Get/Set)ConsoleScreenBufferInfoEx since they + * are only available on Vista and beyond. + * + * Todo: + * - Implement soft tabs + */ + +/* +Copyright (c) 2009, Robert Nelson +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include <windows.h> +#include <stdio.h> +#include <assert.h> +#include "AnsiTerm.h" + +extern "C" unsigned char fCRLF; +extern "C" void dbglog( char *pattn, ... ); + +CAnsiTerm::CSICode CAnsiTerm::s_CSITable[] = +{ + { '[', DS_CSIParam }, + { '#', DS_DECPrivate }, + { '(', DS_SelectG0 }, + { ')', DS_SelectG1 }, + { '=', DS_None, &ProcessDECKPAM }, // Keypad Application Mode + { '>', DS_None, &ProcessDECKPNM }, // Keypad Numeric Mode + { '7', DS_None, &ProcessDECSC }, // Save Cursor + { '8', DS_None, &ProcessDECRC }, // Restore Cursor + { 'D', DS_None, &ProcessIND }, // Index + { 'E', DS_None, &ProcessNEL }, // Next Line + { 'H', DS_None, &ProcessHTS }, // Horizontal Tab Set + { 'M', DS_None, &ProcessRI }, // Reverse Index + { 'Z', DS_None, &ProcessDECID }, // Identify Terminal + { 'c', DS_None, &ProcessRIS }, // Reset to Initial State + { 's', DS_None, &ProcessSCP }, // Save Cursor Position + { 'u', DS_None, &ProcessRCP }, // Restore Cursor Position + { '\0' } +}; + +CAnsiTerm::CSIFunction CAnsiTerm::s_DECFunction[] = +{ + { '3', &ProcessDECDHLT }, // Double Height Line Top + { '4', &ProcessDECDHLB }, // Double Height Line Bottom + { '5', &ProcessDECSWL }, // Single Width Line + { '6', &ProcessDECDWL }, // Double Width Line + { '8', &ProcessDECALN }, // Screen Alignment Display + { '\0' } +}; + +CAnsiTerm::CSIFunction CAnsiTerm::s_CSIFunction[] = +{ + { 'A', &ProcessCUU }, // Cursor Up + { 'B', &ProcessCUD }, // Cursor Down + { 'C', &ProcessCUF }, // Cursor Forward + { 'D', &ProcessCUB }, // Cursor Backward + { 'H', &ProcessCUP }, // Cursor Position + { 'J', &ProcessED }, // Erase in Display + { 'K', &ProcessEL }, // Erase in Line + { 'c', &ProcessDA }, // Device Attributes + { 'f', &ProcessHVP }, // Horizontal and Vertical Position + { 'g', &ProcessTBC }, // Tabulation Clear + { 'h', &ProcessSM }, // Set Mode + { 'l', &ProcessRM }, // Reset Mode + { 'm', &ProcessSGR }, // Select Graphics Rendition + { 'n', &ProcessDSR }, // Device Status Report + { 'q', &ProcessDECLL }, // DEC Load LEDs + { 'r', &ProcessDECSTBM }, // DEC Set Top and Bottom Margins + { 'x', &ProcessDECREQTPARM }, // Request Terminal Parameters + { 'y', &ProcessDECTST }, // Invoke Confidence Test + { '\0' } +}; + +wchar_t CAnsiTerm::s_GraphicChars[kMaxGraphicsChar - kMinGraphicsChar + 1] = +{ + 0x0020, // 0137 5F 95 _ Blank + 0x2666, // 0140 60 96 ` Diamond + 0x2592, // 0141 61 97 a Checkerboard + 0x2409, // 0142 62 98 b Horizontal Tab + 0x240C, // 0143 63 99 c Form Feed + 0x240D, // 0144 64 100 d Carriage Return + 0x240A, // 0145 65 101 e Line Feed + 0x00B0, // 0146 66 102 f Degree Symbol + 0x00B1, // 0147 67 103 g Plus/Minus + 0x2424, // 0150 68 104 h New Line + 0x240B, // 0151 69 105 i Vertical Tab + 0x2518, // 0152 6A 106 j Lower-right corner + 0x2510, // 0153 6B 107 k Upper-right corner + 0x250C, // 0154 6C 108 l Upper-left corner + 0x2514, // 0155 6D 109 m Lower-left corner + 0x253C, // 0156 6E 110 n Crossing Lines + 0x00AF, // 0157 6F 111 o Horizontal Line - Scan 1 + 0x0070, // 0160 70 112 p Horizontal Line - Scan 3 (No translation) + 0x2500, // 0161 71 113 q Horizontal Line - Scan 5 + 0x0072, // 0162 72 114 r Horizontal Line - Scan 7 (No translation) + 0x005F, // 0163 73 115 s Horizontal Line - Scan 9 + 0x251C, // 0164 74 116 t Left "T" + 0x2524, // 0165 75 117 u Right "T" + 0x2534, // 0166 76 118 v Bottom "T" + 0x252C, // 0167 77 119 w Top "T" + 0x2502, // 0170 78 120 x | Vertical bar + 0x2264, // 0171 79 121 y Less than or equal to + 0x2265, // 0172 7A 122 z Greater than or equal to + 0x03C0, // 0173 7B 123 { Pi + 0x2260, // 0174 7C 124 | Not equal to + 0x00A3, // 0175 7D 125 } UK Pound Sign + 0x00B7 // 0176 7E 126 ~ Centered dot +}; + +wchar_t CAnsiTerm::s_OemToUnicode[256] = +{ + 0x2007, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, // 00-07 + 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, // 08-0F + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, // 10-17 + 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, // 18-1F + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, // 20-27 + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, // 28-2F + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, // 30-37 + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, // 38-3F + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, // 40-47 + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, // 48-4F + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, // 50-57 + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, // 58-5F + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, // 60-67 + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, // 68-6F + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, // 70-77 + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, // 78-7F + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, // 80-87 + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, // 88-8F + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, // 90-97 + 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, // 98-9F + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, // A0-A7 + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, // A8-AF + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, // B0-B7 + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, // B8-BF + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, // C0-C7 + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, // C8-CF + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, // D0-D7 + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, // D8-DF + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, // E0-E7 + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, // E8-EF + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, // F0-F7 + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 // F8-FF +}; + +COLORREF CAnsiTerm::s_ColorTable[kColorTableSize] = +{ + RGB(0, 0, 0), + RGB(0, 0, 128), + RGB(0, 128, 0), + RGB(0, 128, 128), + RGB(128, 0, 0), + RGB(128, 0, 128), + RGB(128, 128, 0), + RGB(192, 192, 192), + RGB(128, 128, 128), + RGB(0, 0, 255), + RGB(0, 255, 0), + RGB(0, 255, 255), + RGB(255, 0, 0), + RGB(255, 0, 255), + RGB(255, 255, 0), + RGB(255, 255, 255) +}; + +CAnsiTerm::PFN_GetConsoleScreenBufferInfoEx CAnsiTerm::s_pfnGetConsoleScreenBufferInfoEx; +CAnsiTerm::PFN_SetConsoleScreenBufferInfoEx CAnsiTerm::s_pfnSetConsoleScreenBufferInfoEx; + +CAnsiTerm::CAnsiTerm(void) +{ + m_hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + GetConsoleMode(m_hConsole, &m_dwOrigConsoleMode); + + SetConsoleMode(m_hConsole, ENABLE_PROCESSED_OUTPUT); + + CONSOLE_CURSOR_INFO cursorInfo; + + GetConsoleCursorInfo(m_hConsole, &cursorInfo); + + m_dwOrigCursorSize = cursorInfo.dwSize; + + WindowSizeChanged(true); +} + +CAnsiTerm::~CAnsiTerm(void) +{ + CONSOLE_CURSOR_INFO cursorInfo = { m_dwOrigCursorSize, TRUE }; + + SetConsoleCursorInfo(m_hConsole, &cursorInfo); + + SetConsoleMode(m_hConsole, m_dwOrigConsoleMode); + + SetConsoleTextAttribute(m_hConsole, m_wOrigConsoleAttribute); + + if (m_bResetColorTable) + { + CONSOLE_SCREEN_BUFFER_INFOEX consoleInfo = { sizeof(consoleInfo) }; + + s_pfnGetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + memcpy(consoleInfo.ColorTable, m_OrigColorTable, kColorTableSize * sizeof(consoleInfo.ColorTable[0])); + + // There is a bug between GetConsoleScreenBufferInfoEx and SetConsoleScreenBufferInfoEx. + // The first treats srWindow.Right and srWindow.Bottom as inclusive and the latter as exclusive. + consoleInfo.srWindow.Right++; + consoleInfo.srWindow.Bottom++; + + s_pfnSetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + // Reset the attributes on existing lines so that at least white on black looks + // correct. + COORD coordStart = { 0, 0 }; + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, m_wOrigConsoleAttribute, m_BufferSize.X * m_BufferSize.Y, coordStart, &dwWritten); + } + + CloseHandle(m_hConsole); +} + +void +CAnsiTerm::WindowSizeChanged(bool bInitial) +{ + WORD wCurrentAttribute; + COORD dwCurrentCursorPosition; + + if (bInitial) + { + HMODULE hKernel32 = GetModuleHandle("kernel32"); + + if (hKernel32 != NULL) + { + s_pfnGetConsoleScreenBufferInfoEx = (PFN_GetConsoleScreenBufferInfoEx)GetProcAddress(hKernel32, "GetConsoleScreenBufferInfoEx"); + s_pfnSetConsoleScreenBufferInfoEx = (PFN_SetConsoleScreenBufferInfoEx)GetProcAddress(hKernel32, "SetConsoleScreenBufferInfoEx"); + + if (s_pfnGetConsoleScreenBufferInfoEx == NULL || s_pfnSetConsoleScreenBufferInfoEx == NULL) + { + s_pfnGetConsoleScreenBufferInfoEx = NULL; + s_pfnSetConsoleScreenBufferInfoEx = NULL; + } + } + + m_bResetColorTable = false; + } + + if (s_pfnGetConsoleScreenBufferInfoEx != NULL) + { + CONSOLE_SCREEN_BUFFER_INFOEX consoleInfo = { sizeof(consoleInfo) }; + + s_pfnGetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + m_BufferSize = consoleInfo.dwSize; + + m_WindowSize.X = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1; + m_WindowSize.Y = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1; + + wCurrentAttribute = consoleInfo.wAttributes; + dwCurrentCursorPosition = consoleInfo.dwCursorPosition; + + if (bInitial) + { + m_bResetColorTable = memcmp(consoleInfo.ColorTable, s_ColorTable, sizeof(s_ColorTable)) != 0; + + if (m_bResetColorTable) + { + // The command prompt (cmd.exe) uses a nonstandard color table + // So we save it away and reset it to match the Console API documentation + size_t colorCopyLen = kColorTableSize * sizeof(consoleInfo.ColorTable[0]); + + memcpy(m_OrigColorTable, consoleInfo.ColorTable, colorCopyLen); + + memcpy(consoleInfo.ColorTable, s_ColorTable, colorCopyLen); + + // There is a bug between GetConsoleScreenBufferInfoEx and SetConsoleScreenBufferInfoEx. + // The first treats srWindow.Right and srWindow.Bottom as inclusive and the latter as exclusive. + consoleInfo.srWindow.Right++; + consoleInfo.srWindow.Bottom++; + + s_pfnSetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + // Reset the attributes on existing lines so that at least white on black looks + // correct. + COORD coordStart = { 0, 0 }; + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, kDefaultAttribute, m_BufferSize.X * m_BufferSize.Y, coordStart, &dwWritten); + } + } + } + else + { + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + + GetConsoleScreenBufferInfo(m_hConsole, &consoleInfo); + + m_BufferSize = consoleInfo.dwSize; + + m_WindowSize.X = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1; + m_WindowSize.Y = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1; + + wCurrentAttribute = consoleInfo.wAttributes; + dwCurrentCursorPosition = consoleInfo.dwCursorPosition; + } + + m_WindowOrigin.X = 0; + m_WindowOrigin.Y = m_BufferSize.Y - m_WindowSize.Y; + + if (bInitial) + { + m_wOrigConsoleAttribute = wCurrentAttribute; + + SHORT nLines = dwCurrentCursorPosition.Y - m_WindowOrigin.Y; + + if (nLines != 0) + { + SMALL_RECT rectSource = { 0, 0, m_BufferSize.X - 1, m_BufferSize.Y - 1 }; + COORD coordDest = { 0, 0 }; + CHAR_INFO charInfo = { ' ', kDefaultAttribute }; + + if (nLines > 0) + { + rectSource.Top = nLines; + } + else + { + coordDest.Y -= nLines; + rectSource.Bottom += nLines; + } + + ScrollConsoleScreenBuffer(m_hConsole, &rectSource, NULL, coordDest, &charInfo); + } + } + + ResetTerm(); +} + +int +CAnsiTerm::ProcessInput(CAnsiTerm::KeyCode keyCode, unsigned char *pOutput, int iOutputSize) +{ + int iOutputLength = 0; + + if (pOutput == NULL || iOutputSize < 1) + { + return 0; + } + + if (!keyCode.bKeyDown) + { + return 0; + } + + if (VK_F1 <= keyCode.VirtualKeyCode && keyCode.VirtualKeyCode <= VK_F12) + { + pOutput[iOutputLength++] = CH_ESC; + pOutput[iOutputLength++] = 'O'; + pOutput[iOutputLength++] = 'P' + keyCode.VirtualKeyCode - VK_F1; + } + else + if (keyCode.VirtualKeyCode == VK_UP || + keyCode.VirtualKeyCode == VK_DOWN || + keyCode.VirtualKeyCode == VK_RIGHT || + keyCode.VirtualKeyCode == VK_LEFT) + { + pOutput[iOutputLength++] = CH_ESC; + + if ((m_bCursorKeyMode && !keyCode.bControl) || + (!m_bCursorKeyMode && keyCode.bControl)) + { + pOutput[iOutputLength++] = 'O'; + } + else + { + pOutput[iOutputLength++] = '['; + } + + switch (keyCode.VirtualKeyCode) + { + case VK_UP: + pOutput[iOutputLength++] = 'A'; + break; + + case VK_DOWN: + pOutput[iOutputLength++] = 'B'; + break; + + case VK_RIGHT: + pOutput[iOutputLength++] = 'C'; + break; + + case VK_LEFT: + pOutput[iOutputLength++] = 'D'; + break; + } + } + else + if (keyCode.VirtualKeyCode == VK_HOME || + keyCode.VirtualKeyCode == VK_INSERT || + keyCode.VirtualKeyCode == VK_DELETE || + keyCode.VirtualKeyCode == VK_END || + keyCode.VirtualKeyCode == VK_PRIOR || + keyCode.VirtualKeyCode == VK_NEXT) + { + pOutput[iOutputLength++] = CH_ESC; + pOutput[iOutputLength++] = '['; + + switch (keyCode.VirtualKeyCode) + { + case VK_HOME: + pOutput[iOutputLength++] = '1'; + break; + + case VK_INSERT: + pOutput[iOutputLength++] = '2'; + break; + + case VK_DELETE: + pOutput[iOutputLength++] = '3'; + break; + + case VK_END: + pOutput[iOutputLength++] = '4'; + break; + + case VK_PRIOR: + pOutput[iOutputLength++] = '5'; + break; + + case VK_NEXT: + pOutput[iOutputLength++] = '6'; + break; + } + + pOutput[iOutputLength++] = '~'; + } + else + if (keyCode.VirtualKeyCode == VK_RETURN) + { + pOutput[iOutputLength++] = CH_CR; + if (fCRLF == 1) + { + pOutput[iOutputLength++] = CH_LF; + } + } + else + if (keyCode.AsciiChar != '\0') + { + pOutput[iOutputLength++] = keyCode.AsciiChar; + } + + return iOutputLength; +} + +bool +CAnsiTerm::ProcessOutput(const unsigned char *szData, int iLength) +{ + const unsigned char *pEnd = &szData[iLength]; + + for (const unsigned char *pCurrent = szData; pCurrent < pEnd; pCurrent++) + { + if (*pCurrent < 0x20 || *pCurrent == 0x7F) + { + dbglog("ProcessOutput: control_ch = %02x\n",*pCurrent); + OutputText(); + + switch (*pCurrent) + { + case CH_NUL: + case CH_ENQ: + case CH_DEL: + // These are ignored + break; + + case CH_BEL: + MessageBeep(MB_ICONASTERISK); + break; + + case CH_BS: + ProcessBackspace(); + break; + + case CH_HT: + ProcessTab(); + break; + + case CH_LF: + case CH_VT: + case CH_FF: + ProcessLinefeed(m_bLineFeedNewLineMode); + break; + + case CH_CR: + ProcessReturn(); + break; + + case CH_SO: + m_SelectedCharset = CharsetG1; + break; + + case CH_SI: + m_SelectedCharset = CharsetG0; + break; + + case CH_XON: + // Not yet implemented + break; + + case CH_XOF: + // Not yet implemented + break; + +#if 0 + case CH_CAN: + case CH_SUB: + // Output error character + break; +#endif + + case CH_ESC: + m_State = DS_Escape; + break; + + default: + AddOutputData(s_OemToUnicode[*pCurrent]); + break; + } + } + else + { + /* db b3 or b0 b3 */ + if (*pCurrent & 0x80) + dbglog("ProcessOutput: state=%d ch=%02x\n",m_State,*pCurrent); + switch (m_State) + { + case DS_Normal: + if (*pCurrent & 0x80) + { + // Could be start of a UTF-8 sequence or an ANSI extended character + + if ((*pCurrent & 0xE0) == 0xC0) + { + m_UTF8Size = 2; + } + else if ((*pCurrent & 0xF0) == 0xE0) + { + m_UTF8Size = 3; + } + else + { + // Not a UTF-8 lead character + AddOutputData(s_OemToUnicode[*pCurrent]); + break; + } + m_UTF8Count = 1; + m_UTF8Buffer[0] = *pCurrent; + m_State = DS_UTF8; + break; + } + + if ((m_SelectedCharset == CharsetG0 && m_G0Charset == SpecialGraphicsCharset) || + (m_SelectedCharset == CharsetG1 && m_G1Charset == SpecialGraphicsCharset)) + { + if (kMinGraphicsChar <= *pCurrent && *pCurrent <= kMaxGraphicsChar) + { + AddOutputData(s_GraphicChars[*pCurrent - kMinGraphicsChar]); + } + else + { + AddOutputData(*pCurrent); + } + } + else + { + AddOutputData(*pCurrent); + } + break; + + case DS_UTF8: + if ((*pCurrent & 0xC0) != 0x80) + { + for (int index = 0; index < m_UTF8Count; index++) + { + AddOutputData(s_OemToUnicode[m_UTF8Buffer[index]]); + } + + if (*pCurrent & 0x80) + { + AddOutputData(s_OemToUnicode[*pCurrent]); + } + else + { + AddOutputData(*pCurrent); + } + m_State = DS_Normal; + } + else + { + m_UTF8Buffer[m_UTF8Count++] = *pCurrent; + + if (m_UTF8Count == m_UTF8Size) + { + wchar_t wchUTF16; + if (m_UTF8Size == 2) + { + wchUTF16 = ((m_UTF8Buffer[0] & 0x1F) << 6) | (m_UTF8Buffer[1] & 0x3F); + } + else + { + wchUTF16 = ((m_UTF8Buffer[0] & 0x0F) << 12) | ((m_UTF8Buffer[1] & 0x3F) << 6) | (m_UTF8Buffer[2] & 0x3F); + } + + AddOutputData(wchUTF16); + m_State = DS_Normal; + } + } + break; + + case DS_Escape: + for (int index = 0; s_CSITable[index].chCode != '\0'; index++) + { + if (*pCurrent == s_CSITable[index].chCode) + { + if (s_CSITable[index].dsNextState != DS_None) + { + m_State = s_CSITable[index].dsNextState; + m_Parameters[0] = 0; + m_ParameterCount = 0; + m_bParametersStart = true; + } + else + { + (this->*s_CSITable[index].pfnProcess)(); + m_State = DS_Normal; + } + break; + } + } + + if (m_State == DS_Escape) + { + AddOutputData(L'^'); + AddOutputData(L'['); + AddOutputData(*pCurrent); + m_State = DS_Normal; + } + break; + + case DS_CSIParam: + if (m_bParametersStart) + { + m_bParametersStart = false; + + if (*pCurrent == '?') + { + m_bPrivateParameters = true; + break; + } + else + { + m_bPrivateParameters = false; + } + } + if ('0' <= *pCurrent && *pCurrent <= '9') + { + if (m_ParameterCount < kMaxParameterCount) + { + m_Parameters[m_ParameterCount] *= 10; + m_Parameters[m_ParameterCount] += *pCurrent - '0'; + } + } + else if (*pCurrent == ';') + { + if (m_ParameterCount < kMaxParameterCount) + { + m_ParameterCount++; + } + + if (m_ParameterCount < kMaxParameterCount) + { + m_Parameters[m_ParameterCount] = 0; + } + } + else + { + if (m_ParameterCount < kMaxParameterCount) + { + m_ParameterCount++; + } + + for (int index = 0; s_CSIFunction[index].chCode != '\0'; index++) + { + if (*pCurrent == s_CSIFunction[index].chCode) + { + (this->*s_CSIFunction[index].pfnProcess)(); + m_State = DS_Normal; + break; + } + } + if (m_State != DS_Normal) + { + DisplayCSI(*pCurrent); + m_State = DS_Normal; + } + } + break; + + case DS_DECPrivate: + for (int index = 0; s_DECFunction[index].chCode != '\0'; index++) + { + if (*pCurrent == s_DECFunction[index].chCode) + { + (this->*s_DECFunction[index].pfnProcess)(); + m_State = DS_Normal; + break; + } + } + + if (m_State != DS_Normal) + { + AddOutputData(L'^'); + AddOutputData(L'['); + AddOutputData(L'#'); + AddOutputData(*pCurrent); + } + break; + + case DS_SelectG0: + ProcessSCSG0(*pCurrent); + m_State = DS_Normal; + break; + + case DS_SelectG1: + ProcessSCSG1(*pCurrent); + m_State = DS_Normal; + break; + + default: + dbglog("ProcessOutput: illegal m_State=%d\n",m_State); + assert(false); + break; + } + } + } + + OutputText(); + + return true; +} + +void +CAnsiTerm::DisplayCSI(char ch) +{ + char szParam[15]; + + AddOutputData(L'^'); + AddOutputData(L'['); + AddOutputData(L'['); + for (int idxParam = 0; idxParam < m_ParameterCount; idxParam++) + { + if (idxParam > 0) + { + AddOutputData(L';'); + } + + int iLenParam = sprintf(szParam, "%d", m_Parameters[idxParam]); + + for (int idxChar = 0; idxChar < iLenParam; idxChar++) + { + AddOutputData(szParam[idxChar]); + } + } + AddOutputData(ch); +} + +bool +CAnsiTerm::ResetTerm(void) +{ + m_State = DS_Normal; + + m_SelectedCharset = CharsetG0; + m_G0Charset = AsciiCharset; + m_G1Charset = SpecialGraphicsCharset; + + m_Cursor.X = 0; + m_Cursor.Y = 0; + + m_SavedCursor = m_Cursor; + + m_sTopMargin = 0; + m_sBottomMargin = m_WindowSize.Y - 1; + + m_Attribute = kDefaultAttribute; + + UpdateTextAttribute(); + + m_dwOutputCount = 0; + + // if (fCRLF == 1) + m_bLineFeedNewLineMode = true; /*was false*/ + m_bCursorKeyMode = false; + m_bAnsiMode = true; + m_bColumnMode = true; + m_bScrollingMode = false; + m_bScreenMode = false; + m_bOriginMode = false; + m_bAutoRepeatingMode = true; + m_bInterlaceMode = false; + m_bDisplayCursor = true; + m_bAutoWrapMode = true; /*default to wrap*/ + + EraseDisplay(EraseAll); + + SetCursorPosition(); + + DisplayCursor(); + + return true; +} + +bool +CAnsiTerm::DisplayCursor(void) +{ + CONSOLE_CURSOR_INFO cursorInfo = { 100, m_bDisplayCursor }; + + return SetConsoleCursorInfo(m_hConsole, &cursorInfo) != FALSE; +} + +bool +CAnsiTerm::UpdateTextAttribute(void) +{ + return SetConsoleTextAttribute(m_hConsole, m_Attribute) != FALSE; +} + +bool +CAnsiTerm::GetCursorPosition(void) +{ + CONSOLE_SCREEN_BUFFER_INFO bufferInfo; + + if (GetConsoleScreenBufferInfo(m_hConsole, &bufferInfo)) + { + m_Cursor = bufferInfo.dwCursorPosition; + m_Cursor.Y -= m_WindowOrigin.Y + (m_bOriginMode ? m_sTopMargin : 0); + + return true; + } + + return false; +} + +bool +CAnsiTerm::SetCursorPosition(void) +{ + COORD cursor = m_Cursor; + + cursor.Y += m_WindowOrigin.Y + (m_bOriginMode ? m_sTopMargin : 0); + + return SetConsoleCursorPosition(m_hConsole, cursor) != FALSE; +} + +bool +CAnsiTerm::ScrollDisplay(int n, bool bWindowOnly) +{ + SHORT nLines = (SHORT)n; + if (nLines == 0) + { + return true; + } + + SMALL_RECT rectSource = { 0, 0, m_BufferSize.X - 1, m_BufferSize.Y - 1 }; + COORD coordDest = { 0, 0 }; + CHAR_INFO charInfo = { ' ', m_Attribute }; + + if (nLines > 0) + { + if (bWindowOnly || m_sTopMargin > 0) + { + coordDest.Y = m_WindowOrigin.Y + m_sTopMargin; + rectSource.Top = m_WindowOrigin.Y + m_sTopMargin + nLines; + rectSource.Bottom = m_WindowOrigin.Y + m_sBottomMargin; + } + else + { + rectSource.Top = nLines; + rectSource.Bottom = m_WindowOrigin.Y + m_sBottomMargin; + } + } + else + { + if (bWindowOnly) + { + coordDest.Y = m_WindowOrigin.Y + m_sTopMargin - nLines; + rectSource.Top = m_WindowOrigin.Y + m_sTopMargin; + rectSource.Bottom = m_WindowOrigin.Y + m_sBottomMargin + 1 + nLines; + } + else + { + coordDest.Y -= nLines; + } + + rectSource.Bottom += nLines; + } + + return ScrollConsoleScreenBuffer(m_hConsole, &rectSource, NULL, coordDest, &charInfo) != FALSE; +} + +bool +CAnsiTerm::EraseLine(EraseType eType) +{ + DWORD dwLength; + + COORD coordStart = m_WindowOrigin; + + coordStart.Y += m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0); + + switch (eType) + { + case EraseCursorToEnd: + if (m_Cursor.X < m_WindowSize.X) + { + coordStart.X += m_Cursor.X; + dwLength = m_BufferSize.X - m_Cursor.X; + } + else + { + dwLength = 0; + } + break; + + case EraseBeginningToCursor: + if (m_Cursor.X < m_WindowSize.X) + { + dwLength = m_Cursor.X + 1; + } + else + { + dwLength = m_BufferSize.X; + } + break; + + case EraseAll: + dwLength = m_BufferSize.X; + break; + + default: + return false; + } + + if (dwLength > 0) + { + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, m_Attribute, dwLength, coordStart, &dwWritten); + return FillConsoleOutputCharacter(m_hConsole, ' ', dwLength, coordStart, &dwWritten) != FALSE; + } + else + { + return true; + } +} + +bool +CAnsiTerm::EraseDisplay(EraseType eType) +{ + COORD coordStart = m_WindowOrigin; + DWORD dwLength; + + switch (eType) + { + case EraseCursorToEnd: + if (m_Cursor.X < m_WindowSize.X) + { + coordStart.X += m_Cursor.X; + coordStart.Y += m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0); + dwLength = (m_WindowSize.Y - m_Cursor.Y - (m_bOriginMode ? m_sTopMargin : 0)) * m_BufferSize.X - m_Cursor.X; + } + else if (m_Cursor.Y < (m_WindowSize.Y - 1)) + { + coordStart.X = 0; + coordStart.Y += m_Cursor.Y + 1; + dwLength = (m_WindowSize.Y - m_Cursor.Y - (m_bOriginMode ? m_sTopMargin : 0) - 1) * m_BufferSize.X; + } + else + { + dwLength = 0; + } + break; + + case EraseBeginningToCursor: + if (m_Cursor.X < m_WindowSize.X) + { + dwLength = (m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0)) * m_BufferSize.X + m_Cursor.X; + } + else + { + dwLength = (m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0) + 1) * m_BufferSize.X; + } + break; + + case EraseAll: + dwLength = m_BufferSize.X * m_WindowSize.Y; + break; + + default: + return false; + } + + if (dwLength > 0) + { + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, m_Attribute, dwLength, coordStart, &dwWritten); + return FillConsoleOutputCharacter(m_hConsole, ' ', dwLength, coordStart, &dwWritten) != FALSE; + } + else + { + return true; + } +} + +DWORD +CAnsiTerm::OutputText(void) +{ + if (m_dwOutputCount == 0) + { + return 0; + } + + DWORD dwTotalWritten = 0; + wchar_t * pwszCurrent = m_OutputBuffer; + DWORD dwLeftToWrite = m_dwOutputCount; + + while (dwLeftToWrite > 0) + { + DWORD dwWritten; + + if (m_Cursor.X >= m_WindowSize.X) + { + if (m_bAutoWrapMode) + { + ProcessLinefeed(true); + } + else + { + m_Cursor.X = m_WindowSize.X - 1; + + SetCursorPosition(); + + if (WriteConsoleW(m_hConsole, &m_OutputBuffer[m_dwOutputCount - 1], 1, &dwWritten, NULL)) + { + assert(dwWritten == 1); + } + + m_Cursor.X++; + dwTotalWritten += dwLeftToWrite; + break; + } + } + + DWORD dwPartialCount = min(dwLeftToWrite, (DWORD)(m_WindowSize.X - m_Cursor.X)); + + if (WriteConsoleW(m_hConsole, pwszCurrent, dwPartialCount, &dwWritten, NULL)) + { + assert(dwWritten == dwPartialCount); + } + else + { + DWORD dwError = GetLastError(); + } + + m_Cursor.X += (SHORT)dwPartialCount; + pwszCurrent += dwPartialCount; + dwTotalWritten += dwPartialCount; + dwLeftToWrite -= dwPartialCount; + } + + m_dwOutputCount = 0; + + return dwTotalWritten; +} + +bool +CAnsiTerm::ProcessBackspace(void) +{ + if (m_Cursor.X > 0) + { + if (m_Cursor.X < m_WindowSize.X) + { + m_Cursor.X--; + } + else + { + m_Cursor.X = m_WindowSize.X - 1; + } + + return SetCursorPosition(); + } + return true; +} + +bool +CAnsiTerm::ProcessTab(void) +{ + if (m_Cursor.X >= m_WindowSize.X) + { + if (m_bAutoWrapMode) + { + ProcessLinefeed(true); + } + else + { + return true; + } + } + + int newX = m_Cursor.X + 8; + + newX &= ~7; + + if (newX >= m_WindowSize.X) + { + newX = m_WindowSize.X - 1; + } + + int cntSpaces = newX - m_Cursor.X; + + for (int index = 0; index < cntSpaces; index++) + { + AddOutputData(L' '); + } + + return true; +} + +bool +CAnsiTerm::ProcessReverseLinefeed(void) +{ + if (m_Cursor.Y == 0) + { + ScrollDisplay(-1, true); + } + else + { + m_Cursor.Y--; + } + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessLinefeed(bool bNewLine) +{ + if (bNewLine) + { + m_Cursor.X = 0; + } + + if (m_bOriginMode || (m_Cursor.Y >= m_sTopMargin && m_Cursor.Y <= m_sBottomMargin)) + { + if (m_Cursor.Y >= (m_sBottomMargin - m_sTopMargin)) + { + ScrollDisplay(1, false); + m_Cursor.Y = m_sBottomMargin; + } + else + { + m_Cursor.Y++; + } + } + else if (m_Cursor.Y < m_sBottomMargin) + { + m_Cursor.Y++; + } + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessReturn(void) +{ + m_Cursor.X = 0; + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessDECALN(void) +{ + // Fill the display with 'E' for adjusting the CRT on a VT100 - Ignore it + return true; +} + +bool +CAnsiTerm::ProcessDECDHLB(void) +{ + // Double Height Line Bottom - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECDHLT(void) +{ + // Double Height Line Top - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECDWL(void) +{ + // Double Width Line - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECID(void) +{ + return ProcessDA(); +} + +bool +CAnsiTerm::ProcessDECKPAM(void) +{ + // Keypad Application Mode - Not yet implemented + return true; +} + +bool +CAnsiTerm::ProcessDECKPNM(void) +{ + // Keypad Numeric Mode - Not yet implemented + return true; +} + +bool +CAnsiTerm::ProcessDECLL(void) +{ + // Load LEDs - Not Supported + return true; +} + +bool +CAnsiTerm::ProcessDECRC(void) +{ + return ProcessRCP(); +} + +bool +CAnsiTerm::ProcessDECREQTPARM(void) +{ + // Request Terminal Parameters (Baud Rate, Parity, etc) - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECSC(void) +{ + return ProcessSCP(); +} + +bool +CAnsiTerm::ProcessDECSTBM(void) +{ + assert(m_ParameterCount >= 1); + + if (m_Parameters[0] > 0) + { + m_Parameters[0]--; + } + + if (m_ParameterCount < 2) + { + m_Parameters[1] = m_WindowSize.Y - 1; + } + else + { + if (m_Parameters[1] > 0) + { + m_Parameters[1]--; + } + else + { + m_Parameters[1] = m_WindowSize.Y - 1; + } + } + + if (m_Parameters[0] >= m_WindowSize.Y || + m_Parameters[1] >= m_WindowSize.Y || + m_Parameters[0] >= m_Parameters[1]) + { + return false; + } + + m_sTopMargin = (SHORT)m_Parameters[0]; + m_sBottomMargin = (SHORT)m_Parameters[1]; + + m_Cursor.X = 0; + m_Cursor.Y = 0; + + SetCursorPosition(); + + return true; +} + +bool +CAnsiTerm::ProcessDECSWL(void) +{ + // Single Width Line - Since Double Width Line isn't supported, this isn't necessary + return true; +} + +bool +CAnsiTerm::ProcessDECTST(void) +{ + // Perform Self Test - Not supported + return true; +} + +bool +CAnsiTerm::ProcessCUB(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.X -= min(m_Cursor.X, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessCUD(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.Y += min((m_bOriginMode ? m_sBottomMargin : m_WindowSize.Y - 1) - m_Cursor.Y, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessCUF(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.X += min(m_WindowSize.X - m_Cursor.X - 1, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessCUP(void) +{ + return ProcessHVP(); +} + +bool +CAnsiTerm::ProcessCUU(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.Y -= min(m_Cursor.Y, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessDA(void) +{ + // Send Device Attributes - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDSR(void) +{ + // Send Device Status Request - Not supported + return true; +} + +bool +CAnsiTerm::ProcessED(void) +{ + return EraseDisplay((EraseType)m_Parameters[0]); +} + +bool +CAnsiTerm::ProcessEL(void) +{ + return EraseLine((EraseType)m_Parameters[0]); +} + +bool +CAnsiTerm::ProcessHTS(void) +{ + // Soft Tab Set - Not implemented yet + return true; +} + +bool +CAnsiTerm::ProcessHVP(void) +{ + assert(m_ParameterCount >= 1); + + if (m_Parameters[0] > 0) + { + m_Parameters[0]--; + } + + if (m_ParameterCount < 2) + { + m_Parameters[1] = 0; + } + else + { + if (m_Parameters[1] > 0) + { + m_Parameters[1]--; + } + } + + if (m_bOriginMode) + { + if (m_Parameters[0] >= (m_sBottomMargin - m_sTopMargin + 1)) + { + m_Parameters[0] = m_sBottomMargin - m_sTopMargin; + } + } + else + { + if (m_Parameters[0] >= m_WindowSize.Y) + { + m_Parameters[0] = m_WindowSize.Y - 1; + } + } + + if (m_Parameters[1] >= m_WindowSize.X) + { + m_Parameters[1] = m_WindowSize.X - 1; + } + + m_Cursor.Y = (SHORT)m_Parameters[0]; + m_Cursor.X = (SHORT)m_Parameters[1]; + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessIND(void) +{ + return ProcessLinefeed(false); +} + +bool +CAnsiTerm::ProcessNEL(void) +{ + return ProcessLinefeed(true); +} + +bool +CAnsiTerm::ProcessRCP(void) +{ + m_Cursor = m_SavedCursor; + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessRI(void) +{ + return ProcessReverseLinefeed(); +} + +bool +CAnsiTerm::ProcessRIS(void) +{ + return ResetTerm(); +} + +bool +CAnsiTerm::ProcessRM(void) +{ + if (m_bPrivateParameters) + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[index]) + { + case 0: + default: + assert(false); + break; + case DECCKM: + m_bCursorKeyMode = false; + break; + case DECANM: + m_bAnsiMode = false; + break; + case DECCOLM: + m_bColumnMode = false; + break; + case DECSCLM: + m_bScrollingMode = false; + break; + case DECSCNM: + m_bScreenMode = false; + break; + case DECOM: + m_bOriginMode = false; + m_Cursor.X = 0; + m_Cursor.Y = 0; + SetCursorPosition(); + break; + case DECAWM: + m_bAutoWrapMode = false; + break; + case DECARM: + m_bAutoRepeatingMode = false; + break; + case DECINLM: + m_bInterlaceMode = false; + break; + case DECTCEM: + m_bDisplayCursor = false; + DisplayCursor(); + break; + } + } + } + else + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[index]) + { + case 20: m_bLineFeedNewLineMode = false; break; // LNM + default: assert(false); break; + } + } + } + return true; +} + +bool +CAnsiTerm::ProcessSCP(void) +{ + m_SavedCursor = m_Cursor; + return true; +} + +bool +CAnsiTerm::ProcessSCSG0(char ch) +{ + switch (ch) + { + case 'B': // ASCII Charset + m_G0Charset = AsciiCharset; + break; + + case '0': // Special Graphics Charset + m_G0Charset = SpecialGraphicsCharset; + break; + + case 'A': // UK Charset + case '1': // Alternate Character ROM Standard Charset + case '2': // Alternate Character ROM Special Graphics Charset + default: // Unsupported + return false; + + } + return true; +} + +bool +CAnsiTerm::ProcessSCSG1(char ch) +{ + switch (ch) + { + case 'B': // ASCII Charset + m_G1Charset = AsciiCharset; + break; + + case '0': // Special Graphics Charset + m_G1Charset = SpecialGraphicsCharset; + break; + + case 'A': // UK Charset + case '1': // Alternate Character ROM Standard Charset + case '2': // Alternate Character ROM Special Graphics Charset + default: // Unsupported + return false; + + } + return true; +} + +bool +CAnsiTerm::ProcessSGR(void) +{ + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[index]) + { + case 0: + m_Attribute = kDefaultAttribute; + break; + + case 1: + m_Attribute |= FOREGROUND_INTENSITY; + break; + + case 4: + m_Attribute |= COMMON_LVB_UNDERSCORE; + break; + + case 5: + // Blinking isn't supported + break; + + case 7: + m_Attribute |= COMMON_LVB_REVERSE_VIDEO; + break; + + case 22: + m_Attribute &= ~FOREGROUND_INTENSITY; + break; + + case 24: + m_Attribute &= ~COMMON_LVB_UNDERSCORE; + break; + + case 25: + // Blinking isn't supported + break; + + case 27: + m_Attribute &= ~COMMON_LVB_REVERSE_VIDEO; + break; + + case 30: // Black text + m_Attribute &= ~(FOREGROUND_INTENSITY | COMMON_LVB_UNDERSCORE | + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + break; + + case 31: // Red text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_RED; + break; + + case 32: // Green text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_GREEN; + break; + + case 33: // Yellow text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_RED | FOREGROUND_GREEN; + break; + + case 34: // Blue text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_BLUE; + break; + + case 35: // Magenta text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_RED | FOREGROUND_BLUE; + break; + + case 36: // Cyan text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + + case 37: // White text + m_Attribute |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + + case 40: // Black background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + break; + + case 41: // Red background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_RED; + break; + + case 42: // Green background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_GREEN; + break; + + case 43: // Yellow background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_RED | BACKGROUND_GREEN; + break; + + case 44: // Blue background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_BLUE; + break; + + case 45: // Magenta background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_RED | BACKGROUND_BLUE; + break; + + case 46: // Cyan background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + + case 47: // White background + m_Attribute |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + + default: + assert(false); + break; + } + } + + UpdateTextAttribute(); + + return true; +} + +bool +CAnsiTerm::ProcessSM(void) +{ + + dbglog("ProcessSM: start, priv=%d param0=%d cnt=%d\n", + m_bPrivateParameters,m_Parameters[0],m_ParameterCount); + if (m_bPrivateParameters) + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[0]) + { + case 0: + default: + assert(false); + break; + case DECCKM: + m_bCursorKeyMode = true; + break; + case DECANM: + m_bAnsiMode = true; + break; + case DECCOLM: + m_bColumnMode = true; + break; + case DECSCLM: + m_bScrollingMode = true; + break; + case DECSCNM: + m_bScreenMode = true; + break; + case DECOM: + m_bOriginMode = true; + m_Cursor.X = 0; + m_Cursor.Y = 0; + m_SavedCursor = m_Cursor; + SetCursorPosition(); + break; + case DECAWM: + m_bAutoWrapMode = true; + break; + case DECARM: + m_bAutoRepeatingMode = true; + break; + case DECINLM: + m_bInterlaceMode = true; + break; + case DECTCEM: + m_bDisplayCursor = true; + DisplayCursor(); + break; + } + } + } + else + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[0]) + { + case 20: m_bLineFeedNewLineMode = true; break; // LNM + default: + dbglog("ProcessSM: param %d != 20\n",m_Parameters[0]); + assert(false); break; + } + } + } + return true; +} + +bool +CAnsiTerm::ProcessTBC(void) +{ + // Soft Tab Clear - Not implemented yet + return true; +} + +static CAnsiTerm *g_pDisplay; + +typedef unsigned char uchar; + +extern "C" +{ + +void console_open(char fdebugcmd) +{ + g_pDisplay = new CAnsiTerm(); +} + +void console_close(void) +{ + delete g_pDisplay; + g_pDisplay = NULL; +} + +int console_in(DWORD keydata, uchar *pdata, int len) +{ + if (keydata == ~0) + { + g_pDisplay->WindowSizeChanged(false); + return 0; + } + + return g_pDisplay->ProcessInput(*(CAnsiTerm::KeyCode *)&keydata, pdata, len); +} + +void console_out(uchar *pdata, int len) +{ + if (len > 0) + { + g_pDisplay->ProcessOutput(pdata, len); + } +} + +} diff --git a/util/AnsiTerm.h b/util/AnsiTerm.h new file mode 100644 index 0000000..13d10f2 --- /dev/null +++ b/util/AnsiTerm.h @@ -0,0 +1,316 @@ +/* + * AnsiTerm.h + * Windows ANSI Terminal Emulation + * + * Author: Robert Nelson robertnelson at users.sourceforge.net + * Copyright (c) 2009 Robert Nelson + * + * 10/07/09 Robert Nelson - Created + * See ChangeLog for further changes + */ + +/* +Copyright (c) 2009, Robert Nelson +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +class CAnsiTerm +{ +public: + struct KeyCode + { + unsigned char bKeyDown:1; + unsigned char bEnhanced:1; + unsigned char bCapsLock:1; + unsigned char bScrollLock:1; + unsigned char bNumLock:1; + unsigned char bShift:1; + unsigned char bControl:1; + unsigned char bAlt:1; + unsigned char RepeatCount; + unsigned char VirtualKeyCode; + unsigned char AsciiChar; + }; + +private: + enum ControlCharacters + { + CH_NUL = 0x00, // Ignored on input + CH_ENQ = 0x05, // Transmit answerback + CH_BEL = 0x07, // Ring Bell + CH_BS = 0x08, // Move left one character, no effect in column 0 + CH_HT = 0x09, // Tab + CH_LF = 0x0A, // Line feed or new line depending on line mode + CH_VT = 0x0B, // Vertical tab, same as line feed + CH_FF = 0x0C, // Form feed, same as line feed + CH_CR = 0x0D, // Carriage return, return to column 0 + CH_SO = 0x0E, // Shift Out, Invoke G1 charset + CH_SI = 0x0F, // Shift In, Invoke G0 charset + CH_XON = 0x11, // Resume transmission + CH_XOF = 0x13, // Suspend transmission + CH_CAN = 0x18, // Cancel, aborts the current control sequence + CH_SUB = 0x1A, // Same as Cancel + CH_ESC = 0x1B, // Escape, start of control sequence + CH_DEL = 0x7F // Delete, ignored + }; + + enum DECModes + { + DECCKM = 1, // Cursor Key Mode (set = application codes) + DECANM = 2, // Ansi Mode (set = ansi) + DECCOLM = 3, // 80/132 Column Mode (set = 132) + DECSCLM = 4, // Scroll Mode (set = smooth) + DECSCNM = 5, // Screen Mode (set = black on white) + DECOM = 6, // Origin Mode (set = origin relative to top margin) + DECAWM = 7, // Autowrap Mode (set = wrap) + DECARM = 8, // Autorepeat Mode (set = repeat) + DECINLM = 9, // Interlace Mode (set = interlace) + DECTCEM = 25 // Text Cursor Enable Mode + + }; + + enum DisplayState + { + DS_None, + DS_Normal, + DS_UTF8, + DS_Escape, + DS_CSIParam, + DS_DECPrivate, + DS_SelectG0, + DS_SelectG1 + }; + + enum SelectedCharset + { + CharsetG0, + CharsetG1 + }; + + enum CharacterSet + { + AsciiCharset = 0, + SpecialGraphicsCharset = 1, + UKCharset = 2 + }; + + enum EraseType + { + EraseCursorToEnd = 0, + EraseBeginningToCursor = 1, + EraseAll = 2 + }; + + static const int kMaxParameterCount = 16; + + static const int kOutputBufferSize = 256; + + static const int kMinGraphicsChar = 0x5F; + static const int kMaxGraphicsChar = 0x7E; + + static const int kColorTableSize = 16; + + static const WORD kDefaultAttribute = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + + struct CSICode + { + char chCode; + DisplayState dsNextState; + bool (CAnsiTerm::*pfnProcess)(void); + }; + + struct CSIFunction + { + char chCode; + bool (CAnsiTerm::*pfnProcess)(void); + }; + +protected: + typedef struct _CONSOLE_SCREEN_BUFFER_INFOEX { + ULONG cbSize; + COORD dwSize; + COORD dwCursorPosition; + WORD wAttributes; + SMALL_RECT srWindow; + COORD dwMaximumWindowSize; + WORD wPopupAttributes; + BOOL bFullscreenSupported; + COLORREF ColorTable[16]; + } CONSOLE_SCREEN_BUFFER_INFOEX, *PCONSOLE_SCREEN_BUFFER_INFOEX; + + typedef BOOL (WINAPI *PFN_GetConsoleScreenBufferInfoEx)( + HANDLE hConsoleOutput, + PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx); + + typedef BOOL (WINAPI *PFN_SetConsoleScreenBufferInfoEx)( + HANDLE hConsoleOutput, + PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx); + + static PFN_GetConsoleScreenBufferInfoEx s_pfnGetConsoleScreenBufferInfoEx; + static PFN_SetConsoleScreenBufferInfoEx s_pfnSetConsoleScreenBufferInfoEx; + +private: + static CSICode s_CSITable[]; + static CSIFunction s_DECFunction[]; + static CSIFunction s_CSIFunction[]; + static wchar_t s_GraphicChars[kMaxGraphicsChar - kMinGraphicsChar + 1]; + static wchar_t s_OemToUnicode[256]; + static COLORREF s_ColorTable[kColorTableSize]; + + +public: + CAnsiTerm(void); + virtual ~CAnsiTerm(void); + + void WindowSizeChanged(bool bInitial); + + int ProcessInput(KeyCode keyCode, unsigned char *pOutput, int iOutputLen); + + bool ProcessOutput(const unsigned char *szData, int iLength); + +protected: + virtual bool ResetTerm(void); + virtual bool GetCursorPosition(void); + virtual bool SetCursorPosition(void); + virtual bool DisplayCursor(void); + + virtual bool ScrollDisplay(int nLines, bool bWindowOnly); + virtual bool EraseLine(EraseType eType); + virtual bool EraseDisplay(EraseType eType); + virtual bool UpdateTextAttribute(void); + + virtual DWORD OutputText(void); + +private: + bool ProcessBackspace(void); + bool ProcessTab(void); + bool ProcessLinefeed(bool bNewLine); + bool ProcessReverseLinefeed(void); + bool ProcessReturn(void); + + void AddOutputData(wchar_t wchData) + { + m_OutputBuffer[m_dwOutputCount++] = wchData; + + if (m_dwOutputCount >= kOutputBufferSize) + { + OutputText(); + } + } + + void DisplayCSI(char ch); + + bool ProcessSCSG0(char ch); + bool ProcessSCSG1(char ch); + + bool ProcessDECALN(void); + bool ProcessDECDHLB(void); + bool ProcessDECDHLT(void); + bool ProcessDECDWL(void); + bool ProcessDECID(void); + bool ProcessDECKPAM(void); + bool ProcessDECKPNM(void); + bool ProcessDECLL(void); + bool ProcessDECRC(void); + bool ProcessDECREQTPARM(void); + bool ProcessDECSC(void); + bool ProcessDECSTBM(void); + bool ProcessDECSWL(void); + bool ProcessDECTST(void); + + bool ProcessCUB(void); + bool ProcessCUD(void); + bool ProcessCUF(void); + bool ProcessCUP(void); + bool ProcessCUU(void); + bool ProcessDA(void); + bool ProcessDSR(void); + bool ProcessED(void); + bool ProcessEL(void); + bool ProcessHTS(void); + bool ProcessHVP(void); + bool ProcessIND(void); + bool ProcessNEL(void); + bool ProcessRCP(void); + bool ProcessRI(void); + bool ProcessRIS(void); + bool ProcessRM(void); + bool ProcessSCP(void); + bool ProcessSGR(void); + bool ProcessSM(void); + bool ProcessTBC(void); + +private: + HANDLE m_hConsole; + DWORD m_dwOrigConsoleMode; + WORD m_wOrigConsoleAttribute; + DWORD m_dwOrigCursorSize; + COLORREF m_OrigColorTable[kColorTableSize]; + bool m_bResetColorTable; + DisplayState m_State; + + SelectedCharset m_SelectedCharset; + CharacterSet m_G0Charset; + CharacterSet m_G1Charset; + + COORD m_BufferSize; + COORD m_WindowSize; + COORD m_WindowOrigin; + COORD m_Cursor; + COORD m_SavedCursor; + SHORT m_sTopMargin; + SHORT m_sBottomMargin; + WORD m_Attribute; + wchar_t m_OutputBuffer[kOutputBufferSize]; + DWORD m_dwOutputCount; + + unsigned char m_UTF8Buffer[3]; + int m_UTF8Count; + int m_UTF8Size; + + int m_Parameters[kMaxParameterCount]; + int m_ParameterCount; + bool m_bParametersStart; + bool m_bPrivateParameters; + + // Modes + bool m_bLineFeedNewLineMode; // LNM + bool m_bCursorKeyMode; // DECCKM +// Always set - VT52 not supported + bool m_bAnsiMode; // DECANM +// Not used - column width is based on width of console window + bool m_bColumnMode; // DECCOLM +// Not used - always reset + bool m_bScrollingMode; // DECSCLM +// Not implemented - always reset + bool m_bScreenMode; // DECSCNM + bool m_bOriginMode; // DECOM + bool m_bAutoWrapMode; // DECAWM +// Not implemented - always set + bool m_bAutoRepeatingMode; // DECARM +// Not implemented - always reset + bool m_bInterlaceMode; // DECINLM + bool m_bDisplayCursor; // DECTCEM +}; diff --git a/util/Makefile.am b/util/Makefile.am new file mode 100644 index 0000000..3726107 --- /dev/null +++ b/util/Makefile.am @@ -0,0 +1,200 @@ + +localedir = $(datadir)/locale +INCLUDES = -I.. +OS_CF = @OS_CFLAGS@ @CROSS_CFLAGS@ +OS_LF = @OS_LFLAGS@ @CROSS_LFLAGS@ +AM_CPPFLAGS = $(OS_CF) -DLOCALEDIR=\"$(localedir)\" +AM_CPPFLAGS += @IA64_CFLAGS@ @GPL_CFLAGS@ +LDADD = $(OS_LF) +LDSAM = $(OS_LF) @LD_SAMX@ +CFLAGS_SAMX = -O2 -g -I. -I.. $(OS_CF) @LANPLUS_CFLAGS@ +CFLAGS_SAM = -O2 -g -I. -I.. $(OS_CF) +# May be /usr/bin/install or /bin/install +INSTALLBIN = install -c +extradir = $(datadir)/ipmiutil +inc_dir = $(includedir) +tmpobj = obj +tmpwin = tmp +LIBDIR = @LIB_DIR@ + +CMDMOD = ipmicmd.c mem_if.c ipmidir.c imbapi.c ipmimv.c ipmild.c ipmibmc.c ipmilipmi.c subs.c +CMDMOD += md5.c md2.c ipmilan.c +CMDMOD += ipmilanplus.c +# CMDMOD = ipmicmd.c mem_if.c @OS_DRIVERS@ +# am: configure substitutions are not allowed in _SOURCES variables +LIBOBJ = ipmicmd.o mem_if.o ipmidir.o imbapi.o ipmimv.o ipmild.o ipmibmc.o ipmilipmi.o subs.o md5.o md2.o $(tmpobj)/ipmilan.o $(tmpobj)/ipmilanplus.o +OEMMOD = oem_kontron.c oem_fujitsu.c oem_intel.c oem_sun.c oem_supermicro.c oem_dell.c oem_quanta.c oem_hp.c oem_newisys.c iekanalyzer.c + + +AM_CPPFLAGS += -I. -I.. -DMETACOMMAND +METASOURCE = ipmiutil.c ialarms.c ihealth.c ievents.c ifru.c ifru_picmg.c igetevent.c ireset.c icmd.c ilan.c isensor.c isel.c iserial.c iwdt.c isol.c idiscover.c iconfig.c ipicmg.c ifirewall.c ifwum.c ihpm.c itsol.c idcmi.c $(OEMMOD) $(CMDMOD) +LDADD += -lpthread + +# The LanDesk library is proprietary, so it is incompatible with ALLOW_GPL. +# To build with LanDesk support: +# First copy the library to ../lib/libipmiapi.a +# Then ./configure --enable-landesk +# Result: +# AM_CPPFLAGS += -DLINK_LANDESK +# LDADD += -lipmiapi -L../lib +AM_CPPFLAGS += @LANDESK_CFLAGS@ +LDADD += @LANDESK_LDADD@ + +# For lanplus plugin support (IPMI LAN 2.0 RMCP+) used by SOL: +# If ./configure --disable-lanplus +# AM_CPPFLAGS += +# LDADD += +# Otherwise default result is lanplus enabled: +# AM_CPPFLAGS += -DHAVE_LANPLUS +# LDADD += -L../lib -lipmi_lanplus -L/usr/local/lib -lcrypto +# LDADD += -L../lib -lintf_lanplus -L/usr/local/lib -lcrypto (older) +# Could also use CMDMOD += ipmilan2.c instead, if completed. +AM_CPPFLAGS += @LANPLUS_CFLAGS@ +LDADD += @LANPLUS_LIB@ @LANPLUS_CRYPTO@ +LANPLUS_OBJ = $(shell ar t @LANPLUS_LIB@ 2>/dev/null) + +# sbin_PROGRAMS are built by default and copied to /usr/sbin at install time +# EXTRA_PROGRAMS are built by default but not included in the install package +# TESTPROGS are not built by default. To build, do 'make ifruset', for example. +bin_PROGRAMS = ipmiutil ievents idiscover +sbin_PROGRAMS = ipmi_port iseltime +DEV_LIB = libipmiutil.a +SHR_LIB = libipmiutil.so +SHRLINK = @SHR_LINK@ +EXTRA_PROGRAMS = ipmi_sample ipmi_sample_evt +TESTPROGS = libimbapi.a iconfig ipmimv ifruset ipmi_sample2 ialarms_enc +# OLDPROGS are old/previous binaries that may exist and need to be deleted. +OLDPROGS = alarms bmchealth fruconfig getevent hwreset icmd isolconsole pefconfig sensor showsel tmconfig wdt + +# To build an imb api library (libimbapi.a): +libimbapi.a: imbapi.c + mkdir -p $(tmpobj) + $(CC) -I. -I.. $(OS_CF) -fPIC $(CFLAGS) -o $(tmpobj)/imbapi.o -c imbapi.c + $(AR) cru libimbapi.a $(tmpobj)/imbapi.o + $(RANLIB) libimbapi.a + rm -f $(tmpobj)/imbapi.o + +# Build a lib to support all of the IPMI drivers (libipmiutil.a) +# If LANPLUS_SAM = yes, include LANPLUS_OBJ, else do not. +# See configure --enable-liblanplus to change this +$(DEV_LIB): $(CMDMOD:.c=.o) @LANPLUS_LIB@ + mkdir -p $(tmpobj) + if [ "x@LANPLUS_SAM@" = "xyes" ]; then \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + ar x @LANPLUS_LIB@ ; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) $(LANPLUS_OBJ); \ + $(RANLIB) $(DEV_LIB); \ + else \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) ; \ + $(RANLIB) $(DEV_LIB) ; \ + fi + +$(SHR_LIB): $(CMDMOD:.c=.o) @LANPLUS_LIB@ + mkdir -p $(tmpobj) + if [ "x@LANPLUS_SAM@" = "xyes" ]; then \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + ar x @LANPLUS_LIB@ ; \ + $(CC) $(LDFLAGS) -shared -o $(SHR_LIB) $(LIBOBJ) $(LANPLUS_OBJ); \ + else \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + $(CC) $(LDFLAGS) -shared -o $(SHR_LIB) $(LIBOBJ) ; \ + fi + +# To build ipmiutil, need to use METACFLAGS for each .c/.o + +idiscover$(EXEEXT): idiscover.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) $(OS_LF) -o idiscover idiscover.c + +ipmimv: ipmimv.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -DTEST_BIN -o ipmimv ipmimv.c + +ievents$(EXEEXT): ievents.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -DALONE -o ievents ievents.c + +ipmi_sample: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -c ipmi_sample.c + $(CC) -g -O2 -o ipmi_sample ipmi_sample.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ialarms_enc: $(DEV_LIB) ialarms.c oem_intel.c + $(CC) $(CFLAGS_SAM) -DTEST_ENC -o ialarms2.o -c ialarms.c + $(CC) $(CFLAGS_SAM) -DNO_EVENTS -o oem_intel2.o -c oem_intel.c + $(CC) -g -O2 -o ialarms_enc ialarms2.o oem_intel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifru_picmg2.o: ifru_picmg.c + $(CC) $(CFLAGS_SAM) -o ifru_picmg2.o -c ifru_picmg.c + +# To build ipmi_sample with GET_SENSORS enabled, need isensors.o, ievents.o +# Note that this does not include oem_intel, etc. for OEM SEL decoding. +ipmi_sample2: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c ifru.c isel.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -D GET_SENSORS -D GET_FRU -o ipmi_sample2.o -c ipmi_sample.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -o ievents2.o -c ievents.c + $(CC) $(CFLAGS_SAM) -o ifru2.o -c ifru.c + $(CC) $(CFLAGS_SAM) -o isel2.o -c isel.c + $(CC) -g -O2 -o ipmi_sample2 ipmi_sample2.o isensor2.o ievents2.o ifru2.o ifru_picmg2.o isel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ipmi_sample_evt: $(DEV_LIB) ipmi_sample_evt.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -o ipmi_sample_evt.o -c ipmi_sample_evt.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -DSENSORS_OK -o ievents2.o -c ievents.c + $(CC) -g -O2 -o ipmi_sample_evt ipmi_sample_evt.o isensor2.o ievents2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifruset: $(DEV_LIB) ifruset.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -c ifruset.c + $(CC) -g -O2 -o ifruset ifruset.o ifru_picmg2.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +iseltime: $(DEV_LIB) iseltime.c + $(CC) $(CFLAGS_SAM) -c iseltime.c + $(CC) -g -O2 -o iseltime iseltime.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +ipmi_port$(EXEEXT): ipmi_port.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -o ipmi_port ipmi_port.c + +iconfig: iconfig.c $(DEV_LIB) + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -o iconfig iconfig.c $(DEV_LIB) @LANPLUS_CRYPTO@ + +# @LANPLUS_LIB@ is ../lib/libipmi_lanplus.a +../lib/libipmi_lanplus.a: + cd ../lib; make + +ipmiutil_SOURCES = $(METASOURCE) + +ipmiutil$(EXEEXT): $(METASOURCE:.c=.o) @LANPLUS_LIB@ + $(CC) $(CFLAGS) $(LDFLAGS) -o ipmiutil $(METASOURCE:.c=.o) $(LDADD) + +ievents_SOURCES = ievents.c + +idiscover_SOURCES = idiscover.c + +ipmi_port_SOURCES = ipmi_port.c + + +EXTRA_DIST = imb_api.h ipmicmd.h ipmidir.h ipmilan.h ipmilanplus.h AnsiTerm.h ifirewall.h ifwum.h ihpm.h ipicmg.h ipmiutil.h md2.h oem_dell.h oem_fujitsu.h oem_intel.h oem_kontron.h oem_sun.h idcmi.h isensor.h iekanalyzer.h + +all-am: Makefile $(bin_PROGRAMS) $(sbin_PROGRAMS) $(EXTRA_PROGRAMS) $(DEV_LIB) $(SHRLINK) + +install-data-am: $(EXTRA_PROGRAMS) $(DEV_LIB) $(SHRLINK) + @INS_LIB@ mkdir -p $(DESTDIR)$(extradir) + @INS_LIB@ mkdir -p $(DESTDIR)$(LIBDIR) + @INS_LIB@ mkdir -p $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f ipmi_sample.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmi_sample_evt.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmicmd.h $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f isensor.c ievents.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f isensor.h ievents.h $(DESTDIR)$(extradir) + @INS_LIB@ cp -f Makefile.sample $(DESTDIR)$(extradir)/Makefile + @INS_LIB@ cp -f $(DEV_LIB) $(DESTDIR)$(LIBDIR) + if [ "x$(SHRLINK)" != "x" ]; then \ + @INS_LIB@ cp -f $(SHR_LIB) $(DESTDIR)$(LIBDIR) ; \ + fi + +clean-generic: + rm -f $(DEV_LIB) $(EXTRA_PROGRAMS) $(OLDPROGS) $(TESTPROGS) $(SHRLINK) + if [ -d $(tmpobj) ]; then rm -rf $(tmpobj) ; fi + if [ -d $(tmpwin) ]; then rm -rf $(tmpwin) ; fi + rm -f *.log *.tmp debug*.list *.o *.pdb *.lo *.la *.so diff --git a/util/Makefile.am-so b/util/Makefile.am-so new file mode 100644 index 0000000..97d9c34 --- /dev/null +++ b/util/Makefile.am-so @@ -0,0 +1,241 @@ + +localedir = $(datadir)/locale +INCLUDES = -I. -I.. +OS_CF = @OS_CFLAGS@ @CROSS_CFLAGS@ +OS_LF = @OS_LFLAGS@ @CROSS_LFLAGS@ +AM_CPPFLAGS = $(OS_CF) -DLOCALEDIR=\"$(localedir)\" +AM_CPPFLAGS += @IA64_CFLAGS@ @GPL_CFLAGS@ +LDADD = $(OS_LF) +LDSAM = $(OS_LF) @LD_SAMX@ +CFLAGS_SAMX = -O2 -g -I. -I.. $(OS_CF) @LANPLUS_CFLAGS@ +CFLAGS_SAM = -O2 -g -I. -I.. $(OS_CF) +# May be /usr/bin/install or /bin/install +INSTALLBIN = install -c +extradir = $(datadir)/ipmiutil +inc_dir = $(includedir) +tmpobj = obj +tmpwin = tmp +LIBDIR = @LIB_DIR@ + +CMDSRC = ipmicmd.c mem_if.c ipmidir.c imbapi.c ipmimv.c ipmild.c ipmibmc.c ipmilipmi.c subs.c +CMDSRC += md5.c md2.c ipmilan.c +CMDSRC += ipmilanplus.c +# CMDSRC = ipmicmd.c mem_if.c @OS_DRIVERS@ +# am: configure substitutions are not allowed in _SOURCES variables +CMDOBJ = $(tmpobj)/ipmicmd.o $(tmpobj)/mem_if.o $(tmpobj)/ipmidir.o $(tmpobj)/imbapi.o $(tmpobj)/ipmimv.o $(tmpobj)/ipmild.o $(tmpobj)/ipmibmc.o $(tmpobj)/ipmilipmi.o $(tmpobj)/subs.o $(tmpobj)/md5.o $(tmpobj)/md2.o $(tmpobj)/ipmilan.o $(tmpobj)/ipmilanplus.o +LIBOBJ = $(CMDOBJ) +OEMMOD = oem_kontron.c oem_fujitsu.c oem_intel.c oem_sun.c iekanalyzer.c oem_supermicro.c oem_dell.c oem_quanta.c oem_hp.c oem_newisys.c + + +AM_CPPFLAGS += -I. -I.. -DMETACOMMAND +METASOURCE = ipmiutil.c ialarms.c ihealth.c ievents.c ifru.c ifru_picmg.c igetevent.c ireset.c icmd.c ilan.c isensor.c isel.c iserial.c iwdt.c isol.c idiscover.c iconfig.c ipicmg.c ifirewall.c ifwum.c ihpm.c itsol.c idcmi.c $(OEMMOD) +LDADD += -lpthread + +# The LanDesk library is proprietary, so it is incompatible with ALLOW_GPL. +# To build with LanDesk support: +# First copy the library to ../lib/libipmiapi.a +# Then ./configure --enable-landesk +# Result: +# AM_CPPFLAGS += -DLINK_LANDESK +# LDADD += -lipmiapi -L../lib +AM_CPPFLAGS += @LANDESK_CFLAGS@ +LDADD += @LANDESK_LDADD@ + +# For lanplus plugin support (IPMI LAN 2.0 RMCP+) required by SOL: +# If ./configure --disable-lanplus +# AM_CPPFLAGS += +# LDADD += +# LANPLUS_SRC = +# Otherwise default result is lanplus enabled: +# AM_CPPFLAGS += -DHAVE_LANPLUS +# LDADD += -L../lib -lipmi_lanplus -L/usr/local/lib -lcrypto +# LDADD += -L../lib -lintf_lanplus -L/usr/local/lib -lcrypto (older) +# LANPLUS_SRC = $(LANPLUS_DIR)/lanplus.c ... +AM_CPPFLAGS += @LANPLUS_CFLAGS@ -I../lib/lanplus -I../lib/lanplus/inc +LDADD += @LANPLUS_LIB@ @LANPLUS_CRYPTO@ +LANPLUS_OBJ = $(shell ar t @LANPLUS_LIB@ 2>/dev/null) +LANPLUS_DIR = ../lib/lanplus +LANPLUS_SRC = $(LANPLUS_DIR)/lanplus.c $(LANPLUS_DIR)/lanplus_dump.c \ + $(LANPLUS_DIR)/lanplus_strings.c $(LANPLUS_DIR)/lanplus_crypt.c \ + $(LANPLUS_DIR)/lanplus_crypt_impl.c $(LANPLUS_DIR)/helper.c \ + $(LANPLUS_DIR)/ipmi_strings.c + +# sbin_PROGRAMS are built by default and copied to /usr/sbin at install time +# EXTRA_PROGRAMS are built by default but not included in the install package +# TESTPROGS are not built by default. To build, do 'make ifruset', for example. +bin_PROGRAMS = ipmiutil ievents idiscover +sbin_PROGRAMS = ipmi_port +DEV_LIB = libipmiutil.a +EXTRA_PROGRAMS = ipmi_sample ipmi_sample_evt +TESTPROGS = libimbapi.a iconfig ipmimv ifruset ipmi_sample2 ialarms_enc iseltime +# OLDPROGS are old/previous binaries that may exist and need to be deleted. +OLDPROGS = alarms bmchealth fruconfig getevent hwreset icmd isolconsole pefconfig sensor showsel tmconfig wdt + +lib_LTLIBRARIES = libipmiutil.la +libipmiutil_la_SOURCES = $(CMDSRC) $(LANPLUS_SRC) +libipmiutil_la_LDFLAGS = -export-dynamic + +# To build an imb api library (libimbapi.a): +libimbapi.a: imbapi.c + mkdir -p $(tmpobj) + $(CC) -I. -I.. $(OS_CF) -fPIC $(CFLAGS) -o $(tmpobj)/imbapi.o -c imbapi.c + $(AR) cru libimbapi.a $(tmpobj)/imbapi.o + $(RANLIB) libimbapi.a + rm -f $(tmpobj)/imbapi.o + +# Build a lib to support all of the IPMI drivers (libipmiutil.a) +# If LANPLUS_SAM = yes, include LANPLUS_OBJ, else do not. +# See configure --enable-liblanplus to change this +$(DEV_LIB): $(CMDOBJ) @LANPLUS_LIB@ + mkdir -p $(tmpobj) + if [ "x@LANPLUS_SAM@" = "xyes" ]; then \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + ar x @LANPLUS_LIB@ ; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) $(LANPLUS_OBJ); \ + $(RANLIB) $(DEV_LIB); \ + else \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) ; \ + $(RANLIB) $(DEV_LIB) ; \ + fi + rm -f $(tmpobj)/ipmilan.o $(tmpobj)/ipmilanplus.o + +# To build ipmiutil, need to use METACFLAGS for each .c/.o + +idiscover: idiscover.c + $(CC) $(OS_CF) $(CFLAGS) $(LDFLAGS) $(OS_LF) -o idiscover idiscover.c + +ipmimv: ipmimv.c + $(CC) $(OS_CF) $(CFLAGS) $(LDFLAGS) -DTEST_BIN -o ipmimv ipmimv.c + +ievents: ievents.c + $(CC) $(OS_CF)$(CFLAGS) $(LDFLAGS) -DALONE -o ievents ievents.c + +ipmi_sample: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -c ipmi_sample.c + $(CC) -g -O2 -o ipmi_sample ipmi_sample.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ialarms_enc: $(DEV_LIB) ialarms.c oem_intel.c + $(CC) $(CFLAGS_SAM) -DTEST_ENC -o ialarms2.o -c ialarms.c + $(CC) $(CFLAGS_SAM) -DNO_EVENTS -o oem_intel2.o -c oem_intel.c + $(CC) -g -O2 -o ialarms_enc ialarms2.o oem_intel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifru_picmg2.o: ifru_picmg.c + $(CC) $(CFLAGS_SAM) -o ifru_picmg2.o -c ifru_picmg.c + +# To build ipmi_sample with GET_SENSORS enabled, need isensors.o, ievents.o +# Note that this does not include oem_intel, etc. for OEM SEL decoding. +ipmi_sample2: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c ifru.c isel.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -D GET_SENSORS -D GET_FRU -o ipmi_sample2.o -c ipmi_sample.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -o ievents2.o -c ievents.c + $(CC) $(CFLAGS_SAM) -o ifru2.o -c ifru.c + $(CC) $(CFLAGS_SAM) -o isel2.o -c isel.c + $(CC) -g -O2 -o ipmi_sample2 ipmi_sample2.o isensor2.o ievents2.o ifru2.o ifru_picmg2.o isel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ipmi_sample_evt: $(DEV_LIB) ipmi_sample_evt.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -o ipmi_sample_evt.o -c ipmi_sample_evt.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -DSENSORS_OK -o ievents2.o -c ievents.c + $(CC) -g -O2 -o ipmi_sample_evt ipmi_sample_evt.o isensor2.o ievents2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifruset: $(DEV_LIB) ifruset.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -c ifruset.c + $(CC) -g -O2 -o ifruset ifruset.o ifru_picmg2.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +iseltime: $(DEV_LIB) iseltime.c + $(CC) $(CFLAGS_SAM) -c iseltime.c + $(CC) -g -O2 -o iseltime iseltime.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +ipmi_port: ipmi_port.c + $(CC) $(CFLAGS) $(LDFLAGS) -o ipmi_port ipmi_port.c + +#xmlconfig: xmlconfig.c $(DEV_LIB) +# $(CC) $(CFLAGS) $(LDFLAGS) -o xmlconfig xmlconfig.c libipmiutil.a @LANPLUS_CRYPTO@ + +iconfig: iconfig.c $(DEV_LIB) + $(CC) $(CFLAGS) $(LDFLAGS) -o iconfig iconfig.c $(DEV_LIB) @LANPLUS_CRYPTO@ + +# @LANPLUS_LIB@ is ../lib/libipmi_lanplus.a +../lib/libipmi_lanplus.a: + cd ../lib; make + +ipmiutil_SOURCES = $(METASOURCE) + +ipmiutil: $(METASOURCE:.c=.o) $(CMDOBJ) @LANPLUS_LIB@ + $(CC) $(CFLAGS) $(LDFLAGS) -o ipmiutil $(METASOURCE:.c=.o) $(CMDOBJ) $(LDADD) + +$(tmpobj)/ipmicmd.o: ipmicmd.c + mkdir -p $(tmpobj) + @$(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmicmd.o -c ipmicmd.c + +$(tmpobj)/subs.o: subs.c + @$(CC) $(CFLAGS_SAMX) -o $(tmpobj)/subs.o -c subs.c + +$(tmpobj)/mem_if.o: mem_if.c + @$(CC) $(CFLAGS_SAMX) -o $(tmpobj)/mem_if.o -c mem_if.c + +$(tmpobj)/ipmidir.o: ipmidir.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmidir.c + +$(tmpobj)/imbapi.o: imbapi.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c imbapi.c + +$(tmpobj)/ipmimv.o: ipmimv.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmimv.c + +$(tmpobj)/ipmild.o: ipmild.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmild.c + +$(tmpobj)/ipmibmc.o: ipmibmc.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmibmc.c + +$(tmpobj)/ipmilipmi.o: ipmilipmi.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmilipmi.c + +$(tmpobj)/ipmilan.o: ipmilan.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmilan.c + +$(tmpobj)/ipmilanplus.o: ipmilanplus.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmilanplus.c + +$(tmpobj)/md5.o: md5.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c md5.c + +$(tmpobj)/md2.o: md2.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c md2.c + +#%.o: %.c +# $(CC) -c $(OS_CF) $(CFLAGS) $(AM_CPPFLAGS) -o $@ $< + +ievents_SOURCES = ievents.c + +idiscover_SOURCES = idiscover.c + +ipmi_port_SOURCES = ipmi_port.c + +# xmlconfig_SOURCES = xmlconfig.c $(CMDSRC) + +EXTRA_DIST = imb_api.h ipmicmd.h ipmidir.h ipmilan.h ipmilanplus.h AnsiTerm.h iekanalyzer.h ifirewall.h ifwum.h ihpm.h ipicmg.h ipmiutil.h md2.h oem_dell.h oem_fujitsu.h oem_intel.h oem_kontron.h oem_sun.h idcmi.h isensor.h + +all-am: Makefile $(DEV_LIB) $(bin_PROGRAMS) $(sbin_PROGRAMS) $(EXTRA_PROGRAMS) + +install-data-am: $(EXTRA_PROGRAMS) $(DEV_LIB) + @INS_LIB@ mkdir -p $(DESTDIR)$(extradir) + @INS_LIB@ mkdir -p $(DESTDIR)$(LIBDIR) + @INS_LIB@ mkdir -p $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f ipmi_sample.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmi_sample_evt.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmicmd.h $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f isensor.c ievents.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f isensor.h ievents.h $(DESTDIR)$(extradir) + @INS_LIB@ cp -f Makefile.sample $(DESTDIR)$(extradir)/Makefile + @INS_LIB@ cp -f $(DEV_LIB) $(DESTDIR)$(LIBDIR) + +clean-generic: + rm -f $(DEV_LIB) $(EXTRA_PROGRAMS) $(OLDPROGS) $(TESTPROGS) + if [ -d $(tmpobj) ]; then rm -rf $(tmpobj) ; fi + if [ -d $(tmpwin) ]; then rm -rf $(tmpwin) ; fi + rm -f *.log *.tmp debug*.list *.o *.pdb *.lo *.so *.la diff --git a/util/Makefile.in b/util/Makefile.in new file mode 100644 index 0000000..a8eb9b9 --- /dev/null +++ b/util/Makefile.in @@ -0,0 +1,766 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = ipmiutil$(EXEEXT) ievents$(EXEEXT) idiscover$(EXEEXT) +sbin_PROGRAMS = ipmi_port$(EXEEXT) iseltime$(EXEEXT) +EXTRA_PROGRAMS = ipmi_sample$(EXEEXT) ipmi_sample_evt$(EXEEXT) +subdir = util +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS) +am_idiscover_OBJECTS = idiscover.$(OBJEXT) +idiscover_OBJECTS = $(am_idiscover_OBJECTS) +idiscover_LDADD = $(LDADD) +am__DEPENDENCIES_1 = +idiscover_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_ievents_OBJECTS = ievents.$(OBJEXT) +ievents_OBJECTS = $(am_ievents_OBJECTS) +ievents_LDADD = $(LDADD) +ievents_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_ipmi_port_OBJECTS = ipmi_port.$(OBJEXT) +ipmi_port_OBJECTS = $(am_ipmi_port_OBJECTS) +ipmi_port_LDADD = $(LDADD) +ipmi_port_DEPENDENCIES = $(am__DEPENDENCIES_1) +ipmi_sample_SOURCES = ipmi_sample.c +ipmi_sample_OBJECTS = ipmi_sample.$(OBJEXT) +ipmi_sample_LDADD = $(LDADD) +ipmi_sample_DEPENDENCIES = $(am__DEPENDENCIES_1) +ipmi_sample_evt_SOURCES = ipmi_sample_evt.c +ipmi_sample_evt_OBJECTS = ipmi_sample_evt.$(OBJEXT) +ipmi_sample_evt_LDADD = $(LDADD) +ipmi_sample_evt_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_1 = oem_kontron.$(OBJEXT) oem_fujitsu.$(OBJEXT) \ + oem_intel.$(OBJEXT) oem_sun.$(OBJEXT) oem_supermicro.$(OBJEXT) \ + oem_dell.$(OBJEXT) oem_quanta.$(OBJEXT) oem_hp.$(OBJEXT) \ + oem_newisys.$(OBJEXT) iekanalyzer.$(OBJEXT) +am__objects_2 = ipmicmd.$(OBJEXT) mem_if.$(OBJEXT) ipmidir.$(OBJEXT) \ + imbapi.$(OBJEXT) ipmimv.$(OBJEXT) ipmild.$(OBJEXT) \ + ipmibmc.$(OBJEXT) ipmilipmi.$(OBJEXT) subs.$(OBJEXT) \ + md5.$(OBJEXT) md2.$(OBJEXT) ipmilan.$(OBJEXT) \ + ipmilanplus.$(OBJEXT) +am__objects_3 = ipmiutil.$(OBJEXT) ialarms.$(OBJEXT) ihealth.$(OBJEXT) \ + ievents.$(OBJEXT) ifru.$(OBJEXT) ifru_picmg.$(OBJEXT) \ + igetevent.$(OBJEXT) ireset.$(OBJEXT) icmd.$(OBJEXT) \ + ilan.$(OBJEXT) isensor.$(OBJEXT) isel.$(OBJEXT) \ + iserial.$(OBJEXT) iwdt.$(OBJEXT) isol.$(OBJEXT) \ + idiscover.$(OBJEXT) iconfig.$(OBJEXT) ipicmg.$(OBJEXT) \ + ifirewall.$(OBJEXT) ifwum.$(OBJEXT) ihpm.$(OBJEXT) \ + itsol.$(OBJEXT) idcmi.$(OBJEXT) $(am__objects_1) \ + $(am__objects_2) +am_ipmiutil_OBJECTS = $(am__objects_3) +ipmiutil_OBJECTS = $(am_ipmiutil_OBJECTS) +ipmiutil_LDADD = $(LDADD) +ipmiutil_DEPENDENCIES = $(am__DEPENDENCIES_1) +iseltime_SOURCES = iseltime.c +iseltime_OBJECTS = iseltime.$(OBJEXT) +iseltime_LDADD = $(LDADD) +iseltime_DEPENDENCIES = $(am__DEPENDENCIES_1) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(idiscover_SOURCES) $(ievents_SOURCES) $(ipmi_port_SOURCES) \ + ipmi_sample.c ipmi_sample_evt.c $(ipmiutil_SOURCES) iseltime.c +DIST_SOURCES = $(idiscover_SOURCES) $(ievents_SOURCES) \ + $(ipmi_port_SOURCES) ipmi_sample.c ipmi_sample_evt.c \ + $(ipmiutil_SOURCES) iseltime.c +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CROSS_CFLAGS = @CROSS_CFLAGS@ +CROSS_LFLAGS = @CROSS_LFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPL_CFLAGS = @GPL_CFLAGS@ +IA64_CFLAGS = @IA64_CFLAGS@ +INIT_DIR = @INIT_DIR@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INS_LIB = @INS_LIB@ +LANDESK_CFLAGS = @LANDESK_CFLAGS@ +LANDESK_LDADD = @LANDESK_LDADD@ +LANPLUS_CFLAGS = @LANPLUS_CFLAGS@ +LANPLUS_CRYPTO = @LANPLUS_CRYPTO@ +LANPLUS_LDADD = @LANPLUS_LDADD@ +LANPLUS_LIB = @LANPLUS_LIB@ +LANPLUS_SAM = @LANPLUS_SAM@ +LDFLAGS = @LDFLAGS@ +LD_SAMX = @LD_SAMX@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_DIR = @LIB_DIR@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +OS_CFLAGS = @OS_CFLAGS@ +OS_DRIVERS = @OS_DRIVERS@ +OS_LFLAGS = @OS_LFLAGS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_DIR = @PKG_DIR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SHR_LINK = @SHR_LINK@ +STRIP = @STRIP@ +SUBDIR_S = @SUBDIR_S@ +SYSTEMD_DIR = @SYSTEMD_DIR@ +VERSION = @VERSION@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +localedir = $(datadir)/locale +INCLUDES = -I.. +OS_CF = @OS_CFLAGS@ @CROSS_CFLAGS@ +OS_LF = @OS_LFLAGS@ @CROSS_LFLAGS@ + +# The LanDesk library is proprietary, so it is incompatible with ALLOW_GPL. +# To build with LanDesk support: +# First copy the library to ../lib/libipmiapi.a +# Then ./configure --enable-landesk +# Result: +# AM_CPPFLAGS += -DLINK_LANDESK +# LDADD += -lipmiapi -L../lib + +# For lanplus plugin support (IPMI LAN 2.0 RMCP+) used by SOL: +# If ./configure --disable-lanplus +# AM_CPPFLAGS += +# LDADD += +# Otherwise default result is lanplus enabled: +# AM_CPPFLAGS += -DHAVE_LANPLUS +# LDADD += -L../lib -lipmi_lanplus -L/usr/local/lib -lcrypto +# LDADD += -L../lib -lintf_lanplus -L/usr/local/lib -lcrypto (older) +# Could also use CMDMOD += ipmilan2.c instead, if completed. +AM_CPPFLAGS = $(OS_CF) -DLOCALEDIR=\"$(localedir)\" @IA64_CFLAGS@ \ + @GPL_CFLAGS@ -I. -I.. -DMETACOMMAND @LANDESK_CFLAGS@ \ + @LANPLUS_CFLAGS@ $(am__empty) +LDADD = $(OS_LF) -lpthread @LANDESK_LDADD@ @LANPLUS_LIB@ \ + @LANPLUS_CRYPTO@ $(am__empty) +LDSAM = $(OS_LF) @LD_SAMX@ +CFLAGS_SAMX = -O2 -g -I. -I.. $(OS_CF) @LANPLUS_CFLAGS@ +CFLAGS_SAM = -O2 -g -I. -I.. $(OS_CF) +# May be /usr/bin/install or /bin/install +INSTALLBIN = install -c +extradir = $(datadir)/ipmiutil +inc_dir = $(includedir) +tmpobj = obj +tmpwin = tmp +LIBDIR = @LIB_DIR@ +CMDMOD = ipmicmd.c mem_if.c ipmidir.c imbapi.c ipmimv.c ipmild.c \ + ipmibmc.c ipmilipmi.c subs.c md5.c md2.c ipmilan.c \ + ipmilanplus.c +# CMDMOD = ipmicmd.c mem_if.c @OS_DRIVERS@ +# am: configure substitutions are not allowed in _SOURCES variables +LIBOBJ = ipmicmd.o mem_if.o ipmidir.o imbapi.o ipmimv.o ipmild.o ipmibmc.o ipmilipmi.o subs.o md5.o md2.o $(tmpobj)/ipmilan.o $(tmpobj)/ipmilanplus.o +OEMMOD = oem_kontron.c oem_fujitsu.c oem_intel.c oem_sun.c oem_supermicro.c oem_dell.c oem_quanta.c oem_hp.c oem_newisys.c iekanalyzer.c +METASOURCE = ipmiutil.c ialarms.c ihealth.c ievents.c ifru.c ifru_picmg.c igetevent.c ireset.c icmd.c ilan.c isensor.c isel.c iserial.c iwdt.c isol.c idiscover.c iconfig.c ipicmg.c ifirewall.c ifwum.c ihpm.c itsol.c idcmi.c $(OEMMOD) $(CMDMOD) +LANPLUS_OBJ = $(shell ar t @LANPLUS_LIB@ 2>/dev/null) +DEV_LIB = libipmiutil.a +SHR_LIB = libipmiutil.so +SHRLINK = @SHR_LINK@ +TESTPROGS = libimbapi.a iconfig ipmimv ifruset ipmi_sample2 ialarms_enc +# OLDPROGS are old/previous binaries that may exist and need to be deleted. +OLDPROGS = alarms bmchealth fruconfig getevent hwreset icmd isolconsole pefconfig sensor showsel tmconfig wdt +ipmiutil_SOURCES = $(METASOURCE) +ievents_SOURCES = ievents.c +idiscover_SOURCES = idiscover.c +ipmi_port_SOURCES = ipmi_port.c +EXTRA_DIST = imb_api.h ipmicmd.h ipmidir.h ipmilan.h ipmilanplus.h AnsiTerm.h ifirewall.h ifwum.h ihpm.h ipicmg.h ipmiutil.h md2.h oem_dell.h oem_fujitsu.h oem_intel.h oem_kontron.h oem_sun.h idcmi.h isensor.h iekanalyzer.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign util/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign util/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)" + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \ + rm -f "$(DESTDIR)$(sbindir)/$$f"; \ + done + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ialarms.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icmd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iconfig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/idcmi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/idiscover.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iekanalyzer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ievents.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifirewall.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifru.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifru_picmg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifwum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/igetevent.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ihealth.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ihpm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ilan.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imbapi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipicmg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_port.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_sample.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_sample_evt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmibmc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmicmd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmidir.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmilan.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmilanplus.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmild.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmilipmi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmimv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmiutil.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ireset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iseltime.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isensor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iserial.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/itsol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iwdt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem_if.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_dell.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_fujitsu.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_hp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_intel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_kontron.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_newisys.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_quanta.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_sun.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_supermicro.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subs.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool \ + clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-exec-am: install-binPROGRAMS install-sbinPROGRAMS + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am \ + uninstall-sbinPROGRAMS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-sbinPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-sbinPROGRAMS install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-info-am uninstall-sbinPROGRAMS + + +# To build an imb api library (libimbapi.a): +libimbapi.a: imbapi.c + mkdir -p $(tmpobj) + $(CC) -I. -I.. $(OS_CF) -fPIC $(CFLAGS) -o $(tmpobj)/imbapi.o -c imbapi.c + $(AR) cru libimbapi.a $(tmpobj)/imbapi.o + $(RANLIB) libimbapi.a + rm -f $(tmpobj)/imbapi.o + +# Build a lib to support all of the IPMI drivers (libipmiutil.a) +# If LANPLUS_SAM = yes, include LANPLUS_OBJ, else do not. +# See configure --enable-liblanplus to change this +$(DEV_LIB): $(CMDMOD:.c=.o) @LANPLUS_LIB@ + mkdir -p $(tmpobj) + if [ "x@LANPLUS_SAM@" = "xyes" ]; then \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + ar x @LANPLUS_LIB@ ; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) $(LANPLUS_OBJ); \ + $(RANLIB) $(DEV_LIB); \ + else \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) ; \ + $(RANLIB) $(DEV_LIB) ; \ + fi + +$(SHR_LIB): $(CMDMOD:.c=.o) @LANPLUS_LIB@ + mkdir -p $(tmpobj) + if [ "x@LANPLUS_SAM@" = "xyes" ]; then \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + ar x @LANPLUS_LIB@ ; \ + $(CC) $(LDFLAGS) -shared -o $(SHR_LIB) $(LIBOBJ) $(LANPLUS_OBJ); \ + else \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + $(CC) $(LDFLAGS) -shared -o $(SHR_LIB) $(LIBOBJ) ; \ + fi + +# To build ipmiutil, need to use METACFLAGS for each .c/.o + +idiscover$(EXEEXT): idiscover.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) $(OS_LF) -o idiscover idiscover.c + +ipmimv: ipmimv.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -DTEST_BIN -o ipmimv ipmimv.c + +ievents$(EXEEXT): ievents.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -DALONE -o ievents ievents.c + +ipmi_sample: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -c ipmi_sample.c + $(CC) -g -O2 -o ipmi_sample ipmi_sample.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ialarms_enc: $(DEV_LIB) ialarms.c oem_intel.c + $(CC) $(CFLAGS_SAM) -DTEST_ENC -o ialarms2.o -c ialarms.c + $(CC) $(CFLAGS_SAM) -DNO_EVENTS -o oem_intel2.o -c oem_intel.c + $(CC) -g -O2 -o ialarms_enc ialarms2.o oem_intel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifru_picmg2.o: ifru_picmg.c + $(CC) $(CFLAGS_SAM) -o ifru_picmg2.o -c ifru_picmg.c + +# To build ipmi_sample with GET_SENSORS enabled, need isensors.o, ievents.o +# Note that this does not include oem_intel, etc. for OEM SEL decoding. +ipmi_sample2: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c ifru.c isel.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -D GET_SENSORS -D GET_FRU -o ipmi_sample2.o -c ipmi_sample.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -o ievents2.o -c ievents.c + $(CC) $(CFLAGS_SAM) -o ifru2.o -c ifru.c + $(CC) $(CFLAGS_SAM) -o isel2.o -c isel.c + $(CC) -g -O2 -o ipmi_sample2 ipmi_sample2.o isensor2.o ievents2.o ifru2.o ifru_picmg2.o isel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ipmi_sample_evt: $(DEV_LIB) ipmi_sample_evt.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -o ipmi_sample_evt.o -c ipmi_sample_evt.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -DSENSORS_OK -o ievents2.o -c ievents.c + $(CC) -g -O2 -o ipmi_sample_evt ipmi_sample_evt.o isensor2.o ievents2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifruset: $(DEV_LIB) ifruset.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -c ifruset.c + $(CC) -g -O2 -o ifruset ifruset.o ifru_picmg2.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +iseltime: $(DEV_LIB) iseltime.c + $(CC) $(CFLAGS_SAM) -c iseltime.c + $(CC) -g -O2 -o iseltime iseltime.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +ipmi_port$(EXEEXT): ipmi_port.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -o ipmi_port ipmi_port.c + +iconfig: iconfig.c $(DEV_LIB) + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -o iconfig iconfig.c $(DEV_LIB) @LANPLUS_CRYPTO@ + +# @LANPLUS_LIB@ is ../lib/libipmi_lanplus.a +../lib/libipmi_lanplus.a: + cd ../lib; make + +ipmiutil$(EXEEXT): $(METASOURCE:.c=.o) @LANPLUS_LIB@ + $(CC) $(CFLAGS) $(LDFLAGS) -o ipmiutil $(METASOURCE:.c=.o) $(LDADD) + +all-am: Makefile $(bin_PROGRAMS) $(sbin_PROGRAMS) $(EXTRA_PROGRAMS) $(DEV_LIB) $(SHRLINK) + +install-data-am: $(EXTRA_PROGRAMS) $(DEV_LIB) $(SHRLINK) + @INS_LIB@ mkdir -p $(DESTDIR)$(extradir) + @INS_LIB@ mkdir -p $(DESTDIR)$(LIBDIR) + @INS_LIB@ mkdir -p $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f ipmi_sample.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmi_sample_evt.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmicmd.h $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f isensor.c ievents.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f isensor.h ievents.h $(DESTDIR)$(extradir) + @INS_LIB@ cp -f Makefile.sample $(DESTDIR)$(extradir)/Makefile + @INS_LIB@ cp -f $(DEV_LIB) $(DESTDIR)$(LIBDIR) + if [ "x$(SHRLINK)" != "x" ]; then \ + @INS_LIB@ cp -f $(SHR_LIB) $(DESTDIR)$(LIBDIR) ; \ + fi + +clean-generic: + rm -f $(DEV_LIB) $(EXTRA_PROGRAMS) $(OLDPROGS) $(TESTPROGS) $(SHRLINK) + if [ -d $(tmpobj) ]; then rm -rf $(tmpobj) ; fi + if [ -d $(tmpwin) ]; then rm -rf $(tmpwin) ; fi + rm -f *.log *.tmp debug*.list *.o *.pdb *.lo *.la *.so +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/util/Makefile.sample b/util/Makefile.sample new file mode 100644 index 0000000..2976dd5 --- /dev/null +++ b/util/Makefile.sample @@ -0,0 +1,28 @@ +# Makefile for ipmi_sample program +# +TARGETS = ipmi_sample ipmi_sample_evt +incl_dir = /usr/include +CFLAGS_SAM = -O2 -g -I. -DLINUX +LDFLAGS = -lpthread +# if building without lanplus, comment out these two lines +CFLAGS_SAM += -DHAVE_LANPLUS +LDFLAGS += -lcrypto + +# see /usr/lib/libipmiutil.a +LDFLAGS += -lipmiutil + +all: $(TARGETS) + +ipmi_sample: ipmi_sample.c $(incl_dir)/ipmicmd.h + $(CC) $(CFLAGS_SAM) -c ipmi_sample.c + $(CC) -g -O2 -o ipmi_sample ipmi_sample.o $(LDFLAGS) + +ipmi_sample_evt: ipmi_sample_evt.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -c ipmi_sample_evt.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -DSENSORS_OK -o ievents2.o -c ievents.c + $(CC) -g -O2 -o ipmi_sample_evt ipmi_sample_evt.o isensor2.o ievents2.o $(LDFLAGS) + +clean-generic: + rm -f $(TARGETS) *.o *.tmp + diff --git a/util/ialarms.c b/util/ialarms.c new file mode 100644 index 0000000..dbbdf0c --- /dev/null +++ b/util/ialarms.c @@ -0,0 +1,689 @@ +/* + * ialarms.c + * + * This tool reads and sets the alarms panel on an Intel Telco chassis. + * Note that the Intel Server Management software will set these alarms + * based on firmware-detected thresholds and events. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2003-2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 02/25/03 Andy Cress - created + * 04/08/03 Andy Cress - added -i for ChassisIdentify + * 04/30/03 Andy Cress - only try to set ID on/off if option specified + * 01/20/04 Andy Cress - mods for mBMC w Chesnee platform + * 05/05/04 Andy Cress - call ipmi_close before exit + * 10/11/04 Andy Cress 1.4 - if -o set relays too (fsetall) + * 11/01/04 Andy Cress 1.5 - add -N / -R for remote nodes + * 03/07/05 Andy Cress 1.6 - add bus for Intel TIGI2U + * 03/28/05 Andy Cress 1.7 - add check for BMC TAM if setting alarms + * 06/22/05 Andy Cress 1.8 - adding fpicmg for ATCA alarm LEDs + * 03/17/06 Andy Cress 1.9 - adding BUS_ID7 for Harbison + * 04/20/07 Andy Cress 1.25 - adding disk Enclosure HSC LEDs + */ +/*M* +Copyright (c) 2003-2006, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#ifdef WIN32 +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include "getopt.h" +#elif defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#include "ipmicmd.h" +#include "oem_intel.h" + +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "ialarms"; +static char fdebug = 0; +static char fbmctam = 0; +static char fpicmg = 0; +static char fHasAlarms = 0; +static char fNSC = 0; +static char fHasEnc = 0; /* Has disk Enclosure HSC? */ +static int maxdisks = 6; /* default to max of 6 disks */ +static uchar fdoencl = 1; +static uchar picmg_id = 0; /* always 0 for picmg */ +static uchar fru_id = 0; /* fru device id */ +//static uchar led_id = 0; /* 0 = blue led, 1,2,3=led1,2,3 */ +static uchar ipmi_maj, ipmi_min; + +#define ENC_LED_WRITE 0x21 // only used for Ballenger-CT HSC +#define ENC_LED_READ 0x20 // only used for Ballenger-CT HSC + +#define NETFN_ENC 0x30 +#define NETFN_PICMG 0x2c +#define PICMG_GET_LED_PROPERTIES 0x05 +#define PICMG_SET_LED_STATE 0x07 +#define PICMG_GET_LED_STATE 0x08 + +#ifdef METACOMMAND +extern int get_alarms_fujitsu(uchar *rgalarms); +extern int show_alarms_fujitsu(uchar *rgalarms); +extern int set_alarms_fujitsu(uchar num, uchar val); +extern int get_led_status_intel(uchar *pstate); +#endif +#ifdef ALONE +extern int get_led_status_intel(uchar *pstate); +#endif + +static uchar busid = PRIVATE_BUS_ID; +static uchar enc_sa = HSC_SA; +static char fRomley = 0; + +static int get_enc_leds(uchar *val) +{ + uchar idata[16]; + uchar rdata[16]; + int rlen, i; + int rv = 0; + uchar cc; + char *pstr = NULL; + rlen = sizeof(rdata); + for (i = 0; i < 3; i++) { + rv = ipmi_cmdraw( ENC_LED_READ, NETFN_ENC, enc_sa, PUBLIC_BUS,BMC_LUN, + idata,0, rdata, &rlen, &cc, fdebug); + if (fdebug) + printf("get_enc_leds() rv=%d cc=%x val=%02x\n",rv,cc,rdata[0]); + if (rv == 0 && cc == 0x83) os_usleep(0,50000); /* HSC busy, wait 50ms */ + else break; + } + if (rv != 0) pstr = decode_rv(rv); + else if (cc != 0) pstr = decode_cc(0,cc); + /* if get cc==0x83 here, the power state may be soft-off */ + if (rv == 0 && cc != 0) rv = cc; + if (rv == 0) { /*success*/ + *val = rdata[0]; + } else /*error*/ + printf("get_enc_leds: error %s\n",pstr); + return(rv); +} + +static int set_enc_leds(uchar val) +{ + uchar idata[16]; + uchar rdata[16]; + int rlen; + int rv = 0; + uchar cc; + + idata[0] = val; + rlen = sizeof(rdata); + rv = ipmi_cmdraw( ENC_LED_WRITE, NETFN_ENC, enc_sa, PUBLIC_BUS,BMC_LUN, + idata,1, rdata, &rlen, &cc, fdebug); + if (fdebug) printf("set_enc_leds(%02x) rv = %d, cc = %x\n",val,rv,cc); + if (rv == 0 && cc != 0) rv = cc; + return(rv); +} + +static void show_enc_leds(uchar val) +{ + char *enc_pattn = "disk slot %d LED: %s\n"; + uchar mask; + int i, n; + if (fdebug) printf("val = %02x\n",val); + n = maxdisks; + if (n > 8) n = 8; + mask = 0x01; + /* Ballenger HSC only supports 6 slots, some support 8 */ + for (i = 0; i < n; i++) { + if (val & mask) printf(enc_pattn,i,"ON"); + else printf(enc_pattn,i,"off"); + mask = (mask << 1); + } +} + +static int set_chassis_id(uchar val) +{ + uchar inputData[4]; + uchar responseData[16]; + int responseLength = 4; + uchar completionCode; + int ret; + uchar ilen; + + ilen = 1; + inputData[0] = val; /* #seconds to turn on id, 0=turn off */ + /* IPMI 2.0 has an optional 2nd byte, + * if 01, turn ID on indefinitely. */ + if (val == 255 && ipmi_maj >= 2) { + inputData[1] = 1; + ilen = 2; + } + /* CHASSIS_IDENTIFY=0x04, using NETFN_CHAS (=00) */ + ret = ipmi_cmd(CHASSIS_IDENTIFY, inputData, ilen, responseData, + &responseLength, &completionCode, fdebug); + if (ret == 0 && completionCode != 0) ret = completionCode; + if (ret != 0) { + printf("set_chassis_id: ret = %d, ccode %02x, value = %02x\n", + ret, completionCode, val); + } + return(ret); +} /*end set_chassis_id*/ + + +static int get_alarms_picmg(uchar *rgv, uchar picmgid, uchar fruid, uchar led) +{ + uchar inputData[4]; + uchar responseData[16]; + int responseLength; + uchar completionCode; + int ret, i; + + if (rgv == NULL) return(ERR_BAD_PARAM); + inputData[0] = picmgid; + inputData[1] = fruid; + inputData[2] = led; // 0 = blue led + responseLength = sizeof(responseData); + ret = ipmi_cmdraw( PICMG_GET_LED_STATE, NETFN_PICMG, + BMC_SA, PUBLIC_BUS,BMC_LUN, + inputData,3, responseData, &responseLength, + &completionCode, fdebug); + if ((ret != 0) || (completionCode != 0)) { + if (fdebug) + printf("get_alarms_picmg(%d,%d,%d): ret = %d, ccode %02x\n", + picmgid,fruid,led,ret, completionCode); + if (ret == 0) ret = completionCode; + return(ret); + } + /* if here, success */ + if (fdebug) { + printf("get_alarms_picmg(%d,%d,%d): ", picmgid,fruid,led); + for (i = 0; i < responseLength; i++) + printf("%02x ",responseData[i]); + printf("\n"); + } + memcpy(rgv,responseData,responseLength); + return(ret); +} + +static int set_alarms_picmg(uchar val, uchar picmgid, uchar fruid, uchar led, + char color) +{ + uchar inputData[6]; + uchar responseData[16]; + int responseLength; + uchar completionCode; + int ret, i; + + inputData[0] = picmgid; + inputData[1] = fruid; + inputData[2] = led; // 0 = blue led + inputData[3] = val; + inputData[4] = 0; + switch(color) { + case 'w': i = 6; break; + case 'o': i = 5; break; + case 'a': i = 4; break; + case 'g': i = 3; break; + case 'r': i = 2; break; + case 'b': + default: i = 1; break; + } + inputData[5] = (uchar)i; // 1 = blue + responseLength = sizeof(responseData); + ret = ipmi_cmdraw( PICMG_SET_LED_STATE, NETFN_PICMG, + BMC_SA, PUBLIC_BUS,BMC_LUN, + inputData,6, responseData, &responseLength, + &completionCode, fdebug); + if ((ret != 0) || (completionCode != 0)) { + printf("set_alarms_picmg(%02x,%d,%d,%d): ret = %d, ccode %02x\n", + val,picmgid,fruid,led,ret, completionCode); + if (ret == 0) ret = completionCode; + return(ret); + } + printf("set_alarms_picmg(%02x,%d,%d,%d): ", val,picmgid,fruid,led); + for (i = 0; i < responseLength; i++) + printf("%02x ",responseData[i]); + printf("\n"); + return(ret); /* success */ +} + +static void show_alarms_picmg(uchar *v, uchar pid, uchar fruid, uchar led) +{ + char led_str[10]; + char state_str[20]; + char *func_str; + char *color_str; + if (v == NULL) return; + if (fdebug) + printf("picmg(%d,%d,%d) alarm LED state is %02x %02x %02x %02x %02x\n", + pid,fruid,led,v[0],v[1],v[2],v[3],v[4]); + switch(led) { + case 0: strcpy(led_str,"HSLed"); break; /*Blue LED*/ + default: sprintf(led_str," Led%d",led); break; + } + state_str[0] = 0; + if (v[1] & 0x01) strcat(state_str,"local"); + if (v[1] & 0x02) strcat(state_str," override"); + if (v[1] & 0x04) strcat(state_str," lamptest"); + switch(v[2]) { + case 0x00: func_str = "off"; break; + case 0xFF: func_str = "ON"; break; + default: func_str = "Blink"; break; /*duration of blink/off*/ + } + /* v[3] is duration of blink/on in tens of msec */ + switch(v[4]) { + case 6: color_str = "white"; break; + case 5: color_str = "orange"; break; + case 4: color_str = "amber"; break; + case 3: color_str = "green"; break; + case 2: color_str = "red"; break; + case 1: + default: color_str = "blue"; break; + } + printf("picmg(%d,%d) %s is %s,%s,%s\n",fruid,led,led_str, + state_str,func_str,color_str); +} + + +#ifdef METACOMMAND +int i_alarms(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret = 0; + int c; + uchar fsetled = 0; + uchar fsetall = 0; + uchar fsetdisk = 0; + uchar fsetid = 0; + uchar fcrit = 2; + uchar fmaj = 2; + uchar fmin = 2; + uchar fpow = 2; + uchar fdiska = 2; + uchar fdiskb = 2; + uchar fdiskn = 2; + uchar ndisk = 0; + int fid = 0; + uchar alarms = 0; + uchar rgalarms[10] = {0,0,0,0,0,0}; + uchar newvalue = 0xff; + uchar diskled = 0xff; + uchar encled = 0; + uchar devrec[16]; + uchar ledn = 0; + uchar ledv = 0; + char ledc = 'c'; + int i; + int flags = 0; + int prod_id, vend_id; + + printf("%s ver %s\n", progname,progver); + /* default to admin privilege if get/set alarms remotely */ + parse_lan_options('V',"4",0); + + while ( (c = getopt( argc, argv,"rxa:b:c:d:efm:n:p:i:ow:Z:EF:P:N:R:U:T:V:J:Y?")) != EOF ) + switch(c) { + case 'r': fsetled=0; fsetid=0; fsetdisk = 0; break; /* read only */ + case 'a': fdiska = atob(optarg); /* set disk A LED value */ + fsetdisk = 1; break; + case 'b': fdiskb = atob(optarg); /* set disk B LED value */ + fsetdisk = 2; break; + case 'c': fcrit = atob(optarg); /* set critical alarm value */ + fsetled = 1; break; + case 'd': ndisk = optarg[0] & 0x0f; /* set disk N LED on or off */ + fdiskn = optarg[1] & 0x0f; + fsetdisk = 3; break; + case 'e': fdoencl = 0; /* skip disk/enclosure LEDs */ + case 'f': fdiska = 10; /* set all disk LEDs off */ + fsetdisk = 1; break; + case 'm': fmaj = atob(optarg); /* set major alarm value */ + fsetled = 1; break; + case 'n': fmin = atob(optarg); /* set minor alarm value */ + fsetled = 1; break; + case 'p': fpow = atob(optarg); /* set power alarm value */ + fsetled = 1; break; + case 'w': ledn = optarg[0] & 0x0f; /* set picmg LED N on or off */ + ledv = optarg[1] & 0x0f; + ledc = optarg[2]; /*color char, usu 'b' for blue*/ + fsetled = 1; break; + case 'i': fid = atoi(optarg); /* set chassis id on/off */ + if (fid > 255) { + printf("Adjusting %d to max 255 sec for ID\n",fid); + fid = 255; + } + fsetid=1; break; + case 'o': fcrit=0; fmaj=0; fmin=0; fpow=0; /* set all alarms off */ + fsetdisk = 1; fdiska = 0; fdiskb = 0; fsetall=1; + fsetled = 1; fsetid=1; fid=0; break; + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-abcdfimnoprx -NUPRETVFY]\n", progname); + printf(" where -r means read-only\n"); + printf(" -i5 sets Chassis ID on for 5 sec\n"); + printf(" -i0 sets Chassis ID off\n"); + printf(" -a1 sets Disk A Fault on\n"); + printf(" -a0 sets Disk A Fault off\n"); + printf(" -b1 sets Disk B Fault on\n"); + printf(" -b0 sets Disk B Fault off\n"); + printf(" -c1 sets Critical Alarm on\n"); + printf(" -c0 sets Critical Alarm off\n"); + printf(" -d31 sets Disk 3 Fault on (disks 0-6)\n"); + printf(" -d30 sets Disk 3 Fault off\n"); + printf(" -e skip disk Enclosure LEDs\n"); + printf(" -f sets all Disk Fault LEDs off\n"); + printf(" -m1 sets Major Alarm on\n"); + printf(" -m0 sets Major Alarm off\n"); + printf(" -n1 sets Minor Alarm on\n"); + printf(" -n0 sets Minor Alarm off\n"); + printf(" -p1 sets Power Alarm on\n"); + printf(" -p0 sets Power Alarm off\n"); + printf(" -o sets all Alarms off\n"); + printf(" -w21b writes picmg LED 2 on(1) color=blue(b)\n"); + printf(" -x show eXtra debug messages\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + /* + * Check the Device ID to determine which bus id to use. + */ + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + goto do_exit; + } else { + int j; + + if (fdebug) { + printf("devid: "); + for (j = 0; j < 16; j++) printf("%02x ",devrec[j]); + printf("\n"); + } + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + prod_id = devrec[9] + (devrec[10] << 8); + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + + printf("-- %s version %x.%x, IPMI version %d.%d \n", + "BMC", devrec[2], devrec[3], ipmi_maj, ipmi_min); + } + +#ifdef TEST_ENC + fHasEnc = 1; + fHasAlarms = 0; + fbmctam = 0; + fpicmg = 0; + fRomley = 1; + maxdisks = 8; +#else + ret = ipmi_getpicmg(devrec,16,fdebug); + if (ret == 0) { + fpicmg = 1; + fHasAlarms = 1; + } else ret = 0; /* ignore error if not picmg */ + +#if defined(METACOMMAND) || defined(ALONE) + { + uchar rgalarms[3]; + uchar idstate; + char *pmsg; + switch(vend_id) { + case VENDOR_NSC: /* for Intel TIGPT1U */ + case VENDOR_INTEL: /* requires oem_intel.c */ + /* check_prod_capab */ + ret = detect_capab_intel(vend_id,prod_id,&flags,&maxdisks,fdebug); + busid = (uchar)ret; + if (fdebug) printf("prod_capab: busid=%x, flags=%02x\n",busid,flags); + if ((flags & HAS_ALARMS_MASK) != 0) fHasAlarms = 1; + if ((flags & HAS_BMCTAM_MASK) != 0) fbmctam = 1; + if ((flags & HAS_ENCL_MASK) != 0) fHasEnc = 1; + if ((flags & HAS_PICMG_MASK) != 0) fpicmg = 1; + if ((flags & HAS_NSC_MASK) != 0) fNSC = 1; + if ((flags & HAS_ROMLEY_MASK) != 0) fRomley = 1; + /* get ID LED status */ + ret = get_led_status_intel(&idstate); + if (ret == 0) { + switch(idstate) { + case 1: pmsg = "ON"; break; + case 2: pmsg = "Blink"; break; + default: pmsg = "off"; break; + } + printf("ID LED: %s\n",pmsg); + } + break; +#ifdef METACOMMAND + case VENDOR_KONTRON: + if (prod_id == 1590) { fHasEnc = 1; maxdisks = 8; } + break; + case VENDOR_FUJITSU: + printf("Getting Fujitsu alarm LEDs ...\n"); + ret = get_alarms_fujitsu(rgalarms); + if (fdebug) printf("get_alarms_fujitsu ret = %d\n",ret); + /* if ret != 0, fall through and try default methods */ + if (ret == 0) { + show_alarms_fujitsu(rgalarms); + if (fsetid) { + printf("\nSetting fujitsu ID LED to %02x ...\n", fid); + ret = set_alarms_fujitsu(0, (uchar)fid); + printf("set_alarms_fujitsu ret = %d\n",ret); + ret = get_alarms_fujitsu(rgalarms); + if (ret == 0) show_alarms_fujitsu(rgalarms); + } + fHasAlarms = 0; /*skip the other LED functions*/ + } + break; + case VENDOR_SUN: + printf("Do get_alarms_sun() \n"); // TODO: add this +/* + ret = get_alarms_sun(); + if (ret == 0) show_alarms_sun() + if (fsetled) { + printf("\nSetting sun(%d) alarm LED to %02x %c...\n", + ledn,ledv,ledc); + ret = set_alarms_sun(ledv,ledn,ledc); + printf("set_alarms_sun ret = %d\n",ret); + ret = get_alarms_sun(rgalarms,ledn); + if (ret == 0) show_alarms_sun(rgalarms,ledn); + } +*/ + break; +#endif + default: + break; + } + } +#endif + +#endif + if (fHasAlarms) + { /* get the telco picmg or intel alarm LED states */ + if (fpicmg) { + for (i = 0; i < 5; i++) { + ret = get_alarms_picmg(rgalarms,picmg_id,fru_id,(uchar)i); + if (ret == 0) + show_alarms_picmg(rgalarms,picmg_id,fru_id,(uchar)i); + } + } else { + alarms = get_alarms_intel(busid); + if (alarms == 0) { /* failed to get alarm panel data */ + if (fHasAlarms) { /* baseboard which may have Telco alarm panel*/ + printf("Could not obtain Telco LED states, Telco alarm panel " + "may not be present.\n\n"); + } + fHasAlarms = 0; + } else { /* have Telco alarm panel data */ + ret = 0; + show_alarms_intel(alarms); + } + } + + if (fsetled) { + if (fpicmg) { + printf("\nSetting picmg(%d,%d) alarm LED to %02x %c...\n", + fru_id,ledn,ledv,ledc); + ret = set_alarms_picmg(ledv,picmg_id,fru_id,ledn,ledc); + printf("set_alarms_picmg ret = %d\n",ret); + ret = get_alarms_picmg(rgalarms,picmg_id,fru_id,ledn); + if (ret == 0) show_alarms_picmg(rgalarms,picmg_id,fru_id,ledn); + } else { /* not picmg, set Intel Telco Alarm LEDs */ + if (fbmctam) { /* Platform supports BMC Telco Alarms Manager */ + ret = check_bmctam_intel(); + } /*endif fbmctam*/ + if (ret == LAN_ERR_ABORT) { + printf("Conflict with BMC TAM - Skipping TAM LEDs.\n"); + } else { + if (fsetall) newvalue = 0xFF; /* alarms and relays */ + else { + newvalue = alarms; + if (fcrit == 1) newvalue &= 0xFD; /*bit1 = 0*/ + else if (fcrit == 0) newvalue |= 0xF2; + if (fmaj == 1) newvalue &= 0xFB; /*bit2 = 0*/ + else if (fmaj == 0) newvalue |= 0xF4; + if (fmin == 1) newvalue &= 0xF7; /*bit3 = 0*/ + else if (fmin == 0) newvalue |= 0xF8; + if (fpow == 1) newvalue &= 0xFE; /*bit0 = 0*/ + else if (fpow == 0) newvalue |= 0xF1; + } + printf("\nSetting alarms to %02x ...\n",newvalue); + ret = set_alarms_intel(newvalue,busid); + alarms = get_alarms_intel(busid); + show_alarms_intel(alarms); + } + } /*end else Intel*/ + } /*endif fsetled*/ + } /*endif fHasAlarms*/ + + if (fsetid) { + printf("Setting ID LED to %d ...\n\n",fid); + ret = set_chassis_id((uchar)fid); + } + + if (fHasEnc && fdoencl) { /* disk enclosure exists */ + if (fRomley) { /* Romley (Patsburg) */ + int rv; /*do not change ret*/ + rv = get_enc_leds_intel(&encled); + if (rv == 0) { + show_enc_leds_intel(encled,maxdisks); + if (fsetdisk) { + /* Set fault if user param, and disk is present. */ + if (fsetall) newvalue = 0x00; /* all LEDs off */ + else if (fdiska == 10) newvalue = 0x00; + else { + newvalue = encled; + if (fdiskb == 1) newvalue |= 0x02; + else if (fdiskb == 0) newvalue &= 0xFD; + if (fdiska == 1) newvalue |= 0x01; + else if (fdiska == 0) newvalue &= 0xFE; + if (fdiskn == 1) newvalue |= (0x01 << ndisk); + else if (fdiskn == 0) newvalue &= ~(0x01 << ndisk); + } + printf("\nSetting Enclosure LEDs to %02x ...\n",newvalue); + ret = set_enc_leds_intel(newvalue); + ret = get_enc_leds_intel(&encled); + show_enc_leds_intel(encled,maxdisks); + } + } + } else { /* Vitesse disk Enclosure chipset */ + ret = get_enc_leds(&encled); + if (ret == 0) { + show_enc_leds(encled); + if (fsetdisk) { + /* Set fault if user param, and disk is present. */ + if (fsetall) newvalue = 0x00; /* all LEDs off */ + else if (fdiska == 10) newvalue = 0x00; + else { + newvalue = encled; + if (fdiskb == 1) newvalue |= 0x02; + else if (fdiskb == 0) newvalue &= 0xFD; + if (fdiska == 1) newvalue |= 0x01; + else if (fdiska == 0) newvalue &= 0xFE; + if (fdiskn == 1) newvalue |= (0x01 << ndisk); + else if (fdiskn == 0) newvalue &= ~(0x01 << ndisk); + } + printf("\nSetting Enclosure LEDs to %02x ...\n",newvalue); + ret = set_enc_leds(newvalue); + ret = get_enc_leds(&encled); + show_enc_leds(encled); + } + } + } /*end-else Vitesse*/ + } /*endif fHasEnc*/ + else if (fNSC && fdoencl) { /*Chesnee NSC platform has special disk LEDs*/ + diskled = get_nsc_diskleds(busid); + show_nsc_diskleds(diskled); + if (fsetdisk) { + newvalue = diskled; + // newvalue |= 0xFC; /*leave upper bits high (off) */ + /* Set fault if user param, and disk is present. */ + if (fdiskb == 1) newvalue &= 0xFE; /*bit0=0*/ + else if (fdiskb == 0) newvalue |= 0x01; + if (fdiska == 1) newvalue &= 0xFD; /*bit1=0*/ + else if (fdiska == 0) newvalue |= 0x02; + else if (fdiska == 10) newvalue = 0x00; + printf("\nSetting Disk LEDs to %02x ...\n",newvalue); + ret = set_nsc_diskleds(newvalue,busid); + diskled = get_nsc_diskleds(busid); + show_nsc_diskleds(diskled); + } + } +do_exit: + ipmi_close_(); + // show_outcome(progname,ret); + return (ret); +} /* end main()*/ + +/* end ialarms.c */ diff --git a/util/icmd.c b/util/icmd.c new file mode 100644 index 0000000..5911262 --- /dev/null +++ b/util/icmd.c @@ -0,0 +1,366 @@ +/* + * icmd.c + * + * This tool takes command line input as an IPMI command. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2003-2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 03/30/04 Andy Cress - created + * 04/08/04 Andy Cress - display response data, changed usage order + * 05/05/04 Andy Cress - call ipmi_close before exit + * 11/01/04 Andy Cress - add -N / -R for remote nodes + * 12/08/04 Andy Cress v1.5 changed usage order, moved bus to first byte, + * gives better compatibility with ipmicmd.exe. + * 04/13/06 Andy Cress v1.6 fixed istart for -U -R + */ +/*M* +Copyright (c) 2006, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#if defined(EFI) + #ifndef NULL + #define NULL 0 + #endif + #include <types.h> + #include <libdbg.h> + #include <unistd.h> + #include <errno.h> +#else + /* Linux, Solaris, BSD, Windows */ + #include <stdio.h> + #include <stdlib.h> + #include <sys/types.h> + #include <sys/stat.h> + #include <fcntl.h> + #include <string.h> + #ifdef WIN32 + #include "getopt.h" + #elif defined(DOS) + #include <dos.h> + #include "getopt.h" + #elif defined(HPUX) + /* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> + #else + #include <getopt.h> + #endif +#endif +#include "ipmicmd.h" +extern void ipmi_lan_set_timeout(int ipmito, int tries, int pingto); + +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "icmd"; +static char fdebug = 0; +static char fquiet = 0; +static char fset_mc = 0; +static char ftest = 0; +static int vend_id; +static int prod_id; +static char fmBMC = 0; +static char fdecimal = 0; +extern int fjustpass; /*see ipmicmd.c*/ + +#define PRIVATE_BUS_ID 0x03 // w Sahalee, the 8574 is on Private Bus 1 +#define PERIPHERAL_BUS_ID 0x24 // w mBMC, the 8574 is on the Peripheral Bus +#define MAXRQLEN 64 +#define MAXRSLEN 200 + +static char usagemsg[] = "Usage: %s [-kqmsxEFNPRTUV] bus rsSa netFn/lun cmd [data bytes]\n"; +static uchar busid = PRIVATE_BUS_ID; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = 0; /*0x20*/ +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + +static int send_icmd(uchar *cmd, int len) +{ + uchar responseData[MAXRSLEN]; + int responseLength; + uchar completionCode; + int ret, i; + uchar netfn, lun; + ushort icmd; + + /* icmd format: 0=bus, 1=rsSa, 2=netFn/lun, 3=cmd, 4-n=data */ + netfn = cmd[2] >> 2; + lun = cmd[2] & 0x03; + icmd = cmd[3] + (netfn << 8); + if (fjustpass) { + ret = ipmi_cmdraw(IPMB_SEND_MESSAGE,NETFN_APP,BMC_SA,0,0, + &cmd[0],(uchar)(len), responseData, &responseLength, + &completionCode, fdebug); + } else { + responseLength = sizeof(responseData); + if (g_addrtype == ADDR_IPMB) { /* && (g_sa != 0) */ + /* if -m used, do ipmi_cmd_mc for IPMB commands */ + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + ret = ipmi_cmd_mc(icmd, &cmd[4], (uchar)(len-4), responseData, + &responseLength, &completionCode, fdebug); + ipmi_restore_mc(); + } else { + /* ipmi_cmdraw: bus, cmd, netfn, sa, lun, pdata, ... */ + ret = ipmi_cmdraw(cmd[3], netfn, cmd[1], cmd[0], lun, &cmd[4], + (uchar)(len-4), responseData, &responseLength, + &completionCode, fdebug); + } + } + if (ret < 0) { + printf("ipmi_cmd: ret = %d %s\n",ret,decode_rv(ret)); + return(ret); + } else if ((ret != 0) || (completionCode != 0)) { + printf("ipmi_cmd: ret = %d, ccode %02x %s\n", + ret, completionCode, decode_cc(icmd,completionCode)); + return(ret); + } else if (responseLength > 0) { + /* show the response data */ + printf("respData[len=%d]: ",responseLength); + for (i = 0; i < responseLength; i++) + printf("%02x ",responseData[i]); + printf("\n"); + } + return(ret); +} /*end send_icmd()*/ + + +#ifdef METACOMMAND +int i_cmd(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret = 0; + int c; + uchar devrec[17]; + uchar cmdbuf[MAXRQLEN]; + int maxlen = MAXRQLEN; + int i, j, istart, cmdlen; + int fskipdevid = 0; + int fprivset = 0; + int cmdmin; + char *s1; + + istart = 1; + while ( (c = getopt( argc, argv,"djkm:qst:xN:P:R:U:EF:J:T:V:YZ:?")) != EOF ) + switch(c) { + case 'j': /* just pass the bytes to KCS */ + fjustpass = 1; + break; + case 'd': /* decimal command bytes, skipping bus and sa, + which matches 'ipmitool raw' format. */ + fdecimal = 1; + break; + case 'm': /* specific MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + printf("set MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'q': fquiet = 1; fskipdevid = 1; break; /* minimal output */ + case 's': fskipdevid = 1; break; /* skip devid */ + case 't': /* set IPMI timeout for ipmilan, usu 2 * 4 = 8 sec */ + i = atoi(optarg); + if (i >= 2) { j = i / 2; i = j; } + else { i = 1; j = 1; } + ipmi_lan_set_timeout(i,j,1); + break; + case 'k': /* check for IPMI access */ + ftest = 1; + break; + case 'x': fdebug = 1; break; /* debug messages */ + case 'V': /* priv level */ + fprivset = 1; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("%s ver %s\n", progname,progver); + printf(usagemsg, progname); + printf(" where -x shows eXtra debug messages\n"); + printf(" -d decimal input, matching ipmitool syntax\n"); + printf(" -k check for IPMI access\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -q quiet mode, with minimal headers\n"); + printf(" -s skips the GetDeviceID command\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + if (ftest) { + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret == 0) { + /*check if a driver is loaded, or direct*/ + i = get_driver_type(); + printf("IPMI access is ok, driver type = %s\n",show_driver_type(i)); + if ((i == DRV_KCS) || (i == DRV_SMB)) + printf("Using driverless method\n"); + } + else printf("IPMI access error %d\n",ret); + goto do_exit; + } + + if (!fquiet) { + printf("%s ver %s\n", progname,progver); + printf("This is a test tool to compose IPMI commands.\n"); + printf("Do not use without knowledge of the IPMI specification.\n"); + } + istart = optind; + if (fdebug) printf("icmd: argc=%d istart=%d\n",argc,istart); + + if (fset_mc == 1) { + /* target a specific MC via IPMB (usu a picmg blade) */ + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + } else g_sa = BMC_SA; + + for (i = 0; i < istart; i++) { + argv++; argc--; + } + if (argc < maxlen) maxlen = argc; + if (fdebug) printf("icmd: len=%d, cmd byte0=%s\n",maxlen,argv[0]); + if (fdecimal) { + uchar b; + cmdbuf[0] = g_bus; + cmdbuf[1] = g_sa; + for (i = 0; i < maxlen; i++) { + if (argv[i][0] == '0' && argv[i][1] == 'x') /*0x00*/ + b = htoi(&argv[i][2]); + else b = atob(argv[i]); /*decimal default, or 0x00*/ + if (i == 0) { /*special handling for netfn */ + cmdbuf[i+2] = (b << 2) | (g_lun & 0x03); + } else + cmdbuf[i+2] = b; + } + cmdlen = i + 2; + } else { + for (i = 0; i < maxlen; i++) { + cmdbuf[i] = htoi(argv[i]); + } + cmdlen = i; + } + + if (fdebug) { + printf("ipmi_cmd: "); + for (i = 0; i < cmdlen; i++) + printf("%02x ",cmdbuf[i]); + printf("\n"); + } + + if (is_remote() && fprivset == 0) { /*IPMI LAN, privilege not set by user*/ + /* commands to other MCs require admin privilege */ + if ((g_sa != BMC_SA) || (cmdbuf[1] != BMC_SA)) + parse_lan_options('V',"4",0); + } + + if (!fskipdevid) { + /* + * Check the Device ID to determine which bus id to use. + */ + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + goto do_exit; + } else { + uchar b, j; + char *pstr; + + if (fdebug) { + printf("devid: "); + for (j = 0; j < 16; j++) printf("%02x ",devrec[j]); + printf("\n"); + } + b = devrec[4] & 0x0f; + j = devrec[4] >> 4; + prod_id = devrec[9] + (devrec[10] << 8); + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + if (vend_id == VENDOR_NSC) { /* NSC = 0x000322 */ + fmBMC = 1; /*NSC miniBMC*/ + } else if (vend_id == VENDOR_INTEL) { /* Intel = 0x000157 */ + switch(prod_id) { + case 0x4311: /* Intel NSI2U*/ + fmBMC = 1; /* Intel miniBMC*/ + break; + case 0x003E: /* NSN2U or CG2100*/ + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + break; + default: + break; + } + } + if (fmBMC) { /*NSC mini-BMC*/ + pstr = "mBMC"; + busid = PERIPHERAL_BUS_ID; /*used by alarms MWR*/ + } else { /* treat like Intel Sahalee = 57 01 */ + pstr = "BMC"; + busid = PRIVATE_BUS_ID; /*used by alarms MWR*/ + } + printf("-- %s version %x.%x, IPMI version %d.%d \n", + pstr, devrec[2], devrec[3], b, j); + } + // ret = ipmi_getpicmg( devrec, sizeof(devrec),fdebug); + // if (ret == 0) fpicmg = 1; + } /*endif skip devid*/ + + if (fjustpass) cmdmin = 2; + else cmdmin = 4; + if (cmdlen < cmdmin) { + printf("command length (%d) is too short\n",cmdlen); + printf(usagemsg, progname); + } else { + ret = send_icmd(cmdbuf,cmdlen); + if (!fquiet) printf("send_icmd ret = %d\n",ret); + } +do_exit: + ipmi_close_(); + // if (!fquiet) show_outcome(progname,ret); + return (ret); +} /* end main()*/ + +/* end icmd.c */ diff --git a/util/iconfig.c b/util/iconfig.c new file mode 100644 index 0000000..0bb54e9 --- /dev/null +++ b/util/iconfig.c @@ -0,0 +1,2680 @@ +/*--------------------------------------------------------------------------- + * Filename: iconfig.c (was bmcconfig.c) + * + * Author: arcress at users.sourceforge.net + * Copyright (c) 2009 Kontron America, Inc. + * + * Abstract: + * This tool saves and restores the BMC Configuration parameters. + * This includes BMC PEF, LAN, Serial, User, Channel, and SOL parameters. + * + * ----------- Change History ----------------------------------------------- + * 08/18/08 Andy Cress - created from pefconfig.c + */ +/*M* + *--------------------------------------------------------------------------- +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *--------------------------------------------------------------------------- + *M*/ +#ifdef WIN32 +#include <winsock2.h> +#include <iphlpapi.h> +#include <windows.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#include <string.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <errno.h> +#endif +#ifdef SOLARIS +#include <sys/sockio.h> +#define SIOCGIFHWADDR SIOCGENADDR +#define ifr_netmask ifr_ifru.ifru_addr +#elif defined(BSD) +#include <sys/sockio.h> +#define SIOCGIFHWADDR SIOCGIFMAC +#define ifr_netmask ifr_ifru.ifru_addr +#elif defined(MACOS) +#include <sys/sockio.h> +// #define SIOCGIFHWADDR SIOCGIFMAC +#define ifr_netmask ifr_ifru.ifru_addr +#endif +#include "ipmicmd.h" +#include "oem_intel.h" + +extern int find_ifname(char *ifname); /*see idiscover.c*/ +/* atoip was moved to subs.c, defined in ipmicmd.h */ + +#define SELprintf printf +#define RTF_UP 0x0001 /* route usable */ + +#define SOL_ENABLE_FLAG 0x01 +#define SOL_DISABLE_FLAG 0x00 +#define SOL_PRIVILEGE_LEVEL_USER 0x02 +#define SOL_PREFERRED_BAUD_RATE 0x07 /*19.2k*/ +/* For IPMI 1.5, use Intel SOL commands & subfunctions */ +#define SOL_ENABLE_PARAM 0x01 +#define SOL_AUTHENTICATION_PARAM 0x02 +#define SOL_ACC_INTERVAL_PARAM 0x03 +#define SOL_RETRY_PARAM 0x04 +#define SOL_BAUD_RATE_PARAM 0x05 /*non-volatile*/ +#define SOL_VOL_BAUD_RATE_PARAM 0x06 /*volatile*/ +/* For IPMI 2.0, use IPMI SOL commands & subfunctions */ +#define SOL_ENABLE_PARAM2 0x08 +#define SOL_AUTHENTICATION_PARAM2 0x09 +#define SOL_BAUD_RATE_PARAM2 0x11 + +/* IPMI 2.0 SOL PAYLOAD commands */ +#define SET_PAYLOAD_ACCESS 0x4C +#define GET_PAYLOAD_ACCESS 0x4D +#define GET_PAYLOAD_SUPPORT 0x4E + +/* Channel Access values */ +#define CHAN_ACC_DISABLE 0x20 /* PEF off, disabled*/ +#define CHAN_ACC_PEFON 0x02 /* PEF on, always avail */ +#define CHAN_ACC_PEFOFF 0x22 /* PEF off, always avail*/ +/* special channel access values for ia64 */ +#define CHAN_ACC_PEFON64 0x0A /* PEF on, always avail, UserLevelAuth=off */ +#define CHAN_ACC_PEFOFF64 0x2A /* PEF off, always avail, UserLevelAuth=off */ + + /* TSRLT2/TIGPR2U Channels: 0=IPMB, 1=Serial/EMP, 6=LAN2, 7=LAN1 */ + /* S5000/other Channels: 1=LAN1, 2=LAN2, 3=LAN3, 4=Serial, 6=pci, 7=sys */ +#define LAN_CH 1 +#define SER_CH 4 +#define MAXCHAN 12 /*was 16, reduced for gnu ipmi_lan*/ +#define NUM_DEVICES_TO_CHECK 32 /*for GetBmcEthDevice()*/ +#define MAC_LEN 6 /*length of MAC Address*/ +#define PSW_LEN 16 /*see also PSW_MAX=20 in ipmicmd.h*/ +#define MAXPEF 41 /* max pefnum offset = 40 (41 entries) */ + + /* IP address source values */ +#define SRC_STATIC 0x01 +#define SRC_DHCP 0x02 /* BMC running DHCP */ +#define SRC_BIOS 0x03 /* BIOS, sometimes DHCP */ +#define SRC_OTHER 0x04 + +/* PEF event severities */ +#define PEF_SEV_UNSPEC 0x00 +#define PEF_SEV_MON 0x01 +#define PEF_SEV_INFO 0x02 +#define PEF_SEV_OK 0x04 +#define PEF_SEV_WARN 0x08 +#define PEF_SEV_CRIT 0x10 +#define PEF_SEV_NORECOV 0x20 + +typedef struct +{ /* See IPMI Table 15-2 */ + uchar rec_id; + uchar fconfig; + uchar action; + uchar policy; + uchar severity; + uchar genid1; + uchar genid2; + uchar sensor_type; + uchar sensor_no; + uchar event_trigger; + uchar data1; + uchar mask1; + uchar res[9]; +} PEF_RECORD; + +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "iconfig"; +static char fdebug = 0; +static char fipmilan = 0; +static FILE * fd_bmc = NULL; +static char fIPMI10 = 0; /* =1 if IPMI v1.0 or less */ +static char fIPMI20 = 0; /* =1 if IPMI v2.0 or greater */ +static char fSOL20 = 1; /* =1 if SOL v2.0 is ok */ +static char freadonly = 1; /* =1 to only read LAN & PEF parameters */ +static char func = 'd'; /* function: display, save, restore */ +static char fdomac = 0; /* =1 to restore MAC also */ +static char fpassword = 0; /* =1 user-specified a password, so set it. */ +static uchar fmBMC = 0; +static uchar fiBMC = 0; +static uchar fRomley = 0; +static char fipv6 = 0; +static char fcanonical = 0; +static char fchan2wart = 0; /* =1 if need wart to skip channel 2 */ +static char bdelim = BCOLON; /*':' as default*/ +static char bcomment = BCOMMENT; /* '#' */ +static char pefmax = MAXPEF; /* 20 for Sahalee, 30 for miniBMC */ +static int nerrs = 0; +static int ngood = 0; +static int lasterr = 0; +static uchar nusers = 5; +static uchar max_users = 5; +static uchar enabled_users = 0; +static uchar last_user_enable = 0; /* last user enabled */ +static uchar passwordData[16]; +static uchar fsetifn = 0; +static ushort setsolcmd; +static ushort getsolcmd; +static uchar sol_bchan = 0; +static uchar authmask = 0; +static uchar lan_access = 0x04; /* see SetPassword*/ + +static uchar pefnum = 12; +static uchar fsharedMAC = 0; +//static uchar alertnum = 1; +//static uchar rgdestip[4]; +static uchar rgdestmac[6]; +static uchar rggwymac[6]; +#ifdef WIN32 +static uchar rggwyip[4] = {0,0,0,0}; +static uchar rgmyip [4] = {0,0,0,0}; /*WIN32*/ +static uchar rgmymac[6] = {0xFF,0,0,0,0,0}; /*WIN32*/ +static uchar rgsubnet[4] = {0,0,0,0}; /*WIN32*/ +static uchar osmyip[4] = {0,0,0,0}; +static uchar osmymac[6] = {0xff,0,0,0,0,0}; +#endif +static uchar bmcmyip[4] = {0,0,0,0}; +static uchar bmcdestip[4] = {0,0,0,0}; +static uchar bmcmymac[6] = {0xFF,0,0,0,0,0}; +static char ifname[16] = "eth0"; /* interface name */ +static char ifname0[16] = "eth0"; /* first interface name */ +static char ifpattn[14] = "eth"; /* default, discovered via find_ifname */ +static int vend_id; +static int prod_id; +static uchar ser_ch = 0; /*was SER_CH==4*/ +static uchar lan_ch = LAN_CH; +static uchar lan_ch_parm = 0xff; +static uchar lan_ch_sav = 0xff; +static uchar gcm_ch = 0; +static uchar SessInfo[16]; +static uchar chan_type[MAXCHAN]; +static int nlans = 0; +#define MAX_PEFPARAMS 14 /* max pef params = 14 */ +static char **pefdesc; +static char *pefdesc1[MAXPEF] = { /* for Sahalee BMC */ +/* 0 0x00 */ "", +/* 1 0x01 */ "Temperature Sensor", +/* 2 0x02 */ "Voltage Sensor", +/* 3 0x04 */ "Fan Failure", +/* 4 0x05 */ "Chassis Intrusion", +/* 5 0x08 */ "Power Supply Fault", +/* 6 0x0c */ "Memory ECC Error", +/* 7 0x0f */ "FRB Failure", +/* 8 0x07 */ "BIOS POST Error", +/* 9 0x13 */ "Fatal NMI", +/*10 0x23 */ "Watchdog Timer Reset", +/*11 0x12 */ "System Restart", +/*12 0x20 */ "OS Critical Stop", +/*13 0x09 */ "Power Redundancy Lost", +/*14 0x00 */ "reserved", +/*15 0x00 */ "reserved", +/*16 0x00 */ "reserved", +/*17 */ "reserved", +/*18 */ "reserved", +/*19 */ "reserved", +/*20 */ "reserved", +/*21 */ "reserved", +/*22 */ "reserved", +/*23 */ "reserved", +/*24 */ "reserved", +/*25 */ "reserved", +/*26 */ "reserved", +/*27 */ "reserved", +/*28 */ "reserved", +/*29 */ "unused", +/*30 */ "unused" }; + +static char *pefdesc2[MAXPEF] = { /* for NSC miniBMC */ +/* 0 */ "", +/* 1 0x02*/ "Voltage Sensor Assert", +/* 2 0x23*/ "Watchdog FRB Timeout", /* was "Proc FRB Thermal", */ +/* 3 0x02*/ "Voltage Sensor Deassert", +/* 4 0x07*/ "Proc1 IERR", +/* 5 0xff*/ "Digital Sensor OK", +/* 6 0x14*/ "Chassis Identify", +/* 7 0x13*/ "NMI Button", +/* 8 0x14*/ "Clear CMOS via Panel", +/* 9 0x0f*/ "OS Load POST Code", +/*10 0x20*/ "OS Critical Stop", +/*11 0x09 */ "Power Redundancy Lost", +/*12 0x00*/ "reserved", +/*13 */ "reserved", +/*14 */ "reserved", +/*15 */ "reserved", +/*16 */ "reserved", +/*17 */ "reserved", +/*18 */ "reserved", +/*19 */ "reserved", +/*20 */ "reserved", +/*21 */ "reserved", +/*22 */ "reserved", +/*23 */ "reserved", +/*24 */ "reserved", +/*25 */ "reserved", +/*26 0x05*/ "Chassis Intrusion", +/*27 0x0f*/ "POST Code Error", +/*28 0x02*/ "Voltage Failure", +/*29 0x04*/ "Fan Failure", +/*30 0x01*/ "Temperature Failure"}; + +#define NLAN 39 +static struct { + int cmd; + int sz; + char desc[28]; +} lanparams[NLAN] = { /* see IPMI Table 19-4 */ + /* 0 */ { 0, 1, "Set in progress"}, + /* 1 */ { 1, 1, "Auth type support"}, + /* 2 */ { 2, 5, "Auth type enables"}, + /* 3 */ { 3, 4, "IP address"}, + /* 4 */ { 4, 1, "IP addr src"}, /* (DHCP/Static) */ + /* 5 */ { 5, 6, "MAC addr"}, + /* 6 */ { 6, 4, "Subnet mask"}, + /* 7 */ { 7, 3, "IPv4 header"}, + /* 8 */ { 8, 2, "Prim RMCP port"}, + /* 9 */ { 9, 2, "Sec RMCP port"}, + /* 10 */ {10, 1, "BMC grat ARP"}, + /* 11 */ {11, 1, "grat ARP interval"}, + /* 12 */ {12, 4, "Def gateway IP"}, + /* 13 */ {13, 6, "Def gateway MAC"}, + /* 14 */ {14, 4, "Sec gateway IP"}, + /* 15 */ {15, 6, "Sec gateway MAC"}, + /* 16 */ {16,18, "Community string"}, + /* 17 */ {17, 1, "Num dest"}, + /* 18 */ {18, 5, "Dest type"}, + /* 19 */ {19, 13, "Dest address"}, + /* 20 */ {20, 2, "VLAN ID"}, + /* 21 */ {21, 1, "VLAN Priority"}, + /* 22 */ {22, 1, "Cipher Suite Support"}, + /* 23 */ {23,17, "Cipher Suites"}, + /* 24 */ {24, 9, "Cipher Suite Privilege"}, + /* 25 */ {25, 4, "VLAN Dest Tag"}, + /* 26 */ {96, 28, "OEM Alert String"}, + /* 27 */ {97, 1, "Alert Retry Algorithm"}, + /* 28 */ {98, 3, "UTC Offset"}, + /* 29 */ {102, 1, "IPv6 Enable"}, + /* 30 */ {103, 1, "IPv6 Addr Source"}, + /* 31 */ {104,16, "IPv6 Address"}, + /* 32 */ {105, 1, "IPv6 Prefix Len"}, + /* 33 */ {106,16, "IPv6 Default Gateway"}, + /* 34 */ {108,17, "IPv6 Dest address"}, + /* 35 */ {192, 4, "DHCP Server IP"}, + /* 36 */ {193, 6, "DHCP MAC Address"}, + /* 37 */ {194, 1, "DHCP Enable"}, + /* 38 */ {201, 2, "Channel Access Mode(Lan)"} +}; + +#define NSER 22 /* max=32 */ +static struct { + int cmd; + int sz; + char desc[28]; +} serparams[NSER] = { /* see IPMI Table 20-4 */ + /* 0 */ { 0, 1, "Set in progress"}, + /* 1 */ { 1, 1, "Auth type support"}, + /* 2 */ { 2, 5, "Auth type enables"}, + /* 3 */ { 3, 1, "Connection Mode"}, + /* 4 */ { 4, 1, "Sess Inactiv Timeout"}, + /* 5 */ { 5, 5, "Channel Callback"}, + /* 6 */ { 6, 1, "Session Termination"}, + /* 7 */ { 7, 2, "IPMI Msg Comm"}, + /* 8 */ { 8, 2, "Mux Switch"}, + /* 9 */ { 9, 2, "Modem Ring Time"}, + /* 10 */ {10,17, "Modem Init String"}, + /* 11 */ {11, 5, "Modem Escape Seq"}, + /* 12 */ {12, 8, "Modem Hangup Seq"}, + /* 13 */ {13, 8, "Modem Dial Command"}, + /* 14 */ {14, 1, "Page Blackout Interval"}, + /* 15 */ {15,18, "Community String"}, + /* 16 */ {16, 1, "Num of Alert Dest"}, + /* 17 */ {17, 5, "Destination Info"}, + /* 18 */ {18, 1, "Call Retry Interval"}, + /* 19 */ {19, 3, "Destination Comm Settings"}, + /* 20 */ {29, 2, "Terminal Mode Config"}, + /* 21 */ {201, 2,"Channel Access Mode (Ser)"} +}; + +#define NSYS 6 /* num SystemParam */ +#define CHAS_RESTORE 0x00 /*chassis power restore policy*/ +#define SYS_INFO 0x01 /*System Info (1,2,3,4) */ +#define LAN_FAILOVER 0x02 /*Intel LAN Failover*/ +/* TODO: Future DCMI 1.5 params */ +#define DCMI_POWER 0x03 /*DCMI Power limit*/ +#define DCMI_THERMAL 0x04 /*DCMI Thermal params*/ +#define DCMI_CONFIG 0x05 /*DCMI Config params*/ + +static int GetDeviceID(uchar *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (pLanRecord == NULL) return(-1); + + status = ipmi_cmd(GET_DEVICE_ID, inputData, 0, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("GetDeviceID: completion code=%x\n", + completionCode); + status = completionCode; + } else { + memcpy(pLanRecord,&responseData[0],responseLength); + set_mfgid(&responseData[0],responseLength); + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*end GetDeviceID() */ + +static int GetChanAcc(uchar chan, uchar parm, uchar *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (pLanRecord == NULL) return(-1); + responseLength = 3; + inputData[0] = chan; + inputData[1] = parm; /* 0x80 = active, 0x40 = non-volatile */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_CHANNEL_ACC, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("%c GetChanAcc: completion code=%x\n", + bcomment,completionCode); + status = completionCode; + } else { + // dont copy first byte (Parameter revision, usu 0x11) + memcpy(pLanRecord,&responseData[0],responseLength); + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*GetChanAcc()*/ + +static int SetChanAcc(uchar chan, uchar parm, uchar val, uchar access) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (fmBMC) return(0); /* mBMC doesn't support this */ + /* parm: 0x80 = active, 0x40 = set non-vol*/ + responseLength = 1; + inputData[0] = chan; /* channel */ + inputData[1] = (parm & 0xc0) | (val & 0x3F); + inputData[2] = (parm & 0xc0) | access; /* set priv level */ + + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_CHANNEL_ACC, inputData, 3, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("SetChanAcc: completion code=%x\n", + completionCode); + status = completionCode; + } else { + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*SetChanAcc()*/ + +static int GetUser(int user_num) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status, i; + uchar completionCode; + char inputData[24]; + + inputData[0] = lan_ch; + inputData[1] = (uchar)user_num; /* usually = 1 for BMC LAN */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_USER_ACCESS, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + if (status == 0 && completionCode == 0) { + uchar c; + if (user_num == 1) { + max_users = responseData[0] & 0x3f; + enabled_users = responseData[1] & 0x3f; + if (enabled_users > nusers) nusers = enabled_users; + } + fprintf(fd_bmc,"UserAccess %d,%d%c %02x %02x %02x %02x \n", + lan_ch,user_num,bdelim,responseData[0],responseData[1], + responseData[2], responseData[3]); + c = responseData[3]; + inputData[0] = (uchar)user_num; /* usually = 1 for BMC LAN */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_USER_NAME, inputData, 1, responseData, + &responseLength, &completionCode, fdebug); + if (status != 0 || completionCode != 0) + responseData[0] = 0; + else { + fprintf(fd_bmc,"UserName %d%c",user_num,bdelim); + for (i=0; i< responseLength; i++) + fprintf(fd_bmc," %02x",responseData[i]); + fprintf(fd_bmc,"\n"); + fprintf(fd_bmc,"%c UserPassword %d%c",bcomment,user_num,bdelim); + for (i=0; i< PSW_LEN; i++) + fprintf(fd_bmc," 00"); + fprintf(fd_bmc,"\n"); + } + } else + printf("%c GetUserAccess(%d,%d), status=%x, ccode=%x\n", + bcomment,lan_ch,user_num, status, completionCode); + return(status); +} /*end GetUser()*/ + +static int GetSerEntry(uchar subfunc, uchar bset, uchar *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + uchar chan; + + if (pLanRecord == NULL) + { + if (fdebug) + printf("GetSerEntry(%d): error, output buffer is NULL\n",subfunc); + return (-1); + } + + chan = ser_ch; /* 1=EMP, 0=IPMB, 6=LAN2, 7=LAN1 */ + + inputData[0] = chan; // flags, channel 3:0 (1=EMP) + inputData[1] = subfunc; // Param selector + inputData[2] = bset; // Set selector + inputData[3] = 0; // Block selector + if (subfunc == 10) { + inputData[2] = 0; + inputData[3] = 1; + } + + status = ipmi_cmd(GET_SER_CONFIG, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetSerEntry(%d,%d): completion code=%x\n", + chan,subfunc,completionCode); + status = completionCode; + } else { + // dont copy first byte (Parameter revision, usu 0x11) + memcpy(pLanRecord,&responseData[1],responseLength-1); + pLanRecord[responseLength-1] = 0; + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetSerEntry(%d,%d): ipmi_cmd status=%x ccode=%x\n", + chan,subfunc,status,completionCode); + return status; +} + +static int SetSerEntry(uchar subfunc, uchar *pSerRecord, int reqlen) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + + if (pSerRecord == NULL) { + if (fdebug) + printf("SetSerEntry(%d): error, input buffer is NULL\n", + subfunc); + return (-1); + } + inputData[0] = ser_ch; // flags, channel 3:0 (EMP) + inputData[1] = subfunc; // Param selector + memcpy(&inputData[2],pSerRecord,reqlen); + status = ipmi_cmd(SET_SER_CONFIG, inputData, (uchar)(reqlen+2), + responseData, &responseLength, &completionCode, fdebug); + + if (fdebug) + printf("SetSerEntry: ipmi_cmd status=%d, completion code=%d\n", + status,completionCode); + if (status == ACCESS_OK) { + if( completionCode ) { + status = completionCode; + if (completionCode == 0x80) + printf("SetSerEntry(%d): Parameter not supported\n", + subfunc); + else + printf("SetSerEntry(%d): completion code=%x\n", + subfunc, completionCode); + } + // else successful, done + } + return status; +} /* end SetSerEntry() */ + +static int GetLanEntry(uchar subfunc, uchar bset, uchar *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status, n; + uchar completionCode; + uchar chan; + + if (pLanRecord == NULL) { + if (fdebug) printf("GetLanEntry: error, output buffer is NULL\n"); + return (-1); + } + + chan = lan_ch; /* LAN 1 = 7 */ + + inputData[0] = chan; // flags, channel 3:0 (LAN 1) + inputData[1] = subfunc; // Param selector (3 = ip addr) + inputData[2] = bset; // Set selector + inputData[3] = 0; // Block selector + + status = ipmi_cmd(GET_LAN_CONFIG, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetLanEntry(%d,%d): completion code=%x\n", + chan,subfunc,completionCode); + status = completionCode; + } else { + // dont copy first byte (Parameter revision, usu 0x11) + if (responseLength > 0) { + n = responseLength-1; + memcpy(pLanRecord,&responseData[1],n); + } else n = 0; + pLanRecord[n] = 0; + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetLanEntry(%d,%d): status=%d completionCode=%x\n", + chan,subfunc,status,completionCode); + return (status); +} /* end GetLanEntry() */ + +static int SetLanEntry(uchar subfunc, uchar *pLanRecord, int reqlen) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + + if (pLanRecord == NULL) + { + if (fdebug) + printf("SetLanEntry(%d): error, input buffer is NULL\n",subfunc); + return (-1); + } + + if ((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) { + /* SUPERMICRO cannot set grat arp or grat arp interval */ + if (subfunc == 10 || subfunc == 11) return(0); + } + inputData[0] = lan_ch; // flags, channel 3:0 (LAN 1) + inputData[1] = subfunc; // Param selector (3 = ip addr) + memcpy(&inputData[2],pLanRecord,reqlen); + + status = ipmi_cmd(SET_LAN_CONFIG, inputData, (uchar)(reqlen+2), + responseData, &responseLength,&completionCode,fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("SetLanEntry(%d,%d): completion code=%x\n", + lan_ch,subfunc,completionCode); + return(completionCode); + } else { + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("SetLanEntry(%d,%d): ipmi_cmd status=%d ccode=%x\n", + lan_ch,subfunc,status,completionCode); + return (status); +} /* end SetLanEntry() */ + +static int GetPefEntry(uchar subfunc, ushort rec_id, PEF_RECORD *pPefRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status, n; + uchar completionCode; + + if (pPefRecord == NULL) + { + if (fdebug) + printf("GetPefEntry(%d): error, output buffer is NULL\n",subfunc); + return (-1); + } + + inputData[0] = subfunc; // Parameter = Evt Filter Table + inputData[1] = (uchar)rec_id; + inputData[2] = 0; + + status = ipmi_cmd(GET_PEF_CONFIG, inputData, 3, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetPefEntry(%d/%d): completion code=%x\n", + subfunc,rec_id,completionCode); + status = completionCode; + } else { + /* expect PEF record to be >=21 bytes */ + if (responseLength > 1) n = responseLength-1; + else n = 0; + if (n > 21) n = 21; + // dont copy first byte (Parameter revision, usu 0x11) + if (n == 0) memset(pPefRecord,0,21); + else memcpy(pPefRecord,&responseData[1],n); + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetPefEntry: ipmi_cmd status=%x completionCode=%x\n", + status, completionCode); + return status; +} /* end GetPefEntry() */ + +static int SetPefEntry(PEF_RECORD *pPefRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; /* sizeof(PEF_RECORD) = 21 +1=22 */ + int status; + uchar completionCode; + uchar subfunc; + + subfunc = 0x06; // Parameter = Evt Filter Table + + if (pPefRecord == NULL) { + if (fdebug) + printf("SetPefEntry: error, output buffer is NULL\n"); + return (-1); + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + // 06 0c 80 01 01 00 ff ff 20 ff 6f ff 00 00 00 00 00 00 00 00 00 00 + // memset(&inputData[0],0,requestData.dataLength); + inputData[0] = subfunc; + memcpy(&inputData[1],pPefRecord,sizeof(PEF_RECORD)); + + status = ipmi_cmd(SET_PEF_CONFIG, inputData, sizeof(PEF_RECORD)+1, + responseData, &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("SetPefEntry: completion code=%x\n", + completionCode); // responseData[0]); + status = completionCode; + } else { + //successful, done + return(0); + } + + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("SetPefEntry: ipmi_cmd status=%d ccode=%x\n", + status,completionCode); + return(status); + +} /* end SetPefEntry() */ + +static int MacIsValid(uchar *mac) +{ + int fvalid = 0; + int i; + /* check for initial invalid value of FF:00:... */ + if (mac[0] == 0xFF && mac[1] == 0x00) /* marked as invalid */ + return(fvalid); + /* check for all zeros */ + for (i = 0; i < MAC_LEN; i++) + if (mac[i] != 0) { /* not all zeros */ + fvalid = 1; + break; + } + return(fvalid); +} + +static int IpIsValid(uchar *ipadr) +{ + int fvalid = 1; + if (ipadr[0] == 0) fvalid = 0; + return(fvalid); +} + +static int SubnetIsValid(uchar *subnet) +{ + int fvalid = 0; + /* if masking off at least one bit, say valid */ + if ((subnet[0] & 0x80) == 0x80) fvalid = 1; + return(fvalid); +} + +#ifdef WIN32 +/* + * Obtain network adapter information (Windows). + */ +static PIP_ADAPTER_ADDRESSES GetAdapters() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + ULONG OutBufferLength = 0; + ULONG RetVal = 0, i; + + // The size of the buffer can be different + // between consecutive API calls. + // In most cases, i < 2 is sufficient; + // One call to get the size and one call to get the actual parameters. + // But if one more interface is added or addresses are added, + // the call again fails with BUFFER_OVERFLOW. + // So the number is picked slightly greater than 2. + // We use i <5 in the example + for (i = 0; i < 5; i++) { + RetVal = GetAdaptersAddresses( + AF_INET, 0, NULL, + AdapterAddresses, + &OutBufferLength); + + if (RetVal != ERROR_BUFFER_OVERFLOW) { + break; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + + AdapterAddresses = (PIP_ADAPTER_ADDRESSES) malloc(OutBufferLength); + if (AdapterAddresses == NULL) { + RetVal = GetLastError(); + break; + } + } + if (RetVal == NO_ERROR) { + // If successful, return pointer to structure + return AdapterAddresses; + } + else { + LPVOID MsgBuf; + + printf("Call to GetAdaptersAddresses failed.\n"); + if (FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + RetVal, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &MsgBuf, + 0, + NULL )) { + printf("\tError: %s", MsgBuf); + } + LocalFree(MsgBuf); + } + return NULL; +} + +/* + * Set BMC MAC corresponding to current BMC IP address (Windows). + */ +static int GetLocalMACByIP() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + addr = AdapterList->FirstUnicastAddress; + if (addr == NULL) si = NULL; + else si = (struct sockaddr_in*)addr->Address.lpSockaddr; + if (si != NULL) { + if(memcmp(&si->sin_addr.s_addr, rgmyip, 4) == 0) { + memcpy(rgmymac, AdapterList->PhysicalAddress, MAC_LEN); + result = 1; + break; + } + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +/* + * Set BMC MAC corresponding to current BMC IP address (Windows). + */ +static int GetLocalIPByMAC(uchar *macadr) { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + if(memcmp(AdapterList->PhysicalAddress, macadr, MAC_LEN) == 0) { + addr = AdapterList->FirstUnicastAddress; + + si = (struct sockaddr_in*)addr->Address.lpSockaddr; + if (fdebug) { + uchar *psaddr; + psaddr = (uchar *)&si->sin_addr.s_addr; + printf("mac match: rgmyip=%d.%d.%d.%d s_addr=%d.%d.%d.%d\n", + rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3], + psaddr[0], psaddr[1], psaddr[2], psaddr[3]); + } + if (!IpIsValid(rgmyip) && (fsharedMAC==1)) /*not specified, shared*/ + memcpy(rgmyip, &si->sin_addr.s_addr, 4); + memcpy(osmyip, &si->sin_addr.s_addr, 4); + memcpy(osmymac, AdapterList->PhysicalAddress, MAC_LEN); + wcstombs(ifname,AdapterList->FriendlyName, sizeof(ifname)); + result = 1; + break; + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +/* + * Set MAC and IP address from given interface name (Windows). + */ +static int GetLocalDataByIface() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + size_t origsize, newsize, convertedChars; + wchar_t* wcstring; + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + origsize = strlen(ifname) + 1; + newsize = origsize; + convertedChars = 0; + wcstring = (wchar_t*) malloc(sizeof(wchar_t) * newsize) ; + if (wcstring == NULL) AdapterList = NULL; /*skip loop, do free*/ + else mbstowcs(wcstring, ifname, origsize ); + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + if(wcsstr(AdapterList->FriendlyName, wcstring)) { + printf("Using interface: %S\n", AdapterList->FriendlyName); + printf("\t%S\n", AdapterList->Description); + addr = AdapterList->FirstUnicastAddress; + + si = (struct sockaddr_in*)addr->Address.lpSockaddr; + memcpy(rgmyip, &si->sin_addr.s_addr, 4); + memcpy(rgmymac, AdapterList->PhysicalAddress, MAC_LEN); + + result = 1; + break; + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +static int FindEthNum(uchar *macadrin) +{ + int i; + uchar macadr[MAC_LEN]; + memcpy(macadr,macadrin,MAC_LEN); + if (fsharedMAC == 0 && vend_id == VENDOR_INTEL) { + /* Intel factory assigns them this way, so use that to compare */ + macadr[MAC_LEN-1] -= 2; /*OS MAC = BMC MAC - 2*/ + } + i = GetLocalIPByMAC(macadr); + if (fdebug) /* show the local OS eth if and MAC */ + printf("FindEth: OS %s IP=%d.%d.%d.%d MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + ifname, rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3], + rgmymac[0], rgmymac[1], rgmymac[2], rgmymac[3], + rgmymac[4], rgmymac[5]); + /* The actual Windows ethernet interface is determined + * in Get_IPMac_Addr using ipconfig, so + * init eth interface number as eth0 for Windows. */ + return(i); +} +#elif defined(HPUX) +static int FindEthNum(uchar *macadrin) +{ + return(0); +} +#else +/* Linux, BSD, Solaris */ +static char *get_ifreq_mac(struct ifreq *ifrq) +{ + char *ptr; +#ifdef SOLARIS + ptr = (char *)&ifrq->ifr_ifru.ifru_enaddr[0]; +#elif BSD + ptr = (char *)&ifrq->ifr_ifru.ifru_addr.sa_data[0]; +#elif MACOS + static uchar mactmp[MAC_LEN]; + ptr = &mactmp[0]; + MacSetInvalid(ptr); +#else + ptr = (char *)&ifrq->ifr_hwaddr.sa_data[0]; +#endif + return (ptr); +} + + +static int FindEthNum(uchar *macadrin) +{ /*only used for Linux*/ + struct ifreq ifr; + int skfd; + int nCurDevice; + uchar macadr[MAC_LEN]; + char szDeviceName[ 16 ]; /* sizeof(ifpattn), MAX_DEVICE_NAME_LENGTH + 1 */ + int devnum = -1; + int n; + + memcpy(macadr,macadrin,MAC_LEN); + if (fsharedMAC == 0 && vend_id == VENDOR_INTEL) { + /* Intel factory assigns them this way, so use that to compare */ + macadr[MAC_LEN-1] -= 2; /*OS MAC = BMC MAC - 2*/ + } + n = find_ifname(szDeviceName); + if (n >= 0) { + n = strlen_(szDeviceName); + if (n < sizeof(ifpattn)) { + strcpy(ifname0,szDeviceName); + strcpy(ifpattn,szDeviceName); + ifpattn[n - 1] = 0; /*truncate last digit*/ + } + if (fdebug) + printf("found ifname %s, pattern %s\n",szDeviceName,ifpattn); + } + + if ( ( skfd = socket(AF_INET, SOCK_DGRAM, 0 ) ) < 0) { + if ( fdebug ) { + perror("socket"); + return devnum; + } + } + + for( nCurDevice = 0 ; + (nCurDevice < NUM_DEVICES_TO_CHECK) && (devnum == -1); + nCurDevice++ ) + { + sprintf( szDeviceName, "%s%d", ifpattn, nCurDevice ); + strcpy(ifr.ifr_name, szDeviceName ); +#ifdef SIOCGIFHWADDR + if (ioctl(skfd, SIOCGIFHWADDR, &ifr) > 0) { + if ( fdebug ) + printf("FindEthNum: Could not get MAC address for %s\n", + szDeviceName); + } else +#endif + { + if (memcmp(get_ifreq_mac(&ifr), macadr, MAC_LEN) == 0) { + devnum = nCurDevice; + break; + } + } + } + close(skfd); + return(devnum); +} +#endif + +/* + * GetBmcEthDevice + * Attempt to auto-detect the BMC LAN channel and matching OS eth port. + * INPUT: lan_parm = lan channel from user -L option, 0xFF if not specified + * OUTPUT: lan_ch is set to BMC LAN channel number + * if success, returns index of OS eth port (0, 1, ...). + * if no lan channels found, returns -2. + * if other error, returns -1. + */ +static int GetBmcEthDevice(uchar lan_parm) +{ + uchar LanRecord[30]; + int devnum = -1; + int ret; + uchar bmcMacAddress[ MAC_LEN ]; /*MAC_LEN = 6*/ + int rlen; + uchar iData[2]; + uchar rData[10]; + uchar cc; + int i = 0; + int j, jstart, jend, jlan; + uchar mtype; + uchar *pb; + int fchgmac; + + /* Find the LAN channel(s) via Channel Info */ + if (lan_parm < MAXCHAN) { /* try user-specified channel only */ + lan_ch = lan_parm; + jstart = lan_parm; + jend = lan_parm+1; + } else { + jstart = 1; + jend = MAXCHAN; + for (j = 0; j < MAXCHAN; j++) chan_type[j] = 0; + } + memset(bmcMacAddress,0xff,sizeof(bmcMacAddress)); /*initialize to invalid*/ + for (j = jstart; j < jend; j++) { + rlen = sizeof(rData); + iData[0] = (uchar)j; /*channel #*/ + memset(rData,0,9); /*initialize recv data*/ + ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, fdebug); + if (ret == 0xcc || cc == 0xcc) /* special case for ipmi_lan */ + continue; + if (ret != 0) { + if (fdebug) printf("get_chan_info rc = %x\n",ret); + break; + } + mtype = rData[1]; /* channel medium type */ + chan_type[j] = mtype; + if (mtype == 4) { /* 802.3 LAN type*/ + if (fdebug) printf("chan[%d] = lan\n",j); + jlan = lan_ch; /*save prev lan chan */ + /* Get BMC MAC for this LAN channel. */ + /* Note: BMC MAC may not be valid yet. */ + lan_ch = (uchar)j; /*set lan channel for GetLanEntry()*/ + ret = GetLanEntry( 5 /*MAC_ADDRESS_LAN_PARAM*/,0, LanRecord); + if ( ret < 0 ) { + lan_ch = (uchar)jlan; /*restore lan_ch*/ + printf( "GetBmcEthDevice: GetLanEntry failed\n" ); + return devnum; + } + pb = &LanRecord[0]; + if (fdebug) printf("chan[%d] BMC MAC %x:%x:%x:%x:%x:%x\n",j, + pb[0], pb[1], pb[2], pb[3], pb[4], pb[5] ); + fchgmac = 0; + if (!MacIsValid(bmcMacAddress)) /* old MAC not valid */ + fchgmac = 1; + else if (MacIsValid(pb) && /* new MAC is valid and */ + (memcmp(bmcMacAddress,pb, sizeof(bmcMacAddress)) > 0)) + fchgmac = 1; /* new MAC lower */ + if (fchgmac) { /* use lowest valid MAC */ + memcpy(bmcMacAddress,pb,sizeof(bmcMacAddress)); + lan_ch = (uchar)j; + } else lan_ch = (uchar)jlan; /* restore prev lan chan */ + i++; /* i = num lan channels found */ + } else if (mtype == 5) { /* serial type*/ + if (fdebug) printf("chan[%d] = serial\n",j); + ser_ch = (uchar)j; /* set to last serial channel */ + } else if (mtype == 7) { /* PCI SMBus */ + if (fdebug) printf("chan[%d] = pci_smbus\n",j); + } else if (mtype == 12) { /* system interface */ + if (fdebug) printf("chan[%d] = system_interface\n",j); + } else /* other channel medium types, see IPMI 1.5 Table 6-3 */ + if (fdebug) printf("chan[%d] = %d\n",j,mtype); + } + nlans = i; + if (i == 0) return(-2); /* no lan channels found */ + if (fdebug) printf("lan_ch detected = %d\n",lan_ch); + + devnum = FindEthNum(bmcMacAddress); + if ( fdebug ) + printf("GetBmcEthDevice: channel %d, %s%d\n",lan_ch,ifpattn,devnum); + return devnum; +} + +/* + * atomac - converts ASCII string to binary MAC address (array). + * Accepts input formatted as 11:22:33:44:55:66 or 11-22-33-44-55-66. + */ +static void atomac(uchar *array, char *instr) +{ + int i,j,n; + char *pi; + j = 0; + pi = instr; + n = strlen_(instr); + for (i = 0; i <= n; i++) { + if (instr[i] == ':') { + array[j++] = htoi(pi); + pi = &instr[i+1]; + } else if (instr[i] == '-') { + array[j++] = htoi(pi); + pi = &instr[i+1]; + } else if (instr[i] == 0) { + array[j++] = htoi(pi); + } + if (j >= MAC_LEN) break; /*safety valve*/ + } + if (fdebug) + printf("atomac: %02x %02x %02x %02x %02x %02x\n", + array[0],array[1],array[2],array[3], array[4],array[5]); +} /*end atomac()*/ + +/* file_grep/findmatch no longer used here, see ievents.c */ + +/* + * Get_Mac + * This routine finds a MAC address from a given IP address. + * Usually for the Alert destination. + * It uses ARP cache to do this. + */ +#ifdef WIN32 +static int Get_Mac(uchar *ipadr,uchar *macadr) +{ + DWORD dwRetVal; + IPAddr DestIp = 0; + IPAddr SrcIp = 0; /* default for src ip */ + ULONG MacAddr[2]; /* for 6-byte hardware addresses */ + ULONG PhysAddrLen = MAC_LEN; /* default to length of six bytes */ + BYTE *bPhysAddr; + + + memcpy(&DestIp, ipadr, 4); + + /* invoke system ARP query */ + dwRetVal = SendARP(DestIp, SrcIp, MacAddr, &PhysAddrLen); + + if (dwRetVal == NO_ERROR) + { /* no error - get the MAC */ + bPhysAddr = (BYTE *) & MacAddr; + if (PhysAddrLen) { + memcpy(macadr, bPhysAddr, MAC_LEN); + } else + printf("Warning: SendArp completed successfully, but returned length=0\n"); + } else if (dwRetVal == ERROR_GEN_FAILURE) + { /* MAC not available in this netowork - get gateway MAC */ + memcpy(macadr, rggwymac, MAC_LEN); + } else + { /* other errors */ + printf("Error: SendArp failed with error: %d", dwRetVal); + switch (dwRetVal) { + case ERROR_INVALID_PARAMETER: + printf(" (ERROR_INVALID_PARAMETER)\n"); + break; + case ERROR_INVALID_USER_BUFFER: + printf(" (ERROR_INVALID_USER_BUFFER)\n"); + break; + case ERROR_BAD_NET_NAME: + printf(" (ERROR_GEN_FAILURE)\n"); + break; + case ERROR_BUFFER_OVERFLOW: + printf(" (ERROR_BUFFER_OVERFLOW)\n"); + break; + case ERROR_NOT_FOUND: + printf(" (ERROR_NOT_FOUND)\n"); + break; + default: + printf("\n"); + break; + } + return 1; + } + return 0; +} /* end Get_Mac()*/ +/*endif WIN32 */ +#else +/*else Linux */ +static int Get_Mac(uchar *ipadr,uchar *macadr) +{ + FILE *fparp; + char buff[1024]; + /* char arpfile[] = "/proc/net/arp"; */ + char alertfile[] = "/tmp/dest.arping"; + char arping_cmd[128]; + char *pb, *pm, *px; + int num, i; + int foundit = 0; + int ret = 0; + char *_ifname; + + if (strcmp(ifname,"gcm") == 0) _ifname = ifname0; + else _ifname = ifname; + + /* Get a MAC address for a given IP address */ + if (ipadr[0] != 0) { /* if valid IP address */ + + /* make sure the destination is in the arp cache */ + sprintf(arping_cmd, + "arping -I %s -c 2 %d.%d.%d.%d |grep reply |tail -n1 >%s\n", + _ifname,ipadr[0],ipadr[1],ipadr[2],ipadr[3],alertfile); + if (fdebug) printf("%s", arping_cmd); + system(arping_cmd); + + fparp = fopen(alertfile,"r"); + if (fparp == NULL) { + fprintf(stdout,"Get_Mac: Cannot open %s, errno = %d\n", + alertfile,get_errno()); + ret = -1; + } else { + while (fgets(buff, 1023, fparp)) { + /* should only run through loop once */ + num = strcspn(buff," \t"); /* skip 1st word ("Unicast") */ + i = strspn(&buff[num]," \t"); + pb = &buff[num+i]; + if (strncmp(pb,"reply",5) == 0) { /* valid output */ + /* Find the ip address */ + pb += 6 + 5; /* skip "reply from " */ + num = strcspn(pb," \t"); + pb[num] = 0; + if (fdebug) printf("Alert ip=%s\n",pb); + /* IP address should already match input param */ + /* if (rgdestip[0] == 0) atoip(rgdestip,pb); */ + /* Now find the mac address */ + pm = strchr(&pb[num+1],'['); + if (pm == NULL) pm = &pb[num+2]; /* just in case */ + pm++; + px = strchr(pm,']'); + if (px == NULL) px = pm + 17; /* just in case */ + px[0] = 0; + if (fdebug) printf("Alert mac=%s\n",pm); + foundit = 1; + if (!MacIsValid(macadr)) atomac(macadr,pm); + break; + } + } /*end while*/ + fclose(fparp); + } /*end else file opened*/ + } /*endif valid IP */ + else ret = -1; + + if (ret == -1 || foundit == 0) { /* couldn't get it */ + if (MacIsValid(rggwymac) && !MacIsValid(rgdestmac)) + memcpy(rgdestmac,rggwymac,6); /* get to it from the default gateway */ + } + return(ret); +} /* end Get_Mac()*/ +/*end else Linux*/ +#endif + +#ifdef WIN32 + +/* + * Set subnet mask based on current IP address (Windows). + */ +static int SetSubnetMask() { + PMIB_IPADDRTABLE pIPAddrTable; + unsigned int i; + DWORD dwSize = 0, dwRetVal; + LPVOID lpMsgBuf; + + pIPAddrTable = (MIB_IPADDRTABLE*) malloc( sizeof( MIB_IPADDRTABLE) ); + + if ( pIPAddrTable ) { + // Make an initial call to GetIpAddrTable to get the + // necessary size into the dwSize variable + if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free( pIPAddrTable ); + pIPAddrTable = (MIB_IPADDRTABLE *) malloc ( dwSize ); + } + } else + printf("Memory allocation failed.\n"); + + if ( pIPAddrTable ) { + // Make a second call to GetIpAddrTable to get the + // actual data we want + if ( (dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 )) == NO_ERROR ) { + for(i = 0; i < pIPAddrTable->dwNumEntries; ++i) { + if(memcmp(&(pIPAddrTable->table[i].dwAddr), rgmyip, 4) == 0) { + memcpy(rgsubnet, &(pIPAddrTable->table[i].dwMask), 4); + free( pIPAddrTable ); + return 1; + } + } + } else { + if (FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dwRetVal, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL )) { + printf("\tError: %s", lpMsgBuf); + } + + printf("Call to GetIpAddrTable failed.\n"); + } + } + + if ( pIPAddrTable ) + free( pIPAddrTable ); + + return 0; +} + +/* + * Extract gateway address from routing table (Windows). + */ +static int SetDefaultGateway() { + PMIB_IPFORWARDTABLE pIpForwardTable; + DWORD dwRetVal, dwSize; + + unsigned int nord_mask; + unsigned int nord_ip; + unsigned int nord_net; + + unsigned int i; + + nord_mask = *((unsigned int *)rgsubnet); + nord_ip = *((unsigned int *)rgmyip); + + nord_net = nord_ip & nord_mask; + + pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(sizeof(MIB_IPFORWARDTABLE)); + if (pIpForwardTable == NULL) { + printf("Error allocating memory\n"); + return 0; + } + + dwSize = 0; + if (GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free(pIpForwardTable); + pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(dwSize); + if (pIpForwardTable == NULL) { + printf("Error allocating memory\n"); + return 0; + } + } + + /* + * Note that the IPv4 addresses returned in + * GetIpForwardTable entries are in network byte order + */ + if ((dwRetVal = GetIpForwardTable(pIpForwardTable, &dwSize, 0)) == NO_ERROR) { + for (i = 0; i < (int) pIpForwardTable->dwNumEntries; i++) { + unsigned int gwaddr = pIpForwardTable->table[i].dwForwardNextHop; + if(nord_net == (gwaddr & nord_mask) && nord_ip != gwaddr) + { /* searching for gateways from our network with different address than ours */ + memcpy(rggwyip, &gwaddr, 4); + return 0; + } + } + free(pIpForwardTable); + return 1; + } + else { + printf("\tGetIpForwardTable failed.\n"); + free(pIpForwardTable); + return 0; + } + +} +/*endif WIN32*/ +#endif + +static int ShowChanAcc(uchar bchan) +{ + uchar LanRecord[30]; + int ret = 0; + + ret = GetChanAcc(bchan, 0x40, LanRecord); + if (fdebug) + printf(" GetChanAcc(%d) ret = %d, data = %02x %02x\n", + bchan,ret, LanRecord[0], LanRecord[1]); + if (ret == 0) + fprintf(fd_bmc,"ChannelAccess %d%c %02x %02x \n", + bchan,bdelim,LanRecord[0],LanRecord[1]); + return(ret); +} + +static int GetSerialOverLan( uchar chan, uchar bset, uchar block ) +{ + uchar requestData[24]; + uchar rData[MAX_BUFFER_SIZE]; + int rlen; + int status, i; + uchar ccode; + uchar enable_parm, auth_parm, baud_parm; + uchar user; + + if (fIPMI20 && fSOL20) { + getsolcmd = GET_SOL_CONFIG2; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + } else { + getsolcmd = GET_SOL_CONFIG; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + chan = 0; /*override chan for IPMI 1.5*/ + } + printf("%c## %s, GetSOL for channel %d ...\n",bcomment,progname,chan); + + requestData[0] = chan; /*channel*/ + requestData[1] = enable_parm; + requestData[2] = bset; /*set*/ + requestData[3] = block; /*block*/ + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd, requestData,4, rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + if (ccode == 0xC1) { /* unsupported command */ + printf("%c Serial-Over-Lan not available on this platform\n", + bcomment); + return(status); + } else { + printf("%c SOL Enable ccode = %x\n",bcomment,ccode); + status = ccode; + } + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,enable_parm,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + + requestData[0] = chan; + requestData[1] = auth_parm; + requestData[2] = bset; // selector + requestData[3] = block; // block + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd, requestData,4,rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("%c SOL Auth ccode = %x\n",bcomment,ccode); + status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,auth_parm,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + + requestData[0] = chan; + requestData[1] = SOL_ACC_INTERVAL_PARAM; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd, requestData,4,rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("%c SOL Accum Interval ccode = %x\n",bcomment,ccode); + status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,SOL_ACC_INTERVAL_PARAM,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + + requestData[0] = chan; + requestData[1] = SOL_RETRY_PARAM; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd, requestData,4,rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("%c SOL Retry ccode = %x\n",bcomment,ccode); + status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,SOL_RETRY_PARAM,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + + if (!fRomley) { + requestData[0] = chan; + requestData[1] = baud_parm; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("%c SOL nvol Baud ccode = %x\n",bcomment,ccode); + status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,baud_parm,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + + requestData[0] = chan; + requestData[1] = SOL_VOL_BAUD_RATE_PARAM; /*0x06*/ + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("%c SOL vol Baud ccode = %x\n",bcomment,ccode); + status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,SOL_VOL_BAUD_RATE_PARAM,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + } + + if (fIPMI20) { + requestData[0] = chan; + rlen = sizeof(rData); + status = ipmi_cmdraw(GET_PAYLOAD_SUPPORT, NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + requestData,1,rData, &rlen, &ccode, fdebug); + if ((status != 0) || (ccode != 0)) { + printf("%c SOL Payload Support(%d) error %d, ccode = %x\n", + bcomment,chan,status,ccode); + if (status == 0) status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLPayloadSupport %d%c",chan,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + /* get Payload Access for nusers, not just lan_user */ + for (user = 1; user <= nusers; user++) + { + /* IPMI 2.0 nusers >= 4 users */ + requestData[0] = chan; + requestData[1] = user; + rlen = sizeof(rData); + status = ipmi_cmdraw(GET_PAYLOAD_ACCESS, NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + requestData,2,rData, &rlen, &ccode, fdebug); + if ((status != 0) || (ccode != 0)) { + printf("%c SOL Payload Access(%d,%d) error %d, ccode = %x\n", + bcomment,chan,user,status,ccode); + if (status == 0) status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLPayloadAccess %d,%d%c",chan,user,bdelim); + for (i = 0; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + } /*end user loop*/ + } + + return(status); +} /*end GetSerialOverLan */ + +static char *PefDesc(int idx, uchar stype) +{ + char *pdesc; + if (pefdesc == NULL) pdesc = "reserved"; + else pdesc = pefdesc[idx]; + if ((stype != 0) && (strcmp(pdesc,"reserved") == 0)) { + /* pefdesc may not match on some non-Intel systems. */ + /* so use sensor type */ + switch(stype) { + case 0x01: pdesc = "Temperature"; break; + case 0x02: pdesc = "Voltage"; break; + case 0x04: pdesc = "Fan"; break; + case 0x05: pdesc = "Chassis"; break; + case 0x07: pdesc = "BIOS"; break; + case 0x08: pdesc = "Power Supply"; break; + case 0x09: pdesc = "Power Unit"; break; + case 0x0c: pdesc = "Memory"; break; + case 0x0f: pdesc = "Boot"; break; + case 0x12: pdesc = "System Restart"; break; + case 0x13: pdesc = "NMI"; break; + case 0x23: pdesc = "Watchdog"; break; + case 0x20: pdesc = "OS Critical Stop"; break; + default: pdesc = "Other"; break; + } + } + return(pdesc); +} + +static int GetSessionInfo(uchar *rData, int sz) +{ + int rv, rlen; + uchar ccode; + uchar iData[5]; + + iData[0] = 0x00; /*get data for this session*/ + rlen = sz; + rv = ipmi_cmdraw(CMD_GET_SESSION_INFO,NETFN_APP, BMC_SA,PUBLIC_BUS,BMC_LUN, + iData,1,rData, &rlen, &ccode, fdebug); + if ((rv == 0) && (ccode != 0)) rv = ccode; + return(rv); +} + +static int GetPefCapabilities(uchar *bmax) +{ + int rv, rlen; + uchar ccode; + uchar rData[MAX_BUFFER_SIZE]; + + rlen = sizeof(rData); + rv = ipmi_cmdraw(0x10, NETFN_SEVT, BMC_SA,PUBLIC_BUS,BMC_LUN, + NULL,0,rData, &rlen, &ccode, fdebug); + if ((rv == 0) && (ccode != 0)) rv = ccode; + if ((rv == 0) && (bmax != NULL)) + *bmax = rData[2]; /*max num PEF table entries*/ + return(rv); +} + +int WaitForSetComplete(int limit) +{ + int rv = 0; + int i; + uchar bdata[4]; + + for (i = 0; i < limit; i++) { + rv = GetLanEntry(0, 0, bdata); + if (fdebug) printf("WaitForSetComplete(%d): i=%d rv=%d val=%x\n", + limit,i,rv,bdata[1]); + if ((rv == 0) && (bdata[1] == 0)) break; + else os_usleep(0,100); + } + return(rv); +} + +int SerialIsOptional(int bparam) +{ + /* These Serial Parameters are for optional Modem/Callback functions. */ + int optvals[9] = { 5, 9, 10, 11, 12, 13, 14, 20, 21 }; + int rv = 0; + int i; + for (i = 0; i < sizeof(optvals); i++) { + if (optvals[i] == bparam) { rv = 1; break; } + } + return(rv); +} + +static int parse_line(char *line, char *keyret, char *value) +{ + char *eol; + char *key; + char *val; + int i, n; + + key = &line[0]; + eol = &line[strlen(line)]; + while( *key < 0x21 && key < eol ) + key++; /*remove leading whitespace */ + if( key[0] == bcomment ) return 2; /*skip comments */ + /* + * find the value set, delimited by bdelim (':' or '|') + */ + val = strchr( line, bdelim ); + if( val == NULL ) return 1; /* skip if empty or no delimeter */ + val[0] = 0; /*stringify the key*/ + val++; + while( val[0] < 0x21 && val < eol ) + val++; /*remove leading whitespace */ + /* + * truncate trailing newline/whitespace after last word + */ + n = strlen_( val ); + for( i = n; i >= 0; i-- ) /*decrease from end*/ + if( val[i] >= 0x21 ) break; /*found last valid char */ + if (i < n) val[i + 1] = 0; + + strcpy(keyret, key); /*has keyword and params*/ + strcpy(value, val); /*has list of hex values*/ + return 0; +} + +#ifdef METACOMMAND +int i_config(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret; + PEF_RECORD *pPefRecord; + PEF_RECORD PefRecord; + uchar LanRecord[64]; + uchar bParams[5]; + char filename[80] = ""; + int i, j, c, n; + uchar idx; + // char *pstr; + uchar bset = 0; + int ndest = 4; + int idest; + // char mystr[80]; + uchar * pc; int sz; + char line[240]; /* hdr(18) + data(192 = 64 * 3) + '\0' = 211 */ + char key[40]; + char value[100]; + uchar rData[50]; + int rlen; + uchar cc; + uchar chan; + char *pk; + char fpefok = 1; + char fignore_err; + + // progname = argv[0]; + printf("%s ver %s \n",progname,progver); + func = 'l'; freadonly = 1; /*list is default*/ + + while ((c = getopt(argc, argv,"cdmlr:s:xL:T:V:J:EYF:P:N:R:U:Z:?")) != EOF) + switch(c) { + case 'c': fcanonical = 1; bdelim = BDELIM; break; + case 'd': func = 'd'; freadonly = 0; break; /*set Defaults*/ + case 'l': func = 'l'; freadonly = 1; break; /*list*/ + case 'm': fdomac = 1; break; /*restore mac*/ + case 'r': func = 'r'; freadonly = 0; /*restore*/ + sz = strlen_(optarg); + if (sz > sizeof(filename)) sz = sizeof(filename); + strncpy(filename,optarg,sz); + break; + case 's': func = 's'; freadonly = 1; /*save*/ + sz = strlen_(optarg); + if (sz > sizeof(filename)) sz = sizeof(filename); + strncpy(filename,optarg,sz); + break; + case 'x': fdebug = 1; break; + case 'p': /* password to set */ + fpassword = 1; + if (strlen_(optarg) > 16) optarg[16] = 0; + strcpy(passwordData,optarg); + if (fdebug) printf("Password = %s\n",passwordData); + /* Hide password from 'ps' */ + memset(optarg, ' ', strlen_(optarg)); + break; + case 'L': + lan_ch_parm = atob(optarg); + if (lan_ch_parm >= MAXCHAN) lan_ch_parm = 0xff; /*invalid*/ + break; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-clmpxLNUPREFTJVY -r <file> -s <file>]\n", + progname); + printf("where -l Lists BMC configuration parameters\n"); + printf(" -r Restores BMC configuration from <file>\n"); + printf(" -s Saves BMC configuration to <file>\n"); + printf(" -c canonical output with delimiter '%c'\n",BDELIM); + printf(" -m Set BMC MAC during restore\n"); + printf(" -x show eXtra debug messages\n"); + printf(" -p <psw> specify a user password to set\n"); + printf(" -L 3 specify lan channel number 3\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + switch(func) { + case 'l': fd_bmc = stdout; break; + case 'r': fd_bmc = fopen(filename,"r"); break; + case 's': fd_bmc = fopen(filename,"w"); break; + default: break; + } + if (fd_bmc == NULL) { + printf("Error: cannot open %s\n",filename); + ret = ERR_FILE_OPEN; + fd_bmc = stdout; + goto do_exit; + } + fipmilan = is_remote(); + + if (fipmilan) parse_lan_options('V',"4",0); + + ret = GetDeviceID( LanRecord); + if (ret != 0) { + goto do_exit; + } else { /* success */ + uchar ipmi_maj, ipmi_min; + ipmi_maj = LanRecord[4] & 0x0f; + ipmi_min = LanRecord[4] >> 4; + show_devid( LanRecord[2], LanRecord[3], ipmi_maj, ipmi_min); + if (ipmi_maj == 0) fIPMI10 = 1; + else if (ipmi_maj == 1 && ipmi_min < 5) fIPMI10 = 1; + else fIPMI10 = 0; /* >= IPMI 1.5 is ok */ + if (ipmi_maj >= 2) fIPMI20 = 1; + /* nusers can be up to 15 max */ + if (fIPMI20) nusers = 5; + else nusers = 3; + if (fIPMI10) { + printf("%c This IPMI v%d.%d system does not support PEF records.\n", + bcomment,ipmi_maj,ipmi_min); + /* Wont handle PEF, but continue and look for BMC LAN anyway */ + // fIPMI10 = 1; + // ipmi_close_(); + // exit(1); + } + prod_id = LanRecord[9] + (LanRecord[10] << 8); + vend_id = LanRecord[6] + (LanRecord[7] << 8) + + (LanRecord[8] << 16); + /* check Device ID response for Manufacturer ID = 0x0322 (NSC) */ + if (vend_id == VENDOR_NSC) { /* NSC = 0x000322 */ + fmBMC = 1; /*NSC miniBMC*/ + if (pefnum == 12) pefnum = 10; /* change CritStop pefnum to 0x0a */ + pefdesc = &pefdesc2[0]; + pefmax = 30; + fsharedMAC = 1; /*LAN1 shares MAC with OS*/ + } else if (vend_id == VENDOR_LMC) { /* LMC (on SuperMicro) = 0x000878 */ + fmBMC = 0; + pefdesc = NULL; /* unknown, see PefDesc() */ + if (pefnum == 12) pefnum = 15; /* change CritStop pefnum */ + pefmax = 16; + fsharedMAC = 0; /* not-shared BMC LAN port */ + } else if (vend_id == VENDOR_INTEL) { /* Intel = 0x000157 */ + pefdesc = &pefdesc1[0]; /*Intel defaults*/ + pefmax = 20; /*Intel default pefmax = 20*/ + switch(prod_id) { + case 0x4311: /* Intel NSI2U*/ + fmBMC = 1; /* Intel miniBMC*/ + if (pefnum == 12) pefnum = 14; /* change CritStop pefnum */ + pefdesc = &pefdesc2[0]; + pefmax = 30; + fsharedMAC = 1; /*LAN1 shares MAC with OS*/ + break; + case 0x0026: + case 0x0028: + case 0x0811: /* Alcolu & TIGW1U */ + fmBMC = 0; /* Intel Sahalee BMC*/ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + gcm_ch = 3; + break; + case 0x003E: /*NSN2U or CG2100 Urbanna*/ + fiBMC = 1; /* Intel iBMC */ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + set_max_kcs_loops(URNLOOPS); /*longer for SetLan cmds (default 300)*/ + break; + case 0x0107: /* Intel Caneland*/ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + gcm_ch = 3; + break; + case 0x0022: /* Intel TIGI2U*/ + fsharedMAC = 1; /*LAN1 shares MAC with OS*/ + gcm_ch = 3; + nusers = 4; + break; + default: /* else other Intel */ + if (fIPMI20) fsharedMAC = 0; /* recent, not-shared BMC MAC */ + else fsharedMAC = 1; /* usu IPMI 1.x has shared BMC MAC */ +#ifdef TEST + /* also check for ia64, and set chan_pefon, chan_pefoff accordingly*/ + if (prod_id == 0x0100) { /* Intel Tiger2, Itanium2 */ + chan_pefon = CHAN_ACC_PEFON64; + chan_pefoff = CHAN_ACC_PEFOFF64; + } +#endif + break; + } /*end switch*/ + if (is_romley(vend_id,prod_id)) { + fRomley = 1; + fiBMC = 1; /* Intel iBMC */ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + set_max_kcs_loops(URNLOOPS); /*longer for SetLan cmds */ + fipv6 = 1; + } + } else if (vend_id == VENDOR_KONTRON) { + //if (prod_id == 0x1590) fchan2wart = 1; /* KTC5520 chan2 wart */ + fsharedMAC = 0; /* not-shared BMC MAC */ + pefdesc = NULL; /* unknown, see PefDesc() */ + if (pefnum == 12) pefnum = 15; /* change CritStop pefnum to 15 */ + } else { /* else other vendors */ + if (fIPMI20) fsharedMAC = 0; /* recent, not-shared BMC MAC */ + else fsharedMAC = 1; /* usu IPMI 1.x has shared BMC MAC */ + fmBMC = 0; + pefdesc = NULL; /* unknown, see PefDesc() */ + if (pefnum == 12) pefnum = 15; /* change CritStop pefnum to 15? */ + pefmax = 20; + } + if (fmBMC) nusers = 1; + } + + ret = GetPefCapabilities(&bset); + if ((ret == 0) && (bset <= MAXPEF)) pefmax = bset; + + /* Get the BMC LAN channel & match it to an OS eth if. */ + i = GetBmcEthDevice(lan_ch_parm); + if (i == -2) { /* no lan channels */ + printf("This system does not support BMC LAN channels.\n"); + ret = ERR_NOT_ALLOWED; + goto do_exit; + } else if (i < 0) { /* mac not found, use platform defaults */ + i = 0; /* default to eth0, lan_ch set already. */ + if (vend_id == VENDOR_INTEL) { + if ((prod_id == 0x001B) || (prod_id == 0x000c)) { + /* Intel TIGPR2U or TSRLT2 defaults are special */ + if (lan_ch_parm == 6) + { i = 0; lan_ch = 6; } + else { i = 1; lan_ch = 7; } + ser_ch = 1; + } + } + } + if ((gcm_ch != 0) && (lan_ch_parm == 0xff)) { + /* Has a GCM, and user didn't specify -L */ + /* Need this to avoid picking channel 3, the IMM GCM channel. */ + lan_ch = 1; /*default BMC LAN channel*/ + // i = 1; /*default eth1*/ + } + if (fsetifn == 0) { + if (lan_ch == gcm_ch) strcpy(ifname,"gcm"); + else sprintf(ifname,"%s%d",ifpattn,i); + } + if (fdebug) printf("lan_ch = %d, ifname = %s\n",lan_ch,ifname); + + /* initialize the correct SOL command values */ + if (fIPMI20 && fSOL20) { + setsolcmd = SET_SOL_CONFIG2; + getsolcmd = GET_SOL_CONFIG2; + sol_bchan = lan_ch; + } else { + setsolcmd = SET_SOL_CONFIG; + getsolcmd = GET_SOL_CONFIG; + sol_bchan = 0x00; /*override chan for IPMI 1.5*/ + } + + memset(SessInfo,0,sizeof(SessInfo)); + ret = GetSessionInfo(SessInfo,sizeof(SessInfo)); + // rlen = sizeof(SessInfo)); ret = get_session_info(0,0,SessInfo,&rlen); + if (fdebug) printf("GetSessionInfo ret=%d, data: %02x %02x %02x %02x \n", + ret,SessInfo[0],SessInfo[1],SessInfo[2],SessInfo[3]); + if (!freadonly && fipmilan) { /* setting LAN params, and using IPMI LAN */ + if (SessInfo[2] > 1) { /* another session is active also */ + printf("Another session is also active, cannot change IPMI LAN settings now.\n"); + ret = ERR_NOT_ALLOWED; + goto do_exit; + } + } + + /* set the lan_user appropriately */ + if (freadonly) + { + if (!fIPMI10) { + printf("%c## %s, GetPefEntry ...\n",bcomment,progname); + for (idx = 1; idx <= pefmax; idx++) + { + ret = GetPefEntry( 0x06, (ushort)idx, &PefRecord); + if (ret == 0) { // Show the PEF record + pc = (uchar *)&PefRecord; + sz = 21; // sizeof(PEF_RECORD) = 21 + printf("%c PefParam(%d): %s\n",bcomment,idx,PefDesc(idx,pc[7])); + fprintf(fd_bmc,"PEFParam %d,%02d%c",6,idx,bdelim); + for (i = 0; i < sz; i++) fprintf(fd_bmc," %02x",pc[i]); + fprintf(fd_bmc,"\n"); + } else { + char *pstr; + if (ret > 0) pstr = decode_cc(0,(uchar)ret); + else pstr = ""; + printf("%c GetPefEntry(%d): ret = %d %s\n",bcomment,idx,ret,pstr); + if (ret == 0xC1) { + fpefok = 0; + ndest = 0; + break; + } + } + } + if (fpefok) { + ret = GetPefEntry(0x01, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + fprintf(fd_bmc,"PEFParam %d%c %02x\n",1,bdelim,LanRecord[0]); + } + ret = GetPefEntry(0x02, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + fprintf(fd_bmc,"PEFParam %d%c %02x\n",2,bdelim,LanRecord[0]); + } + ret = GetPefEntry(0x03, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) + fprintf(fd_bmc,"PEFParam %d%c %02x\n", 3,bdelim,LanRecord[0]); + if (!fmBMC) { + ret = GetPefEntry(0x04, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) + fprintf(fd_bmc,"PEFParam %d%c %02x\n",4,bdelim,LanRecord[0]); + /* fmBMC gets cc=0x80 here */ + } + /* note that ndest should be read from lan param 17 below. */ + for (i = 1; i <= ndest; i++) + { + ret = GetPefEntry(0x09, (ushort)i,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + fprintf(fd_bmc,"PEFParam %d,%d%c %02x %02x %02x %02x \n",9,i,bdelim, + LanRecord[0], LanRecord[1],LanRecord[2], LanRecord[3]); + } + } /*endfor ndest*/ + } /*endif fpefok*/ + } /*endif not fIPMI10*/ + + for (chan = lan_ch; chan < MAXCHAN; chan++ ) + { + if (chan_type[chan] != 4) continue; /*chan != LAN, skip it*/ + lan_ch = chan; + printf("%c## %s, GetLanEntry for channel %d ...\n",bcomment,progname,lan_ch); + idest = 1; + for (idx = 0; idx < NLAN; idx++) + { + int ival; + if (idx == 8 || idx == 9) continue; /* not implemented */ + ival = lanparams[idx].cmd; + if (ival >= 96 && ival <= 98) continue; /* not implemented */ + if (ival >= 102 && ival <= 108) { /*custom IPv6 parameters*/ + if (fipv6 == 0) continue; /*skip these*/ + } + if (ival == 194 && vend_id == VENDOR_KONTRON) { /*oem hostname parm*/ + lanparams[idx].sz = 36; + strcpy(lanparams[idx].desc,"IPMI Hostname"); + } else if (ival >= 192 && ival <= 194) { /*custom DHCP parameters*/ + if (vend_id != VENDOR_INTEL) continue; + if (fmBMC || fiBMC || fRomley || fcanonical) continue; /*skip*/ + } + /* VLAN params 20-25, fIPMI20 only*/ + if (ival >= 20 && ival <= 25) { if (!fIPMI20) continue; } + if (ival == 11) { /*grat arp interval*/ + if (vend_id == VENDOR_SUPERMICROX) continue; + if (vend_id == VENDOR_SUPERMICRO) continue; + } + if (ival == 14 || ival == 15) { /*secondary gateway is optional*/ + if (vend_id == VENDOR_KONTRON) continue; + } + if (ival == 201) { /*Get Channel Access*/ + ret = ShowChanAcc(lan_ch); + } else { + if (ival == 18 || ival == 19) { /*dest params*/ + if (ndest == 0) continue; /*skip if none*/ + bset = (uchar)idest; /* dest id = 1 thru n */ + } else bset = 0; + ret = GetLanEntry((uchar)ival, bset, LanRecord); + } + if (ret == 0) { // Show the LAN record + pc = (uchar *)&LanRecord; + sz = lanparams[idx].sz; + if (ival == 201) ; /* ShowChanAcc(lan_ch) above */ + else { + fprintf(fd_bmc,"LanParam %d,%d,%d%c ",lan_ch,ival,bset,bdelim); + for (i = 0; i < sz; i++) fprintf(fd_bmc," %02x",pc[i]); + fprintf(fd_bmc,"\n"); + if (ival == 3) + printf("%c LanParam(%d,%d,%d) IP address: %d.%d.%d.%d\n", + bcomment, lan_ch,ival,bset, + pc[0], pc[1], pc[2], pc[3]); + } + + if (ival == 1) { + authmask = pc[0]; /* auth type support mask */ + /* if (fmBMC) authmask is usually 0x15, else 0x14 */ + } else if (ival == 3) { + if (IpIsValid(pc)) memcpy(bmcmyip,pc,4); + } else if (ival == 5) { + if (MacIsValid(pc)) memcpy(bmcmymac,pc,MAC_LEN); + } else if (ival == 17) { /* num dest */ + ndest = pc[0]; /* save the number of destinations */ + } else if (ival == 19) { /* dest addr */ + if (IpIsValid(&pc[3])) memcpy(bmcdestip,&pc[3],4); + } + + if (ival == 18 || ival == 19) { + if (idest < ndest) { + idest++; + idx--; /* repeat this param*/ + } else idest = 1; + } + } else { /* ret != 0 */ + if (ival >= 20 && ival <= 25) ; + else + printf("%c GetLanEntry(%d,%d,%d), ret = %d\n",bcomment,lan_ch,ival,bset,ret); + if (ival == 17) ndest = 0; /*error getting num dest*/ + } + } /*end for NLAN*/ + if (!fIPMI10) { /* Get SOL params */ + ret = GetSerialOverLan(lan_ch,0,0); + if (ret != 0) printf("%c GetSOL error %d\n",bcomment,ret); + } + for (idx = 1; idx <= nusers; idx++) + GetUser(idx); + if (lan_ch_parm != 0xff) chan = MAXCHAN; + } /*end-for chan*/ + + printf("%c## %s, GetSerEntry for channel %d ...\n",bcomment,progname,ser_ch); + if (fmBMC || (ser_ch == 0)) { /* mBMC doesn't support serial */ + printf("%cNo serial channel support on this platform\n", + bcomment); + } else { + idest = 1; + for (idx = 0; idx < NSER; idx++) { + int ival; + // if (idx == 9) continue; /* not implemented */ + ival = serparams[idx].cmd; + if (vend_id == VENDOR_SUPERMICRO && ival == 8) continue; + if (ival == 201) { + j = ShowChanAcc(ser_ch); + } else { + if (ival == 17 || ival == 19 || ival == 21 || ival == 23) + bset = (uchar)idest; + else bset = 0; /*default*/ + ret = GetSerEntry((uchar)ival, bset, LanRecord); + if (ret == 0) { // Show the SER record + pc = (uchar *)&LanRecord; + sz = serparams[idx].sz; + fprintf(fd_bmc,"SerialParam %d,%d,%d%c", + ser_ch,ival,bset,bdelim); + for (i = 0; i < sz; i++) + fprintf(fd_bmc," %02x",pc[i]); /* show in hex */ + fprintf(fd_bmc,"\n"); + if (ival == 16) ndest = pc[0]; + } else { /*ret != 0, error*/ + char *pstr; + char *tag; + if (SerialIsOptional(ival)) tag = "Optional"; + else tag = ""; + if (ret > 0) pstr = decode_cc(0,ret); + else pstr = ""; + printf("%c GetSerEntry(%d,%d): %s ret = %d %s\n", + bcomment,ser_ch,ival,tag,ret,pstr); + if (ival == 16) ndest = 0; + if (ret == 0xC1) { + ret = 0; + break; /*not supported, exit for loop*/ + } + } + } + if (ival == 17 || ival == 19 || ival == 21 || ival == 23) { + if (idest < ndest) { + idest++; + idx--; /* repeat this param*/ + } else idest = 1; + } + } /*end for NSER*/ + lan_ch_sav = lan_ch; + lan_ch = ser_ch; /* use ser_ch for User functions now */ + for (idx = 1; idx <= nusers; idx++) + GetUser(idx); + lan_ch = lan_ch_sav; + } /*endif serial*/ + + printf("%c## %s, GetSystemParams ...\n",bcomment,progname); + for (idx = 0; idx < NSYS; idx++) { /*Get System Params*/ + switch(idx) { + case 0: j = CHAS_RESTORE; bset = 0; break; + case 1: j = SYS_INFO; bset = 1; break; + case 2: j = SYS_INFO; bset = 2; break; + case 3: j = SYS_INFO; bset = 3; break; + case 4: j = SYS_INFO; bset = 4; break; + case 5: + default: j = LAN_FAILOVER; bset = 0; break; + } + fignore_err = 0; + pc = (uchar *)&LanRecord; + switch(j) { + case CHAS_RESTORE: /* Chassis Status, Power Restore Policy */ + sz = 0; + rlen = sizeof(rData); + ret = ipmi_cmdraw(CHASSIS_STATUS, NETFN_CHAS, + BMC_SA,PUBLIC_BUS,BMC_LUN, + pc,0,rData,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + if (ret == 0) { + sz = rlen; + memcpy(pc,&rData,sz); /*should be 3 bytes*/ + } + break; + case SYS_INFO: /* System Info */ + if (! fIPMI20) continue; /*skip if not IPMI 2.0*/ + rlen = sizeof(LanRecord); /* param from read */ + ret = get_system_info(bset,LanRecord,&rlen); + /* find actual string size (ends at first 0x00) */ + for (i=0; i<rlen; i++) if (LanRecord[i] == 0) break; + if (i < rlen) rlen = i; + sz = rlen; + fignore_err = 1; + break; + case LAN_FAILOVER: /* Intel LAN Failover */ + if (is_romley(vend_id,prod_id)) + ret = lan_failover_intel(0xFF,&LanRecord[0]); + else continue; /*skip if not Intel Romley */ + sz = 1; + fignore_err = 1; + break; + default: /*do nothing*/ + sz = 0; + ret = LAN_ERR_NOTSUPPORT; + break; + } /*end switch*/ + if (ret == 0) { + fprintf(fd_bmc,"SystemParam %d,%d%c ",j,bset,bdelim); + for (i = 0; i < sz; i++) fprintf(fd_bmc," %02x",pc[i]); + fprintf(fd_bmc,"\n"); + } else { + char *pstr; + if (ret > 0) pstr = decode_cc(0,ret); + else pstr = ""; + if (fdebug || !fignore_err) + printf("%c GetSystemParam(%d,%d): ret = %d %s\n", + bcomment,j,bset,ret,pstr); + if (fignore_err) ret = 0; + } + } /*end-for System Params*/ + + } /*endif readonly*/ + + if (!freadonly) /* Set parameters via Restore */ + { + if (fipmilan) { /* Sets not valid via ipmi_lan if same channel. */ + printf("\nWarning: Setting LAN %d params while using a LAN channel.\n", lan_ch); + } + GetUser(1); /*sets num enabled_users */ + + /* Set BMC parameters. (restore) */ + /* read each record from the file */ + while ( fgets( line, sizeof(line), fd_bmc) != NULL ) + { + ret = parse_line(line, key, value); + if (ret != 0) { + if (ret == 2) ret = 0; /*just skip comment*/ + else if (fdebug) printf("parse error on line: %s\n",line); + continue; + } + + /* get parameters from key */ + sz = sizeof(bParams); + memset(bParams,0,sz); + pk = strchr(key,' '); /*skip keyword, to first param*/ + if (pk == NULL) { + pk = &key[0]; + } + for (n=0; n<sz; n++) + { + pc = strchr(pk,','); + if (pc != NULL) { + *pc = 0; + bParams[n] = atob(pk); + pk = (char *)++pc; + } else { + bParams[n] = atob(pk); + break; + } + } + /* n == number of params, usually 3 */ + chan = bParams[0]; + idx = bParams[1]; + bset = bParams[2]; + /* get data from value */ + pc = value; + sz = strlen_(value); + for (j=0,i=0; i<sz; i+=3) + LanRecord[j++] = htoi(&pc[i]); + if (fdebug) { + printf("Record(%d,%d,%d):",chan,idx,bset); + for (i=0; i<j; i++) printf(" %02x",LanRecord[i]); + printf("\n"); + } + + if (strncasecmp(key,"LanParam",8) == 0) { + if (idx == 0) continue; /*skip Set in progress*/ + if (idx == 1 || idx == 17) continue; /*read-only params*/ + if (idx == 5 && fIPMI20) /*BMC MAC address & IPMI 2.0(not shared)*/ + if (fdomac == 0) continue; /*skip BMC MAC unless -m */ + if ((idx == 10) && (chan == gcm_ch)) continue; /*skip Lan3 arp*/ + if ((vend_id == VENDOR_PEPPERCON) && (idx == 7)) continue; + if ((idx == 18 || idx == 19) && (ndest == 0)) continue; + if (idx >= 22 && idx <= 24) continue; /*read-only Cipher*/ + else if (idx >= 20 && idx <= 25) { /*VLAN*/ + if (!fIPMI20) continue; + } + if (idx == 18) j--; /*one less byte for Set than from Get*/ + lan_ch = chan; + if (idx == 3) { /* 3 = IP address */ + uchar bdata[2]; + bdata[0] = 0x00; /*disable grat arp while setting IP*/ + ret = SetLanEntry(10, &bdata[0], 1); + if (fdebug) printf("SetLanEntry(%d,10,0), ret = %d\n",chan,ret); + WaitForSetComplete(4); /*wait if it is a slow MC */ + bdata[0] = SRC_STATIC; /*set src to static before setting IP*/ + ret = SetLanEntry(4, &bdata[0], 1); + if (fdebug) printf("SetLanEntry(%d,4,0), ret = %d\n",chan,ret); + WaitForSetComplete(4); /*wait if it is a slow MC */ + } + else if ((idx == 6) || (idx == 12)) WaitForSetComplete(4); + ret = SetLanEntry(idx, LanRecord, j); + if ((ret != 0) && (idx >= 20 && idx <= 25)) ; /*VLAN optional*/ + else { + printf("SetLanEntry(%d,%d), ret = %d\n",chan,idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + + } else if (strncasecmp(key,"PEFParam",8) == 0) { + if (fpefok == 0) continue; + idx = bParams[0]; + bset = bParams[1]; + if (idx == 6) { /*PEF table rules*/ + pPefRecord = (PEF_RECORD *)&LanRecord[0]; + if (pPefRecord->fconfig == 0xC0) { + pPefRecord->fconfig = 0x80; /* enabled, software */ + ret = SetPefEntry(pPefRecord); + if (fdebug) + printf("SetPefEntry(%d,%d/80) ret = %d\n",idx,bset,ret); + pPefRecord->fconfig = 0xC0; + } + ret = SetPefEntry(pPefRecord); + printf("SetPefEntry(%d,%d) ret = %d\n",idx,bset,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } else { + pc = (uchar *)&PefRecord; + pc[0] = idx; + for (i=0; i<j; i++) + pc[i+1] = LanRecord[i]; + rlen = sizeof(rData); + ret = ipmi_cmd(SET_PEF_CONFIG, pc,j+1, rData,&rlen, &cc,fdebug); + if ((ret == 0) && (cc != 0)) ret = cc; + if ((idx == 9) && (bset > 1) && (ret != 0)); /*9=PEF Policy*/ + else { + printf("SetPefEntry(%d,%d) ret = %d\n",idx,bset,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + if (ret == 0xC1) { fpefok = 0; ndest = 0; } + + } else if (strncasecmp(key,"SerialParam",11) == 0) { + if (idx == 0) continue; /*skip Set in progress*/ + if (idx == 1 || idx == 16) continue; /*read-only param*/ + if (vend_id == VENDOR_PEPPERCON) { + if ((idx >= 3) && (idx <= 6)) continue; + } + if ((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) { + if (idx == 3) continue; + if ((idx >= 6) && (idx <= 8)) continue; + if (idx == 29) continue; + } + if (fmBMC || (ser_ch == 0)) continue; /*doesn't support serial*/ + ser_ch = chan; + ret = SetSerEntry(idx, LanRecord, j); + if ((ret != 0) && SerialIsOptional(idx)) ; /*ignore errors if opt*/ + else { + printf("SetSerEntry(%d,%d,%d), ret = %d\n",chan,idx,bset,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else if (strncasecmp(key,"ChannelAccess",13) == 0) { + if (((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) && chan == 3) ; /*skip serial*/ + else { + ret = SetChanAcc(chan, 0x80, LanRecord[0], LanRecord[1]); + if (fdebug) printf("SetChanAcc(%d/active), ret = %d\n",chan,ret); + ret = SetChanAcc(chan, 0x40, LanRecord[0], LanRecord[1]); + printf("SetChanAcc(%d), ret = %d\n",chan,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + + } else if (strncasecmp(key,"UserName",8) == 0) { + if (fchan2wart && (lan_ch == 2)) continue; + idx = bParams[0]; + if (idx <= 1) ; /*skip if anonymous user 1*/ + else if (idx == 2 && vend_id == VENDOR_SUPERMICROX) ; /*skip user2*/ + else if (idx == 2 && vend_id == VENDOR_SUPERMICRO) ; /*skip user2*/ + else { + pc = (uchar *)&PefRecord; + pc[0] = idx; /*user num*/ + memcpy(&pc[1],&LanRecord[0],16); + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_NAME,pc,17, rData,&rlen, &cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + if (ret == 0xCC) ; /*SetUserName matching previous gives this*/ + else { + printf("SetUserName(%d) ret = %d\n",idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + if (fpassword) { + pc = (uchar *)&PefRecord; + pc[0] = idx; /*user num*/ + pc[1] = 0x02; /*set password*/ + memset(&pc[2],0, PSW_LEN); + strcpy(&pc[2],passwordData); + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_PASSWORD,pc,2+PSW_LEN,rData,&rlen, + &cc,fdebug); + printf("SetUserPassword(%d) ret = %d\n",idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else if (strncasecmp(key,"UserPassword",12) == 0) { + if (fchan2wart && (lan_ch == 2)) continue; + idx = bParams[0]; + pc = (uchar *)&PefRecord; + pc[0] = idx; /*user num*/ + pc[1] = 0x02; /*set password*/ + memset(&pc[2],0,PSW_LEN); + strcpy(&pc[2],passwordData); + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_PASSWORD,pc,2+PSW_LEN,rData,&rlen, + &cc,fdebug); + printf("SetUserPassword(%d) ret = %d\n",idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } else if (strncasecmp(key,"UserAccess",10) == 0) { + if ((idx > enabled_users) && ((LanRecord[3] & 0x10) == 0)) continue; + if (vend_id == VENDOR_KONTRON) { + if (idx == 1) continue; + if (idx > enabled_users) continue; + } + if (ipmi_reserved_user(vend_id,idx) == 1) continue; + if (fchan2wart && (lan_ch == 2)) continue; + pc = (uchar *)&PefRecord;; + pc[0] = 0x80 | (LanRecord[3] & 0x70) | chan; /*User Channel Access*/ + pc[1] = idx; /*user id*/ + pc[2] = (LanRecord[3] & 0x0F); /*User Privilege (Admin,User,Oper)*/ + pc[3] = 0x00; /* User Session Limit, 0=not limited*/ + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_ACCESS,pc,4, rData,&rlen, &cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + if (ret != 0xCC) { /*if invalid user, ignore errors*/ + printf("SetUserAccess (%x %x %x %x) ret = %d\n", + pc[0],pc[1],pc[2],pc[3],ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + if ((LanRecord[3] & 0x0f) != 0x0F) { /*not NoAccess, enable user*/ + if (idx > last_user_enable) last_user_enable = idx; + pc[0] = idx; /*user number, 1=null_user */ + pc[1] = 0x01; /*enable user*/ + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_PASSWORD,pc,2, rData,&rlen, &cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + printf("SetUserEnable (%x %x) ret = %d\n",pc[0],pc[1],ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else if (strncasecmp(key,"SOLParam",8) == 0) { + if (fchan2wart && (chan == 2)) continue; + pc = (uchar *)&PefRecord;; + pc[0] = chan; + pc[1] = idx; /*sol parameter number*/ + memcpy(&pc[2],&LanRecord,j); + rlen = sizeof(rData); + ret = ipmi_cmd(setsolcmd, pc, j+2, rData,&rlen, &cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + printf("SetSOLParam (%d,%d) ret = %d\n",chan,idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + + } else if (strncasecmp(key,"SOLPayloadSupport",17) == 0) { + ; /* Nothing to do, this is a read-only parameter */ + + } else if (strncasecmp(key,"SOLPayloadAccess",16) == 0) { + if (fIPMI20) { + if (ipmi_reserved_user(vend_id,idx) == 1) continue; + pc = (uchar *)&PefRecord;; + pc[0] = chan; + pc[1] = idx; // lan_user + memcpy(&pc[2],&LanRecord,j); + rlen = sizeof(rData); + ret = ipmi_cmdraw(SET_PAYLOAD_ACCESS,NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + pc,j+2,rData,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + printf("SetSOLPayloadAccess (%d,%d) ret = %d\n", + chan,idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else if (strncasecmp(key,"SystemParam",11) == 0) { + idx = bParams[0]; + bset = bParams[1]; + switch(idx) { + case CHAS_RESTORE: /* Chassis Power Restore Policy*/ + if (vend_id == VENDOR_KONTRON) continue; /*N/A, cannot set it*/ + pc = (uchar *)&PefRecord;; + i = (LanRecord[0] & 0x60); /*restore policy bits*/ + if (i & 0x20) pc[0] = 0x01; /*last_state*/ + else if (i & 0x40) pc[0] = 0x02; /*turn_on*/ + else pc[0] = 0x00; /*stay_off*/ + rlen = sizeof(rData); + ret = ipmi_cmdraw(0x06 , NETFN_CHAS, + BMC_SA,PUBLIC_BUS,BMC_LUN, + pc,1,rData,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + break; + case SYS_INFO: /* System Info */ + if (! fIPMI20) continue; /*skip if not IPMI 2.0*/ + /* j = #bytes read into LanRecord */ + ret = set_system_info(bset,LanRecord,j); + break; + case LAN_FAILOVER: /* Intel LAN Failover */ + if (is_romley(vend_id,prod_id)) + ret = lan_failover_intel(LanRecord[0],(uchar *)&i); + else continue; /*skip if not Intel Romley*/ + break; + default: + ret = LAN_ERR_NOTSUPPORT; + } + printf("SetSystemParam(%d,%d) ret = %d\n",idx,bset,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } /*end-else*/ + + } /*end-while*/ + + /* Disable any users not enabled above */ + for (i = last_user_enable+1; i < max_users; i++) { + pc[0] = (uchar)i; /*user number, 1=null_user */ + pc[1] = 0x00; /*disable user*/ + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_PASSWORD,pc,2, rData,&rlen, &cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + printf("SetUserEnable (%x %x) ret = %d\n",pc[0],pc[1],ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } /*endif not readonly*/ + +do_exit: + if (fd_bmc != stdout) fclose(fd_bmc); + ipmi_close_(); + if (nerrs > 0) { + printf("Warning: %d ok, %d errors occurred, last error = %d\n",ngood,nerrs,lasterr); + ret = lasterr; + } + // show_outcome(progname,ret); + return(ret); +} /* end main()*/ + +/* end iconfig.c */ diff --git a/util/idcmi.c b/util/idcmi.c new file mode 100644 index 0000000..1e53ae8 --- /dev/null +++ b/util/idcmi.c @@ -0,0 +1,976 @@ +/* + * idcmi.c + * Data Center Manageability Interface (DCMI) command support + * + * Change history: + * 11/17/2011 ARCress - created + * + *--------------------------------------------------------------------- + */ +/*M* +Copyright (c) 2011 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ + +#ifdef WIN32 +#include <windows.h> +#include <stdlib.h> +#include "getopt.h" +#else +#include <sys/types.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#include <sys/time.h> +#else +#include <stdlib.h> +#include <getopt.h> +#endif +#endif +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> + +#include "ipmicmd.h" +#include "isensor.h" +#include "idcmi.h" + +static char * progname = "idcmi"; +static char * progver = "2.93"; +extern char fdebug; /*from ipmicmd.c*/ +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static uchar dcmi_ver = 0x00; /* 0x10, 0x11, or 0x15 */ +static uchar fpwm = 0; /* =1 if Power Management supported */ +static uchar do_sensors = 0; +static uchar set_asset = 0; +static uchar set_mcid = 0; +static char *asset_new = NULL; +static char *mcid_new = NULL; +static int asset_len = 0; +static int mcid_len = 0; +static char mc_id[64]; +static char asset[64]; + +#ifdef NOT +/* see idcmi.h */ +#define NETFN_DCMI 0x2C +#define CMD_DCMI_GET_CAPAB 0x01 +#define CMD_DCMI_GET_POWREAD 0x02 +#define CMD_DCMI_GET_POWLIMIT 0x03 +#define CMD_DCMI_SET_POWLIMIT 0x04 +#define CMD_DCMI_ACT_POWLIMIT 0x05 +#define CMD_DCMI_GET_ASSETTAG 0x06 +#define CMD_DCMI_GET_SENSORINF 0x07 +#define CMD_DCMI_SET_ASSETTAG 0x08 +#define CMD_DCMI_GET_MCIDSTR 0x09 +#define CMD_DCMI_SET_MCIDSTR 0x0A +/* for DCMI 1.5 only */ +#define CMD_DCMI_SET_THERMLIM 0x0B +#define CMD_DCMI_GET_THERMLIM 0x0C +#define CMD_DCMI_GET_TEMPRDNGS 0x10 +#define CMD_DCMI_SET_CONFIG 0x12 +#define CMD_DCMI_GET_CONFIG 0x13 +#endif + +static int dcmi_usage(void) +{ + printf("Usage: %s [-admsx -NUPREFTVY] <function>\n", progname); + printf(" -a Set DCMI Asset Tag to this string\n"); + printf(" -d Set DCMI MC ID to this string\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -s Get DCMI sensor info\n"); + printf(" -x Display extra debug messages\n"); + print_lan_opt_usage(); + printf("where <function> is one of:\n"); + printf(" info Get DCMI Capabilities, MC ID, asset tag (default)\n"); + printf(" power [get] Get Power reading & limit\n"); + printf(" power set_limit <power> Set Power limit\n"); + printf(" power set_action <action> Set Power limit exception action\n"); + printf(" (action = no_action | power_off | log_sel)\n"); + printf(" power set_correction <ms> Set Power limit correction time (in ms)\n"); + printf(" power set_sample <sec> Set Power limit sampling period (in sec)\n"); + printf(" power activate Activate Power limit\n"); + printf(" power deactivate Deactivate Power limit\n"); + printf(" thermal Get/Set DCMI Thermal parameters\n"); + printf(" config Get/Set DCMI Configuration parameters\n"); + printf(" help Show this help message\n"); + return(ERR_USAGE); +} + +static int dcmi_get_capab(int param, uchar *pdata, int sdata) +{ + uchar idata[4]; + uchar rdata[32]; + int rlen; + uchar cc; + int rv, i; + + if (pdata == NULL || sdata == 0) return(ERR_BAD_PARAM); + idata[0] = 0xDC; + idata[1] = (uchar)param; + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_CAPAB, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,2, rdata, &rlen, &cc, fdebug); + if ((rv != 0) || (cc != 0)) { + if (fdebug) + printf("dcmi_get_capab(%d): rv = %d, ccode %02x\n",param,rv,cc); + if (rv == 0) rv = cc; + return(rv); + } + /* if here, success */ + if (fdebug) { /*show raw response*/ + printf("dcmi_get_capab(%d): rlen = %d\n",param,rlen); + for (i = 0; i < rlen; i++) printf("%02x ",rdata[i]); + printf("\n"); + } + if (rlen > sdata) { + if (fdebug) + printf("dcmi_get_capab(%d): data truncated from %d to %d\n", + param,rlen,sdata); + rlen = sdata; + } + memcpy(pdata,rdata,rlen); + return(rv); +} + +static int dcmi_get_power_read(int param, uchar *pdata, int sdata) +{ + uchar idata[5]; + uchar rdata[32]; + int rlen; + uchar cc; + int rv, i; + + if (pdata == NULL || sdata == 0) return(ERR_BAD_PARAM); + idata[0] = 0xDC; + idata[1] = (uchar)param; /*mode 1 or 2*/ + idata[2] = 0x00; + idata[3] = 0x00; + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_POWREAD, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,4, rdata, &rlen, &cc, fdebug); + if (rv == 0) rv = cc; + if (fdebug) { /*show raw response*/ + printf("dcmi_get_power_read(%d): rv = %d rlen = %d\n",param,rv,rlen); + for (i = 0; i < rlen; i++) printf("%02x ",rdata[i]); + printf("\n"); + } + if (rv == 0) { /* if here, success */ + if (rlen > sdata) { + if (fdebug) + printf("dcmi_get_power_read(%d): data truncated from %d to %d\n", + param,rlen,sdata); + rlen = sdata; + } + memcpy(pdata,rdata,rlen); + } + return(rv); +} + +static int dcmi_get_power_limit( uchar *pdata, int sdata) +{ + uchar idata[5]; + uchar rdata[32]; + int rlen; + uchar cc; + int rv, i; + + if (pdata == NULL || sdata == 0) return(ERR_BAD_PARAM); + idata[0] = 0xDC; + idata[1] = 0x00; + idata[2] = 0x00; + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_POWLIMIT, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,3, rdata, &rlen, &cc, fdebug); + if (rv == 0) rv = cc; + if (fdebug) { /*show raw response*/ + printf("dcmi_get_power_limit: rv = %d rlen = %d\n",rv,rlen); + for (i = 0; i < rlen; i++) printf("%02x ",rdata[i]); + printf("\n"); + } + if (rv == 0) { /* if here, success */ + if (rlen > sdata) { + if (fdebug) + printf("dcmi_get_power_limit: data truncated from %d to %d\n", + rlen,sdata); + rlen = sdata; + } + memcpy(pdata,rdata,rlen); + } + return(rv); +} + +static int dcmi_set_power_limit(int param,int value, uchar *pow, int spow) +{ + int rv = 0; + uchar idata[32]; + uchar rdata[32]; + int rlen; + uchar cc; + + if (spow > 15) spow = 15; + memcpy(idata,pow,spow); + switch(param) + { + case CORRECTION_TIME: + idata[10]=(uchar)((value >> 24) & 0xff); + idata[9] =(uchar)((value >> 16) & 0xff); + idata[8] =(uchar)((value >> 8) & 0xff); + idata[7] =(uchar)((value) & 0xff); + break; + case EXCEPTION_ACTION: + idata[4] = (uchar)(value & 0xff); + break; + case POWER_LIMIT: + idata[5] = (uchar)(value & 0xff); + idata[6] = (uchar)((value >> 8) & 0xff); + break; + case SAMPLE_PERIOD: + idata[14] = (uchar)((value >> 8) & 0xff); + idata[13] = (uchar)(value & 0xff); + break; + default: + return ERR_BAD_PARAM; + break; + } + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_SET_POWLIMIT, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,15, rdata, &rlen,&cc, fdebug); + if (fdebug) + printf("dcmi_set_power_limit(%d,%d): rv = %d cc = %x\n", + param,value,rv,cc); + if (rv == 0) rv = cc; + return (rv); +} + + +static int dcmi_power_limit_activate ( int yes) +{ + int rv; + uchar idata[5]; + uchar rdata[32]; + int rlen; + uchar cc; + if (yes < 0) return (ERR_BAD_PARAM); + if (yes > 1) return (ERR_BAD_PARAM); + + idata[0] = 0xDC; + idata[1] = yes; + idata[2] = 0x00; + idata[3] = 0x00; + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_ACT_POWLIMIT, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,4, rdata, &rlen, &cc, fdebug); + if (fdebug) + printf("dcmi_power_limit_activate(%d): rv = %d cc = %x\n",yes,rv,cc); + if (rv == 0) rv = cc; + return(rv); +} + +void dcmi_show_power_read(int parm, uchar *cdata, int sdata) +{ + int i; + ulong sample_period; + time_t t = 0; + uchar state; + + if (fdebug) { /*++++*/ + printf("dcmi_show_power_read(%d,%p,%d) called\n",parm,cdata,sdata); + for (i = 0; i < sdata; i++) printf("%02x ",cdata[i]); + printf("\n"); + } + if (sdata < 18) { + printf("power_read data length %d is too short\n",sdata); + return; + } + if (cdata[0] != 0xDC) { + printf("power_read: invalid first data byte (0x%02x)\n",cdata[0]); + return; + } + memcpy(&t,&cdata[9],4); + sample_period = cdata[13]; + sample_period += (cdata[14] << 8); + sample_period += (cdata[15] << 16); + sample_period += (cdata[16] << 24); + state = cdata[17]; + switch(parm) { + case 1: /* Mode 1 - System Power Statistics */ + printf(" Current Power: %d Watts\n",cdata[1]+(cdata[2]<<8)); + printf(" Min Power over sample duration: %d Watts\n",cdata[3]+(cdata[4]<<8)); + printf(" Max Power over sample duration: %d Watts\n",cdata[5]+(cdata[6]<<8)); + printf(" Avg Power over sample duration: %d Watts\n",cdata[7]+(cdata[8]<<8)); + printf(" Timestamp: %s\n",ctime(&t)); + printf(" Sampling period: %d ms\n",sample_period); + printf(" Power reading state is: %s\n",(state&0x40)? "active":"not active"); + break; + case 2: /* Mode 2 - Enhanced System Power Statistics */ + printf("Enhanced Power Mode 2 decoding not yet implemented\n"); + /* TODO */ + // break; + default: + for (i = 0; i < sdata; i++) printf("%02x ",cdata[i]); + printf("\n"); + break; + } +} + +void dcmi_show_power_limit(uchar *cdata, int sdata, int rv) +{ + ulong correction_time; + char *pstr; + + correction_time = cdata[6]; + correction_time += (cdata[7] << 8); + correction_time += (cdata[8] << 16); + correction_time += (cdata[9] << 24); + + if (rv == 0) pstr = "(active)"; + else if (rv == 0x80) pstr = "(inactive)"; + else pstr = "(error)"; + printf(" Exception Action: "); + if (cdata[3] & 0x01) + printf("Hard Power off\n"); + else if ((cdata[3] & 0x11) == 0x11) + printf("SEL logging\n"); + else + printf("OEM defined\n"); + printf(" Power Limit: %d Watts %s\n",cdata[4]+(cdata[5]<<8), pstr); + printf(" Correction Time: %d ms\n", correction_time); + printf(" Sampling period: %d sec\n", cdata[12]+(cdata[13]<<8)); +} + +static int dcmi_get_sensorinf(uchar styp, uchar snum, uchar offset, + uchar *pdata, int sdata) +{ + uchar idata[5]; + uchar rdata[32]; + int rlen; + uchar cc; + int rv, i; + + if (pdata == NULL || sdata == 0) return(ERR_BAD_PARAM); + idata[0] = 0xDC; + idata[1] = styp; /*sensor type, 0x01 = Temperature*/ + idata[2] = snum; /*sensor number */ + idata[3] = 0x00; /*Entity Instance, 0 = all instances*/ + idata[4] = offset; /*Entity Instance start/offset */ + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_SENSORINF, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,5, rdata, &rlen, &cc, fdebug); + if (rv == 0) rv = cc; + if (fdebug) { /*show raw response*/ + printf("dcmi_get_sensorinf(%d): rlen = %d\n",snum,rlen); + for (i = 0; i < rlen; i++) printf("%02x ",rdata[i]); + printf("\n"); + } + if (rv == 0) { /* if here, success */ + if (rlen > sdata) { + if (fdebug) + printf("dcmi_get_sensorinf(%d): data truncated from %d to %d\n", + snum,rlen,sdata); + rlen = sdata; + } + memcpy(pdata,rdata,rlen); + } + return(rv); +} + +static char *entstr(int i) +{ + char *pstr = NULL; + switch(i) { + case 0: pstr = "Inlet"; break; + case 1: pstr = "CPU"; break; + case 2: + default: + pstr = "Baseboard"; break; + } + return(pstr); +} + +static int dcmi_get_sensors(int styp) +{ + int i, j, n, r, recs; + uchar offset, id; + uchar dbuf[20]; + uchar s1; + int rv; + uchar *sdrs = NULL; + uchar sdr[128]; + + offset = 0; + r = 1; n = 8; + s1 = 0x40; /*0x40,0x41,0x42*/ + rv = get_sdr_cache(&sdrs); + + printf("---Sensors---\n"); + for (i = 0; i < 3; i++) + { + rv = dcmi_get_sensorinf(styp,s1+i,offset,dbuf,sizeof(dbuf)); + if (rv != 0) break; + n = dbuf[1]; + recs = dbuf[2]; + printf(" %d %s temp sensors: \tn_returned=%d\n",n,entstr(i),recs); + for (r = 0; r < n; r += recs) + { + recs = dbuf[2]; + if (recs == 0) break; + for (j = 0; j < r; j++) { + id = (dbuf[4 + (2*j)] << 8) + dbuf[3 + (2*j)]; + if (fdebug) printf("j=%d id=%x \n",j,id); + /* get the sensor info for each record id */ + rv = find_sdr_next(sdr,sdrs,(id-1)); + ShowSDR("",sdr); + } + offset += recs; + rv = dcmi_get_sensorinf(1,s1+i,offset,dbuf,sizeof(dbuf)); + if (rv != 0) break; + } + } + if (rv != 0) printf("dcmi_get_sensors(%d,%d) error %d\n",styp,i,rv); + free_sdr_cache(sdrs); + return(rv); +} + +static int dcmi_get_asset_tag(char *pdata, int sdata, int *dlen) +{ + uchar idata[4]; + uchar rdata[32]; + int rlen; + uchar cc; + int n, rv = -1; + int sz_chunk = 16; + int sz_all; + + if (pdata == NULL || sdata < 16) return(ERR_BAD_PARAM); + memset(pdata,0,sdata); + sz_all = sdata; + for (n = 0; (n < sdata && n < sz_all); n += sz_chunk) { + idata[0] = 0xDC; + idata[1] = n; /*offset*/ + idata[2] = sz_chunk; /*bytes to read*/ + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_ASSETTAG, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,3, rdata, &rlen, &cc, fdebug); + if (fdebug) + printf("dcmi_get_asset(%d): rv=%d ccode=%02x rlen=%d\n", + n,rv,cc,rlen); + if (rv == 0) rv = cc; + if (rv == 0) { /* if here, success */ + if (n == 0) sz_all = rdata[1]; + if ((n + sz_chunk) > sdata) { + if (fdebug) + printf("dcmi_get_asset(%d): data truncated from %d to %d\n", + n,(n+sz_chunk),sdata); + sz_chunk = (sdata - n); + } + memcpy(&pdata[n],&rdata[2],sz_chunk); + } else break; + } /*end-for loop*/ + pdata[n] = 0; /*stringify*/ + if (dlen != NULL) *dlen = n; + return(rv); +} + +static int dcmi_get_mc_id(char *pdata, int sdata, int *dlen) +{ + uchar idata[4]; + uchar rdata[32]; + int rlen; + uchar cc; + int n, rv = -1; + int sz_chunk = 16; + int sz_all; + + if (pdata == NULL || sdata < 16) return(ERR_BAD_PARAM); + memset(pdata,0,sdata); + sz_all = sdata; + for (n = 0; (n < sdata && n < sz_all); n += sz_chunk) { + idata[0] = 0xDC; + idata[1] = n; /*offset*/ + idata[2] = sz_chunk; /*bytes to read*/ + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_MCIDSTR, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,3, rdata, &rlen, &cc, fdebug); + if (fdebug) + printf("dcmi_get_mc_id(%d): rv=%d ccode=%02x rlen=%d\n", + n,rv,cc,rlen); + if (rv == 0) rv = cc; + if (rv == 0) { /* if here, success */ + if (n == 0) sz_all = rdata[1]; + if ((n + sz_chunk) > sdata) { + if (fdebug) + printf("dcmi_get_mc_id(%d): data truncated from %d to %d\n", + n,(n+sz_chunk),sdata); + sz_chunk = (sdata - n); + } + memcpy(&pdata[n],&rdata[2],sz_chunk); + } else break; + } /*end-for loop*/ + pdata[n] = 0; /*stringify*/ + if (dlen != NULL) *dlen = n; + return(rv); +} + +static int dcmi_set_asset_tag(char *pdata, int sdata) +{ + int rv = -1; + uchar idata[32]; + uchar rdata[8]; + uchar cc; + int ilen, rlen, n; + int sz_chunk = 16; + + if (pdata == NULL || sdata < 2) return(ERR_BAD_PARAM); + for (n = 0; (n < sdata); n += sz_chunk) { + idata[0] = 0xDC; + idata[1] = n; /*offset*/ + idata[2] = sz_chunk; /*bytes to read*/ + memset(&idata[3],0x20,sz_chunk); + ilen = 3 + sz_chunk; + if ((n + sz_chunk) > sdata) sz_chunk = sdata - n; + memcpy(&idata[3],&pdata[n],sz_chunk); + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_SET_ASSETTAG, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,ilen, rdata, &rlen, &cc, fdebug); + if (rv == 0) { + if (fdebug) + printf("dcmi_set_asset_tag(%d,%d,%d) cc=%x resp: %02x %02x %02x\n", + sdata,n,sz_chunk,cc,rdata[0],rdata[1],rdata[2]); + rv = cc; + } + if (rv != 0) break; + } + return(rv); +} + +static int dcmi_set_mc_id(char *pdata, int sdata) +{ + int rv = -1; + uchar idata[32]; + uchar rdata[8]; + uchar cc; + int ilen, rlen, n; + int sz_chunk = 16; + + if (pdata == NULL || sdata < 2) return(ERR_BAD_PARAM); + for (n = 0; (n < sdata); n += sz_chunk) { + if ((n + sz_chunk) > sdata) sz_chunk = sdata - n; + idata[0] = 0xDC; + idata[1] = n; /*offset*/ + idata[2] = sz_chunk; /*bytes to read*/ + memset(&idata[3],0x20,sz_chunk); + ilen = 3 + sz_chunk; + if ((n + sz_chunk) > sdata) sz_chunk = sdata - n; + memcpy(&idata[3],&pdata[n],sz_chunk); + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_SET_MCIDSTR, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,ilen, rdata, &rlen, &cc, fdebug); + if (rv == 0) { + if (fdebug) printf("dcmi_set_mc_id(%d,%d,%d) resp: %02x %02x %02x\n", + sdata,n,sz_chunk,rdata[0], rdata[1], rdata[2]); + rv = cc; + } + if (rv != 0) break; + } + return(rv); +} + +static int dcmi_show_asset_tag(void) +{ + int rv = -1; + rv = dcmi_get_asset_tag(asset,sizeof(asset),&asset_len); + if (rv == 0) printf("DCMI Asset Tag: \t%s\n",asset); + return(rv); +} + +static int dcmi_show_mc_id(void) +{ + int rv = -1; + rv = dcmi_get_mc_id(mc_id,sizeof(mc_id),&mcid_len); + if (rv == 0) printf("DCMI Mgt Controller ID: \t%s\n",mc_id); + return(rv); +} + +static char *supported[2] = { "Unsupported", "Supported" }; + +void dcmi_show_capab(int parm, uchar *cdata, int sdata) +{ + char mystr[64] = ""; + int i, j, k, n, f; + switch(parm) + { + case 1: + printf("DCMI Version: \t%d.%d\n",cdata[1],cdata[2]); + dcmi_ver = ((cdata[1] & 0x0f) << 4) + (cdata[2] & 0x0f); + if (cdata[5] & 0x01) { fpwm = 1; } + else { fpwm = 0; } + printf("DCMI Power Management: \t%s\n",supported[fpwm]); + if (cdata[6] & 0x01) f = 1; + else f = 0; + printf("DCMI System Interface Access:\t%s\n",supported[f]); + if (cdata[6] & 0x02) f = 1; + else f = 0; + printf("DCMI Serial TMode Access:\t%s\n",supported[f]); + if (cdata[6] & 0x02) f = 1; + else f = 0; + printf("DCMI Secondary LAN Channel:\t%s\n",supported[f]); + break; + case 2: + mystr[0] = 0; + if (cdata[5] & 0x80) strcat(mystr,"Overwrite "); + else strcat(mystr,"NoOverwrite "); + if (cdata[5] & 0x40) strcat(mystr,"FlushAll "); + if (cdata[5] & 0x20) strcat(mystr,"FlushRec"); + printf("DCMI SEL Management: \t%s\n",mystr); + n = ((cdata[5] & 0x0F) << 8) + cdata[4]; + printf("DCMI SEL num entries: \t%d\n",n); + i = cdata[8]; + printf("DCMI Temperature Polling: \t%d sec\n",i); + break; + case 3: + n = ((cdata[4] & 0xFE) >> 1); + printf("DCMI PWM Slave_Address: \t%02x\n",n); + n = ((cdata[5] & 0xF0) >> 4); + printf("DCMI PWM Channel: \t%02x\n",n); + printf("DCMI PWM Dev_Rev: \t%02x\n",(cdata[5] & 0x0F)); + break; + case 4: + printf("DCMI LanPlus primary chan:\t%02x\n",cdata[4]); + printf("DCMI LanPlus secondary chan:\t%02x\n",cdata[5]); + printf("DCMI Serial channel: \t%02x\n",cdata[6]); + break; + case 5: + n = cdata[4]; + if (n > (5 + sdata)) n = sdata - 5; /*truncate*/ + for (i = 0; i < n; i++) { + j = (cdata[5+i] & 0x0f); + k = ((cdata[5+i] & 0xf0) >> 4); + switch(k) { + case 3: strcpy(mystr,"days"); break; + case 2: strcpy(mystr,"hrs"); break; + case 1: strcpy(mystr,"min"); break; + case 0: + default: strcpy(mystr,"sec"); break; + } + printf("DCMI Power Stats Duration(%d):\t%d %s\n",i,j,mystr); + } + break; + default: + printf("DCMI(%d) data: %02x %02x %02x %02x %02x %02x %02x %02x\n", + parm,cdata[1],cdata[2],cdata[3],cdata[4], + cdata[5], cdata[6], cdata[7], cdata[8]); + break; + } +} + +static int dcmi_show_all_capab(void) +{ + int rv = -1; + int i; + uchar cdata[32]; + + for (i = 1; i <= 5; i++) + { + /* only read power stats(5) when power management is supported */ + if (i == 5 && fpwm == 0) continue; + rv = dcmi_get_capab(i, cdata, sizeof(cdata)); + if (rv != 0) { + if (i == 1 && rv == CC_DCMI_INVALID_COMMAND) { /*0xC1 on first*/ + printf("DCMI not supported on this platform\n"); + break; + } else if (i == 5 && rv == CC_DCMI_RECORD_NOT_PRESENT) /*0xCB*/ + rv = 0; /*optional, ignore this error*/ + /*else just dont show the param*/ + } else dcmi_show_capab(i,cdata,sizeof(cdata)); + + } /*end-for dcmi_capab loop */ + return(rv); +} + +#ifdef METACOMMAND +int i_dcmi(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int rv = 0; + int c, i; + char *s1; + uchar cdata[32]; + uchar powdata[32]; + + printf("%s ver %s\n", progname,progver); + parse_lan_options('V',"4",0); /*default to admin priv*/ + + while ( (c = getopt( argc, argv,"a:d:m:sT:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'a': set_asset = 1; asset_new = optarg; break; + case 'd': set_mcid = 1; mcid_new = optarg; break; + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 's': do_sensors = 1; break; + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + return(dcmi_usage()); + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + if ((argc > 0) && strcmp(argv[0], "help") == 0) { + return(dcmi_usage()); + } + + rv = ipmi_getdeviceid( cdata, sizeof(cdata),fdebug); + if (rv == 0) { + uchar ipmi_maj, ipmi_min; + ipmi_maj = cdata[4] & 0x0f; + ipmi_min = cdata[4] >> 4; + show_devid( cdata[2], cdata[3], ipmi_maj, ipmi_min); + } else goto do_exit; + + if (set_asset) { + rv = dcmi_get_asset_tag(asset,sizeof(asset),&asset_len); + memset(asset,' ',asset_len); /*fill with spaces*/ + asset_len = strlen_(asset_new); + if (asset_len >= sizeof(asset)) asset_len = sizeof(asset) - 1; + memcpy(asset,asset_new,asset_len); + asset[asset_len] = 0; + rv = dcmi_set_asset_tag(asset, asset_len); + printf("Set DCMI Asset Tag to %s, ret = %d\n",asset_new,rv); + } + if (set_mcid) { + rv = dcmi_get_mc_id(mc_id,sizeof(mc_id),&mcid_len); + memset(mc_id,' ',mcid_len); /*fill with spaces*/ + mcid_len = strlen_(mcid_new); + if (mcid_len >= sizeof(mc_id)) mcid_len = sizeof(mc_id) - 1; + memcpy(mc_id,mcid_new,mcid_len); + mc_id[mcid_len] = 0; + rv = dcmi_set_mc_id(mcid_new, mcid_len); + printf("Set DCMI MC ID to %s, ret = %d\n",mcid_new,rv); + } + + if ( (argc == 0) || (strcmp(argv[0], "info") == 0) ) { + rv = dcmi_show_all_capab(); + if (rv == 0) { + rv = dcmi_show_mc_id(); + rv = dcmi_show_asset_tag(); + if (do_sensors) rv = dcmi_get_sensors(1); /*temp sensors*/ + rv = 0; /*ignore errors for optional features*/ + } + } else + { + rv = dcmi_get_capab(1, cdata, sizeof(cdata)); + if (rv == 0) dcmi_show_capab(1,cdata,sizeof(cdata)); + else if (rv == CC_DCMI_INVALID_COMMAND) /*0xC1 on first*/ + printf("DCMI not supported on this platform\n"); + + if (strncmp(argv[0], "power",5) == 0) { + if (fpwm == 0) { /*not supported in capab */ + printf("DCMI Power functions not supported on this platform.\n"); + rv = LAN_ERR_NOTSUPPORT; + } else { + rv = dcmi_get_power_read(1, cdata, sizeof(cdata)); + if (rv == 0) { + dcmi_show_power_read(1,cdata,sizeof(cdata)); + rv = dcmi_get_power_limit(powdata, sizeof(powdata)); + if (rv == 0) + dcmi_show_power_limit(powdata,sizeof(powdata),rv); + else if (rv == 0x80) { + dcmi_show_power_limit(powdata,sizeof(powdata),rv); + rv = 0; + } + } + if (argc < 2) ; /*just get, done above*/ + else if (strncmp(argv[1],"get",3) == 0) ; /*done above*/ + else if (strncmp(argv[1],"set_limit",9) == 0) { + if (argc < 3) return(dcmi_usage()); + i = atoi(argv[2]); + { /*let range checking be done by DCMI*/ + rv = dcmi_set_power_limit (POWER_LIMIT, i, powdata,16); + switch(rv) { + case 0: + printf("DCMI Power limit applied successfully.\n"); + break; + case 0x84: printf("Power limit out of range\n"); break; + case 0x85: printf("Correction time out of range\n"); + break; + case 0x89: + printf("Statistics reporting period out of range\n"); + break; + default: + printf("DCMI Power Limit Set error %d\n",rv); break; + } + if (rv == 0) { + rv = dcmi_power_limit_activate(1); + printf ("DCMI Power Limit Activate returned %d\n",rv); + } + } + } + else if (strncmp(argv[1],"activate",8) == 0) { + rv = dcmi_power_limit_activate(1); + if (rv == 0) + printf ("DCMI Power Limit Activated.\n"); + else printf("DCMI Power Limit Activate error %d\n",rv); + } + else if (strncmp(argv[1],"deactivate",10) == 0) { + rv = dcmi_power_limit_activate(0); + if (rv == 0) + printf("DCMI Power Limit Deactivated.\n"); + else printf("DCMI Power Limit Deactivate error %d\n",rv); + } + else if (strcmp(argv[1],"set_action")==0) { + if (argc < 3) return(dcmi_usage()); + else if (strcmp(argv[2],"no_action") == 0) + rv = dcmi_set_power_limit(EXCEPTION_ACTION,0x00, + powdata,16); + else if (strcmp(argv[2],"log_sel") == 0) + rv = dcmi_set_power_limit(EXCEPTION_ACTION,0x11, + powdata,16); + else if (strcmp(argv[2],"power_off") == 0) + rv = dcmi_set_power_limit(EXCEPTION_ACTION,0x01, + powdata,16); + else return(dcmi_usage()); + if (rv == 0) + printf("exception action set successfully.\n"); + else printf("set_exception action error %d\n",rv); + } + else if (strcmp(argv[1],"set_sample")==0) { + if (argc < 3) return(dcmi_usage()); + i = atoi(argv[2]); + if (i != 0) { + rv = dcmi_set_power_limit (SAMPLE_PERIOD,i,powdata,16); + if (rv == 0x00) + printf("sample period set successfully\n"); + else if (rv == 0x89) + printf("sample period %d out of range\n",i); + else printf("set_sample period error %d\n",rv); + } + else { printf("invalid sample period %d\n",i); + rv = ERR_USAGE; } + } + else if (strcmp(argv[1],"set_correction")==0) { + if (argc < 3) return(dcmi_usage()); + i = atoi(argv[2]); + if (i != 0) { + rv = dcmi_set_power_limit(CORRECTION_TIME,i,powdata,16); + if (rv == 0x00) + printf("correction time set successfully\n"); + else if (rv == 0x85) + printf("correction time %d out of range\n",i); + else { + dcmi_usage(); + rv = ERR_USAGE; + } + } + else { printf("correction time %d invalid\n",i); + rv = ERR_USAGE; } + } + else { + printf("invalid subfunction %s\n",argv[1]); + rv = ERR_USAGE; + } + } /* endif power functions supported */ + + } else if (strcmp(argv[0], "thermal") == 0) { + if (dcmi_ver < 0x15) { /*not supported in DCMI < 1.5 */ + printf("DCMI 1.5 Thermal functions not supported on this platform.\n"); + rv = LAN_ERR_NOTSUPPORT; + } else { + rv = dcmi_get_sensors(1); /*temp sensors*/ +/* These are DCMI 1.5 commands */ +// #define CMD_DCMI_SET_THERMLIM 0x0B +// #define CMD_DCMI_GET_THERMLIM 0x0C +// #define CMD_DCMI_GET_TEMPRDNGS 0x10 +/* TODO: implement these 3 DCMI thermal commands */ + printf("DCMI 1.5 Thermal functions not yet implemented\n"); + rv = ERR_USAGE; + } + } else if (strcmp(argv[0], "config") == 0) { + if (dcmi_ver < 0x15) { /*not supported in DCMI < 1.5 */ + printf("DCMI 1.5 Config functions not supported on this platform.\n"); + rv = LAN_ERR_NOTSUPPORT; + } else { /* These are DCMI 1.5 commands */ +// #define CMD_DCMI_SET_CONFIG 0x12 +// #define CMD_DCMI_GET_CONFIG 0x13 +/* TODO: implement these 2 DCMI config commands */ + printf("DCMI 1.5 Config get/set functions not yet implemented\n"); + rv = ERR_USAGE; + } + } else { + return(dcmi_usage()); + } + } /*else not info command*/ + +do_exit: + ipmi_close_(); + return rv; +} +/* end idcmi.c */ diff --git a/util/idcmi.h b/util/idcmi.h new file mode 100644 index 0000000..a528831 --- /dev/null +++ b/util/idcmi.h @@ -0,0 +1,69 @@ +/* + * idcmi.h + * Data Center Manageability Interface (DCMI) command support + * + * Change history: + * 11/17/2011 ARCress - created + * + *--------------------------------------------------------------------- + */ +/*M* +Copyright (c) 2011 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ + +#ifndef IPMI_DCMI_H +#define IPMI_DCMI_H + +#define CC_DCMI_INVALID_COMMAND 0xC1 +#define CC_DCMI_RECORD_NOT_PRESENT 0xCB +#define NETFN_DCMI 0x2C +/* for DCMI 1.0 and greater */ +#define CMD_DCMI_GET_CAPAB 0x01 +#define CMD_DCMI_GET_POWREAD 0x02 +#define CMD_DCMI_GET_POWLIMIT 0x03 +#define CMD_DCMI_SET_POWLIMIT 0x04 +#define CMD_DCMI_ACT_POWLIMIT 0x05 +#define CMD_DCMI_GET_ASSETTAG 0x06 +#define CMD_DCMI_GET_SENSORINF 0x07 +#define CMD_DCMI_SET_ASSETTAG 0x08 +#define CMD_DCMI_GET_MCIDSTR 0x09 +#define CMD_DCMI_SET_MCIDSTR 0x0A +/* for DCMI 1.5 only */ +#define CMD_DCMI_SET_THERMLIM 0x0B +#define CMD_DCMI_GET_THERMLIM 0x0C +#define CMD_DCMI_GET_TEMPRDNGS 0x10 +#define CMD_DCMI_SET_CONFIG 0x12 +#define CMD_DCMI_GET_CONFIG 0x13 + +/* CMD_DCMI_SET_POWLIMIT options */ +#define CORRECTION_TIME 0x01 +#define EXCEPTION_ACTION 0x02 +#define POWER_LIMIT 0x03 +#define SAMPLE_PERIOD 0x04 + +#endif +/* end idcmi.h */ diff --git a/util/idiscover.c b/util/idiscover.c new file mode 100644 index 0000000..57471e3 --- /dev/null +++ b/util/idiscover.c @@ -0,0 +1,1055 @@ +/* + * idiscover.c + * Discover all IPMI-LAN-enabled nodes on this network or subnet. + * This program is not completely reliable yet, not all IPMI-LAN-enabled + * nodes respond. + * Currently this utility is compiled with NO_THREADS, but threads can + * be enabled by commenting out this flag. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 10/27/06 Andy Cress - created + * 05/01/07 Andy Cress - added -g for GetChannelAuthCap method, + * added -a logic for broadcast ping, + * updated WIN32 logic + * 09/20/07 Andy Cress - fixed send/receive thread order + * 07/15/08 Andy Cress - added -r for ping repeats + * 11/21/08 Andy Cress - detect eth intf and broadcast ip addr + */ +/*M* +Copyright (c) 2006, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <winsock.h> +#include <io.h> +#include <time.h> +#include "getopt.h" +#define NO_THREADS 1 +typedef unsigned int socklen_t; +WSADATA lan_ws; /*global for WSA*/ + +#elif defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#define NO_THREADS 1 + +#else +/* Linux, BSD, Solaris */ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netdb.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#include <sys/sockio.h> +#ifndef HAVE_CONFIG_H +typedef unsigned int socklen_t; +#endif +#else +#include <getopt.h> +#endif + +/* comment out NO_THREADS to use this utility in Linux with threads */ +#define NO_THREADS 1 +#endif +#ifndef ETH_P_IP +#define ETH_P_IP 0x0800 /* Internet Protocol packet, see linux/if_ether.h */ +#endif + +/* TODO: fix RAW for -m in Solaris, FreeBSD, Windows (works in Linux) */ +#ifdef SOLARIS +#include <sys/sockio.h> +#define RAW_DOMAIN AF_INET +#define RAW_PROTO IPPROTO_RAW +static char frawok = 0; /*raw not working in Solaris*/ +#elif BSD +#define RAW_DOMAIN AF_INET +#define RAW_PROTO IPPROTO_RAW +static char frawok = 0; /*raw not working in FreeBSD*/ +#elif MACOS +#define RAW_DOMAIN AF_INET +#define RAW_PROTO IPPROTO_RAW +static char frawok = 0; /*raw not working in FreeBSD*/ +#elif WIN32 +#define RAW_DOMAIN AF_INET +#define RAW_PROTO IPPROTO_ICMP +static char frawok = 0; /*raw not working in Windows*/ +#else +#define RAW_DOMAIN AF_PACKET +#define RAW_PROTO htons(ETH_P_IP) +static char frawok = 1; /*raw works in Linux*/ +#endif + +#include <string.h> +#include "ipmicmd.h" + +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#endif +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#define RMCP_PRI_RMCP_PORT 0x26F +#define SZ_PING 12 +#define IPMI_PING_MAX_LEN 50 /* usu 28 */ +#define CMD_GET_CHAN_AUTH_CAP 0x38 + +#ifdef WIN32 +int GetFirstIP(uchar *ipaddr, uchar *macadr, char *ipname, char fdb); /*ilan.c*/ +#endif + +/* + * Global variables + */ +static char * progver = "1.9"; +static char * progname = "idiscover"; +static char fdebug = 0; +static char fping = 1; +static char fraw = 0; +static char fBroadcastOk = 0; +static char fcanonical = 0; +static int broadcast_pings = 1; +//static uchar ipmi_maj = 0; +//static uchar ipmi_min = 0; +//static uchar netfn; +static ushort g_port = RMCP_PRI_RMCP_PORT; +static SockType g_sockfd = 0; +static SockType g_sockraw = 0; +static int g_limit = 30; /* after this many 'other' packets, stop. */ +static struct sockaddr_in _srcaddr; +// static struct sockaddr_in _destaddrlist[255]; +static struct in_addr _startAddr, _endAddr; +static char g_startDest[MAXHOSTNAMELEN+1] = {'\0'}; +static char g_endDest[MAXHOSTNAMELEN+1] = {'\0'}; +static char g_interface[INET_ADDRSTRLEN+1] = {""}; /*e.g. "eth0"*/ +static int g_num_packets = 0; +static int g_npings = 0; +static int g_npongs = 0; +static int g_recv_status = 0; +static int g_wait = 1; /* num sec to wait */ +static int g_delay = 0; /* num usec between sends */ +static int g_repeat = 1; /* number of times to repeat ping to each node */ +static char bdelim = BDELIM; /* '|' */ + +#ifdef METACOMMAND +extern FILE *fpdbg; /*from ipmicmd.c*/ +extern char *strlasterr(int rv); /*from ipmilan.c*/ +#else +void dump_buf(char *tag, uchar *pbuf, int sz, char fshowascii) +{ + uchar line[17]; + uchar a; + int i, j; + FILE *fpdbg; + + fpdbg = stdout; + line[0] = 0; line[16] = 0; + j = 0; + fprintf(fpdbg,"%s (len=%d): ", tag,sz); + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { j = 0; fprintf(fpdbg,"%s\n %04x: ",line,i); } + if (fshowascii) { + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + } + fprintf(fpdbg,"%02x ",pbuf[i]); + } + if (j < 16) { + line[j] = 0; + for (i = 0; i < (16-j); i++) fprintf(fpdbg," "); + } + fprintf(fpdbg,"%s\n",line); + return; +} +#endif + +void printerr( const char *pattn, ...) +{ + va_list arglist; + FILE *fderr; + + // fderr = fopen("/tmp/idiscover.log","a+"); + // if (fderr == NULL) return; + fderr = stderr; + + va_start(arglist, pattn); + vfprintf(fderr, pattn, arglist); + va_end(arglist); + + // fclose(fderr); +} + +static char *showlasterr(void) +{ + char *str; +#ifdef WIN32 + static char strbuf[80]; + int rv; + char *desc; + rv = WSAGetLastError(); +#ifdef METACOMMAND + /* get descriptions from strlasterr in ipmilan.c */ + desc = strlasterr(rv); +#else + if (rv == WSAECONNRESET) desc = "Connection reset"; /*10054*/ + else if (rv == WSAECONNREFUSED) desc = "Connection refused"; /*10061*/ + else if (rv == WSAEHOSTUNREACH) desc = "No route to host"; /*10065*/ + else desc = ""; +#endif + sprintf(strbuf,"LastError = %d %s",rv,desc); + str = strbuf; +#else + str = strerror(errno); +#endif + return(str); +} + +static void cleanup(void) +{ + SockType *pfd; + int i; + for (i = 0; i < 2; i++) { + if (i == 0) pfd = &g_sockfd; + else pfd = &g_sockraw; + if (*pfd > 0) { +#ifdef WIN32 + closesocket(*pfd); + WSACleanup(); +#else + close(*pfd); +#endif + } + *pfd = 0; + } +} + +void show_usage(void) +{ + printf("Usage: %s [-abegix] \n",progname); + printf(" -a all nodes, enables broadcast ping\n"); + printf(" -b <ip> beginning IP address (x.x.x.x), required\n"); + printf(" -e <ip> ending IP address (x.x.x.x), default is begin IP\n"); + printf(" -g use GetChanAuthCap instead of RMCP ping\n"); + printf(" -i interface name, default is eth0\n"); + printf(" -m get MAC addresses with a raw broadcast ping\n"); + printf(" -p N specific Port (IPMI LAN port=623)\n"); + printf(" -r N number of Repeat pings to each node (default=1)\n"); + // printf(" -s specific subnet\n"); + printf(" -x show eXtra debug messages\n"); +} + +static int os_sleep(unsigned int s, unsigned int u) +{ +#ifdef WIN32 + if (s == 0) { + if (u >= 1000) Sleep(u/1000); + } else { + Sleep(s * 1000); + } +#else +/*Linux*/ +#ifdef SELECT_TIMER + struct timeval tv; + tv.tv_sec = s; + tv.tv_usec = u; + if (select(1, NULL, NULL, NULL, &tv) < 0) + printerr("select: %s\n", showlasterr()); +#else + if (s == 0) { + usleep(u); + } else { + sleep(s); + } +#endif +#endif + return 0; +} + +void split_ip(uint addr, uchar *ip) +{ + ip[3] = (addr & 0x000000ff); + ip[2] = (addr & 0x0000ff00) >> 8; + ip[1] = (addr & 0x00ff0000) >> 16; + ip[0] = (addr & 0xff000000) >> 24; +} + +int ntoi(int addr) +{ + return(addr); +} + +void show_ip(int saddr) +{ + uchar ip[4]; + split_ip(saddr,ip); + printerr("%d.%d.%d.%d\n",ip[0],ip[1],ip[2],ip[3]); +} + +static int ipmilan_sendto(SockType s, const void *msg, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + int n; +#ifdef NEED_PAD + int fusepad = 0; + /* Never need a pad byte for ping/pong packets */ + if (len == 56 || len == 84 || len == 112 || len == 128 || len == 156) { + fusepad = 1; + len += 1; + } +#endif + n = (int)sendto(s,msg,len,flags,to,tolen); + // if (fusepad && (n > 0)) n--; + return(n); +} + +static int ipmilan_recvfrom(SockType s, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + int rv; + rv = (int)recvfrom(s,buf,len,flags,from,fromlen); + /* Sometimes the OS sends an ECONNREFUSED error, but + * retrying will catch the BMC's reply packet. */ +#ifdef WIN32 + if (rv < 0) { + int err; + err = WSAGetLastError(); + if (err == WSAECONNREFUSED) /*10061*/ + rv = (int)recvfrom(s,buf,len,flags,from,fromlen); + } +#else + if ((rv < 0) && (errno == ECONNREFUSED)) + rv = (int)recvfrom(s,buf,len,flags,from,fromlen); +#endif + return(rv); +} + +#if defined(WIN32) +int inet_aton(const char *cp, struct in_addr *inp) +{ + int rv; + int adr; + inp->s_addr = inet_addr(cp); + adr = (int)inp->s_addr; + if (adr == INADDR_NONE) rv = 0; + else rv = 1; /*success*/ + return(rv); +} +#elif defined(SOLARIS) +int find_ifname(char *ifname) +{ return(-1); } +#else +#include <ifaddrs.h> +int find_ifname(char *ifname) +{ + struct ifaddrs *ifaddr, *ifa; + int rv = -1; + if (getifaddrs(&ifaddr) == -1) return(rv); + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) continue; + if ((ifa->ifa_addr->sa_family != AF_INET) && + (ifa->ifa_addr->sa_family != AF_INET6)) continue; + if (strcmp(ifa->ifa_name,"lo") == 0) continue; + /* if here, we have a valid ifname */ + strcpy(ifname,ifa->ifa_name); + if (fdebug) printf("find_ifname: found %s\n",ifname); + rv = 0; + break; + } + freeifaddrs(ifaddr); + return(rv); +} +#endif + +int sock_init( char *_interface, char *_startIP, char *_endIP) +{ + int rv; + uchar *pb; + uchar val; + +#ifdef WIN32 + DWORD rvl; + rvl = WSAStartup(0x0101,&lan_ws); + if (rvl != 0) { + printerr("init: WSAStartup(1.1) error %ld\n", rvl); + return((int)rvl); + } +#else + char findif; +#endif + + if ((g_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == SockInvalid) { + printerr("socket: %s\n", showlasterr()); + return(-1); + } + + memset(&_srcaddr, 0, sizeof(_srcaddr)); + _srcaddr.sin_family = AF_INET; + _srcaddr.sin_port = htons(0); + _srcaddr.sin_addr.s_addr = htonl(INADDR_ANY); + +#ifdef WIN32 + { + int ret; + uchar osip[4]; + uchar osmac[6]; + uchar osname[64]; + char ipstr[20]; + char *temp_start; + if (fBroadcastOk && (g_startDest[0] == 0)) { + ret = GetFirstIP(osip,osmac,osname,fdebug); /*ilan.c*/ + if (ret == 0) { + // osip[3] = 0xFF; /*255 for broadcast*/ + sprintf(ipstr,"%d.%d.%d.255",osip[0],osip[1],osip[2]); + temp_start = ipstr; + strcpy(g_startDest,temp_start); + strcpy(g_endDest,temp_start); + } else { /*use some defaults*/ + strcpy(g_startDest,"255.255.255.255"); + strcpy(g_endDest,"255.255.255.255"); + } + } + } +#elif defined(HPUX) + { /*find the OS eth interface to use*/ + char devname[INET_ADDRSTRLEN+1]; + int i, n; + n = 0; + sprintf(devname,"lan%d",n); + } +#else + { /*find the OS eth interface to use*/ + struct sockaddr_in temp_sockaddr; + char *temp_start; + struct ifreq ifr; + char devname[INET_ADDRSTRLEN+1]; + int i, n; + if (_interface == NULL) findif = 1; + else if (_interface[0] == 0) findif = 1; + else findif = 0; + if (findif) { + n = find_ifname(devname); + if (n >= 0) { + _interface = devname; + findif = 0; + } + } + if (findif) + { /* try again to find the first active ethN interface */ + n = -1; + for (i = 0; (i < 16) && (n == -1); i++) { +#ifdef SOLARIS + sprintf(devname,"e1000g%d",i); +#elif BSD + sprintf(devname,"em%d",i); +#else + sprintf(devname,"eth%d",i); +#endif + strcpy(ifr.ifr_name, devname); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(g_sockfd, SIOCGIFADDR, &ifr) >= 0) { + /* valid IP address, so active interface, use it */ + temp_sockaddr = *((struct sockaddr_in *)&ifr.ifr_addr); + memcpy(&_srcaddr.sin_addr.s_addr, &temp_sockaddr.sin_addr.s_addr, + sizeof(_srcaddr.sin_addr.s_addr)); + strcpy(g_interface, devname); + temp_start = inet_ntoa(temp_sockaddr.sin_addr); + if (temp_start == NULL) temp_start = ""; + else if (fBroadcastOk && (g_startDest[0] == 0)) { + pb = (uchar *)&temp_sockaddr.sin_addr.s_addr; + pb[3] = 0xFF; /*255 for broadcast*/ + temp_start = inet_ntoa(temp_sockaddr.sin_addr); + strcpy(g_startDest,temp_start); + strcpy(g_endDest,temp_start); + } + printf("sock_init: found %s with %s\n",devname,temp_start); + n = i; + break; + } + } + if (n < 0) rv = LAN_ERR_OTHER; /*-13*/ + } else { /* valid _interface string */ + if (strchr(_interface, '.') != NULL) + { /* assume it is an IP address*/ + if ((rv = inet_pton(AF_INET, _interface, &_srcaddr.sin_addr)) < 0) + printerr("inet_pton: %s\n", showlasterr()); + if (rv == 0) + printerr("invalid interface address\n"); + return(rv); + } + else + { /* assume interface name, like eth0 */ + strncpy(ifr.ifr_name, _interface, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(g_sockfd, SIOCGIFADDR, &ifr) < 0) { + printerr("ioctl(%s): %s\n", _interface, showlasterr()); + return(-1); + } + + temp_sockaddr = *((struct sockaddr_in *)&ifr.ifr_addr); + memcpy(&_srcaddr.sin_addr.s_addr, &temp_sockaddr.sin_addr.s_addr, + sizeof(_srcaddr.sin_addr.s_addr)); + if (fBroadcastOk && (g_startDest[0] == 0)) { + pb = (uchar *)&temp_sockaddr.sin_addr.s_addr; + pb[3] = 0xFF; /*255 for broadcast*/ + temp_start = inet_ntoa(temp_sockaddr.sin_addr); + strcpy(g_startDest,temp_start); + strcpy(g_endDest,temp_start); + } + } + } + } +#endif + + if (fBroadcastOk) { + rv = setsockopt(g_sockfd, SOL_SOCKET, SO_BROADCAST, + (char *)&broadcast_pings, sizeof(broadcast_pings)); + if (rv) { + printerr("setsockopt: %s\n", showlasterr()); + return(-1); + } + } + + if (bind(g_sockfd, (struct sockaddr *)&_srcaddr, sizeof(_srcaddr)) < 0) { + printerr("bind: %s\n", showlasterr()); + return(-1); + } + + rv = inet_aton(_startIP, &_startAddr); + if (rv ) { + _startAddr.s_addr = ntohl(_startAddr.s_addr); + if (fdebug) show_ip(_startAddr.s_addr); + pb = (unsigned char*)&_startAddr.s_addr; + if (pb[0] < 1) + printerr("Malformed begin IP: %s\n", _startIP); + else if (!fBroadcastOk && (pb[0] >254) ) + printerr("Malformed begin IP: %s\n", _startIP); + else if (fBroadcastOk) { + val = pb[0] & 0x0f; + if (val == 0x0f) rv = 0; + else printerr("Malformed begin broadcast IP: %s\n", _startIP); + } else rv = 0; + } else { + printerr("Invalid begin IP: %s\n", _startIP); + } + if (rv) return(rv); + + rv = inet_aton(_endIP, &_endAddr); + if (rv ) { + _endAddr.s_addr = ntohl(_endAddr.s_addr); + if (fdebug) show_ip(_endAddr.s_addr); + pb = (unsigned char*)&_endAddr.s_addr; + if (pb[0] < 1) + printerr("Malformed end IP: %s\n", _endIP); + else if (!fBroadcastOk && (pb[0] >254) ) + printerr("Malformed end IP: %s\n", _endIP); + else rv = 0; + } else { + printerr("Invalid end IP: %s\n", _endIP); + } + + /* calculate g_num_packets */ + g_num_packets = ntoi(_endAddr.s_addr) - ntoi(_startAddr.s_addr) + 1; + if (fdebug) printerr("g_num_packets = %d\n",g_num_packets); + if (g_num_packets < 1) g_num_packets = 0; + + return(rv); +} /*end sock_init*/ + +void *receiveThread(void *p) +{ + uchar buffer[IPMI_PING_MAX_LEN]; + struct timeval tv; + fd_set rset; + int rv, len; + static int needlf = 0; + char host[200]; + SockType sockrecv; + int nothers = 0; + int addr_type = AF_INET; /*or AF_INET6*/ +#ifndef WIN32 + struct hostent *h_ent = NULL; + char serv[200]; + int r; +#endif + + sockrecv = g_sockfd; + if (fraw) { /* opening SOCK_RAW requires admin/root privilege. */ + if ((g_sockraw = socket(RAW_DOMAIN, SOCK_RAW,RAW_PROTO)) == SockInvalid) + { + printerr("raw socket: %s\n", showlasterr()); + fraw = 0; + } else { + sockrecv = g_sockraw; + if (fdebug) printf("g_sockraw = %d\n",g_sockraw); + } + } + + /* receive while loop */ + do + { + tv.tv_sec = g_wait; + tv.tv_usec = 0; + FD_ZERO(&rset); + FD_SET(sockrecv, &rset); + g_recv_status = 0; + + if (fdebug) printerr("waiting for ping %d response\n",g_npings); + if ((rv = select((int)(sockrecv+1), &rset, NULL, NULL, &tv)) < 0) { + printerr("select: %s\n", showlasterr()); + cleanup(); + exit(rv); // error, exit idiscover recv thread + } + + if (fdebug) printerr("select rv = %d\n",rv); + if (rv > 0) + { + struct sockaddr_in from; + socklen_t fromlen; + char rstr[40]; + char macstr[20]; + struct in_addr from_ip; + char estr[40]; + + if (needlf) { printf("\n"); needlf = 0; } + g_recv_status = 1; + fromlen = sizeof(from); + len = ipmilan_recvfrom(sockrecv, buffer, IPMI_PING_MAX_LEN, 0, + (struct sockaddr *)&from, &fromlen); + if (fdebug) printerr("recvfrom rv = %d\n",rv); + if (len < 0) { + printerr("ipmilan_recvfrom: %s\n", showlasterr()); + continue; + } + if (fdebug) { + /* can we get the MAC addr of the responder also? */ + // dump_buf("from_addr",(uchar *)&from,fromlen,0); + dump_buf("recvfrom",buffer,len,0); + } + g_recv_status = 2; + g_npongs++; + macstr[0] = 0; + if (fraw) { /* Raw packet, include MAC address string */ + /* + * Sample raw packet for UDP ping response + * dst_mac src_mac eth_p iphdr + * 0000: 00 07 e9 06 15 31 00 0e 0c 2b b5 81 08 00 45 00 + * udp src_ip dst_ip + * 0010: 00 38 00 00 40 00 40 11 b6 01 c0 a8 01 c2 c0 a8 + * rmcp + * 0020: 01 a1 02 6f 80 1e 00 24 0e d1 06 00 ff 06 00 00 + * 0030: 11 be + */ + if ((buffer[23] != 0x11) || (buffer[42] != 0x06)) { + /* [23]: 0x11==UDP, 0x06==TCP ; [42]: 0x06 ==RMCP */ + if (nothers > g_limit) { + if (fdebug) + printf("got %d other packets, stop.\n",nothers); + break; + } + nothers++; + continue; + } + if (buffer[6] == 0xFF || buffer[26] == 0xFF) /*broadcast*/ + continue; + sprintf(macstr,"%02x:%02x:%02x:%02x:%02x:%02x %c", + buffer[6], buffer[7], buffer[8], /*06=src_mac*/ + buffer[9], buffer[10], buffer[11], bdelim); + memcpy(&from_ip,&buffer[26],4); /*26=src_ip*/ + } else { + memcpy(&from_ip,&from.sin_addr,4); + } + host[0] = 0; +#ifndef WIN32 +/* Linux, BSD, Solaris, MacOS */ +#if !defined(CROSS_COMPILE) + h_ent = gethostbyaddr((void *)&from_ip,4,addr_type); + if (h_ent != NULL) { + strncpy(host,h_ent->h_name,sizeof(host)); + } else if (!fraw) +#endif + { + r = getnameinfo((struct sockaddr *)&from, fromlen, + host, sizeof(host), serv, sizeof(serv), 0); + if (r) host[0] = 0; + else if (host[0] >= '0' && host[0] <= '9') host[0] = 0; + } +#endif + // parse the received pong + rstr[0] = 0; + if (fping == 0 && len > 0) { /* -g and got rsp data */ + /* parse GetChanAuthcap response into rstr */ + /* 4 bytes RMCP, 10 bytes IPMI session, then msg */ + /* 6 bytes msg hdr, then rsp data */ + /* 20 = ccode, 21 = chan, 22 = auth type support */ + if (buffer[20] != 0) /*ccode error*/ + sprintf(rstr,"%c (ccode=0x%02x)",bdelim,buffer[20]); + else /*ccode is ok*/ + sprintf(rstr,"%c (channel %d)",bdelim,buffer[21]); + } + if (fcanonical) { + estr[0] = 0; + rstr[0] = 0; + } else { + sprintf(estr,"response from %c ",bdelim); + } + /* &buffer[0] = source MAC, &buffer[6] = destination MAC */ + printf("%.2d%c %s%s %s \t%c %s %s\n", + g_npongs,bdelim,estr,macstr,inet_ntoa(from_ip), + bdelim,host,rstr); + } + else { /*ping, no answer*/ + if (!fBroadcastOk) { + printf("."); fflush(stdout); /*show progress*/ + needlf = 1; + } + } + } +#ifdef NO_THREADS + while(fBroadcastOk && rv > 0); +#else + while(1); +#endif + return(p); +} + +/* + * send_ping_pkt: + * RMCP Ping buffer, sent as a UDP packet to port 0x026f. + * rmcp.ver = 0x06 // RMCP Version 1.0 + * rmcp.resvd = 0x00 // RESERVED + * rmcp.seq = 0xff // no RMCP ACK + * rmcp.class = 0x06 // RMCP_CLASS_ASF + * asf.iana = 0x000011BE // ASF_RMCP_IANA (hi-lo) + * asf.type = 0x80 // ASF_TYPE_PING + * asf.tag = 0x00 // ASF sequence number + * asf.resvd = 0x00 // RESERVED + * asf.len = 0x00 + */ +int send_ping_pkt(struct sockaddr_in *_daddr, uchar seq) +{ + uchar pingbuf[SZ_PING] = {06,0,0xFF,06,0x00,0x00,0x11,0xBE,0x80,0,0,0 }; + int rv, len; + + pingbuf[9] = seq; + len = sizeof(pingbuf); + if (fdebug) dump_buf("send_ping",pingbuf,len,0); + rv = ipmilan_sendto(g_sockfd, pingbuf, len, 0, + (struct sockaddr *)_daddr, sizeof(struct sockaddr_in)); + return(rv); +} + +static int send_poke1(struct sockaddr_in *_daddr) +{ + int rv; + uchar asfpkt[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x20, 0x18, 0xc8, 0xc2, 0x01, 0x01, 0x3c }; + if (fdebug) dump_buf("send_poke1",asfpkt,16,0); + rv = ipmilan_sendto(g_sockfd, asfpkt, 16, 0, + (struct sockaddr *)_daddr, sizeof(struct sockaddr_in)); + return rv; +} + +static uchar cksum(const uchar *buf, register int len) +{ + register uchar csum; + register int i; + + /* 8-bit 2s compliment checksum */ + csum = 0; + for (i = 0; i < len; i++) + csum = (csum + buf[i]) % 256; + csum = -csum; + return(csum); +} + +static int send_getauth(struct sockaddr_in *_daddr, uchar seq) +{ + int rv, len; + // static uchar swseq = 0; + uchar getauthpkt[23] = { 0x06, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x20, 0x18, + 0xc8, 0x81, 0x04, 0x38, 0x0e, 0x04, 0x31 }; + /* + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + * 06 00 ff 07 00 00 00 00 00 00 00 00 00 09 20 18 c8 81 04 38 0e 04 31 + * [RMCP hdr ] [IPMI session hdr (len)] [IPMI msg ] [data] + */ + // getauthpkt[8] = 0x00; /* seq always 00 for GetChanAuthCap */ + getauthpkt[21] = 0x02; /*requested priv_level: 2=user, 4=admin*/ + getauthpkt[22] = cksum(&getauthpkt[17],5); + len = sizeof(getauthpkt); + if (fdebug) dump_buf("send_getauth",getauthpkt,len,0); + rv = ipmilan_sendto(g_sockfd, getauthpkt, len, 0, + (struct sockaddr *)_daddr, sizeof(struct sockaddr_in)); + if (fdebug) + printf("send_getauth: rv = %d\n",rv); + return rv; +} + +int send_probe(struct sockaddr_in *_daddr, uchar seq) +{ + int rv; + + if (fBroadcastOk) { + rv = setsockopt(g_sockfd, SOL_SOCKET, SO_BROADCAST, + (char *)&broadcast_pings, sizeof(broadcast_pings)); + if (fdebug) { + char *estr; + if (rv) estr = showlasterr(); + else estr = ""; + printerr("setsockopt(broadcast): rv=%d %s\n", rv,estr); + } + } + if (fping) + rv = send_ping_pkt( _daddr, seq); + else + rv = send_getauth( _daddr, seq); + return(rv); +} + +void *sendThread(void *p) +{ + int i, j, n; + // char _dest[MAXHOSTNAMELEN+1]; + char _dest_ip[INET_ADDRSTRLEN+1]; + struct sockaddr_in _destaddr; + uchar o[4]; + uint ip; + uchar _seq; + int rv; + + n = g_num_packets; /*num*/ + ip = _startAddr.s_addr; + + for (i = 0; i < n; i++) + { + split_ip(ip,o); + if (o[3] == 0) continue; + if (!fBroadcastOk && (o[3] == 255)) continue; + sprintf(_dest_ip,"%d.%d.%d.%d",o[0],o[1],o[2],o[3]); + + /* set _destaddr */ + _destaddr.sin_family = AF_INET; + _destaddr.sin_port = htons(g_port); + if ( !inet_aton( _dest_ip, &_destaddr.sin_addr)) { + printerr("inet_aton error %s\n",_dest_ip); + continue; + } + + for (j=0; j<g_repeat; j++) + { + /* send ping buffer */ + _seq = 0; + rv = send_probe(&_destaddr,_seq); + g_npings++; + if (fdebug) printerr("sendto[%d,%d] %s rv = %d\n", + g_npings,_seq,_dest_ip,rv); + if (rv < 0) { /*try to send again*/ + rv = send_probe(&_destaddr,++_seq); + if (rv < 0) { + printerr("sendto[%d,%d] %s error %s\n", + g_npings,_seq,_dest_ip,showlasterr()); + continue; + } + } + +#ifdef NO_THREADS + receiveThread(NULL); + if (g_recv_status == 0 && !fBroadcastOk) { + /* nothing returned, try again */ + if (fping) { + rv = send_poke1(&_destaddr); + if (fdebug) printerr("sendto[%d,%d] %s poke rv = %d\n", + g_npings,_seq,_dest_ip,rv); + } + rv = send_probe(&_destaddr,++_seq); + if (fdebug) printerr("sendto[%d,%d] %s rv = %d\n", + g_npings,_seq,_dest_ip,rv); + if (rv >= 0) { + receiveThread(NULL); + } + } +#endif + + /* sleep an interval (g_delay usec) */ + if (g_delay > 0) os_sleep(0,g_delay); + } /*end-for g_repeat*/ + + ip++; /* increment to next IP */ + } + return(p); +} + +#ifdef METACOMMAND +int i_discover(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int rv = 0; + int c; +#ifndef NO_THREADS + char message[32]; + pthread_t thread[2]; + int iret[2]; +#endif + +#ifdef METACOMMAND + fpdbg = stdout; +#endif + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"ab:ce:gi:l:mp:r:s:x?")) != EOF ) + switch(c) { + case 'a': fBroadcastOk = 1; fping = 1; + break; /*all (broadcast ping)*/ + case 'c': /*canonical, CSV*/ + fcanonical = 1; + bdelim = BCOMMA; + break; + case 'm': /* show MAC address, use raw, requires root priv */ + fBroadcastOk = 1; fping = 1; fraw = 1; + break; /*all (broadcast ping)*/ + case 'l': g_limit = atoi(optarg); break; + case 'g': fping = 0; break; /*use get chan auth cap method */ + case 'b': /*begin*/ + strncpy(g_startDest,optarg,MAXHOSTNAMELEN); + break; + case 'e': /*end*/ + strncpy(g_endDest,optarg,MAXHOSTNAMELEN); + break; + case 'i': /*interface*/ + strncpy(g_interface,optarg,sizeof(g_interface)); + break; + case 'p': /*port/socket*/ + g_port = (ushort)atoi(optarg); + break; + case 'r': /*repeat N times*/ + g_repeat = atoi(optarg); + break; + case 's': /*subnet*/ + /* copy optarg from 10.243.42.0 or similar, to + * begin/end range. */ + break; + case 'x': fdebug = 1; break; /* debug messages */ + default: + if (fdebug) printerr("getopt(%c) default\n",c); + show_usage(); + rv = ERR_USAGE; + goto do_exit; + } +#ifdef WIN32 + /* Winsock inet_aton() does not like 255.255.255.255 */ + if (!fBroadcastOk && (g_startDest[0] == 0) ) { + show_usage(); + printerr("A beginning IP is required, using -b\n"); + goto do_exit; + } +#else + if (g_startDest[0] == 0) { + strcpy(g_startDest,"255.255.255.255"); /* INADDR_BROADCAST */ + fBroadcastOk = 1; + } +#endif + if (fraw == 1) { + if (frawok == 0) { + printf("Warning: SOCK_RAW not yet implemented on this OS\n"); + } +#ifdef LINUX + else { + c = geteuid(); + if (c > 1) printf("Must be root/superuser to use SOCK_RAW\n"); + } +#endif + } + if (g_endDest[0] == 0 || fBroadcastOk) + strcpy(g_endDest,g_startDest); /*only one IP address*/ + if (fdebug) + printerr("intf=%s begin=%s end=%s port=%d\n", + g_interface,g_startDest,g_endDest,g_port); + + rv = sock_init(g_interface, g_startDest, g_endDest); + if (fdebug) printerr("sock_init rv = %d, sockfd = %d\n",rv,g_sockfd); + if (rv != 0) { + show_usage(); + printerr("sock_init error %d\n",rv); + goto do_exit; + } + + printf("Discovering IPMI Devices:\n"); +#ifdef NO_THREADS + sendThread(NULL); +#else + iret[1] = pthread_create( &thread[1], NULL, receiveThread, (void*) message); + iret[0] = pthread_create( &thread[0], NULL, sendThread, (void*) message); + pthread_join( thread[0], NULL); + pthread_join( thread[1], NULL); +#endif + + // if (fdebug) + printf("\n%s: %d pings sent, %d responses\n",progname,g_npings,g_npongs); + +do_exit: + cleanup(); + return(rv); +} /* end main()*/ + +/* end idiscover.c */ diff --git a/util/iekanalyzer.c b/util/iekanalyzer.c new file mode 100644 index 0000000..ddeeba8 --- /dev/null +++ b/util/iekanalyzer.c @@ -0,0 +1,4131 @@ +/* + * iekanalyzer.c + * Handle FRU EKey Analyzer functions + * + * Change history: + * 09/08/2010 ARCress - included in source tree + * + *--------------------------------------------------------------------- + */ +/* + * Copyright (c) 2007 Kontron Canada, Inc. All Rights Reserved. + * + * Base on code from + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#ifdef WIN32 +#include <windows.h> +#include "getopt.h" +#else +#include <sys/types.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include "ipmicmd.h" +#include "iekanalyzer.h" + +extern int verbose; /*ipmilanplus.c*/ +extern void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/ +extern void set_loglevel(int level); + +/* fseek wrapper for size_t/long compile warnings */ +static int fseek_(FILE *fp, size_t offset, int whence) +{ return(fseek(fp, (long)offset, whence)); } + +/***************************************************************** +* CONSTANT +*****************************************************************/ +const int ERROR_STATUS = -1; +const int OK_STATUS = 0; + +const char * STAR_LINE_LIMITER = + "*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"; +const char * EQUAL_LINE_LIMITER = + "================================================================="; +const int SIZE_OF_FILE_TYPE = 3; +const unsigned char AMC_MODULE = 0x80; +const int PICMG_ID_OFFSET = 3; +#define MAX_ARGC (MAX_FILE_NUMBER+4) /*8+4=12*/ +#define COMPARE_CANDIDATE 2 +/*In AMC.0 or PICMG 3.0 specification offset start from 0 with 3 bytes of +* Mfg.ID, 1 byte of Picmg record Id, and +* 1 byte of format version, so the data offset start from 5 +*/ +#define LOWER_OEM_TYPE 0xf0 +#define UPPER_OEM_TYPE 0xfe +const int START_DATA_OFFSET = 5; +const unsigned char DISABLE_PORT = 0x1f; + +const struct valstr ipmi_ekanalyzer_module_type[] = { + { ON_CARRIER_FRU_FILE, "On-Carrier Device" }, + { A1_AMC_FRU_FILE, "AMC slot A1" }, + { A2_AMC_FRU_FILE, "AMC slot A2" }, + { A3_AMC_FRU_FILE, "AMC slot A3" }, + { A4_AMC_FRU_FILE, "AMC slot A4" }, + { B1_AMC_FRU_FILE, "AMC slot B1" }, + { B2_AMC_FRU_FILE, "AMC slot B2" }, + { B3_AMC_FRU_FILE, "AMC slot B3" }, + { B4_AMC_FRU_FILE, "AMC slot B4" }, + { RTM_FRU_FILE, "RTM" }, /*This is OEM specific module*/ + { CONFIG_FILE, "Configuration file" }, + { SHELF_MANAGER_FRU_FILE, "Shelf Manager" }, + { 0xffff , NULL }, +}; + +const struct valstr ipmi_ekanalyzer_IPMBL_addr[] = { + { 0x72, "AMC slot A1" }, + { 0x74, "AMC slot A2" }, + { 0x76, "AMC slot A3" }, + { 0x78, "AMC slot A4" }, + { 0x7a, "AMC slot B1" }, + { 0x7c, "AMC slot B2" }, + { 0x7e, "AMC slot B3" }, + { 0x80, "AMC slot B4" }, + { 0x90, "RTM"}, /*This is OEM specific module*/ + { 0xffff , NULL }, +}; + +const struct valstr ipmi_ekanalyzer_link_type[] = { + { 0x00, "Reserved" }, + { 0x01, "Reserved" }, + { 0x02, "AMC.1 PCI Express" }, + { 0x03, "AMC.1 PCI Express Advanced Switching" }, + { 0x04, "AMC.1 PCI Express Advanced Switching" }, + { 0x05, "AMC.2 Ethernet" }, + { 0x06, "AMC.4 Serial RapidIO" }, + { 0x07, "AMC.3 Storage" }, + /*This is OEM specific module*/ + { 0xf0, "OEM Type 0"}, + { 0xf1, "OEM Type 1"}, + { 0xf2, "OEM Type 2"}, + { 0xf3, "OEM Type 3"}, + { 0xf4, "OEM Type 4"}, + { 0xf5, "OEM Type 5"}, + { 0xf6, "OEM Type 6"}, + { 0xf7, "OEM Type 7"}, + { 0xf8, "OEM Type 8"}, + { 0xf9, "OEM Type 9"}, + { 0xfa, "OEM Type 10"}, + { 0xfb, "OEM Type 11"}, + { 0xfc, "OEM Type 12"}, + { 0xfd, "OEM Type 13"}, + { 0xfe, "OEM Type 14"}, + { 0xff , "Reserved" }, +}; + +/*Reference: AMC.1 specification*/ +const struct valstr ipmi_ekanalyzer_extension_PCIE[] = { + { 0x00, "Gen 1 capable - non SSC" }, + { 0x01, "Gen 1 capable - SSC" }, + { 0x02, "Gen 2 capable - non SSC" }, + { 0x03, "Gen 3 capable - SSC" }, + { 0x0f, "Reserved"}, +}; +/*Reference: AMC.2 specification*/ +const struct valstr ipmi_ekanalyzer_extension_ETHERNET[] = { + { 0x00, "1000BASE-BX (SerDES Gigabit) Ethernet link" }, + { 0x01, "10GBASE-BX4 10 Gigabit Ethernet link" }, +}; +/*Reference: AMC.3 specification*/ +const struct valstr ipmi_ekanalyzer_extension_STORAGE[] = { + { 0x00, "Fibre Channel (FC)" }, + { 0x01, "Serial ATA (SATA)" }, + { 0x02, "Serial Attached SCSI (SAS/SATA)" }, +}; + +const struct valstr ipmi_ekanalyzer_asym_PCIE[] = { + { 0x00, "exact match"}, + { 0x01, "provides a Primary PCI Express Port" }, + { 0x02, "provides a Secondary PCI Express Port" }, +}; + +const struct valstr ipmi_ekanalyzer_asym_STORAGE[] = { + { 0x00, "FC or SAS interface {exact match}" }, + { 0x01, "SATA Server interface" }, + { 0x02, "SATA Client interface" }, + { 0x03, "Reserved" }, +}; + +const struct valstr ipmi_ekanalyzer_picmg_record_id[] = { + { 0x04, "Backplane Point to Point Connectivity Record" }, + { 0x10, "Address Table Record" }, + { 0x11, "Shelf Power Distribution Record" }, + { 0x12, "Shelf Activation and Power Management Record" }, + { 0x13, "Shelf Manager IP Connection Record" }, + { 0x14, "Board Point to Point Connectivity Record" }, + { 0x15, "Radial IPMB-0 Link Mapping Record" }, + { 0x16, "Module Current Requirements Record" }, + { 0x17, "Carrier Activation and Power Management Record" }, + { 0x18, "Carrier Point-to-Point Connectivity Record" }, + { 0x19, "AdvancedMC Point-to-Point Connectivity Record" }, + { 0x1a, "Carrier Information Table" }, + { 0x1b, "Shelf Fan Geography Record" }, + { 0x2c, "Carrier Clock Point-to-Point Connectivity Record" }, + { 0x2d, "Clock Configuration Record" }, +}; + +struct ipmi_ek_multi_header { + struct fru_multirec_header header; + unsigned char * data; + struct ipmi_ek_multi_header * prev; + struct ipmi_ek_multi_header * next; +}; + +struct ipmi_ek_amc_p2p_connectivity_record{ + unsigned char guid_count; + struct fru_picmgext_guid * oem_guid; + unsigned char rsc_id; + unsigned char ch_count; + struct fru_picmgext_amc_channel_desc_record * ch_desc; + unsigned char link_desc_count; + struct fru_picmgext_amc_link_desc_record * link_desc; + int * matching_result; /*For link descriptor comparision*/ +}; + +/***************************************************************************** +* Function prototype +******************************************************************************/ +/* global variables */ +static char * progname = "iekanalyzer"; +static char * progver = "1.00"; +static char fdebug = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + +#ifndef HAVE_LANPLUS +/* define these routines in ipmilanplus.c if no lanplus/helper.c */ +extern const char * val2str(uint16_t val, const struct valstr *vs); +#endif +/**************************************************************************** +* command Functions +*****************************************************************************/ +static int ipmi_ekanalyzer_print( int argc, char * opt, + char ** filename, int * file_type ); + +static tboolean ipmi_ekanalyzer_ekeying_match( int argc, char * opt, + char ** filename, int * file_type ); + + +/**************************************************************************** +* Linked list Functions +*****************************************************************************/ +static void ipmi_ek_add_record2list( struct ipmi_ek_multi_header ** record, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last ); + +static void ipmi_ek_display_record( struct ipmi_ek_multi_header * record, + struct ipmi_ek_multi_header * list_head, + struct ipmi_ek_multi_header * list_last ); + +static void ipmi_ek_remove_record_from_list( + struct ipmi_ek_multi_header * record, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last ); + +static int ipmi_ekanalyzer_fru_file2structure( char * filename, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_record, + struct ipmi_ek_multi_header ** list_last ); + +/**************************************************************************** +* Ekeying match Functions +*****************************************************************************/ +static int ipmi_ek_matching_process( int * file_type, int index1, int index2, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last, char * opt, + struct ipmi_ek_multi_header * pphysical ); + +static int ipmi_ek_get_resource_descriptor( int port_count, int index, + struct fru_picmgext_carrier_p2p_descriptor * port_desc, + struct ipmi_ek_multi_header * record ); + +static int ipmi_ek_create_amc_p2p_record( struct ipmi_ek_multi_header * record, + struct ipmi_ek_amc_p2p_connectivity_record * amc_record ); + +static int ipmi_ek_compare_link( struct ipmi_ek_multi_header * physic_record, + struct ipmi_ek_amc_p2p_connectivity_record record1, + struct ipmi_ek_amc_p2p_connectivity_record record2, + char * opt, int file_type1, int file_type2 ); + +static tboolean ipmi_ek_compare_channel_descriptor( + struct fru_picmgext_amc_channel_desc_record ch_desc1, + struct fru_picmgext_amc_channel_desc_record ch_desc2, + struct fru_picmgext_carrier_p2p_descriptor * port_desc, + int index_port, unsigned char rsc_id ); + +static int ipmi_ek_compare_link_descriptor( + struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, + struct ipmi_ek_amc_p2p_connectivity_record record2, int index2 ); + +static int ipmi_ek_compare_asym( unsigned char asym[COMPARE_CANDIDATE] ); + +static int ipmi_ek_compare_number_of_enable_port( + struct fru_picmgext_amc_link_desc_record link_desc[COMPARE_CANDIDATE] ); + +static int ipmi_ek_check_physical_connectivity( + struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, + struct ipmi_ek_amc_p2p_connectivity_record record2, int index2, + struct ipmi_ek_multi_header * record, + int filetype1, int filetype2, char * option ); + +/**************************************************************************** +* Display Functions +*****************************************************************************/ +static int ipmi_ek_display_fru_header( char * filename ); + +static void ipmi_ek_display_fru_header_detail( char * filename ); + +static void ipmi_ek_display_chassis_info_area( FILE * input_file, long offset ); + +static size_t ipmi_ek_display_board_info_area( FILE * input_file, + char * board_type, unsigned int * board_length ); + +static void ipmi_ek_display_product_info_area( FILE * input_file, long offset ); + +static tboolean ipmi_ek_display_link_descriptor( int file_type, + unsigned char rsc_id, char * str, + struct fru_picmgext_amc_link_desc_record link_desc ); + +static void ipmi_ek_display_oem_guid( + struct ipmi_ek_amc_p2p_connectivity_record amc_record1 ); + +static int ipmi_ek_diplay_carrier_connectivity( + struct ipmi_ek_multi_header * record ); + +static int ipmi_ek_display_power( int argc, char * opt, + char ** filename, int * file_type ); + +static void ipmi_ek_display_current_descriptor( + struct fru_picmgext_carrier_activation_record car, + struct fru_picmgext_activation_record * cur_desc, char * filename ); + +static void ipmi_ek_display_backplane_p2p_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_address_table_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_shelf_power_distribution_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_shelf_activation_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_shelf_ip_connection_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_board_p2p_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_radial_ipmb0_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_current_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_activation_record ( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_p2p_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_carrier_info_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_clock_carrier_p2p_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_clock_config_record( + struct ipmi_ek_multi_header * record ); + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_usage +* +* Description : Print the usage (help menu) of ekeying analyzer tool +* +* Restriction : None +* +* Input : None +* +* Output : None +* +* Global : None +* +* Return : None +* +***************************************************************************/ +static void +ipmi_ekanalyzer_usage( void ) +{ + char * help_message = +"Ekeying analyzer tool version 1.00 \r\n\ +ekanalyzer Commands: \r\n\ + print [carrier | power | all] <oc=filename1> <b1=filename2>... \r\n\ + frushow <b2=filename> \r\n\ + summary [match | unmatch | all] <oc=filename1> <b1=filename2>... \r\n\ +"; + printf("%s",help_message); + fflush(stdout); +} + +/************************************************************************** +* +* Function name: ipmi_ek_get_file_type +* +* Description: this function takes an argument, then xtract the file type and +* convert into module type (on carrier, AMC,...) value. +* +* +* Restriction: None +* +* Input: argument: strings contain the type and the name of the file +* together +* +* Output: None +* +* Global: None +* +* Return: Return value of module type: On carrier FRU file, A1 FRUM file... +* if the file type is invalid, it return -1. See structure +* ipmi_ekanalyzer_module_type for a list of valid type. +***************************************************************************/ +static int +ipmi_ek_get_file_type( char * argument ) +{ + // int index_name=0; + int filetype = ERROR_STATUS; + + if( strlen (argument) > MIN_ARGUMENT ){ + if( strncmp( argument, "oc=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = ON_CARRIER_FRU_FILE; + } + else if( strncmp( argument, "a1=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = A1_AMC_FRU_FILE; + } + else if( strncmp( argument, "a2=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = A2_AMC_FRU_FILE; + } + else if( strncmp( argument, "a3=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = A3_AMC_FRU_FILE; + } + else if( strncmp( argument, "a4=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = A4_AMC_FRU_FILE; + } + else if( strncmp( argument, "b1=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = B1_AMC_FRU_FILE; + } + else if( strncmp( argument, "b2=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = B2_AMC_FRU_FILE; + } + else if( strncmp( argument, "b3=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = B3_AMC_FRU_FILE; + } + else if( strncmp( argument, "b4=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = B4_AMC_FRU_FILE; + } + else if( strncmp( argument, "rt=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = RTM_FRU_FILE; + } + else if( strncmp( argument, "rc=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = CONFIG_FILE; + } + else if( strncmp( argument, "sm=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = SHELF_MANAGER_FRU_FILE; + } + else{ + filetype = ERROR_STATUS; + } + } + return filetype; +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_main +* +* Description: Main program of ekeying analyzer. It calls the appropriate +* function according to the command received. +* +* Restriction: None +* +* Input: ipmi_intf * intf: ? +* int argc : number of argument received +* int ** argv: argument strings +* +* Output: None +* +* Global: None +* +* Return: OK_STATUS as success or ERROR_STATUS as error +* +***************************************************************************/ +int +ipmi_ekanalyzer_main( void * intf, int argc, char ** argv ) +{ + int rc = ERROR_STATUS; + int file_type[MAX_FILE_NUMBER]; + char * filename[MAX_FILE_NUMBER]; + unsigned int argument_offset = 0; + unsigned int type_offset = 0; + /*list des multi record*/ + struct ipmi_ek_multi_header * list_head = NULL; + struct ipmi_ek_multi_header * list_record = NULL; + struct ipmi_ek_multi_header * list_last = NULL; + + set_loglevel(LOG_NOTICE); + if ( (argc == 0) || ( (argc - 1) > MAX_FILE_NUMBER ) ){ + lprintf(LOG_ERR, "Too few or too many arguments."); + ipmi_ekanalyzer_usage(); + rc = ERR_BAD_PARAM; + } + else if ( strcmp(argv[argument_offset], "help") == 0) { + ipmi_ekanalyzer_usage(); + rc = ERR_USAGE; + } + else if ( (strcmp(argv[argument_offset], "frushow") == 0) + && (argc > (MIN_ARGUMENT-1) ) + ){ + for ( type_offset = 0; (int)type_offset < (argc-1); type_offset++ ){ + argument_offset++; + file_type[type_offset] = ipmi_ek_get_file_type (argv[argument_offset]); + if ( file_type[type_offset] != ERROR_STATUS ){ + if ( file_type[type_offset] != CONFIG_FILE ){ + /* because of strlen doesn't count '\0', we need to add 1 byte for + * this character to filename size + */ + filename[type_offset] = malloc( strlen(argv[argument_offset]) + 1 + - SIZE_OF_FILE_TYPE + ); + if( filename[type_offset] != NULL ){ + strcpy(filename[type_offset], + &argv[argument_offset][SIZE_OF_FILE_TYPE]); + printf("Start converting file '%s'...\n", filename[type_offset]); + /* Display FRU header offset */ + rc = ipmi_ek_display_fru_header (filename[type_offset]); + + if ( rc != ERROR_STATUS ){ + /* Display FRU header info in detail record */ + ipmi_ek_display_fru_header_detail (filename[type_offset]); + /* Convert from binary data into multi record structure */ + rc = ipmi_ekanalyzer_fru_file2structure ( filename[type_offset], + &list_head, &list_record, &list_last ); + + ipmi_ek_display_record ( list_record, list_head, list_last ); + /* Remove record of list */ + while ( list_head != NULL ){ + ipmi_ek_remove_record_from_list( list_head, + &list_head,&list_last ); + if (verbose > 1) + printf("record has been removed!\n"); + } + } + free (filename[type_offset]); + } + } + } + else{ + lprintf(LOG_ERR, "Invalid file type!"); + lprintf(LOG_ERR, " ekanalyzer frushow <xx=frufile> ..."); + } + } + } + else if ( (strcmp(argv[argument_offset], "print") == 0) + || (strcmp(argv[argument_offset], "summary") == 0) + ){ + /*Display help of the correspond command if there is not enought argument + * passing in command line + */ + if ( argc < MIN_ARGUMENT ){ + printf("Too few argument! \n"); + if ( strcmp(argv[argument_offset], "print") == 0 ){ + lprintf(LOG_ERR, " ekanalyzer print [carrier/power/all]" + " <xx=frufile> <xx=frufile> [xx=frufile]" + ); + } + else{ + lprintf(LOG_ERR, " ekanalyzer summary [match/ unmatch/ all]" + " <xx=frufile> <xx=frufile> [xx=frufile]" + ); + } + } + else{ + char * option; + /*index=1 indicates start position of first file name in command line*/ + int index = 1; + int filename_size=0; + + argument_offset++; + if ( (strcmp(argv[argument_offset], "carrier") == 0) + || (strcmp(argv[argument_offset], "power") == 0) + || (strcmp(argv[argument_offset], "all") == 0) + ){ + option = argv[argument_offset]; + index ++; + argc--; + } + else if ( ( strcmp(argv[argument_offset], "match") == 0 ) + || ( strcmp(argv[argument_offset], "unmatch") == 0 ) + ){ + option = argv[argument_offset]; + index ++; + argc--; + } + /*since the command line must receive xx=filename, so the position of + * "=" sign is 2 + */ + else if ( strncmp(&argv[argument_offset][2], "=", 1) == 0 ){ + option = "default"; + /* Since there is no option from user, the first argument + * becomes first file type */ + index = 1; /* index of argument */ + } + else{ + option = "invalid"; + printf("Invalid option '%s'\n", argv[argument_offset]); + argument_offset--; + if (strcmp(argv[0], "print") == 0){ + lprintf (LOG_ERR, " ekanalyzer print [carrier/power/all]" + " <xx=frufile> <xx=frufile> [xx=frufile]" + ); + } + else{ + lprintf (LOG_ERR, " ekanalyzer summary [match/ unmatch/ all]" + " <xx=frufile> <xx=frufile> [xx=frufile]" + ); + } + rc = ERROR_STATUS; + } + if ( strcmp(option, "invalid") != 0 ){ + int i=0; + + for ( i = 0; i < (argc-1); i++){ + file_type[i] = ipmi_ek_get_file_type (argv[index]); + if ( file_type[i] == ERROR_STATUS ){ + /* display the first 2 charactors (file type) of argument */ + lprintf(LOG_ERR, "Invalid file type: %c%c\n", argv[index][0], + argv[index][1]); + ipmi_ekanalyzer_usage(); + rc = ERROR_STATUS; + break; + } + /*size is equal to string size minus 3 bytes of file type plus + * 1 byte of '\0' since the strlen doesn't count the '\0' + */ + filename_size = strlen_( argv[index] ) - SIZE_OF_FILE_TYPE + 1; + if ( filename_size > 0 ){ + filename[i] = malloc( filename_size ); + if (filename[i] != NULL) + strcpy( filename[i], &argv[index][SIZE_OF_FILE_TYPE] ); + } + rc = OK_STATUS; + index++; + } + if ( rc != ERROR_STATUS ){ + if (verbose > 0){ + for (i = 0; i < (argc-1); i++){ + printf ("Type: %s, ", + val2str((uint16_t)file_type[i], + ipmi_ekanalyzer_module_type)); + printf("file name: %s\n", filename[i]); + } + } + if (strcmp(argv[0], "print") == 0){ + rc = ipmi_ekanalyzer_print( + (argc-1), option, filename, file_type); + } + else{ + rc = ipmi_ekanalyzer_ekeying_match( + (argc-1), option, filename, file_type); + } + for (i = 0; i < (argc-1); i++){ + if (filename[i] != NULL){ + free (filename[i]); + } + } + } /* End of ERROR_STATUS */ + } /* End of comparison of invalid option */ + } /* End of else MIN_ARGUMENT */ + } /* End of print or summary option */ + else{ + lprintf(LOG_ERR, "Invalid ekanalyzer command: %s", argv[0]); + ipmi_ekanalyzer_usage(); + rc = ERROR_STATUS; + } + + return rc; +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_print +* +* Description: this function will display the topology, power or both +* information together according to the option that it received. +* +* Restriction: None +* +* Input: int argc: number of the argument received +* char* opt: option string that will tell what to display +* char** filename: strings that contained filename of FRU data binary file +* int* file_type: a pointer that contain file type (on carrier file, +* a1 file, b1 file...). See structure +* ipmi_ekanalyzer_module_type for a list of valid type +* +* Output: None +* +* Global: None +* +* Return: return 0 as success and -1 as error. +* +***************************************************************************/ +static int +ipmi_ekanalyzer_print( int argc,char * opt, char ** filename, int * file_type ) +{ + int return_value = OK_STATUS; + + /*Display carrier topology*/ + if ( (strcmp(opt, "carrier") == 0) || (strcmp(opt, "default") == 0) ){ + tboolean found_flag = FALSE; + int index = 0; + int index_name[MAX_ARGC]; + int list = 0; + /*list of multi record*/ + struct ipmi_ek_multi_header * list_head[MAX_ARGC]; + struct ipmi_ek_multi_header * list_record[MAX_ARGC]; + struct ipmi_ek_multi_header * list_last[MAX_ARGC]; + + for ( list=0; list < argc; list++ ){ + list_head[list] = NULL; + list_record[list] = NULL; + list_last[list] = NULL; + } + + list=0; /* reset list count */ + for ( index = 0; index < argc; index++ ){ + if ( file_type[index] == ON_CARRIER_FRU_FILE ){ + index_name[list] = index; + return_value = ipmi_ekanalyzer_fru_file2structure( filename[index], + &list_head[list], &list_record[list], &list_last[list] ); + list++; + found_flag = TRUE; + } + } + if ( !found_flag ){ + printf("No carrier file has been found\n"); + return_value = ERROR_STATUS; + } + else{ + int i = 0; + for ( i = 0; i < argc; i++ ){ + /*this is a flag to advoid displaying the same data multiple time*/ + tboolean first_data = TRUE; + for ( list_record[i] = list_head[i]; + list_record[i] != NULL; + list_record[i] = list_record[i]->next ){ + if ( list_record[i]->data[PICMG_ID_OFFSET] + == + FRU_AMC_CARRIER_P2P ){ + if ( first_data ){ + printf("%s\n", STAR_LINE_LIMITER); + printf("From Carrier file: %s\n", filename[index_name[i]]); + first_data = FALSE; + } + return_value = ipmi_ek_diplay_carrier_connectivity( + list_record[i] ); + } + else if ( list_record[i]->data[PICMG_ID_OFFSET] + == + FRU_AMC_CARRIER_INFO ){ + /*See AMC.0 specification Table3-3 for mor detail*/ + #define COUNT_OFFSET 6 + if ( first_data ){ + printf("From Carrier file: %s\n", filename[index_name[i]]); + first_data = FALSE; + } + printf(" Number of AMC bays supported by Carrier: %d\n", + list_record[i]->data[COUNT_OFFSET] ); + } + } + } + /*Destroy the list of record*/ + for ( i = 0; i < argc; i++ ){ + while ( list_head[i] != NULL ){ + ipmi_ek_remove_record_from_list( list_head[i], + &list_head[i], &list_last[i] ); + } + /* display deleted result when we reach the last record */ + if ( ( i == (list-1) ) && verbose ) + printf("Record list has been removed successfully\n"); + } + } + } + else if ( (strcmp(opt, "power") == 0) ){ + printf("Print power information\n"); + return_value = ipmi_ek_display_power(argc, opt, filename, file_type); + } + else if ( strcmp(opt, "all") == 0 ){ + printf("Print all information\n"); + return_value = ipmi_ek_display_power(argc, opt, filename, file_type); + } + else{ + lprintf(LOG_ERR, "Invalid option %s", opt); + return_value = ERROR_STATUS; + } + return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_carrier_connectivity +* +* Description: Display the topology between a Carrier and all AMC modules by +* using carrier p2p connectivity record +* +* Restriction: Ref: AMC.0 Specification: Table 3-13 and Table 3-14 +* +* Input: struct ipmi_ek_multi_header* record: a pointer to the carrier p2p +* connectivity record. +* +* Output: None +* +* Global: None +* +* Return: return 0 on success and -1 if the record doesn't exist. +* +***************************************************************************/ +static int +ipmi_ek_diplay_carrier_connectivity( struct ipmi_ek_multi_header * record ) +{ + int return_value = ERROR_STATUS; + struct fru_picmgext_carrier_p2p_record rsc_desc; + struct fru_picmgext_carrier_p2p_descriptor port_desc; + + if ( record == NULL ){ + lprintf(LOG_ERR, "P2P connectivity record is invalid\n"); + return_value = ERROR_STATUS; + } + else{ + int offset = START_DATA_OFFSET; + if ( verbose > 1 ){ + int k = 0; + printf("Binary data of Carrier p2p connectivity"\ + " record starting from mfg id\n"); + for ( k = 0; k < ( record->header.len ); k++ ){ + printf("%02x ", record->data[k]); + } + printf("\n"); + } + while ( offset <= (record->header.len - START_DATA_OFFSET) ){ + rsc_desc.resource_id = record->data[offset++]; + rsc_desc.p2p_count = record->data[offset++]; + if ( verbose > 0 ){ + printf("resource id= %02x port count= %d\n", + rsc_desc.resource_id,rsc_desc.p2p_count); + } + /*check if it is an AMC Module*/ + if ( ( (rsc_desc.resource_id & AMC_MODULE) ) == AMC_MODULE ) { + /*check if it is an RTM module*/ + if (rsc_desc.resource_id == AMC_MODULE) { + printf(" %s topology:\n", val2str( RTM_IPMB_L, + ipmi_ekanalyzer_IPMBL_addr)); + } + else{ + /*The last four bits of resource ID represent site number + * (mask = 0x0f) + */ + printf(" %s topology:\n", + val2str( (rsc_desc.resource_id & 0x0f), + ipmi_ekanalyzer_module_type)); + } + } + else{ + printf(" On Carrier Device ID %d topology: \n", + (rsc_desc.resource_id & 0x0f)); + } + while ( rsc_desc.p2p_count > 0 ){ + memcpy ( &port_desc, &record->data[offset], + sizeof ( struct fru_picmgext_carrier_p2p_descriptor ) ); + offset += sizeof ( struct fru_picmgext_carrier_p2p_descriptor ); + if ( (port_desc.remote_resource_id & AMC_MODULE) == AMC_MODULE ){ + printf("\tPort %d =====> %s, Port %d\n", port_desc.local_port, + val2str( (port_desc.remote_resource_id & 0x0f), + ipmi_ekanalyzer_module_type), port_desc.remote_port ); + } + else{ + printf("\tPort %d =====> On Carrier Device ID %d, Port %d\n", + port_desc.local_port,(port_desc.remote_resource_id & 0x0f), + port_desc.remote_port ); + } + rsc_desc.p2p_count--; + } + } + return_value = OK_STATUS; + } + return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_power +* +* Description: Display the power management of the Carrier and AMC module by +* using current management record. If the display option equal to all, +* it will display power and carrier topology together. +* +* Restriction: Reference: AMC.0 Specification, Table 3-11 +* +* Input: int argc: number of the argument received +* char* opt: option string that will tell what to display +* char** filename: strings that contained filename of FRU data binary file +* int* file_type: a pointer that contain file type (on carrier file, +* a1 file, b1 file...) +* +* Output: None +* +* Global: None +* +* Return: return 0 on success and -1 if the record doesn't exist. +* +***************************************************************************/ +static int +ipmi_ek_display_power(int argc, char * opt, char ** filename, int * file_type) +{ + int num_file=0; + int return_value = ERROR_STATUS; + int index = 0; + + /*list des multi record*/ + struct ipmi_ek_multi_header * list_head[MAX_ARGC]; + struct ipmi_ek_multi_header * list_record[MAX_ARGC]; + struct ipmi_ek_multi_header * list_last[MAX_ARGC]; + + for ( num_file = 0; num_file < argc; num_file++ ){ + list_head[num_file] = NULL; + list_record[num_file] = NULL; + list_last[num_file] = NULL; + } + + for ( num_file = 0; num_file < argc; num_file++ ){ + tboolean is_first_data = TRUE; + if ( file_type[num_file] == CONFIG_FILE ){ + num_file++; + } + + if ( is_first_data ){ + printf("%s\n", STAR_LINE_LIMITER); + printf("\nFrom %s file '%s'\n", + val2str( (uint16_t)file_type[num_file], + ipmi_ekanalyzer_module_type), + filename[num_file]); + is_first_data = FALSE; + } + + return_value = ipmi_ekanalyzer_fru_file2structure( filename[num_file], + &list_head[num_file], &list_record[num_file], &list_last[num_file]); + + if ( list_head[num_file] != NULL ){ + for ( list_record[num_file] = list_head[num_file]; + list_record[num_file] != NULL; + list_record[num_file] = list_record[num_file]->next + ){ + if ( ( strcmp(opt, "all") == 0 ) + && ( file_type[num_file] == ON_CARRIER_FRU_FILE ) + ){ + if ( list_record[num_file]->data[PICMG_ID_OFFSET] + == + FRU_AMC_CARRIER_P2P + ){ + return_value = ipmi_ek_diplay_carrier_connectivity( + list_record[num_file] ); + } + else if ( list_record[num_file]->data[PICMG_ID_OFFSET] + == + FRU_AMC_CARRIER_INFO + ){ + /*Ref: See AMC.0 Specification Table 3-3: Carrier Information + * Table about offset value + */ + printf( " Number of AMC bays supported by Carrier: %d\n", + list_record[num_file]->data[START_DATA_OFFSET+1] ); + } + } + /*Ref: AMC.0 Specification: Table 3-11 + * Carrier Activation and Current Management Record + */ + if ( list_record[num_file]->data[PICMG_ID_OFFSET] + == + FRU_AMC_ACTIVATION + ){ + int index_data = START_DATA_OFFSET; + struct fru_picmgext_carrier_activation_record car; + struct fru_picmgext_activation_record * cur_desc; + + memcpy ( &car, &list_record[num_file]->data[index_data], + sizeof (struct fru_picmgext_carrier_activation_record) ); + index_data += + sizeof (struct fru_picmgext_carrier_activation_record); + cur_desc = malloc (car.module_activation_record_count * \ + sizeof (struct fru_picmgext_activation_record) ); + for(index=0; index<car.module_activation_record_count; index++){ + memcpy( &cur_desc[index], + &list_record[num_file]->data[index_data], + sizeof (struct fru_picmgext_activation_record) ); + + index_data += sizeof (struct fru_picmgext_activation_record); + } + /*Display the current*/ + ipmi_ek_display_current_descriptor( car, + cur_desc, filename[num_file] ); + free (cur_desc); + } + /*Ref: AMC.0 specification, Table 3-10: Module Current Requirement*/ + else if ( list_record[num_file]->data[PICMG_ID_OFFSET] + == FRU_AMC_CURRENT + ){ + float power_in_watt = 0; + float current_in_amp = 0; + + printf(" %s power required (Current Draw): ", + val2str ( (uint16_t)file_type[num_file], ipmi_ekanalyzer_module_type) ); + current_in_amp = + (float)(list_record[num_file]->data[START_DATA_OFFSET]*0.1); + power_in_watt = current_in_amp * AMC_VOLTAGE; + printf("%.2f Watts (%.2f Amps)\n",power_in_watt, current_in_amp); + } + } + return_value = OK_STATUS; + /*Destroy the list of record*/ + for ( index = 0; index < argc; index++ ){ + while ( list_head[index] != NULL ){ + ipmi_ek_remove_record_from_list ( list_head[index], + &list_head[index],&list_last[index] ); + } + if ( verbose > 1 ) + printf("Record list has been removed successfully\n"); + } + } + } + printf("%s\n", STAR_LINE_LIMITER); + return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_current_descriptor +* +* Description: Display the current descriptor under format xx Watts (xx Amps) +* +* Restriction: None +* +* Input: struct fru_picmgext_carrier_activation_record car: contain binary data +* of carrier activation record +* struct fru_picmgext_activation_record * cur_desc: contain current +* descriptor +* char* filename: strings that contained filename of FRU data binary file +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_current_descriptor( + struct fru_picmgext_carrier_activation_record car, + struct fru_picmgext_activation_record * cur_desc, char * filename ) +{ + int index = 0; + float power_in_watt = 0.0; + float current_in_amp = 0.0; + + for ( index = 0; index < car.module_activation_record_count; index++ ){ + /*See AMC.0 specification, Table 3-12 for detail about calculation*/ + current_in_amp = (float)(cur_desc[index].max_module_curr * 0.1); + power_in_watt = (float) current_in_amp * AMC_VOLTAGE; + + printf(" Carrier AMC power available on %s:\n", + val2str( cur_desc[index].ibmb_addr, ipmi_ekanalyzer_IPMBL_addr ) ); + printf("\t- Local IPMB Address \t: %02x\n", cur_desc[index].ibmb_addr); + printf("\t- Maximum module Current\t: %.2f Watts (%.2f Amps)\n", + power_in_watt, current_in_amp ); + } + /*Display total power on Carrier*/ + current_in_amp = (float)(car.max_internal_curr * 0.1); + power_in_watt = (float) current_in_amp * AMC_VOLTAGE; + printf(" Carrier AMC total power available for all bays from file '%s':", + filename); + printf(" %.2f Watts (%.2f Amps)\n", power_in_watt, current_in_amp ); +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_ekeying_match +* +* Description: Check for possible Ekeying match between two FRU files +* +* Restriction: None +* +* Input: argc: number of the argument received +* opt: string that contains display option received from user. +* filename: strings that contained filename of FRU data binary file +* file_type: a pointer that contain file type (on carrier file, +* a1 file, b1 file...) +* +* Output: None +* +* Global: None +* +* Return: return TRUE on success and FALSE if the record doesn't exist. +* +***************************************************************************/ +static tboolean +ipmi_ekanalyzer_ekeying_match( int argc, char * opt, + char ** filename, int * file_type ) +{ + tboolean return_value = FALSE; + + if ( (strcmp(opt, "carrier") == 0 ) || (strcmp(opt, "power") == 0) ){ + lprintf(LOG_ERR, " ekanalyzer summary [match/ unmatch/ all]"\ + " <xx=frufile> <xx=frufile> [xx=frufile]"); + return_value = ERROR_STATUS; + } + else{ + int num_file=0; + // int index_data = 0; + // int first_data = 1; + tboolean amc_file = FALSE; /*used to indicate the present of AMC file*/ + tboolean oc_file = FALSE; /*used to indicate the present of Carrier file*/ + + /*Check for possible ekeying match between files*/ + for ( num_file=0; num_file < argc; num_file++ ){ + if ( ( file_type[num_file] == ON_CARRIER_FRU_FILE ) + || ( file_type[num_file] == CONFIG_FILE ) + || ( file_type[num_file] == SHELF_MANAGER_FRU_FILE ) + ){ + amc_file = FALSE; + } + else { /*there is an amc file*/ + amc_file = TRUE; + break; + } + } + if ( amc_file == FALSE ){ + printf("\nNo AMC FRU file is provided --->" \ + " No possible ekeying match!\n"); + return_value = ERROR_STATUS; + } + else{ + /*If no carrier file is provided, return error*/ + for ( num_file=0; num_file < argc; num_file++ ){ + if ( (file_type[num_file] == ON_CARRIER_FRU_FILE ) + || ( file_type[num_file] == CONFIG_FILE ) + || ( file_type[num_file] == SHELF_MANAGER_FRU_FILE ) + ){ + oc_file = TRUE; + break; + } + } + if ( !oc_file ){ + printf("\nNo Carrier FRU file is provided" \ + " ---> No possible ekeying match!\n"); + return_value = ERROR_STATUS; + } + else{ + /*list des multi record*/ + struct ipmi_ek_multi_header * list_head[MAX_ARGC]; + struct ipmi_ek_multi_header * list_record[MAX_ARGC]; + struct ipmi_ek_multi_header * list_last[MAX_ARGC]; + struct ipmi_ek_multi_header * pcarrier_p2p = NULL; + int list = 0; + int match_pair = 0; + // tboolean match_result = FALSE; + + /*Create an empty list*/ + for ( list=0; list<argc; list++ ){ + list_head[list] = NULL; + list_record[list] = NULL; + list_last[list] = NULL; + } + list=0; + + for ( num_file=0; num_file < argc; num_file++ ){ + if (file_type[num_file] != CONFIG_FILE){ + return_value = ipmi_ekanalyzer_fru_file2structure( + filename[num_file], &list_head[num_file], + &list_record[num_file], &list_last[num_file]); + } + } + /*Get Carrier p2p connectivity record for physical check*/ + for (num_file=0; num_file < argc; num_file++){ + if (file_type[num_file] == ON_CARRIER_FRU_FILE ){ + for ( pcarrier_p2p=list_head[num_file]; + pcarrier_p2p != NULL ; + pcarrier_p2p = pcarrier_p2p->next + ){ + if ( pcarrier_p2p->data[PICMG_ID_OFFSET] + == FRU_AMC_CARRIER_P2P + ){ + break; + } + } + break; + } + } + /*Determine the match making pair*/ + while ( match_pair < argc ){ + for ( num_file = (match_pair+1); num_file<argc; num_file++ ){ + if ( ( file_type[match_pair] != CONFIG_FILE ) + && ( file_type[num_file] != CONFIG_FILE ) + ){ + if ( ( file_type[match_pair] != ON_CARRIER_FRU_FILE ) + || ( file_type[num_file] != ON_CARRIER_FRU_FILE ) + ){ + printf("%s vs %s\n", + val2str((uint16_t)file_type[match_pair], + ipmi_ekanalyzer_module_type), + val2str((uint16_t)file_type[num_file], + ipmi_ekanalyzer_module_type)); + /*Ekeying match between 2 files*/ + if (verbose>0){ + printf("Start matching process\n"); + } + return_value = ipmi_ek_matching_process( file_type, + match_pair, num_file, list_head, + list_last, opt, pcarrier_p2p); + } + } + } + match_pair ++; + } + for( num_file=0; num_file < argc; num_file++ ){ + if (list_head[num_file] != NULL ){ + ipmi_ek_remove_record_from_list( list_head[num_file], + &list_record[num_file], &list_last[num_file]); + } + if ( ( num_file == argc-1 ) && verbose ) + printf("Record list has been removed successfully\n"); + } + return_value = OK_STATUS; + } + } + } + return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_matching_process +* +* Description: This function process the OEM check, Physical Connectivity check, +* and Link Descriptor comparison to do Ekeying match +* +* Restriction: None +* +* Input: file_type: a pointer that contain file type (on carrier file, +* a1 file, b1 file...) +* index1: position of the first record in the list of the record +* index2: position of the second record in the list of the record +* ipmi_ek_multi_header ** list_head: pointer to the header of a +* linked list that contain FRU multi record +* ipmi_ek_multi_header ** list_last: pointer to the tale of a +* linked list that contain FRU multi record +* opt: string that contain display option such as "match", "unmatch", or +* "all". +* pphysical: a pointer that contain a carrier p2p connectivity record +* to perform physical check +* +* Output: None +* +* Global: None +* +* Return: return OK_STATUS on success and ERROR_STATUS if the record doesn't +* exist. +* +***************************************************************************/ +static int ipmi_ek_matching_process( int * file_type, int index1, int index2, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last, char * opt, + struct ipmi_ek_multi_header * pphysical ) +{ + int result = ERROR_STATUS; + struct ipmi_ek_multi_header * record; + int num_amc_record1 = 0;/*Number of AMC records in the first module*/ + int num_amc_record2 = 0;/*Number of AMC records in the second module*/ + + /* Comparison between an On-Carrier and an AMC*/ + if ( file_type[index2] == ON_CARRIER_FRU_FILE ){ + int index_temp = 0; + index_temp = index1; + index1 = index2; /*index1 indicate on carrier*/ + index2 = index_temp; /*index2 indcate an AMC*/ + } + /*Calculate record size for Carrier file*/ + for ( record=list_head[index1]; record != NULL;record = record->next ){ + if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ + num_amc_record2++; + } + } + /*Calculate record size for amc file*/ + for ( record=list_head[index2]; record != NULL;record = record->next){ + if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ + num_amc_record1++; + } + } + if ( (num_amc_record1 > 0) && (num_amc_record2 > 0) ){ + int index_record1 = 0; + int index_record2 = 0; + /* Multi records of AMC module */ + struct ipmi_ek_amc_p2p_connectivity_record * amc_record1 = NULL; + /* Multi records of Carrier or an AMC module */ + struct ipmi_ek_amc_p2p_connectivity_record * amc_record2 = NULL; + + amc_record1 = malloc ( num_amc_record1 * \ + sizeof(struct ipmi_ek_amc_p2p_connectivity_record)); + amc_record2 = malloc ( num_amc_record2 * \ + sizeof(struct ipmi_ek_amc_p2p_connectivity_record)); + + for (record=list_head[index2]; record != NULL;record = record->next){ + if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ + result = ipmi_ek_create_amc_p2p_record( record, + &amc_record1[index_record1] ); + if (result != ERROR_STATUS){ + struct ipmi_ek_multi_header * current_record = NULL; + + for ( current_record=list_head[index1]; + current_record != NULL ; + current_record = current_record->next + ){ + if ( current_record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ + result = ipmi_ek_create_amc_p2p_record( current_record, + &amc_record2[index_record2] ); + if ( result != ERROR_STATUS ){ + if ( result == OK_STATUS ){ + /*Compare Link descriptor*/ + result = ipmi_ek_compare_link ( pphysical, + amc_record1[index_record1], + amc_record2[index_record2], + opt, file_type[index1], file_type[index2]); + } + index_record2++; + } + } /*end of FRU_AMC_P2P */ + } /* end of for loop */ + index_record1++; + } + } + } + free(amc_record1) ; + free(amc_record2) ; + } + else{ + printf("No amc record is found!\n"); + } + + return result; +} + +/************************************************************************** +* +* Function name: ipmi_ek_check_physical_connectivity +* +* Description: This function check for point to point connectivity between +* two modules by comparing each enable port in link descriptor +* with local and remote ports of port descriptor in +* carrier point-to-point connectivity record according to the +* corresponding file type ( a1, b1, b2...). +* +* Restriction: In order to perform physical check connectivity, it needs to +* compare between 2 AMC Modules, so the use of index ( 1 and 2 ) +* can facilitate the comparison in this case. +* +* Input: record1: is an AMC p2p record for an AMC module +* record2 is an AMC p2p record for an On-Carrier record or an AMC module +* char* opt: option string that will tell if a matching result, unmatched +* result or all the results will be displayed. +* file_type1: indicates type of the first module +* file_type2: indicates type of the second module +* +* Output: None +* +* Global: None +* +* Return: return OK_STATUS if both link are matched, otherwise +* return ERROR_STATUS +* +***************************************************************************/ +static int +ipmi_ek_check_physical_connectivity( + struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, + struct ipmi_ek_amc_p2p_connectivity_record record2, int index2, + struct ipmi_ek_multi_header * record, + int filetype1, int filetype2, char * option ) +{ + int return_status = OK_STATUS; + + if ( record == NULL ){ + printf("NO Carrier p2p connectivity !\n"); + return_status = ERROR_STATUS; + } + else{ + #define INVALID_AMC_SITE_NUMBER -1 + int index = START_DATA_OFFSET; + int amc_site = INVALID_AMC_SITE_NUMBER; + struct fru_picmgext_carrier_p2p_record rsc_desc; + struct fru_picmgext_carrier_p2p_descriptor * port_desc = NULL; + + /* Get the physical connectivity record */ + while ( index < record->header.len ) { + rsc_desc.resource_id = record->data[index++]; + rsc_desc.p2p_count = record->data[index++]; + /* carrier p2p record starts with on-carrier device */ + if ( (rsc_desc.resource_id == record1.rsc_id) + || + (rsc_desc.resource_id == record2.rsc_id) + ){ + if (rsc_desc.p2p_count <= 0){ + printf("No p2p count\n"); + return_status = ERROR_STATUS; + } + else{ + port_desc = malloc ( rsc_desc.p2p_count * + sizeof(struct fru_picmgext_carrier_p2p_descriptor) ); + index = ipmi_ek_get_resource_descriptor( rsc_desc.p2p_count, + index, port_desc, record ); + amc_site = INVALID_AMC_SITE_NUMBER; + break; + } + } + else{ /* carrier p2p record starts with AMC module */ + if (rsc_desc.resource_id == AMC_MODULE){ + if (filetype1 != ON_CARRIER_FRU_FILE){ + amc_site = filetype1; + } + else{ + amc_site = filetype2; + } + } + else{ + amc_site = rsc_desc.resource_id & 0x0f; + } + if ( amc_site > 0 ){ + if ( (amc_site == filetype1) || (amc_site == filetype2) ){ + port_desc = malloc ( rsc_desc.p2p_count * + sizeof(struct fru_picmgext_carrier_p2p_descriptor) ); + index = ipmi_ek_get_resource_descriptor( rsc_desc.p2p_count, + index, port_desc, record ); + break; + } + } + else{ + return_status = ERROR_STATUS; + } + } + /*If the record doesn't contain the same AMC site number in command + * line, go to the next record + */ + index += ( sizeof(struct fru_picmgext_carrier_p2p_descriptor) * + rsc_desc.p2p_count ); + } + + if ( (port_desc != NULL) && (return_status != ERROR_STATUS) ){ + int j=0; + + for ( j = 0; j < rsc_desc.p2p_count; j++ ){ + /* Compare only enable channel descriptor */ + if ( record1.ch_desc[index1].lane0port != DISABLE_PORT ){ + /* matching result from channel descriptor comparison */ + tboolean match_lane = FALSE; + + match_lane = ipmi_ek_compare_channel_descriptor ( + record1.ch_desc[index1], record2.ch_desc[index2], + port_desc, j, rsc_desc.resource_id ); + + if ( match_lane ){ + if ( filetype1 != ON_CARRIER_FRU_FILE ){ + if ( ( + (filetype1 == (rsc_desc.resource_id & 0x0f)) + && + (filetype2 ==(port_desc[j].remote_resource_id &0x0f)) + ) + || + ( + (filetype2 == (rsc_desc.resource_id & 0x0f)) + && + (filetype1 ==(port_desc[j].remote_resource_id &0x0f)) + ) + ){ + if ( ! (strcmp(option, "unmatch") == 0) ){ + printf("%s port %d ==> %s port %d\n", + val2str((uint16_t)filetype2, ipmi_ekanalyzer_module_type), + record1.ch_desc[index1].lane0port, + val2str((uint16_t)filetype1, ipmi_ekanalyzer_module_type), + record2.ch_desc[index2].lane0port); + } + return_status = OK_STATUS; + + break; + } + else{ + if (verbose >= 2){ //was == LOG_DEBUG) + printf("No point 2 point connectivity\n"); + } + return_status = ERROR_STATUS; + } + } + else{ + if ( (record2.rsc_id == (rsc_desc.resource_id) ) + && + (filetype2 == (port_desc[j].remote_resource_id & 0x0f)) + ){ + if ( ! (strcmp(option, "unmatch") == 0) ){ + printf("%s port %d ==> %s port %d\n", + val2str((uint16_t)filetype2, ipmi_ekanalyzer_module_type), + record1.ch_desc[index1].lane0port, + val2str((uint16_t)filetype1, ipmi_ekanalyzer_module_type), + record2.ch_desc[index2].lane0port); + } + return_status = OK_STATUS; + break; + } + else if ( (filetype2 == (rsc_desc.resource_id & 0x0f) ) + && + (record2.rsc_id == (port_desc[j].remote_resource_id)) + ){ + if ( ! (strcmp(option, "unmatch") == 0) ){ + printf("%s port %d ==> %s %x port %d\n", + val2str((uint16_t)filetype2, ipmi_ekanalyzer_module_type), + record1.ch_desc[index1].lane0port, + val2str((uint16_t)filetype1, ipmi_ekanalyzer_module_type), + record2.rsc_id,record2.ch_desc[index2].lane0port); + } + return_status = OK_STATUS; + break; + } + else{ + if (verbose >= 2){ //was == LOG_DEBUG + printf("No point 2 point connectivity\n"); + } + return_status = ERROR_STATUS; + } + } + } + else{ + if (verbose >= 2){ //was == LOG_DEBUG + printf("No point 2 point connectivity\n"); + } + return_status = ERROR_STATUS; + } + } + else{ /*If the link is disable, the result is always true*/ + return_status = OK_STATUS; + } + } + } + else{ + if (verbose >= 2) { //was == LOG_WARN + printf("Invalid Carrier p2p connectivity record\n"); + } + return_status = ERROR_STATUS; + } + if (port_desc != NULL){ + free (port_desc); + } + } + return return_status; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_link +* +* Description: This function compares link grouping id of each +* amc p2p connectiviy record +* +* Restriction: None +* +* Input: record1: is an AMC p2p record for an AMC module +* record2 is an AMC p2p record for an On-Carrier record or an AMC module +* char* opt: option string that will tell if a matching result, unmatched +* result or all the results will be displayed. +* file_type1: indicates type of the first module +* file_type2: indicates type of the second module +* +* Output: None +* +* Global: None +* +* Return: return 0 if both link are matched, otherwise return -1 +* +***************************************************************************/ +static int +ipmi_ek_compare_link( struct ipmi_ek_multi_header * physic_record, + struct ipmi_ek_amc_p2p_connectivity_record record1, + struct ipmi_ek_amc_p2p_connectivity_record record2, char * opt, + int file_type1, int file_type2 ) +{ + int result = ERROR_STATUS; + int index1 = 0; /*index for AMC module*/ + int index2 = 0; /*index for On-carrier type*/ + + record1.matching_result = malloc ( record1.link_desc_count * sizeof(int) ); + record2.matching_result = malloc ( record2.link_desc_count * sizeof(int) ); + /*Initialize all the matching_result to false*/ + for( index2 = 0; index2 < record2.link_desc_count; index2++ ){ + record2.matching_result[index2] = FALSE; + } + for( index1 = 0; index1 < record1.link_desc_count; index1++ ){ + for( index2 = 0; index2 < record2.link_desc_count; index2++ ){ + if( record1.link_desc[index1].group_id == 0 ){ + if( record2.link_desc[index2].group_id == 0 ){ + result = ipmi_ek_compare_link_descriptor( + record1, index1, record2, index2 ); + if ( result == OK_STATUS ){ + /*Calculate the index for Channel descriptor in function of + * link designator channel ID + */ + /*first channel_id in the AMC Link descriptor of record1*/ + static int flag_first_link1; + int index_ch_desc1; /*index of channel descriptor */ + /*first channel_id in the AMC Link descriptor of record2*/ + static int flag_first_link2; + int index_ch_desc2; /*index of channel descriptor*/ + + if (index1==0){ /*this indicate the first link is encounter*/ + flag_first_link1 = record1.link_desc[index1].channel_id; + } + index_ch_desc1 = record1.link_desc[index1].channel_id - + flag_first_link1; + if (index2==0){ + flag_first_link2 = record2.link_desc[index2].channel_id; + } + index_ch_desc2 = record2.link_desc[index2].channel_id - + flag_first_link2; + /*Check for physical connectivity for each link*/ + result = ipmi_ek_check_physical_connectivity ( record1, + index_ch_desc1, record2, index_ch_desc2, + physic_record, file_type1, file_type2, opt ); + if ( result == OK_STATUS ){ + /*Display the result if option = match or all*/ + if ( (strcmp( opt, "match" ) == 0) + || (strcmp( opt, "all" ) == 0) + || (strcmp( opt, "default" ) == 0) + ){ + tboolean isOEMtype = FALSE; + printf(" Matching Result\n"); + isOEMtype = ipmi_ek_display_link_descriptor( file_type1, + record2.rsc_id, + "From", record2.link_desc[index2]); + if (isOEMtype){ + ipmi_ek_display_oem_guid (record2); + } + isOEMtype = ipmi_ek_display_link_descriptor( file_type2, + record1.rsc_id, + "To", record1.link_desc[index1] ); + if (isOEMtype){ + ipmi_ek_display_oem_guid (record1); + } + printf(" %s\n", STAR_LINE_LIMITER); + } + record2.matching_result[index2] = TRUE; + record1.matching_result[index1] = TRUE; + /*quit the fist loop since the match is found*/ + index2 = record2.link_desc_count; + } + } + } + } + else { /*Link Grouping ID is non zero, Compare all link descriptor + * that has non-zero link grouping id together + */ + if (record2.link_desc[index2].group_id != 0 ){ + result = ipmi_ek_compare_link_descriptor( + record1, index1, record2, index2 ); + if ( result == OK_STATUS ){ + /*Calculate the index for Channel descriptor in function of + * link designator channel ID + */ + /*first channel_id in the AMC Link descriptor of record1*/ + static int flag_first_link1; + int index_ch_desc1; /*index of channel descriptor */ + /*first channel_id in the AMC Link descriptor of record2*/ + static int flag_first_link2; + int index_ch_desc2; /*index of channel descriptor*/ + + if (index1==0){ /*this indicate the first link is encounter*/ + flag_first_link1 = record1.link_desc[index1].channel_id; + } + index_ch_desc1 = record1.link_desc[index1].channel_id - + flag_first_link1; + if (index2==0){ + flag_first_link2 = record2.link_desc[index2].channel_id; + } + index_ch_desc2 = record2.link_desc[index2].channel_id - + flag_first_link2; + /*Check for physical connectivity for each link*/ + result = ipmi_ek_check_physical_connectivity ( + record1, index_ch_desc1, record2, index_ch_desc2, + physic_record, file_type1, file_type2, opt ); + if ( result == OK_STATUS ){ + if ( (strcmp( opt, "match" ) == 0) + || (strcmp( opt, "all" ) == 0) + || (strcmp( opt, "default" ) == 0) + ){ + tboolean isOEMtype = FALSE; + printf(" Matching Result\n"); + isOEMtype = ipmi_ek_display_link_descriptor( file_type1, + record2.rsc_id, + "From", record2.link_desc[index2] ); + if ( isOEMtype ){ + ipmi_ek_display_oem_guid (record2); + } + isOEMtype = ipmi_ek_display_link_descriptor( file_type2, + record1.rsc_id, + "To", record1.link_desc[index1] ); + if (isOEMtype){ + ipmi_ek_display_oem_guid (record1); + } + printf(" %s\n", STAR_LINE_LIMITER); + } + record2.matching_result[index2] = TRUE; + record1.matching_result[index1] = TRUE; + /*leave the fist loop since the match is found*/ + index2 = record2.link_desc_count; + } + } + } + } + } + } + + if ( (strcmp(opt, "unmatch") == 0) || (strcmp(opt, "all") == 0) ){ + int isOEMtype = FALSE; + printf(" Unmatching result\n"); + for (index1 = 0; index1 < record1.link_desc_count; index1++){ + isOEMtype = ipmi_ek_display_link_descriptor( file_type2, + record1.rsc_id, "", record1.link_desc[index1] ); + if ( isOEMtype ){ + ipmi_ek_display_oem_guid (record1); + } + printf(" %s\n", STAR_LINE_LIMITER); + } + for ( index2 = 0; index2 < record2.link_desc_count; index2++){ + if ( !record2.matching_result[index2] ){ + isOEMtype = ipmi_ek_display_link_descriptor( file_type1, + record2.rsc_id, "", record2.link_desc[index2] ); + if ( isOEMtype ){ + ipmi_ek_display_oem_guid (record2); + } + printf(" %s\n", STAR_LINE_LIMITER); + } + } + } + + free (record1.matching_result); + free (record2.matching_result); + + return result; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_channel_descriptor +* +* Description: This function compares 2 channel descriptors of 2 AMC +* point-to-point connectivity records with port descriptor of +* carrier point-to-point connectivity record. The comparison is +* made between each enable port only. +* +* Restriction: Reference: AMC.0 specification: +* - Table 3-14 for port descriptor +* - Table 3-17 for channel descriptor +* +* Input: ch_desc1: first channel descriptor +* ch_desc2: second channel descriptor +* port_desc: a pointer that contain a list of port descriptor +* index_port: index of the port descriptor +* rsc_id: resource id that represents as local resource id in the +* resource descriptor table. +* +* Output: None +* +* Global: None +* +* Return: return TRUE if both channel descriptor are matched, +* or FALSE otherwise +* +***************************************************************************/ +static tboolean +ipmi_ek_compare_channel_descriptor( + struct fru_picmgext_amc_channel_desc_record ch_desc1, + struct fru_picmgext_amc_channel_desc_record ch_desc2, + struct fru_picmgext_carrier_p2p_descriptor * port_desc, + int index_port, unsigned char rsc_id ) +{ + tboolean match_lane = FALSE; + + /* carrier p2p record start with AMC_MODULE as local port */ + if ( (rsc_id & AMC_MODULE) == AMC_MODULE ){ + if ( (ch_desc1.lane0port == port_desc[index_port].local_port) + && + (ch_desc2.lane0port == port_desc[index_port].remote_port) + ){ + /*check if the port is enable*/ + if (ch_desc1.lane1port != DISABLE_PORT){ + index_port ++; + if ( (ch_desc1.lane1port == port_desc[index_port].local_port) + && + (ch_desc2.lane1port == port_desc[index_port].remote_port) + ){ + if (ch_desc1.lane2port != DISABLE_PORT){ + index_port++; + if ( (ch_desc1.lane2port == port_desc[index_port].local_port) + && + (ch_desc2.lane2port == port_desc[index_port].remote_port) + ){ + if (ch_desc1.lane3port != DISABLE_PORT){ + index_port++; + if ( (ch_desc1.lane3port == + port_desc[index_port].local_port) + && + (ch_desc2.lane3port == + port_desc[index_port].remote_port) + ){ + match_lane = TRUE; + } + } + else{ + match_lane = TRUE; + } + } /* end of if lane2port */ + } + else{ + match_lane = TRUE; + } + } /* end of if lane1port */ + } + else{ /*if the port is disable, the compare result is always true*/ + match_lane = TRUE; + } + }/* end of if lane0port */ + } + /* carrier p2p record start with Carrier as local port */ + else{ + if ( (ch_desc1.lane0port == port_desc[index_port].remote_port) + && + (ch_desc2.lane0port == port_desc[index_port].local_port) + ){ + if (ch_desc1.lane1port != DISABLE_PORT){ + index_port ++; + if ( (ch_desc1.lane1port == port_desc[index_port].remote_port) + && + (ch_desc2.lane1port == port_desc[index_port].local_port) + ){ + if (ch_desc1.lane2port != DISABLE_PORT){ + index_port++; + if ( (ch_desc1.lane2port == port_desc[index_port].remote_port) + && + (ch_desc2.lane2port == port_desc[index_port].local_port) + ){ + if (ch_desc1.lane3port != DISABLE_PORT){ + index_port++; + if ( (ch_desc1.lane3port == + port_desc[index_port].remote_port) + && + (ch_desc2.lane3port == + port_desc[index_port].local_port) + ){ + match_lane = TRUE; + } + } + else{ + match_lane = TRUE; + } + } /* end of if lane2port */ + } + else{ + match_lane = TRUE; + } + } /* end of if lane1port */ + } + else{ + match_lane = TRUE; + } + } /* end of if lane0port */ + } + + return match_lane; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_link_descriptor +* +* Description: This function compares 2 link descriptors of 2 +* amc p2p connectiviy record +* +* Restriction: None +* +* Input: record1: AMC p2p connectivity record of the 1rst AMC or Carrier Module +* index1: index of AMC link descriptor in 1rst record +* record2: AMC p2p connectivity record of the 2nd AMC or Carrier Module +* index1: index of AMC link descriptor in 2nd record +* +* Output: None +* +* Global: None +* +* Return: return OK_STATUS if both link are matched, +* otherwise return ERROR_STATUS +* +***************************************************************************/ +static int +ipmi_ek_compare_link_descriptor( + struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, + struct ipmi_ek_amc_p2p_connectivity_record record2, int index2 ) +{ + int result = ERROR_STATUS; + + if (record1.link_desc[index1].type == record2.link_desc[index2].type){ + /*if it is an OEM type, we compare the OEM GUID*/ + if ( (record1.link_desc[index1].type >= LOWER_OEM_TYPE) + && (record1.link_desc[index1].type <= UPPER_OEM_TYPE) + ){ + if ( (record1.guid_count == 0) && (record2.guid_count == 0) ){ + /*there is no GUID for comparison, so the result is always OK*/ + result = OK_STATUS; + } + else{ + int i=0; + int j=0; + + for( i=0; i<record1.guid_count; i++){ + for( j=0; j < record2.guid_count; j++){ + if( memcmp (&record1.oem_guid[i], &record2.oem_guid[j], + SIZE_OF_GUID ) + == 0 + ){ + result = OK_STATUS; + break; + } + } + } + } + } + else{ + result = OK_STATUS; + } + if (result == OK_STATUS){ + if (record1.link_desc[index1].type_ext + == record2.link_desc[index2].type_ext + ){ + unsigned char asym[COMPARE_CANDIDATE]; + int offset = 0; + + asym[offset++] = record1.link_desc[index1].asym_match; + asym[offset] = record2.link_desc[index2].asym_match; + result = ipmi_ek_compare_asym ( asym ); + if (result == OK_STATUS){ + struct fru_picmgext_amc_link_desc_record link[COMPARE_CANDIDATE]; + int index = 0; + + link[index++] = record1.link_desc[index1]; + link[index] = record2.link_desc[index2]; + result = ipmi_ek_compare_number_of_enable_port( link ); + } + else{ + result = ERROR_STATUS; + } + } + else{ + result = ERROR_STATUS; + } + } + } + else{ + result = ERROR_STATUS; + } + + return result; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_asym +* +* Description: This function compares 2 asymetric match of 2 +* amc link descriptors +* +* Restriction: None +* +* Input: asym[COMPARE_CANDIDATE]: Contain 2 asymetric match for comparison +* +* Output: None +* +* Global: None +* +* Return: return 0 if both asym. match are matched, otherwise return -1 +* +***************************************************************************/ + +static int +ipmi_ek_compare_asym( unsigned char asym[COMPARE_CANDIDATE] ) +{ + int return_value = ERROR_STATUS; + int first_index = 0; + int second_index = 1; + + if ( (asym[first_index] == 0) && (asym[second_index] == 0) ){ + return_value = OK_STATUS; + } + else if ( (asym[first_index] & asym[second_index]) == 0 ){ + return_value = OK_STATUS; + } + else{ + return_value = ERROR_STATUS; + } + return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_link_descriptor +* +* Description: This function compare number of enble port of Link designator +* +* Restriction: None +* +* Input: link_designator1: first link designator +* link_designator2: second link designator +* +* Output: None +* +* Global: None +* +* Return: return 0 if both link are matched, otherwise return -1 +* +***************************************************************************/ +static int +ipmi_ek_compare_number_of_enable_port( + struct fru_picmgext_amc_link_desc_record link_desc[COMPARE_CANDIDATE] ) +{ + int amc_port_count = 0; + int carrier_port_count = 0; + int return_value = ERROR_STATUS; + int index = 0; + + if (link_desc[index].port_flag_0){ /*bit 0 indicates port 0*/ + amc_port_count++; + } + if (link_desc[index].port_flag_1){ /*bit 1 indicates port 1*/ + amc_port_count++; + } + if (link_desc[index].port_flag_2){ /*bit 2 indicates port 2*/ + amc_port_count++; + } + if (link_desc[index++].port_flag_3){ /*bit 3 indicates port 3*/ + amc_port_count++; + } + + /*2nd link designator*/ + if (link_desc[index].port_flag_0){ /*bit 0 indicates port 0*/ + carrier_port_count++; + } + if (link_desc[index].port_flag_1){ /*bit 1 indicates port 1*/ + carrier_port_count++; + } + if (link_desc[index].port_flag_2){ /*bit 2 indicates port 2*/ + carrier_port_count++; + } + if (link_desc[index].port_flag_3){ /*bit 3 indicates port 3*/ + carrier_port_count++; + } + + if(carrier_port_count == amc_port_count){ + + return_value = OK_STATUS; + } + else{ + return_value = ERROR_STATUS; + } + + return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_link_descriptor +* +* Description: Display the link descriptor of an AMC p2p connectivity record +* +* Restriction: See AMC.0 or PICMG 3.0 specification for detail about bit masks +* +* Input: file_type: module type. +* rsc_id: resource id +* char* str: indicates if it is a source (its value= "From") or a +* destination (its value = "To"). ( it is set to "" if it is not +* a source nor destination +* link_desc: AMC link descriptor +* asym: asymetric match +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static tboolean +ipmi_ek_display_link_descriptor( int file_type, unsigned char rsc_id, + char * str, struct fru_picmgext_amc_link_desc_record link_desc ) +{ + tboolean isOEMtype = FALSE; + + if (file_type == ON_CARRIER_FRU_FILE){ + printf(" - %s On-Carrier Device ID %d\n", str, (rsc_id & 0x0f) ); + } + else{ + printf(" - %s %s\n", str, + val2str((uint16_t)file_type,ipmi_ekanalyzer_module_type)); + } + + printf(" - Channel ID %d || ", link_desc.channel_id ); + printf("%s", link_desc.port_flag_0 ? "Lane 0: enable" : ""); + printf("%s", link_desc.port_flag_1 ? ", Lane 1: enable" : ""); + printf("%s", link_desc.port_flag_2 ? ", Lane 2: enable" : ""); + printf("%s", link_desc.port_flag_3 ? ", Lane 3: enable" : ""); + + printf("\n"); + printf(" - Link Type: %s \n", + val2str (link_desc.type, ipmi_ekanalyzer_link_type) ); + switch ( link_desc.type ){ + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE: + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1: + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2: + printf(" - Link Type extension: %s\n", + val2str (link_desc.type_ext, ipmi_ekanalyzer_extension_PCIE) ); + printf(" - Link Group ID: %d || ", link_desc.group_id ); + printf("Link Asym. Match: %s\n", + val2str (link_desc.asym_match, ipmi_ekanalyzer_asym_PCIE) ); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET: + printf(" - Link Type extension: %s\n", + val2str (link_desc.type_ext, ipmi_ekanalyzer_extension_ETHERNET) ); + printf(" - Link Group ID: %d || ", link_desc.group_id ); + printf("Link Asym. Match: %s\n", + val2str (link_desc.asym_match, ipmi_ekanalyzer_asym_PCIE) ); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE: + printf(" - Link Type extension: %s\n", + val2str (link_desc.type_ext, ipmi_ekanalyzer_extension_STORAGE) ); + printf(" - Link Group ID: %d || ", link_desc.group_id ); + printf("Link Asym. Match: %s\n", + val2str (link_desc.asym_match, ipmi_ekanalyzer_asym_STORAGE) ); + break; + default: + printf(" - Link Type extension: %i\n", link_desc.type_ext ); + printf(" - Link Group ID: %d || ", link_desc.group_id ); + printf("Link Asym. Match: %i\n", link_desc.asym_match); + break; + } + /*return as OEM type if link type indicates OEM*/ + if ( (link_desc.type >= LOWER_OEM_TYPE) + && + (link_desc.type <= UPPER_OEM_TYPE) + ){ + isOEMtype = TRUE; + } + + return isOEMtype; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_oem_guid +* +* Description: Display the oem guid of an AMC p2p connectivity record +* +* Restriction: None +* +* Input: amc_record: AMC p2p connectivity record +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_oem_guid( + struct ipmi_ek_amc_p2p_connectivity_record amc_record ) +{ + int index_oem = 0; + int index = 0; + + if ( amc_record.guid_count == 0 ){ + printf("\tThere is no OEM GUID for this module\n"); + } + for (index_oem = 0; index_oem < amc_record.guid_count; index_oem++){ + printf(" - GUID: "); + for(index = 0; index < SIZE_OF_GUID; index++){ + printf("%02x", amc_record.oem_guid[index_oem].guid[index]); + /*For a better look: putting a "-" after displaying four bytes of GUID*/ + if (!(index % 4)){ + printf("-"); + } + } + printf("\n"); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_create_amc_p2p_record +* +* Description: this function create an AMC point 2 point connectivity record +* that contain link descriptor, channel descriptor, oem guid +* +* Restriction: Reference: AMC.0 Specification Table 3-16 +* +* Input: record: a pointer to FRU multi record +* +* Output: amc_record: a pointer to the created AMC p2p record +* +* Global: None +* +* Return: Return OK_STATUS on success, or ERROR_STATUS if no record has been +* created. +* +***************************************************************************/ +static int +ipmi_ek_create_amc_p2p_record( struct ipmi_ek_multi_header * record, + struct ipmi_ek_amc_p2p_connectivity_record * amc_record ) +{ + int return_status = OK_STATUS; + int index_data = START_DATA_OFFSET; + + amc_record->guid_count = record->data[index_data++]; + if ( amc_record->guid_count > 0){ + int index_oem = 0; + amc_record->oem_guid = malloc (amc_record->guid_count * \ + sizeof(struct fru_picmgext_guid) ); + for (index_oem = 0; index_oem < amc_record->guid_count; index_oem++){ + memcpy ( &amc_record->oem_guid[index_oem].guid, + &record->data[index_data], + SIZE_OF_GUID ); + index_data += (int)SIZE_OF_GUID; + } + amc_record->rsc_id = record->data[index_data++]; + amc_record->ch_count = record->data[index_data++]; + /*Calculate link descriptor count*/ + amc_record->link_desc_count = ( (record->header.len) - 8 - + (SIZE_OF_GUID*amc_record->guid_count) - + ( sizeof(struct fru_picmgext_amc_channel_desc_record)* + amc_record->ch_count ) + )/5 ; + } + else{ + amc_record->rsc_id = record->data[index_data++]; + amc_record->ch_count = record->data[index_data++]; + /*Calculate link descriptor count see spec AMC.0 for detail*/ + amc_record->link_desc_count = ( (record->header.len) - 8 - + ( sizeof(struct fru_picmgext_amc_channel_desc_record)* + amc_record->ch_count ) + ) / 5; + } + + if (amc_record->ch_count > 0){ + int ch_index = 0; + amc_record->ch_desc = malloc ( (amc_record->ch_count) * \ + sizeof(struct fru_picmgext_amc_channel_desc_record)); + for (ch_index = 0; ch_index < amc_record->ch_count; ch_index++){ + memcpy(&amc_record->ch_desc[ch_index], &record->data[index_data], + sizeof(struct fru_picmgext_amc_channel_desc_record) ); + + index_data += sizeof(struct fru_picmgext_amc_channel_desc_record) ; + } + } + if (amc_record->link_desc_count > 0){ + int i=0; + amc_record->link_desc = malloc ( amc_record->link_desc_count * + sizeof(struct fru_picmgext_amc_link_desc_record) ); + for (i = 0; i< amc_record->link_desc_count; i++ ){ + memcpy (&amc_record->link_desc[i], &record->data[index_data], + sizeof(struct fru_picmgext_amc_link_desc_record) ); + index_data += sizeof (struct fru_picmgext_amc_link_desc_record); + } + } + else{ + return_status = ERROR_STATUS; + } + + return return_status; +} + +/************************************************************************** +* +* Function name: ipmi_ek_get_resource_descriptor +* +* Description: this function create the resource descriptor of Carrier p2p +* connectivity record. +* +* Restriction: None +* +* Input: port_count: number of port count +* index: index to the position of data start offset +* record: a pointer to FRU multi record +* +* Output: port_desc: a pointer to the created resource descriptor +* +* Global: None +* +* Return: Return index that indicates the current position of data in record. +* +***************************************************************************/ +static int +ipmi_ek_get_resource_descriptor( int port_count, int index, + struct fru_picmgext_carrier_p2p_descriptor * port_desc, + struct ipmi_ek_multi_header * record ) +{ + int num_port = 0; + + while ( num_port < port_count ){ + memcpy ( &port_desc[num_port], &record->data[index], + sizeof (struct fru_picmgext_carrier_p2p_descriptor) ); + index += sizeof (struct fru_picmgext_carrier_p2p_descriptor); + num_port++; + } + + return index; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_fru_header +* +* Description: this function display FRU header offset from a FRU binary file +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +* Definition V1.0, Section 8 +* +* Input: filename: name of FRU binary file +* +* Output: None +* +* Global: None +* +* Return: Return OK_STATUS on sucess, ERROR_STATUS on error +* +***************************************************************************/ +static int +ipmi_ek_display_fru_header( char * filename ) +{ + FILE * input_file; + /* this structure is declared in ipmi_fru.h */ + struct fru_header header; + int return_status = ERROR_STATUS; + + input_file = fopen ( filename, "r"); + if ( input_file == NULL ){ + lprintf(LOG_ERR, "file: '%s' is not found", filename); + return_status = ERROR_STATUS; + } + else{ + if ( !feof (input_file) ){ + fread ( &header, sizeof (struct fru_header), 1, input_file ); + printf("%s\n", EQUAL_LINE_LIMITER); + printf("FRU Header Info\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + printf("Format Version :0x%02x %s\n", (header.version & 0x0f), + ((header.version & 0x0f)==1) ? "" : "{unsupported}"); + printf("Internal Use Offset :0x%02x\n", header.offset.internal); + printf("Chassis Info Offset :0x%02x\n", header.offset.chassis); + printf("Board Info Offset :0x%02x\n", header.offset.board); + printf("Product Info Offset :0x%02x\n", header.offset.product); + printf("MultiRecord Offset :0x%02x\n", header.offset.multi); + printf("Common header Checksum :0x%02x\n", header.checksum); + + return_status = OK_STATUS; + } + else{ + lprintf(LOG_ERR, "Invalid FRU header!"); + return_status = ERROR_STATUS; + } + fclose( input_file ); + } + return return_status; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_fru_header_detail +* +* Description: this function display detail FRU header information +* from a FRU binary file. + +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +* Definition V1.0, Section 8 +* +* Input: filename: name of FRU binary file +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_fru_header_detail( char * filename ) +{ + FILE * input_file; + struct fru_header header; + + input_file = fopen ( filename, "r"); + if ( input_file == NULL ){ + lprintf(LOG_ERR, "file: '%s' is not found", filename); + } + else{ + /* the offset in each fru is in multiple of 8 bytes + * See IPMI Platform Management FRU Information Storage Definition + * for detail + */ + #define FACTOR_OFFSET 8 + + if ( !feof (input_file) ){ + fread ( &header, sizeof( struct fru_header ), 1, input_file ); + } + else{ + lprintf(LOG_ERR, "Invalid FRU header!"); + } + /*** Display FRU Internal Use Info ***/ + if ( !feof (input_file) ){ + unsigned char format_version; + unsigned long len; + + printf("%s\n", EQUAL_LINE_LIMITER); + printf("FRU Internal Use Info\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + + fread ( &format_version, 1, 1, input_file ); + printf("Format Version: %d\n", (format_version & 0x0f) ); + + if ( header.offset.chassis > 0 ){ + len = (header.offset.chassis * FACTOR_OFFSET) + - (header.offset.internal * FACTOR_OFFSET); + } + else{ + len = (header.offset.board * FACTOR_OFFSET) + - (header.offset.internal * FACTOR_OFFSET); + } + printf("Length: %d\n", len); + printf("Data dump:\n"); + while ( (len > 0) && ( !feof (input_file) ) ) { + unsigned char data; + fread ( &data, 1, 1, input_file ); + printf("0x%02x ", data); + len --; + } + printf("\n"); + } + /*** Chassis Info Area ***/ + if (header.offset.chassis != 0){ + long offset = 0; + + offset = header.offset.chassis * FACTOR_OFFSET; + ipmi_ek_display_chassis_info_area (input_file, offset); + } + /*** Display FRU Board Info Area ***/ + if (header.offset.board != 0){ + fseek_( input_file, (header.offset.board * FACTOR_OFFSET), SEEK_SET); + if ( !feof(input_file) ){ + unsigned char data; + unsigned int board_length; + size_t file_offset = ftell (input_file); + + printf("%s\n", EQUAL_LINE_LIMITER); + printf("FRU Board Info Area\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + + fread ( &data, 1, 1, input_file ); /* Format version */ + printf("Format Version: %d\n", (data & 0x0f)); + if ( !feof(input_file) ){ + fread ( &data, 1, 1, input_file ); /* Board Area Length */ + board_length = (data * FACTOR_OFFSET); + printf("Area Length: %d\n", board_length); + /* Decrease the length of board area by 1 byte of format version + * and 1 byte for area length itself. the rest of this length will + * be used to check for additional custom mfg. byte + */ + board_length -= 2; + } + if ( !feof(input_file) ){ + unsigned char lan_code; + fread ( &lan_code, 1, 1, input_file ); /* Language Code */ + printf("Language Code: %d\n", lan_code ); + board_length --; + } + /* Board Mfg Date */ + if ( !feof(input_file) ){ + #define SIZE_MFG_DATE 3 + time_t tval; + unsigned char mfg_date[SIZE_MFG_DATE]; + + fread ( mfg_date, SIZE_MFG_DATE, 1, input_file ); + tval=((mfg_date[2] << 16) + (mfg_date[1] << 8) + (mfg_date[0])); + tval = tval * 60; + tval = (time_t)(tval + secs_from_1970_1996); + printf("Board Mfg Date: %ld, %s", tval, + asctime(localtime(&tval))); + board_length -= SIZE_MFG_DATE; + + /* Board Mfg */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Board Manufacture Data", &board_length); + fseek_(input_file, file_offset, SEEK_SET); + /* Board Product */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Board Product Name", &board_length); + fseek_(input_file, file_offset, SEEK_SET); + /* Board Serial */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Board Serial Number", &board_length); + fseek_(input_file, file_offset, SEEK_SET); + /* Board Part */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Board Part Number", &board_length); + fseek_(input_file, file_offset, SEEK_SET); + /* FRU file ID */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "FRU File ID", &board_length); + fseek_(input_file, file_offset, SEEK_SET); + /* Additional Custom Mfg. */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Custom", &board_length); + } + } + } + /*** Product Info Area ***/ + if ( header.offset.product ){ + if ( !feof(input_file) ){ + long offset = 0; + offset = header.offset.product * FACTOR_OFFSET; + ipmi_ek_display_product_info_area (input_file, offset); + } + } + fclose( input_file ); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_chassis_info_area +* +* Description: this function displays detail format of product info area record +* into humain readable text format +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +* Definition V1.0, Section 10 +* +* Input: input_file: pointer to file stream +* offset: start offset of chassis info area +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_chassis_info_area( FILE * input_file, long offset ) +{ + if ( input_file != NULL ){ + printf("%s\n", EQUAL_LINE_LIMITER); + printf("Chassis Info Area\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + + fseek_(input_file, offset, SEEK_SET); + if ( !feof(input_file) ){ + unsigned char data = 0; + unsigned int len = 0; + + fread (&data, 1, 1, input_file); + printf("Format Version Number: %d\n", (data & 0x0f) ); + if ( !feof(input_file) ){ + fread (&len, 1, 1, input_file); + /* len is in factor of 8 bytes */ + len = len * 8; + printf("Area Length: %d\n", len); + len -= 2; + } + if ( !feof(input_file) ){ + unsigned char ch_type = 0; + size_t file_offset = ftell (input_file); + /* Chassis Type*/ + fread (&ch_type, 1, 1, input_file); + printf("Chassis Type: %d\n", ch_type); + len --; + /* Chassis Part Number*/ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Chassis Part Number", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Chassis Serial */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Chassis Serial Number", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Custom product info area */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Custom", &len); + } + } + } + else{ + lprintf(LOG_ERR, "Invalid Chassis Info Area!"); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_board_info_area +* +* Description: this function displays board info area depending on board type +* that pass in argument. Board type can be: +* Manufacturer, Serial, Product or Part... +* +* Restriction: IPMI Platform Management FRU Information Storage +* Definition V1.0, Section 11 +* +* Input: input_file: pointer to file stream +* board_type: a string that contain board type +* board_length: length of info area +* +* Output: None +* +* Global: None +* +* Return: the current position of input_file +* +***************************************************************************/ +static size_t +ipmi_ek_display_board_info_area( FILE * input_file, char * board_type, + unsigned int * board_length ) +{ + size_t file_offset = ftell (input_file); + unsigned char len = 0; + /* Board length*/ + if ( !feof(input_file) ){ + fread ( &len, 1, 1, input_file ); + (*board_length)--; + } + /* Board Data */ + if ( !feof(input_file) ){ + unsigned int size_board = 0; + + /*Bit 5:0 of Board Mfg type represent legnth*/ + size_board = (len & 0x3f); + if (size_board > 0){ + if ( strncmp( board_type, "Custom", 6 ) == 0 ){ + #define NO_MORE_INFO_FIELD 0xc1 + while ( !feof(input_file) && (*board_length > 0) ){ + if (len != NO_MORE_INFO_FIELD){ + printf("Additional Custom Mfg. length: 0x%02x\n", len); + if ( (size_board > 0) && (size_board < (*board_length)) ){ + unsigned char * additional_data = NULL; + int i=0; + additional_data = malloc (size_board); + if (additional_data != NULL){ + fread ( additional_data, size_board, 1, input_file ); + printf("Additional Custom Mfg. Data: %02x", + additional_data[0]); + for ( i =1; i<(int)size_board; i++){ + printf("-%02x", additional_data[i]); + } + printf("\n"); + free (additional_data); + (*board_length) -= size_board; + } + } + else{ + printf("No Additional Custom Mfg. %d\n", *board_length); + board_length = 0; + } + } + else{ + unsigned char padding; + /*take the rest of data in the area minus 1 byte of checksum*/ + printf("Additional Custom Mfg. length: 0x%02x\n", len); + padding = (*board_length) - 1; + /*we reach the end of the record, so its length is set to 0*/ + board_length = 0; + if ( ( padding > 0 ) && ( !feof(input_file) ) ){ + printf("Unused space: %d (bytes)\n", padding); + fseek_(input_file, padding, SEEK_CUR); + } + if ( !feof(input_file) ){ + unsigned char checksum = 0; + fread ( &checksum, 1, 1, input_file ); + printf("Checksum: 0x%02x\n", checksum); + + } + } + } + } + else{ + unsigned char * data; + unsigned int i=0; + #define TYPE_CODE 0xc0 /*Language code*/ + + data = malloc (size_board); + fread ( data, size_board, 1, input_file ); + printf("%s type: 0x%02x\n", board_type, len); + printf("%s: ", board_type); + for ( i = 0; i < size_board; i++ ){ + if ( (len & TYPE_CODE) == TYPE_CODE ){ + printf("%c", data[i]); + } + /*other than language code (binary, BCD, ASCII 6 bit...) is not + * supported */ + else{ + printf("%02x", data[i]); + } + } + printf("\n"); + free (data); + (*board_length) -= size_board; + file_offset = ftell (input_file); + } + } + else{ + printf("%s: None\n", board_type); + file_offset = ftell (input_file); + } + } + + return file_offset; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_product_info_area +* +* Description: this function displays detail format of product info area record +* into humain readable text format +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +* Definition V1.0, Section 12 +* +* Input: input_file: pointer to file stream +* offset: start offset of product info area +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_product_info_area( FILE * input_file, long offset ) +{ + if ( input_file != NULL ){ + printf("%s\n", EQUAL_LINE_LIMITER); + printf("Product Info Area\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + + fseek_(input_file, offset, SEEK_SET); + if ( !feof(input_file) ){ + unsigned char data = 0; + unsigned int len = 0; + + fread (&data, 1, 1, input_file); + printf("Format Version Number: %d\n", (data & 0x0f) ); + if ( !feof(input_file) ){ + fread (&len, 1, 1, input_file); + /* length is in factor of 8 bytes */ + len = len * 8; + printf("Area Length: %d\n", len); + len -= 2; /* -1 byte of format version and -1 byte itself */ + } + if ( !feof(input_file) ){ + size_t file_offset = ftell (input_file); + + fread (&data, 1, 1, input_file); + printf("Language Code: %d\n", data); + len --; + /* Product Mfg */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Product Manufacture Data", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Product Name */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Product Name", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Product Part */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Product Part/Model Number", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Product Version */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Product Version", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Product Serial */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Product Serial Number", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Product Asset Tag */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Asset Tag", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* FRU file ID */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "FRU File ID", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Custom product info area */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Custom", &len); + } + } + } + else{ + lprintf(LOG_ERR, "Invalid Product Info Area!"); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_record +* +* Description: this function displays FRU multi record information. +* +* Restriction: None +* +* Input: record: a pointer to current record +* list_head: a pointer to header of the list +* list_last: a pointer to tale of the list +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_record( struct ipmi_ek_multi_header * record, + struct ipmi_ek_multi_header * list_head, + struct ipmi_ek_multi_header * list_last ) +{ + if ( list_head == NULL ){ + printf("***empty list***\n"); + } + else{ + printf("%s\n", EQUAL_LINE_LIMITER); + printf("FRU Multi Info area\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + for ( record = list_head; record != NULL; record = record->next ){ + printf("Record Type ID: 0x%02x\n", record->header.type); + printf("Record Format version: 0x%02x\n", record->header.format); + if (record->header.len > PICMG_ID_OFFSET){ + /* In picmg3.0 specification, picmg record id lower than 4 or + * greater than 0x2d is not supported + */ + #define PICMG_ID_LOWER_LIMIT 0x04 + #define PICMG_ID_UPPER_LIMIT 0x2d + unsigned char picmg_id; + + picmg_id = record->data[PICMG_ID_OFFSET]; + printf("Manufacturer ID: %02x%02x%02x h\n", record->data[2], + record->data[1], record->data[0] ); + if( ( picmg_id < PICMG_ID_LOWER_LIMIT ) + || + ( picmg_id > PICMG_ID_UPPER_LIMIT ) ){ + printf("Picmg record ID: Unsupported {0x%02x}\n", picmg_id ); + } + else{ + printf("Picmg record ID: %s {0x%02x}\n", + val2str(picmg_id, ipmi_ekanalyzer_picmg_record_id), + picmg_id ); + } + switch (picmg_id){ + case FRU_PICMG_BACKPLANE_P2P: /*0x04*/ + ipmi_ek_display_backplane_p2p_record (record); + break; + case FRU_PICMG_ADDRESS_TABLE: /*0x10*/ + ipmi_ek_display_address_table_record (record); + break; + case FRU_PICMG_SHELF_POWER_DIST: /*0x11*/ + ipmi_ek_display_shelf_power_distribution_record (record); + break; + case FRU_PICMG_SHELF_ACTIVATION: /*/0x12*/ + ipmi_ek_display_shelf_activation_record (record); + break; + case FRU_PICMG_SHMC_IP_CONN: /*0x13*/ + ipmi_ek_display_shelf_ip_connection_record (record); + break; + case FRU_PICMG_BOARD_P2P: /*0x14*/ + ipmi_ek_display_board_p2p_record (record); + break; + case FRU_RADIAL_IPMB0_LINK_MAPPING: /*0x15*/ + ipmi_ek_display_radial_ipmb0_record (record); + break; + case FRU_AMC_CURRENT: /*0x16*/ + ipmi_ek_display_amc_current_record (record); + break; + case FRU_AMC_ACTIVATION: /*0x17*/ + ipmi_ek_display_amc_activation_record (record); + break; + case FRU_AMC_CARRIER_P2P: /*0x18*/ + ipmi_ek_diplay_carrier_connectivity (record); + break; + case FRU_AMC_P2P: /*0x19*/ + ipmi_ek_display_amc_p2p_record (record); + break; + case FRU_AMC_CARRIER_INFO: /*0x1a*/ + ipmi_ek_display_amc_carrier_info_record (record); + break; + case FRU_PICMG_CLK_CARRIER_P2P: /*0x2c*/ + ipmi_ek_display_clock_carrier_p2p_record (record); + break; + case FRU_PICMG_CLK_CONFIG: /*0x2d*/ + ipmi_ek_display_clock_config_record (record); + break; + default: + if (verbose > 0){ + int i; + printf("%02x %02x %02x %02x %02x ", record->header.type, + record->header.format, record->header.len, + record->header.record_checksum, + record->header.header_checksum ); + for ( i = 0; i < record->header.len; i++ ){ + printf("%02x ", record->data[i]); + } + printf("\n"); + } + break; + } + printf("%s\n", STAR_LINE_LIMITER); + } + } + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_backplane_p2p_record +* +* Description: this function displays backplane p2p record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-40 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_backplane_p2p_record( struct ipmi_ek_multi_header * record ) +{ + uint8_t index; + int offset = START_DATA_OFFSET; + struct fru_picmgext_slot_desc * slot_d + = (struct fru_picmgext_slot_desc*) &record->data[offset]; + + offset += sizeof(struct fru_picmgext_slot_desc); + + while ( offset <= record->header.len ) { + printf(" Channel Type: "); + switch ( slot_d -> chan_type ) + { + case 0x00: + case 0x07: + printf("PICMG 2.9\n"); + break; + case 0x08: + printf("Single Port Fabric IF\n"); + break; + case 0x09: + printf("Double Port Fabric IF\n"); + break; + case 0x0a: + printf("Full Channel Fabric IF\n"); + break; + case 0x0b: + printf("Base IF\n"); + break; + case 0x0c: + printf("Update Channel IF\n"); + break; + default: + printf("Unknown IF\n"); + break; + } + printf(" Slot Address: %02x\n", slot_d -> slot_addr); + printf(" Channel Count: %i\n", slot_d -> chn_count); + + for ( index = 0; index < (slot_d -> chn_count); index++ ) { + struct fru_picmgext_chn_desc * d + = (struct fru_picmgext_chn_desc *) &record->data[offset]; + + if ( verbose ){ + printf( "\t" + "Chn: %02x --> " + "Chn: %02x in " + "Slot: %02x\n", + d->local_chn, d->remote_chn, d->remote_slot + ); + } + offset += sizeof(struct fru_picmgext_chn_desc); + } + slot_d = (struct fru_picmgext_slot_desc*) &record->data[offset]; + offset += sizeof(struct fru_picmgext_slot_desc); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_address_table_record +* +* Description: this function displays address table record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-6 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_address_table_record( struct ipmi_ek_multi_header * record ) +{ + unsigned char entries = 0; + unsigned char i; + int offset = START_DATA_OFFSET; + #define SIZE_SHELF_ADDRESS_BYTE 20 + + printf(" Type/Len: 0x%02x\n", record->data[offset++]); + printf(" Shelf Addr: "); + for ( i = 0; i < SIZE_SHELF_ADDRESS_BYTE; i++ ){ + printf("0x%02x ", record->data[offset++]); + } + printf("\n"); + + entries = record->data[offset++]; + printf(" Addr Table Entries count: 0x%02x\n", entries); + + for ( i = 0; i < entries; i++ ){ + printf("\tHWAddr: 0x%02x - SiteNum: 0x%02x - SiteType: 0x%02x \n", + record->data[offset+0], + record->data[offset+1], + record->data[offset+2]); + offset += 3; + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_power_distribution_record +* +* Description: this function displays shelf power distribution record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-70 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_power_distribution_record( + struct ipmi_ek_multi_header * record ) +{ + int offset = START_DATA_OFFSET; + unsigned char i,j; + unsigned char feeds = 0; + + feeds = record->data[offset++]; + printf(" Number of Power Feeds: 0x%02x\n", feeds); + + for (i=0; i<feeds; i++) { + unsigned char entries; + unsigned long max_ext = 0; + unsigned long max_int = 0; + max_ext = record->data[offset+0] | (record->data[offset+1]<<8); + printf(" Max External Available Current: %ld Amps\n", (max_ext*10) ); + + offset += 2; + + max_int = record->data[offset+0] | (record->data[offset+1]<<8); + printf(" Max Internal Current:\t %ld Amps\n", (max_int*10)); + offset += 2; + printf(" Min Expected Operating Voltage: %ld Volts\n", + (record->data[offset++]/2)); + entries = record->data[offset++]; + printf(" Feed to FRU count: 0x%02x\n", entries); + for (j=0; j<entries; j++) { + printf("\tHW: 0x%02x", record->data[offset++]); + printf("\tFRU ID: 0x%02x\n", record->data[offset++]); + } + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_activation_record +* +* Description: this function displays shelf activation record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-73 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_activation_record( + struct ipmi_ek_multi_header * record ) +{ + unsigned char count = 0; + int offset = START_DATA_OFFSET; + + printf(" Allowance for FRU Act Readiness: 0x%02x\n", + record->data[offset++]); + count = record->data[offset++]; + printf(" FRU activation and Power Desc Cnt: 0x%02x\n", count); + + while ( count > 0 ) { + printf(" FRU activation and Power descriptor:\n"); + printf("\tHardware Address:\t\t0x%02x\n", record->data[offset++]); + printf("\tFRU Device ID:\t\t\t0x%02x\n", record->data[offset++]); + printf("\tMax FRU Power Capability:\t0x%04x Watts\n", + ( record->data[offset+0] | (record->data[offset+1]<<8) )); + offset += 2; + printf("\tConfiguration parameter:\t0x%02x\n", record->data[offset++]); + count --; + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_ip_connection_record +* +* Description: this function displays shelf ip connection record. +* +* Restriction: Fix me: Don't test yet +* Reference: PICMG 3.0 Specification Table 3-31 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_ip_connection_record( + struct ipmi_ek_multi_header * record ) +{ + int ioffset = START_DATA_OFFSET; + if (ioffset > record->header.len){ + printf(" Shelf Manager IP Address: %d.%d.%d.%d\n", + record->data[ioffset+0], record->data[ioffset+1], + record->data[ioffset+2], record->data[ioffset+3]); + ioffset += 4; + } + if (ioffset > record->header.len){ + printf(" Default Gateway Address: %d.%d.%d.%d\n", + record->data[ioffset+0], record->data[ioffset+1], + record->data[ioffset+2], record->data[ioffset+3]); + ioffset += 4; + } + if (ioffset > record->header.len){ + printf(" Subnet Mask: %d.%d.%d.%d\n", + record->data[ioffset+0], record->data[ioffset+1], + record->data[ioffset+2], record->data[ioffset+3]); + ioffset += 4; + } +} + +#ifdef NOT_USED +static void ipmi_ek_display_shelf_fan_geography_record( + struct ipmi_ek_multi_header * record ); + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_fan_geography_record +* +* Description: this function displays shelf fan geography record. +* +* Restriction: Fix me: Don't test yet +* Reference: PICMG 3.0 Specification Table 3-75 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_fan_geography_record( + struct ipmi_ek_multi_header * record ) +{ + int ioffset = START_DATA_OFFSET; + unsigned char fan_count = 0; + + fan_count = record->data[ioffset]; + ioffset ++; + printf(" Fan-to-FRU Entry Count: 0x%02x\n", fan_count); + + while ( (fan_count > 0) && (ioffset <= record->header.len) ){ + printf(" Fan-to-FRU Mapping Entry: {%2x%2x%2x%2x}\n", + record->data[ioffset], record->data[ioffset+1], + record->data[ioffset+2], record->data[ioffset+3] + ); + printf(" Hardware Address: 0x%02x\n", record->data[ioffset++]); + printf(" FRU device ID: 0x%02x\n", record->data[ioffset++]); + printf(" Site Number: 0x%02x\n", record->data[ioffset++]); + printf(" Site Type: 0x%02x\n", record->data[ioffset++]); + fan_count --; + } + +} +#endif + +/************************************************************************** +* +* Function name: ipmi_ek_display_board_p2p_record +* +* Description: this function displays board pont-to-point record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-44 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_board_p2p_record( struct ipmi_ek_multi_header * record ) +{ + unsigned char guid_count; + int offset = START_DATA_OFFSET; + int i = 0; + + guid_count = record->data[offset++]; + printf(" GUID count: %2d\n", guid_count); + + for (i = 0 ; i < guid_count; i++ ) { + int j; + printf("\tGUID: "); + for (j=0; j < sizeof(struct fru_picmgext_guid); j++) { + printf("%02x", record->data[offset+j]); + } + printf("\n"); + offset += sizeof(struct fru_picmgext_guid); + } + + for ( /*offset set above*/ ; + offset < record->header.len; + offset += sizeof(struct fru_picmgext_link_desc) + ) { + /* to solve little endian /big endian problem */ + unsigned long data; + struct fru_picmgext_link_desc * d; + + data = (record->data[offset+0]) | (record->data[offset+1] << 8)\ + | (record->data[offset+2] << 16)\ + | (record->data[offset+3] << 24); + + d = (struct fru_picmgext_link_desc *) &data; + + printf(" Link Descriptor\n"); + printf("\tLink Grouping ID:\t0x%02x\n", d->grouping); + printf("\tLink Type Extension:\t0x%02x - ", d->ext); + + if (d->type == FRU_PICMGEXT_LINK_TYPE_BASE){ + switch (d->ext){ + case 0: + printf("10/100/1000BASE-T Link (four-pair)\n"); + break; + case 1: + printf("ShMC Cross-connect (two-pair)\n"); + break; + default: + printf("Unknwon\n"); + break; + } + } + else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET){ + switch (d->ext){ + case 0: + printf("Fixed 1000Base-BX\n"); + break; + case 1: + printf("Fixed 10GBASE-BX4 [XAUI]\n"); + break; + case 2: + printf("FC-PI\n"); + break; + default: + printf("Unknwon\n"); + break; + } + } + else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND){ + printf("Unknwon\n"); + } + else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR){ + printf("Unknwon\n"); + } + else if (d->type == FRU_PICMGEXT_LINK_TYPE_PCIE){ + printf("Unknwon\n"); + } + else{ + printf("Unknwon\n"); + } + + printf("\tLink Type:\t\t0x%02x - ",d->type); + if (d->type == 0 || d->type == 0xff){ + printf("Reserved\n"); + } + else if (d->type >= 0x06 && d->type <= 0xef) { + printf("Reserved\n"); + } + else if (d->type >= LOWER_OEM_TYPE && d->type <= UPPER_OEM_TYPE) { + printf("OEM GUID Definition\n"); + } + else { + switch (d->type){ + case FRU_PICMGEXT_LINK_TYPE_BASE: + printf("PICMG 3.0 Base Interface 10/100/1000\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET: + printf("PICMG 3.1 Ethernet Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND: + printf("PICMG 3.2 Infiniband Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR: + printf("PICMG 3.3 Star Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_PCIE: + printf("PICMG 3.4 PCI Express Fabric Interface\n"); + break; + default: + printf("Invalid\n"); + break; + } + } + printf("\tLink Designator: \n"); + printf("\t Port 0 Flag: %s\n", + (d->desig_port & 0x01) ? "enable" : "disable"); + printf("\t Port 1 Flag: %s\n", + (d->desig_port & 0x02) ? "enable" : "disable"); + printf("\t Port 2 Flag: %s\n", + (d->desig_port & 0x04) ? "enable" : "disable"); + printf("\t Port 3 Flag: %s\n", + (d->desig_port & 0x08) ? "enable" : "disable"); + + printf("\t Interface: 0x%02x - ", d->desig_if); + switch (d->desig_if){ + case FRU_PICMGEXT_DESIGN_IF_BASE: + printf("Base Interface\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_FABRIC: + printf("Fabric Interface\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL: + printf("Update Channel\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_RESERVED: + printf("Reserved\n"); + break; + default: + printf("Invalid"); + break; + } + printf("\t Channel Number: 0x%02x\n", d->desig_channel); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_radial_ipmb0_record +* +* Description: this function displays radial IPMB-0 record. +* +* Restriction: Fix me: Don't test yet +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_radial_ipmb0_record( struct ipmi_ek_multi_header * record ) +{ + int offset = START_DATA_OFFSET; + #define SIZE_OF_CONNECTOR_DEFINER 3; /*bytes*/ + + /*Ref: PICMG 3.0 Specification Revision 2.0, Table 3-59*/ + printf(" IPMB-0 Connector Definer: "); + #ifndef WORDS_BIGENDIAN + printf("%02x %02x %02x h\n", record->data[offset], + record->data[offset+1], record->data[offset+2]); + #else + printf("%02x %02x %02x h\n", record->data[offset+2], + record->data[offset+1], record->data[offset]); + #endif + /*3 bytes of connector definer was used*/ + offset += SIZE_OF_CONNECTOR_DEFINER; + + printf (" IPMB-0 Connector version ID: "); + #ifndef WORDS_BIGENDIAN + printf("%02x %02x h\n", record->data[offset], record->data[offset+1]); + #else + printf("%02x %02x h\n", record->data[offset+1], record->data[offset]); + #endif + offset += 2; + + printf(" IPMB-0 Hub Descriptor Count: 0x%02x", record->data[offset++]); + if (record->data[offset] > 0){ + for (/*offset*/; offset < record->header.len;){ + unsigned char entry_count = 0; + printf(" IPMB-0 Hub Descriptor\n"); + printf("\tHardware Address: 0x%02x\n", record->data[offset++]); + printf("\tHub Info {0x%02x}: ", record->data[offset]); + /* Bit mask specified in Table 3-59 of PICMG 3.0 Specification */ + if ( (record->data[offset] & 0x01) == 0x01 ){ + printf("IPMB-A only\n"); + } + else if ( (record->data[offset] & 0x02) == 0x02 ){ + printf("IPMB-B only\n"); + } + else if ( (record->data[offset] & 0x03) == 0x03 ){ + printf("IPMB-A and IPMB-B\n"); + } + else{ + printf("Reserved.\n"); + } + offset ++; + + entry_count = record->data[offset++]; + printf("\tAddress Entry count: 0x%02x", entry_count); + while (entry_count > 0){ + printf("\t Hardware Address: 0x%02x\n", record->data[offset++]); + printf("\t IPMB-0 Link Entry: 0x%02x\n",record->data[offset++]); + entry_count --; + } + } + } + +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_current_record +* +* Description: this function displays AMC current record. +* +* Restriction: None +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_current_record( struct ipmi_ek_multi_header * record ) +{ + unsigned char current; + current = record->data[START_DATA_OFFSET]; + printf(" Current draw: %.1f A @ 12V => %.2f Watt\n", + (float) current/10.0, ((float)current/10.0)*12.0 ); + printf("\n"); +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_activation_record +* +* Description: this function displays carrier activation and current management +* record. +* +* Restriction: Reference: AMC.0 Specification Table 3-11 and Table 3-12 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_activation_record( struct ipmi_ek_multi_header * record ) +{ + uint16_t max_current; + int offset = START_DATA_OFFSET; + + max_current = record->data[offset]; + max_current |= record->data[++offset] << 8; + printf(" Maximum Internal Current(@12V): %.2f A [ %.2f Watt ]\n", + (float) max_current / 10, + (float) max_current / 10 * 12); + printf(" Module Activation Readiness: %i sec.\n", + record->data[++offset]); + + printf(" Descriptor Count: %i\n", record->data[++offset]); + for(++offset; (offset < record->header.len); offset += 3 ) + { + struct fru_picmgext_activation_record * a = + (struct fru_picmgext_activation_record *) &record->data[offset]; + + printf("\tIPMB-Address:\t\t0x%x\n", a->ibmb_addr); + printf("\tMax. Module Current:\t%.2f A\n", (float)a->max_module_curr/10); + printf("\n"); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_p2p_record +* +* Description: this function display amc p2p connectivity record in humain +* readable text format +* +* Restriction: Reference: AMC.0 Specification Table 3-16 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_p2p_record( struct ipmi_ek_multi_header * record ) +{ + int index_data = START_DATA_OFFSET; + int oem_count = 0; + int ch_count = 0; + int index=0; + + oem_count = record->data[index_data++]; + printf("OEM GUID count: %02x\n", oem_count); + + if ( oem_count > 0 ){ + while ( oem_count > 0 ){ + printf("OEM GUID: "); + for ( index = 1; index <= SIZE_OF_GUID; index++ ){ + printf("%02x", record->data[index_data++]); + /* For a better look, display a "-" character after each 5 bytes + * of OEM GUID */ + if ( !(index % 5) ){ + printf("-"); + } + } + printf("\n"); + oem_count--; + } + } + if ( ( record->data[index_data] & AMC_MODULE ) == AMC_MODULE ){ + printf("AMC module connection\n"); + } + else{ + printf("On-Carrier Device %02x h\n", ( record->data[index_data] & 0x0f )); + } + index_data ++; + ch_count = record->data[index_data++]; + printf("AMC Channel Descriptor count: %02x h\n", ch_count); + + if ( ch_count > 0 ){ + for ( index = 0; index < ch_count; index++ ){ + struct fru_picmgext_amc_channel_desc_record * ch_desc; + printf(" AMC Channel Descriptor {%02x%02x%02x}\n", + record->data[index_data+2], record->data[index_data+1], + record->data[index_data] + ); + /*Warning: For gcc version between 4.0 and 4.3 this code doesnt work*/ + ch_desc = ( struct fru_picmgext_amc_channel_desc_record * )\ + &record->data[index_data]; + printf(" Lane 0 Port: 0x%02x\n", ch_desc->lane0port); + printf(" Lane 1 Port: 0x%02x\n", ch_desc->lane1port); + printf(" Lane 2 Port: 0x%02x\n", ch_desc->lane2port); + printf(" Lane 3 Port: 0x%02x\n\n", ch_desc->lane3port); + index_data += sizeof (struct fru_picmgext_amc_channel_desc_record) ; + } + } + while ( index_data < record->header.len ){ + /*Warning: For gcc version between 4.0 and 4.3 this code doesnt work*/ + struct fru_picmgext_amc_link_desc_record * link_desc = + (struct fru_picmgext_amc_link_desc_record *)&record->data[index_data]; + + printf(" AMC Link Descriptor:\n" ); + + printf("\t- Link Type: %s \n", + val2str (link_desc->type, ipmi_ekanalyzer_link_type)); + switch ( link_desc->type ){ + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE: + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1: + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2: + printf("\t- Link Type extension: %s\n", + val2str (link_desc->type_ext, ipmi_ekanalyzer_extension_PCIE)); + printf("\t- Link Group ID: %d\n ", link_desc->group_id ); + printf("\t- Link Asym. Match: %s\n", + val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_PCIE)); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET: + printf("\t- Link Type extension: %s\n", + val2str (link_desc->type_ext, + ipmi_ekanalyzer_extension_ETHERNET)); + printf("\t- Link Group ID: %d \n", link_desc->group_id ); + printf("\t- Link Asym. Match: %s\n", + val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_PCIE)); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE: + printf("\t- Link Type extension: %s\n", + val2str (link_desc->type_ext, + ipmi_ekanalyzer_extension_STORAGE)); + printf("\t- Link Group ID: %d \n", link_desc->group_id ); + printf("\t- Link Asym. Match: %s\n", + val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_STORAGE)); + break; + default: + printf("\t- Link Type extension: %i\n", link_desc->type_ext ); + printf("\t- Link Group ID: %d \n", link_desc->group_id ); + printf("\t- Link Asym. Match: %i\n", link_desc->asym_match); + break; + } + printf("\t- AMC Link Designator:\n"); + printf("\t Channel ID: %i\n", link_desc->channel_id); + printf("\t\t Lane 0: %s\n", (link_desc->port_flag_0)?"enable":"disable"); + printf("\t\t Lane 1: %s\n", (link_desc->port_flag_1)?"enable":"disable"); + printf("\t\t Lane 2: %s\n", (link_desc->port_flag_2)?"enable":"disable"); + printf("\t\t Lane 3: %s\n", (link_desc->port_flag_3)?"enable":"disable"); + index_data += sizeof (struct fru_picmgext_amc_link_desc_record); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_carrier_info_record +* +* Description: this function displays Carrier information table. +* +* Restriction: Reference: AMC.0 Specification Table 3-3 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: START_DATA_OFFSET +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_carrier_info_record( struct ipmi_ek_multi_header * record ) +{ + unsigned char extVersion; + unsigned char siteCount; + int offset = START_DATA_OFFSET; + + extVersion = record->data[offset++]; + siteCount = record->data[offset++]; + + printf(" AMC.0 extension version: R%d.%d\n", (extVersion >> 0)& 0x0F, + (extVersion >> 4)& 0x0F ); + printf(" Carrier Sie Number Count: %d\n", siteCount); + + while (siteCount > 0){ + printf("\tSite ID (%d): %s \n", record->data[offset], + val2str(record->data[offset], ipmi_ekanalyzer_module_type) ); + offset++; + siteCount--; + } + printf("\n"); +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_clock_carrier_p2p_record +* +* Description: this function displays Carrier clock point-to-pont +* connectivity record. +* +* Restriction: the following code is copy from ipmi_fru.c with modification in +* reference to AMC.0 Specification Table 3-29 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_clock_carrier_p2p_record( + struct ipmi_ek_multi_header * record ) +{ + unsigned char desc_count; + int i,j; + int offset = START_DATA_OFFSET; + + desc_count = record->data[offset++]; + + for(i=0; i<desc_count; i++){ + unsigned char resource_id; + unsigned char channel_count; + + resource_id = record->data[offset++]; + channel_count = record->data[offset++]; + + printf(" Clock Resource ID: 0x%02x\n", resource_id); + printf(" Type: "); + if((resource_id & 0xC0)>>6 == 0) { + printf("On-Carrier-Device\n"); + } + else if((resource_id & 0xC0)>>6 == 1) { + printf("AMC slot\n"); + } + else if((resource_id & 0xC0)>>6 == 2) { + printf("Backplane\n"); + } + else{ + printf("reserved\n"); + } + printf(" Channel Count: 0x%02x\n", channel_count); + + for(j=0; j<channel_count; j++){ + unsigned char loc_channel, rem_channel, rem_resource; + + loc_channel = record->data[offset++]; + rem_channel = record->data[offset++]; + rem_resource = record->data[offset++]; + + printf("\tCLK-ID: 0x%02x ---> ", loc_channel); + printf(" remote CLKID: 0x%02x ", rem_channel); + if((rem_resource & 0xC0)>>6 == 0) { + printf("[ Carrier-Dev"); + } + else if((rem_resource & 0xC0)>>6 == 1) { + printf("[ AMC slot "); + } + else if((rem_resource & 0xC0)>>6 == 2) { + printf("[ Backplane "); + } + else{ + printf("reserved "); + } + printf(" 0x%02x ]\n", rem_resource&0xF); + } + } + printf("\n"); +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_clock_config_record +* +* Description: this function displays clock configuration record. +* +* Restriction: the following codes are copy from ipmi_fru.c with modification +* in reference to AMC.0 Specification Table 3-35 and Table 3-36 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: START_DATA_OFFSET +* +* Return: None +* +***************************************************************************/ +void +ipmi_ek_display_clock_config_record( struct ipmi_ek_multi_header * record ) +{ + unsigned char resource_id, descr_count; + int i; + int offset = START_DATA_OFFSET; + + resource_id = record->data[offset++]; + descr_count = record->data[offset++]; + printf(" Clock Resource ID: 0x%02x\n", resource_id); + printf(" Clock Configuration Descriptor Count: 0x%02x\n", descr_count); + + for(i=0; i<descr_count; i++){ + unsigned char channel_id, control; + unsigned char indirect_cnt, direct_cnt; + int j=0; + + channel_id = record->data[offset++]; + control = record->data[offset++]; + printf("\tCLK-ID: 0x%02x - ", channel_id); + printf("CTRL 0x%02x [ %12s ]\n", control, + ((control&0x1)==0)?"Carrier IPMC":"Application"); + + indirect_cnt = record->data[offset++]; + direct_cnt = record->data[offset++]; + printf("\t Count: Indirect 0x%02x / Direct 0x%02x\n", indirect_cnt, + direct_cnt ); + + /* indirect desc */ + for(j=0; j<indirect_cnt; j++){ + unsigned char feature; + unsigned char dep_chn_id; + + feature = record->data[offset++]; + dep_chn_id = record->data[offset++]; + printf("\t\tFeature: 0x%02x [%8s] - ", feature, + (feature&0x1)==1?"Source":"Receiver"); + printf(" Dep. CLK-ID: 0x%02x\n", dep_chn_id); + } + + /* direct desc */ + for(j=0; j<direct_cnt; j++){ + unsigned char feature, family, accuracy; + unsigned long freq, min_freq, max_freq; + + feature = record->data[offset++]; + family = record->data[offset++]; + accuracy = record->data[offset++]; + freq = (record->data[offset+0] << 0 ) + | (record->data[offset+1] << 8 ) + | (record->data[offset+2] << 16) + | (record->data[offset+3] << 24); + offset += 4; + min_freq = (record->data[offset+0] << 0 ) + | (record->data[offset+1] << 8 ) + | (record->data[offset+2] << 16) + | (record->data[offset+3] << 24); + offset += 4; + max_freq = (record->data[offset+0] << 0 ) + | (record->data[offset+1] << 8 ) + | (record->data[offset+2] << 16) + | (record->data[offset+3] << 24); + offset += 4; + + printf("\t- Feature: 0x%02x - PLL: %x / Asym: %s\n", + feature, + (feature > 1) & 1, + (feature&1)?"Source":"Receiver"); + printf("\tFamily: 0x%02x - AccLVL: 0x%02x\n", family, accuracy); + printf("\tFRQ: %-9d - min: %-9d - max: %-9d\n", + freq, min_freq, max_freq); + } + printf("\n"); + } +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_fru_file2structure +* +* Description: this function convert a FRU binary file into a linked list of +* FRU multi record +* +* Restriction: None +* +* Input/Ouput: filename1: name of the file that contain FRU binary data +* record: a pointer to current record +* list_head: a pointer to header of the list +* list_last: a pointer to tale of the list +* +* Global: None +* +* Return: return -1 as Error status, and 0 as Ok status +* +***************************************************************************/ +static int +ipmi_ekanalyzer_fru_file2structure( char * filename, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_record, + struct ipmi_ek_multi_header ** list_last ) +{ + int return_status = ERROR_STATUS; + FILE * input_file; + + + input_file = fopen ( filename, "r"); + if ( input_file == NULL ){ + lprintf(LOG_ERR, "File: '%s' is not found", filename); + return_status = ERROR_STATUS; + } + else{ + long multi_offset = 0; + fseek_( input_file, START_DATA_OFFSET, SEEK_SET ); + fread ( &multi_offset, 1, 1, input_file ); + if ( multi_offset <= 0 ){ + lprintf(LOG_NOTICE, "There is no multi record in the file %s\n", + filename); + } + else{ + int record_count = 0; + + if ( verbose >= 2) { // was == LOG_DEBUG + printf( "start multi offset = 0x%02x\n", multi_offset ); + } + /*the offset value is in multiple of 8 bytes.*/ + multi_offset = multi_offset * 8; + fseek_( input_file, multi_offset, SEEK_SET ); + while ( !feof( input_file ) ){ + *list_record = malloc ( sizeof (struct ipmi_ek_multi_header) ); + fread ( &(*list_record)->header, START_DATA_OFFSET, 1, input_file); + if ( (*list_record)->header.len > 0 ){ + (*list_record)->data = + malloc ((*list_record)->header.len); + if ( (*list_record)->data == NULL ){ + lprintf(LOG_ERR, "Lack of memory"); + } + else{ + unsigned char last_record = 0; + + fread ( (*list_record)->data, + ((*list_record)->header.len), 1, input_file); + if ( verbose > 0 ) + printf("Record %d has length = %02x\n", record_count, + (*list_record)->header.len); + if ( verbose > 1 ){ + int i; + printf("%02x\t", (*list_record)->header.type); + for ( i = 0; i < ( (*list_record)->header.len ); i++ ){ + printf("%02x\t", (*list_record)->data[i]); + } + printf("\n"); + } + ipmi_ek_add_record2list ( list_record, list_head, list_last ); + /*mask the 8th bits to see if it is the last record*/ + last_record = ((*list_record)->header.format) & 0x80; + if ( last_record ){ + break; + } + } + } + record_count++; + } + } + fclose( input_file ); + return_status = OK_STATUS; + } + return return_status; +} + + +/************************************************************************** +* +* Function name: ipmi_ek_add_record2list +* +* Description: this function adds a sigle FRU multi record to a linked list of +* FRU multi record. +* +* Restriction: None +* +* Input/Output: record: a pointer to current record +* list_head: a pointer to header of the list +* list_last: a pointer to tale of the list +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_add_record2list( struct ipmi_ek_multi_header ** record, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last ) +{ + if (*list_head == NULL) { + *list_head = *record; + (*record)->prev = NULL; + if (verbose > 2) + printf("Adding first record to list\n"); + } + else { + (*list_last)->next = *record; + (*record)->prev = *list_last; + if (verbose > 2) + printf("Add 1 record to list\n"); + } + *list_last = *record; + (*record)->next = NULL; +} + +/************************************************************************** +* +* Function name: ipmi_ek_remove_record_from_list +* +* Description: this function removes a sigle FRU multi record from a linked +* list of FRU multi record. +* +* Restriction: None +* +* Input/Output: record: a pointer to record to be deleted +* list_head: a pointer to header of the list +* list_last: a pointer to tale of the list +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_remove_record_from_list( struct ipmi_ek_multi_header * record, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last ) +{ + if (record->prev == NULL) + *list_head = record->next; + else + record->prev->next = record->next; + if ( record->next == NULL ) + (*list_last) = record->prev; + else + record->next->prev = record->prev; + free (record); +} + +#ifdef METACOMMAND +int i_ekanalyzer(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + void *intf = NULL; + int rc = 0; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"m:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'x': fdebug = 1; verbose = 2; + break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + ipmi_ekanalyzer_usage(); + return ERR_USAGE; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + rc = ipmi_ekanalyzer_main(intf, argc, argv); + + ipmi_close_(); + return rc; +} + +/*end iekanalyzer.c*/ diff --git a/util/iekanalyzer.h b/util/iekanalyzer.h new file mode 100644 index 0000000..452b935 --- /dev/null +++ b/util/iekanalyzer.h @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2007 Kontron Canada, Inc. All Rights Reserved. + * + * Base on code from + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef IPMI_EKANALYZER_H +#define IPMI_EKANALYZER_H + +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +#if __WORDSIZE == 64 +#define uint64_t unsigned long int +#else +#define uint64_t unsigned long long +#endif +#define TRUE 1 +#define FALSE 0 +#ifndef tboolean +#define tboolean int +#endif +// struct ipmi_intf; + +#define RTM_FRU_FILE 0x00 +#define A1_AMC_FRU_FILE 0x01 +#define A2_AMC_FRU_FILE 0x02 +#define A3_AMC_FRU_FILE 0x03 +#define A4_AMC_FRU_FILE 0x04 +#define B1_AMC_FRU_FILE 0x05 +#define B2_AMC_FRU_FILE 0x06 +#define B3_AMC_FRU_FILE 0x07 +#define B4_AMC_FRU_FILE 0x08 +#define ON_CARRIER_FRU_FILE 0x09 +#define CONFIG_FILE 0x0A +#define SHELF_MANAGER_FRU_FILE 0x0B + +#define MIN_ARGUMENT 0x02 +#define RTM_IPMB_L 0x90 + +#define MAX_FILE_NUMBER 8 +/* this voltag is specified in AMC.0 specification Table 3-10 */ +#define AMC_VOLTAGE 12 /*volts*/ + +#define SIZE_OF_GUID 16 +#define FRU_RADIAL_IPMB0_LINK_MAPPING 0x15 + +//struct valstr { + // uint16_t val; + // const char * str; +//}; +//const char * val2str(ushort val, const struct valstr *vs); + +#ifndef OEM_FRU_H +#define OEM_FRU_H + +#define GET_FRU_INFO 0x10 +#define GET_FRU_DATA 0x11 +#define SET_FRU_DATA 0x12 + +enum { + FRU_CHASSIS_PARTNO, + FRU_CHASSIS_SERIAL, + FRU_BOARD_MANUF, + FRU_BOARD_PRODUCT, + FRU_BOARD_SERIAL, + FRU_BOARD_PARTNO, + FRU_PRODUCT_MANUF, + FRU_PRODUCT_NAME, + FRU_PRODUCT_PARTNO, + FRU_PRODUCT_VERSION, + FRU_PRODUCT_SERIAL, + FRU_PRODUCT_ASSET, +}; + +struct fru_area_chassis { + uint8_t area_ver; + uint8_t type; + uint16_t area_len; + char * part; + char * serial; +}; + +struct fru_area_board { + uint8_t area_ver; + uint8_t lang; + uint16_t area_len; + uint32_t mfg_date_time; + char * mfg; + char * prod; + char * serial; + char * part; + char * fru; +}; + +struct fru_area_product { + uint8_t area_ver; + uint8_t lang; + uint16_t area_len; + char * mfg; + char * name; + char * part; + char * version; + char * serial; + char * asset; + char * fru; +}; + +#pragma pack(1) +struct fru_info { + uint16_t size; + uint8_t access:1; +}; //__attribute__ ((packed)); + +struct fru_header { + uint8_t version; + struct { + uint8_t internal; + uint8_t chassis; + uint8_t board; + uint8_t product; + uint8_t multi; + } offset; + uint8_t pad; + uint8_t checksum; +}; //__attribute__ ((packed)); + +struct fru_multirec_header { +#define FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION 0x00 +#define FRU_RECORD_TYPE_DC_OUTPUT 0x01 +#define FRU_RECORD_TYPE_DC_LOAD 0x02 +#define FRU_RECORD_TYPE_MANAGEMENT_ACCESS 0x03 +#define FRU_RECORD_TYPE_BASE_COMPATIBILITY 0x04 +#define FRU_RECORD_TYPE_EXTENDED_COMPATIBILITY 0x05 +#define FRU_RECORD_TYPE_OEM_EXTENSION 0xc0 + uint8_t type; + uint8_t format; + uint8_t len; + uint8_t record_checksum; + uint8_t header_checksum; +}; //__attribute__ ((packed)); + +struct fru_multirec_powersupply { +#if WORDS_BIGENDIAN + uint16_t capacity; +#else + uint16_t capacity:12; + uint16_t __reserved1:4; +#endif + uint16_t peak_va; + uint8_t inrush_current; + uint8_t inrush_interval; + uint16_t lowend_input1; + uint16_t highend_input1; + uint16_t lowend_input2; + uint16_t highend_input2; + uint8_t lowend_freq; + uint8_t highend_freq; + uint8_t dropout_tolerance; +#if WORDS_BIGENDIAN + uint8_t __reserved2:3; + uint8_t tach:1; + uint8_t hotswap:1; + uint8_t autoswitch:1; + uint8_t pfc:1; + uint8_t predictive_fail:1; +#else + uint8_t predictive_fail:1; + uint8_t pfc:1; + uint8_t autoswitch:1; + uint8_t hotswap:1; + uint8_t tach:1; + uint8_t __reserved2:3; +#endif + uint16_t peak_cap_ht; +#if WORDS_BIGENDIAN + uint8_t combined_voltage1:4; + uint8_t combined_voltage2:4; +#else + uint8_t combined_voltage2:4; + uint8_t combined_voltage1:4; +#endif + uint16_t combined_capacity; + uint8_t rps_threshold; +}; //__attribute__ ((packed)); + +struct fru_multirec_dcoutput { +#if WORDS_BIGENDIAN + uint8_t standby:1; + uint8_t __reserved:3; + uint8_t output_number:4; +#else + uint8_t output_number:4; + uint8_t __reserved:3; + uint8_t standby:1; +#endif + short nominal_voltage; + short max_neg_dev; + short max_pos_dev; + uint16_t ripple_and_noise; + uint16_t min_current; + uint16_t max_current; +}; //__attribute__ ((packed)); + +struct fru_multirec_dcload { +#if WORDS_BIGENDIAN + uint8_t __reserved:4; + uint8_t output_number:4; +#else + uint8_t output_number:4; + uint8_t __reserved:4; +#endif + short nominal_voltage; + short min_voltage; + short max_voltage; + uint16_t ripple_and_noise; + uint16_t min_current; + uint16_t max_current; +}; //__attribute__ ((packed)); + +struct fru_multirec_oem_header { + unsigned char mfg_id[3]; +#define FRU_PICMG_BACKPLANE_P2P 0x04 +#define FRU_PICMG_ADDRESS_TABLE 0x10 +#define FRU_PICMG_SHELF_POWER_DIST 0x11 +#define FRU_PICMG_SHELF_ACTIVATION 0x12 +#define FRU_PICMG_SHMC_IP_CONN 0x13 +#define FRU_PICMG_BOARD_P2P 0x14 +#define FRU_AMC_CURRENT 0x16 +#define FRU_AMC_ACTIVATION 0x17 +#define FRU_AMC_CARRIER_P2P 0x18 +#define FRU_AMC_P2P 0x19 +#define FRU_AMC_CARRIER_INFO 0x1a +#define FRU_UTCA_FRU_INFO_TABLE 0x20 +#define FRU_UTCA_CARRIER_MNG_IP 0x21 +#define FRU_UTCA_CARRIER_INFO 0x22 +#define FRU_UTCA_CARRIER_LOCATION 0x23 +#define FRU_UTCA_SHMC_IP_LINK 0x24 +#define FRU_UTCA_POWER_POLICY 0x25 +#define FRU_UTCA_ACTIVATION 0x26 +#define FRU_UTCA_PM_CAPABILTY 0x27 +#define FRU_UTCA_FAN_GEOGRAPHY 0x28 +#define FRU_UTCA_CLOCK_MAPPING 0x29 +#define FRU_UTCA_MSG_BRIDGE_POLICY 0x2A +#define FRU_UTCA_OEM_MODULE_DESC 0x2B +#define FRU_PICMG_CLK_CARRIER_P2P 0x2C +#define FRU_PICMG_CLK_CONFIG 0x2D + unsigned char record_id; + unsigned char record_version; +}; //__attribute__ ((packed)); + +struct fru_picmgext_guid { + unsigned char guid[16]; +}; //__attribute__ ((packed)); + +#ifndef HAVE_FRU_PICMG_EXT +#define HAVE_FRU_PICMG_EXT +struct fru_picmgext_link_desc { +#ifndef WORDS_BIGENDIAN + unsigned int desig_channel:6; + unsigned int desig_if:2; + unsigned int desig_port:4; +#define FRU_PICMGEXT_LINK_TYPE_BASE 0x01 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET 0x02 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND 0x03 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR 0x04 +#define FRU_PICMGEXT_LINK_TYPE_PCIE 0x05 + unsigned int type:8; + unsigned int ext:4; + unsigned int grouping:8; +#else + unsigned int grouping:8; + unsigned int ext:4; +#define FRU_PICMGEXT_LINK_TYPE_BASE 0x01 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET 0x02 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND 0x03 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR 0x04 +#define FRU_PICMGEXT_LINK_TYPE_PCIE 0x05 + unsigned int type:8; + unsigned int desig_port:4; + unsigned int desig_if:2; + unsigned int desig_channel:6; +#endif +}; //__attribute__ ((packed)); + + +#define FRU_PICMGEXT_AMC_LINK_TYPE_RESERVED 0x00 +#define FRU_PICMGEXT_AMC_LINK_TYPE_RESERVED1 0x01 +#define FRU_PICMGEXT_AMC_LINK_TYPE_PCI_EXPRESS 0x02 +#define FRU_PICMGEXT_AMC_LINK_TYPE_ADVANCED_SWITCHING1 0x03 +#define FRU_PICMGEXT_AMC_LINK_TYPE_ADVANCED_SWITCHING2 0x04 +#define FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET 0x05 +#define FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO 0x06 +#define FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE 0x07 + +/* This is used in command, not in FRU */ +struct fru_picmgext_amc_link_info { + unsigned char linkInfo[3]; +}; //__attribute__ ((packed)); + +#endif + +struct fru_picmgext_amc_link_desc_core { +#ifndef WORDS_BIGENDIAN + unsigned int designator:12; + unsigned int type:8; + unsigned int ext:4; + unsigned int grouping:8; +#else + unsigned int grouping:8; + unsigned int ext:4; + unsigned int type:8; + unsigned int designator:12; +#endif +}; //__attribute__ ((packed)); + +struct fru_picmgext_amc_link_desc_extra { +#ifndef WORDS_BIGENDIAN + unsigned char asymetricMatch:2; + unsigned char reserved:6; +#else + unsigned char reserved:6; + unsigned char asymetricMatch:2; +#endif +}; //__attribute__ ((packed)); + + +struct fru_picmgext_amc_link_desc { +#ifndef WORDS_BIGENDIAN + struct fru_picmgext_amc_link_desc_core core;/* lsb */ + struct fru_picmgext_amc_link_desc_extra extra; +#else + struct fru_picmgext_amc_link_desc_extra extra; + struct fru_picmgext_amc_link_desc_core core;/* lsb */ +#endif +}; //__attribute__ ((packed)); + + +#define FRU_PICMGEXT_OEM_SWFW 0x03 +#define OEM_SWFW_NBLOCK_OFFSET 0x05 +#define OEM_SWFW_FIELD_START_OFFSET 0x06 + + +struct fru_picmgext_chn_desc { +#ifndef WORDS_BIGENDIAN + unsigned char remote_slot:8; + unsigned char remote_chn:5; + unsigned char local_chn:5; + unsigned char:6; +#else + unsigned char:6; + unsigned char local_chn:5; + unsigned char remote_chn:5; + unsigned char remote_slot:8; +#endif +}; //__attribute__ ((packed)); + +struct fru_picmgext_slot_desc { + unsigned char chan_type; + unsigned char slot_addr; + unsigned char chn_count; +}; //__attribute__ ((packed)); + +#define FRU_PICMGEXT_DESIGN_IF_BASE 0x00 +#define FRU_PICMGEXT_DESIGN_IF_FABRIC 0x01 +#define FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL 0x02 +#define FRU_PICMGEXT_DESIGN_IF_RESERVED 0x03 + +struct fru_picmgext_carrier_activation_record { + unsigned short max_internal_curr; + unsigned char allowance_for_readiness; + unsigned char module_activation_record_count; +}; //__attribute__ ((packed)); + +struct fru_picmgext_activation_record { + unsigned char ibmb_addr; + unsigned char max_module_curr; + unsigned char reserved; +}; //__attribute__ ((packed)); + +struct fru_picmgext_carrier_p2p_record { + unsigned char resource_id; + unsigned char p2p_count; +}; //__attribute__ ((packed)); + +struct fru_picmgext_carrier_p2p_descriptor { +#ifndef WORDS_BIGENDIAN + unsigned char remote_resource_id; + unsigned short remote_port:5; + unsigned short local_port:5; + unsigned short reserved:6; +#else + unsigned short reserved:6; + unsigned short local_port:5; + unsigned short remote_port:5; + unsigned char remote_resource_id; +#endif +}; //__attribute__ ((packed)); + +struct fru_picmgext_amc_p2p_record { +#ifndef WORDS_BIGENDIAN + unsigned char resource_id :4; + unsigned char /* reserved */ :3; + unsigned char record_type :1; +#else + unsigned char record_type :1; + unsigned char /* reserved */ :3; + unsigned char resource_id :4; +#endif +}; //__attribute__ ((packed)); + +struct fru_picmgext_amc_channel_desc_record { +#ifndef WORDS_BIGENDIAN + unsigned char lane0port :5; + unsigned char lane1port :5; + unsigned char lane2port :5; + unsigned char lane3port :5; + unsigned char /*reserved */ :4; +#else + unsigned char /*reserved */ :4; + unsigned char lane3port :5; + unsigned char lane2port :5; + unsigned char lane1port :5; + unsigned char lane0port :5; +#endif +}; //__attribute__ ((packed)); + +struct fru_picmgext_amc_link_desc_record { + #define FRU_PICMGEXT_AMC_LINK_TYPE_PCIE 0x02 + #define FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1 0x03 + #define FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2 0x04 + #define FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET 0x05 + #define FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO 0x06 + #define FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE 0x07 + + #define AMC_LINK_TYPE_EXT_PCIE_G1_NSSC 0x00 + #define AMC_LINK_TYPE_EXT_PCIE_G1_SSC 0x01 + #define AMC_LINK_TYPE_EXT_PCIE_G2_NSSC 0x02 + #define AMC_LINK_TYPE_EXT_PCIE_G2_SSC 0x03 + + #define AMC_LINK_TYPE_EXT_ETH_1000_BX 0x00 + #define AMC_LINK_TYPE_EXT_ETH_10G_XAUI 0x01 + + #define AMC_LINK_TYPE_EXT_STORAGE_FC 0x00 + #define AMC_LINK_TYPE_EXT_STORAGE_SATA 0x01 + #define AMC_LINK_TYPE_EXT_STORAGE_SAS 0x02 +#ifndef WORDS_BIGENDIAN + unsigned short channel_id :8; + unsigned short port_flag_0 :1; + unsigned short port_flag_1 :1; + unsigned short port_flag_2 :1; + unsigned short port_flag_3 :1; + unsigned short type :8; + unsigned short type_ext :4; + unsigned short group_id :8; + unsigned char asym_match :2; + unsigned char /* reserved */ :6; +#else + unsigned char /* reserved */ :6; + unsigned char asym_match :2; + unsigned short group_id :8; + unsigned short type_ext :4; + unsigned short type :8; + unsigned short port_flag_3 :1; + unsigned short port_flag_2 :1; + unsigned short port_flag_1 :1; + unsigned short port_flag_0 :1; + unsigned short channel_id :8; +#endif +}; //__attribute__ ((packed)); +#pragma pack() + +/* FRU Board manufacturing date */ +static const uint64_t secs_from_1970_1996 = 820450800; + +#ifdef NOT_USED +static const char * combined_voltage_desc[] = { //__attribute__((unused)) +"12 V", "-12 V", "5 V", "3.3 V"}; +static const char * chassis_type_desc[] = { //__attribute__((unused)) + "Unspecified", "Other", "Unknown", + "Desktop", "Low Profile Desktop", "Pizza Box", + "Mini Tower", "Tower", + "Portable", "LapTop", "Notebook", "Hand Held", + "Docking Station", "All in One", "Sub Notebook", + "Space-saving", "Lunch Box", "Main Server Chassis", + "Expansion Chassis", "SubChassis", "Bus Expansion Chassis", + "Peripheral Chassis", "RAID Chassis", "Rack Mount Chassis"}; +#endif + +#endif /* OEM_FRU_H */ + +#endif /* IPMI_EKANALYZER_H */ diff --git a/util/ievents.c b/util/ievents.c new file mode 100644 index 0000000..72c0b24 --- /dev/null +++ b/util/ievents.c @@ -0,0 +1,2505 @@ +/* + * ievents.c + * + * This file decodes the IPMI event into a readable string. + * It is used by showsel.c and getevent.c. + * + * ievents.c compile flags: + * METACOMMAND - defined if building for ipmiutil meta-command binary + * ALONE - defined if building for ievents standalone binary + * else it could be compiled with libipmiutil.a + * LINUX, BSD, WIN32, DOS - defined for that OS + * + * Author: Andy Cress arcress at users.sourceforge.net + * + * Copyright (c) 2009 Kontron America, Inc. + * Copyright (c) 2006 Intel Corporation. + * + * 05/26/05 Andy Cress - created from showsel.c (see there for history) + * 06/20/05 Andy Cress - changed PowerSupply present/not to Inserted/Removed + * 08/01/05 Andy Cress - added more Power Unit & Battery descriptions + * 03/02/06 Andy Cress - more decoding for Power Unit 0b vs. 6f + * 04/11/07 Andy Cress - added events -p decoding for PET data + * 10/03/07 Andy Cress - added file_grep for -p in Windows + * 03/03/08 Andy Cress - added -f to interpret raw SEL file + */ +/*M* +Copyright (c) 2009 Kontron America, Inc. +Copyright (c) 2006, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#include <stdio.h> +#ifdef WIN32 +#include <windows.h> +#include <stdlib.h> +#include <string.h> +#elif defined(DOS) +#include <dos.h> +#include <stdlib.h> +#include <string.h> +#else +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <syslog.h> +#endif +#include <time.h> + +#include "ipmicmd.h" +#include "ievents.h" + +#define SELprintf printf +#define SMS_SA 0x41 +#define SMI_SA 0x21 +static char *progver = "2.93"; +static char *progname = "ievents"; +static char fsensdesc = 0; /* 1= get extended sensor descriptions*/ +static char fcanonical = 0; /* 1= show canonical, delimited output*/ +static char fgetdevid = 0; /* 1= get device ID */ +static char fnewevt = 0; /* 1= generate New event */ +static char futc = 0; /* 1= raw UTC time */ +static uchar thr_sa = SMS_SA; /* 0x41 (Sms) used by ipmitool PlarformEvents */ +static void *sdrcache = NULL; +static int pet_guid = 8; /*bytes in the input data for the GUID*/ +static char bcomma = ','; +static char bdelim = BDELIM; /* '|' */ +#ifdef ALONE + char fdebug = 0; /* 1= debug output, standalone*/ +static char fsm_debug = 0; +#else +extern char fdebug; /* 1= debug output, from ipmicmd.c*/ +extern char fsm_debug; /*mem_if.c*/ +#endif +#define SDR_SZ 80 + +#pragma pack(1) +typedef struct +{ + ushort record_id; + uchar record_type; + uint timestamp; + ushort generator_id; /*slave_addr/channel*/ + uchar evm_rev; //event message revision + uchar sensor_type; + uchar sensor_number; + uchar event_trigger; + uchar event_data1; + uchar event_data2; + uchar event_data3; +} SEL_RECORD; +#pragma pack() + +#ifdef WIN32 + static char sensfil[80] = "sensor_out.txt"; + static char sensfil2[80] = "%ipmiutildir%\\sensor_out.txt"; + // static char outfil[64] = "stype.tmp"; +#else + static char sensfil[80] = "/var/lib/ipmiutil/sensor_out.txt"; + static char sensfil2[80] = "/usr/share/ipmiutil/sensor_out.txt"; + // static char outfil[] = "/tmp/stype.tmp"; +#endif + static char rawfil[80] = ""; + +char *evt_hdr = "RecId Date/Time_______ SEV Src_ Evt_Type___ Sens# Evt_detail - Trig [Evt_data]\n"; +char *evt_hdr2 = "RecId | Date/Time | SEV | Src | Evt_Type | Sensor | Evt_detail \n"; +#ifdef MOVED +/* moved SEV_* to ipmicmd.h */ +#define SEV_INFO 0 +#define SEV_MIN 1 +#define SEV_MAJ 2 +#define SEV_CRIT 3 +#endif +#define NSEV 4 +char *sev_str[NSEV] = { + /*0*/ "INF", + /*1*/ "MIN", + /*2*/ "MAJ", + /*3*/ "CRT" }; + +/* sensor_types: See IPMI 1.5 Table 36-3, IPMI 2.0 Table 42-3 */ +#define NSTYPES 0x2F +static const char *sensor_types[NSTYPES] = { +/* 00h */ "reserved", +/* 01h */ "Temperature", +/* 02h */ "Voltage", +/* 03h */ "Current", +/* 04h */ "Fan", +/* 05h */ "Platform Security", +/* 06h */ "Security Violation", +/* 07h */ "Processor", +/* 08h */ "Power Supply", +/* 09h */ "Power Unit", +/* 0Ah */ "Cooling Device", +/* 0Bh */ "FRU Sensor", +/* 0Ch */ "Memory", +/* 0Dh */ "Drive Slot", +/* 0Eh */ "POST Memory Resize", +/* 0Fh */ "System Firmware", /*incl POST code errors*/ +/* 10h */ "Event Log", /*SEL Disabled or Cleared */ +/* 11h */ "Watchdog_1", +/* 12h */ "System Event", /* offset 0,1,2 */ +/* 13h */ "Critical Interrupt", /* offset 0,1,2 */ +/* 14h */ "Button", /* offset 0,1,2 */ +/* 15h */ "Board", +/* 16h */ "Microcontroller", +/* 17h */ "Add-in Card", +/* 18h */ "Chassis", +/* 19h */ "Chip Set", +/* 1Ah */ "Other FRU", +/* 1Bh */ "Cable/Interconnect", +/* 1Ch */ "Terminator", +/* 1Dh */ "System Boot Initiated", +/* 1Eh */ "Boot Error", +/* 1Fh */ "OS Boot", +/* 20h */ "OS Critical Stop", +/* 21h */ "Slot/Connector", +/* 22h */ "ACPI Power State", +/* 23h */ "Watchdog_2", +/* 24h */ "Platform Alert", +/* 25h */ "Entity Presence", +/* 26h */ "Monitor ASIC", +/* 27h */ "LAN", +/* 28h */ "Management Subsystem Health", +/* 29h */ "Battery", +/* 2Ah */ "SessionAudit", +/* 2Bh */ "Version Change", +/* 2Ch */ "FRU State", +/* 2Dh */ "SMI Timeout", /* 0xF3 == OEM SMI Timeout */ +/* 2Eh */ "ME" /* 0xDC == ME Node Manager */ +}; + +#define NFWERRS 15 +static struct { /* See Table 36-3, type 0Fh, offset 00h */ + int code; char *msg; + } fwerrs[NFWERRS] = { + { 0x00, "Unspecified"}, + { 0x01, "No system memory"}, + { 0x02, "No usable memory"}, + { 0x03, "Unrecovered Hard Disk"}, + { 0x04, "Unrecovered System Board"}, + { 0x05, "Unrecovered Diskette"}, + { 0x06, "Unrecovered Hard Disk Ctlr"}, + { 0x07, "Unrecovered PS2 USB"}, + { 0x08, "Boot media not found"}, + { 0x09, "Unrecovered video controller"}, + { 0x0A, "No video device"}, + { 0x0B, "Firmware ROM corruption"}, + { 0x0C, "CPU voltage mismatch"}, + { 0x0D, "CPU speed mismatch"}, + { 0x0E, "Reserved" } +}; + +#define NFWSTAT 27 +static struct { /* See Table 36-3, type 0Fh, offset 01h & 02h */ + int code; char *msg; + } fwstat[NFWSTAT] = { + { 0x00, "Unspecified"}, + { 0x01, "Memory init"}, + { 0x02, "Hard disk init"}, + { 0x03, "Secondary processor"}, + { 0x04, "User authentication"}, + { 0x05, "User-init sys setup"}, + { 0x06, "USB configuration"}, + { 0x07, "PCI configuration"}, + { 0x08, "Option ROM init"}, + { 0x09, "Video init"}, + { 0x0a, "Cache init"}, + { 0x0b, "SM Bus init"}, + { 0x0c, "Keyboard init"}, + { 0x0d, "Mgt controller"}, + { 0x0e, "Docking attach"}, + { 0x0f, "Enabling docking"}, + { 0x10, "Docking eject"}, + { 0x11, "Disabling docking"}, + { 0x12, "OS wake-up"}, + { 0x13, "Starting OS boot"}, + { 0x14, "Baseboard init"}, + { 0x15, "reserved"}, + { 0x16, "Floppy init"}, + { 0x17, "Keyboard test"}, + { 0x18, "Mouse test"}, + { 0x19, "Primary processor"}, + { 0x1A, "Reserved"} +}; + +#define NGDESC 12 +static struct { + ushort g_id; + const char desc[8]; +} gen_desc[NGDESC] = { /*empirical, format defined in IPMI 1.5 Table 23-5 */ + { 0x0000, "IPMB"}, + { 0x0001, "EFI "}, + { 0x0003, "BIOS"}, /* BIOS POST */ + { BMC_SA, "BMC "}, /* 0x0020==BMC_SA*/ + { SMI_SA, "SMI "}, /* 0x0021==SMI_SA, platform events */ + { 0x0028, "CHAS"}, /* Chassis Bridge Controller */ + { 0x0031, "mSMI"}, /* BIOS SMI/POST errors on miniBMC or ia64 */ + { 0x0033, "Bios"}, /* BIOS SMI (runtime), usually for memory errors */ + { SMS_SA, "Sms "}, /* 0x0041==SmsOs for MS Win2008 Boot, ipmitool event */ + { 0x002C, "ME "}, /* ME Node Manager for S5500 */ + { 0x602C, "ME "}, /* ME Node Manager for S5500/i7 bus=0x6, sa=0x2C */ + { HSC_SA, "HSC "} /* 0x00C0==HSC_SA for SAF-TE Hot-Swap Controller*/ +}; + +#define NCRITS 10 +char * crit_int_str[NCRITS] = { /* Critical Interrupt descriptions */ + /*00*/ "FP NMI ", /* Front Panel NMI */ + /*01*/ "Bus Timout", + /*02*/ "IOch NMI ", /* IO channel check NMI */ + /*03*/ "Soft NMI ", + /*04*/ "PCI PERR ", + /*05*/ "PCI SERR ", + /*06*/ "EISA Timout", + /*07*/ "Bus Warn ", /* Bus Correctable Error */ + /*08*/ "Bus Error", /* Bus Uncorrectable Error */ + /*09*/ "Fatal NMI" }; + +#define NBOOTI 8 +char * boot_init_str[NBOOTI] = { /* System Boot Initiated */ + /*00*/ "Power Up ", + /*01*/ "Hard Reset", + /*02*/ "Warm Reset", + /*03*/ "PXE Boot ", + /*04*/ "Diag Boot ", + /*05*/ "SW Hard Reset", + /*06*/ "SW Warm Reset", + /*07*/ "RestartCause" }; + +#define NOSBOOT 8 +char * osboot_str[NOSBOOT] = { /* OS Boot */ + /*00*/ "A: boot completed", + /*01*/ "C: boot completed", + /*02*/ "PXE boot completed", + /*03*/ "Diag boot completed", + /*04*/ "CDROM boot completed", + /*05*/ "ROM boot completed", + /*06*/ "Other boot completed" }; + +#define NSLOTC 9 +char * slot_str[NSLOTC] = { /* Slot/Connector descriptions */ + /*00*/ "Fault ", + /*01*/ "Identify", + /*02*/ "Inserted", + /*03*/ "InsReady", + /*04*/ "RemReady", + /*05*/ "PowerOff", + /*06*/ "RemRequest", + /*07*/ "Interlock", + /*08*/ "Disabled" }; + +#define NBATT 3 +char * batt_str[NBATT] = { /* Battery assert descriptions */ + /*00*/ "Low", + /*01*/ "Failed", + /*02*/ "Present" }; +char * batt_clr[NBATT] = { /* Battery deassert descriptions */ + /*00*/ "Low OK", + /*01*/ "Failed OK", + /*02*/ "Absent" }; + +#define N_NMH 6 +char * nmh_str[N_NMH] = { /* ME Node Manager Health (73) descriptions */ + /*10*/ "Policy Misconfig", + /*11*/ "Power Sensor Err", + /*12*/ "Inlet Temp Sensor Err", + /*13*/ "Host Comm Err", + /*14*/ "RTC Sync Err" , + /*15*/ "Plat Shutdown" }; + +#define N_NMFW 6 +char * nmfw_str[N_NMFW] = { /* ME Firmware Health (75) descriptions */ + /*00*/ "Forced GPIO Recov", + /*01*/ "Image Exec Fail", + /*02*/ "Flash Erase Error", + /*03*/ "Flash Corrupt" , + /*04*/ "Internal Watchdog Timeout", // FW Watchdog Timeout, need to flash ME + /*05*/ "BMC Comm Error" }; + +#define N_NM 4 +char * nm_str[N_NM] = { /* Node Manager descriptions */ + /*72*/ "NM Exception", /*or NM Alert Threshold*/ + /*73*/ "NM Health", + /*74*/ "NM Capabilities", + /*75*/ "FW Health" }; + +#define NPROC 11 +char * proc_str[NPROC] = { /* Processor descriptions */ + /*00*/ "IERR", + /*01*/ "Thermal Trip", + /*02*/ "FRB1/BIST failure", + /*03*/ "FRB2 timeout", + /*04*/ "FRB3 Proc error", + /*05*/ "Config error", + /*06*/ "SMBIOS CPU error", + /*07*/ "Present", + /*08*/ "Disabled", + /*09*/ "Terminator", + /*0A*/ "Throttled" }; + +#define NACPIP 15 +char * acpip_str[NACPIP] = { /* ACPI Power State descriptions */ + /*00*/ "S0/G0 Working", + /*01*/ "S1 sleeping, proc/hw context maintained", + /*02*/ "S2 sleeping, proc context lost", + /*03*/ "S3 sleeping, proc/hw context lost, mem ok", /*42 chars*/ + /*04*/ "S4 non-volatile sleep/suspend", + /*05*/ "S5/G2 soft-off", + /*06*/ "S4/S5 soft-off, no specific state", + /*07*/ "G3/Mechanical off", + /*08*/ "Sleeping in an S1/S2/S3 state", + /*09*/ "G1 sleeping", + /*0A*/ "S5 entered by override", + /*0B*/ "Legacy ON state", + /*0C*/ "Legacy OFF state", + /*0D*/ "Unknown", + /*0E*/ "Unknown" }; + +#define NAUDIT 2 +char * audit_str[NAUDIT] = { /* Session Audit descriptions */ + /*00*/ "Activated", + /*01*/ "Deactivated"}; + +#define N_AVAIL 9 +char * avail_str[N_AVAIL] = { /* Discrete Availability, evtype 0x0A */ + /*00*/ "chg to Running", + /*01*/ "chg to In Test", + /*02*/ "chg to Power Off", + /*03*/ "chg to On Line", + /*04*/ "chg to Off Line", + /*05*/ "chg to Off Duty", + /*06*/ "chg to Degraded", + /*07*/ "chg to Power Save", + /*08*/ "Install Error"}; + + +#define NSDESC 87 +struct { + ushort genid; /* generator id: BIOS, BMC, etc. (slave_addr/channel) */ + uchar s_typ; /* 1=temp,2=voltage,4=fan,... */ + uchar s_num; + uchar evtrg; /* event trigger/type, see IPMI 1.5 table 36.1 & 36.2 */ + uchar data1; + uchar data2; + uchar data3; + uchar sev; /* 0=SEV_INFO, 1=SEV_MIN, 2=SEV_MAJ, 3=SEV_CRIT */ + const char desc[40]; +} sens_desc[NSDESC] = { /* if value is 0xff, matches any value */ +{0xffff,0x05, 0xff, 0x6f, 0x40,0xff,0xff, 1,"Chassis Intrusion"}, /*chassis*/ +{0xffff,0x05, 0xff, 0xef, 0x40,0xff,0xff, 0,"Chassis OK"}, /*chassis*/ +{0xffff,0x05, 0xff, 0x6f, 0x44,0xff,0xff, 1,"LAN unplugged"}, /*chassis*/ +{0xffff,0x05, 0xff, 0xef, 0x44,0xff,0xff, 0,"LAN restored "}, /*chassis*/ +{0xffff,0x06, 0xff, 0xff, 0x45,0xff,0xff, 0,"Password"}, /*security*/ +{0xffff,0x07, 0xff, 0xff, 0x41,0xff,0xff, 3,"Thermal trip"}, /*processor*/ +{0xffff,0x08, 0xff, 0x6f, 0x40,0xff,0xff, 0,"Inserted"}, /*PowerSupply*/ +{0xffff,0x08, 0xff, 0x6f, 0x41,0xff,0xff, 2,"Failure detected"},/*PowerSupply*/ +{0xffff,0x08, 0xff, 0x6f, 0x42,0xff,0xff, 1,"Predictive failure"}, +{0xffff,0x08, 0xff, 0x6f, 0x43,0xff,0xff, 0,"AC Lost"}, +{0xffff,0x08, 0xff, 0x6f, 0x46,0xff,0xff, 2,"Config Error"}, +{0xffff,0x08, 0xff, 0xef, 0x40,0xff,0xff, 1,"Removed"}, /*PowerSupply*/ +{0xffff,0x08, 0xff, 0xef, 0x41,0xff,0xff, 0,"is OK "}, /*PowerSupply*/ +{0xffff,0x08, 0xff, 0xef, 0x42,0xff,0xff, 0,"Predictive OK"}, +{0xffff,0x08, 0xff, 0xef, 0x43,0xff,0xff, 0,"AC Regained"}, /*PowerSupply*/ +{0xffff,0x08, 0xff, 0xef, 0x46,0xff,0xff, 0,"Config OK now"}, +{0xffff,0x0c, 0xff, 0xff, 0x00,0xff,0xff, 1,"Correctable ECC"}, /*memory*/ +{0xffff,0x0f, 0x06, 0xff, 0xff,0xff,0xff, 2,"POST Code"}, +{0xffff,0x10, 0x09, 0xff, 0x42,0x0f,0xff, 0,"Log Cleared"}, +{0xffff,0x10, 0xff, 0xff, 0x02,0xff,0xff, 0,"Log Cleared"}, +{0xffff,0x10, 0xff, 0xff, 0xc0,0x03,0xff, 1,"ECC Memory Errors"}, + /* Often see these 3 Boot records with reboot: + * 0003 12 83 6f 05 00 ff = System/SEL ClockSync_1 (start of POST) + * 0003 12 83 6f 05 80 ff = System/SEL ClockSync_2 (end of POST) + * 0003 12 83 6f 01 ff ff = OEM System Boot Event (after POST, loader), or + * 0003 12 83 6f 41 0f ff = OEM System Boot Event (same w 01 & 41) + * can be either 0003 (BIOS) or 0001 (EFI) + */ +{0xffff,0x12, 0xfe, 0xff, 0xc5,0x00,0xff, 0,"Boot: ClockSync_1"}, +{0xffff,0x12, 0xfe, 0xff, 0xc5,0x80,0xff, 0,"Boot: ClockSync_2"}, +{0xffff,0x12, 0x83, 0xff, 0x05,0x00,0xff, 0,"Boot: ClockSync_1"}, +{0xffff,0x12, 0x83, 0xff, 0x05,0x80,0xff, 0,"Boot: ClockSync_2"}, +{0xffff,0x12, 0x83, 0xff, 0x01,0xff,0xff, 0,"OEM System Booted"}, +{0x0001,0x12, 0x08, 0xff, 0x01,0xff,0xff, 0,"OEM System Booted"}, /*ia64*/ +{0xffff,0x12, 0x01, 0x6f, 0x01,0xff,0xff, 0,"OEM System Booted"}, /*S5000*/ +{0xffff,0x12, 0x38, 0x6f, 0x00,0xff,0xff, 0,"OEM System Booted"}, /*KTC*/ +{0xffff,0x12, 0x38, 0xef, 0x00,0xff,0xff, 0,"OEM System Booted"}, /*KTC*/ +{0x0031,0x12, 0x00, 0x6f, 0xc3,0xff,0xff, 0,"PEF Action"}, /*ia64*/ +{BMC_SA,0x12, 0x83, 0x6f, 0x80,0xff,0xff, 0,"System Reconfigured"}, /*BMC*/ +{BMC_SA,0x12, 0x83, 0x0b, 0x80,0xff,0xff, 0,"System Reconfigured"}, /*BMC*/ +{BMC_SA,0x12, 0x0b, 0x6f, 0x80,0xff,0xff, 0,"System Reconfigured"}, /*BMC*/ +{BMC_SA,0x12, 0x83, 0xff, 0x41,0xff,0xff, 0,"OEM System Boot"}, /*BMC*/ +{BMC_SA,0x12, 0x83, 0x6f, 0x42,0xff,0xff, 2,"System HW failure"}, /*BMC*/ +{BMC_SA,0x12, 0x83, 0x6f, 0x04,0xff,0xff, 0,"PEF Action"}, /*BMC*/ +{HSC_SA,0x0d, 0xff, 0x08, 0x00,0xff,0xff, 1,"Device Removed"}, /*HSC*/ +{HSC_SA,0x0d, 0xff, 0x08, 0x01,0xff,0xff, 0,"Device Inserted"}, /*HSC*/ +{0xffff,0x0d, 0xff, 0x6f, 0x00,0xff,0xff, 0,"Drive present"}, /*Romley BMC*/ +{0xffff,0x0d, 0xff, 0xef, 0x00,0xff,0xff, 0,"Drive removed"}, /*BMC*/ +{0xffff,0x0d, 0xff, 0x6f, 0x01,0xff,0xff, 2,"Drive fault"}, +{0xffff,0x0d, 0xff, 0xef, 0x01,0xff,0xff, 0,"Drive fault OK"}, +{0xffff,0x0d, 0xff, 0x6f, 0x02,0xff,0xff, 1,"Drive predict fail"}, +{0xffff,0x0d, 0xff, 0x6f, 0x07,0xff,0xff, 0,"Rebuild in progress"}, +{0xffff,0x0d, 0xff, 0xef, 0x07,0xff,0xff, 0,"Rebuild complete"}, +{0xffff,0x14, 0xff, 0xff, 0x42,0xff,0xff, 1,"Reset Button pressed"}, +{0xffff,0x14, 0xff, 0xff, 0x40,0xff,0xff, 1,"Power Button pressed"}, +{0xffff,0x14, 0xff, 0xff, 0x01,0xff,0xff, 0,"ID Button pressed"}, +{0xffff,0x23, 0xff, 0xff, 0x40,0xff,0xff, 2,"Expired, no action"},/*watchdog2*/ +{0xffff,0x23, 0xff, 0xff, 0x41,0xff,0xff, 3,"Hard Reset action"}, /*watchdog2*/ +{0xffff,0x23, 0xff, 0xff, 0x42,0xff,0xff, 3,"Power down action"}, /*watchdog2*/ +{0xffff,0x23, 0xff, 0xff, 0x43,0xff,0xff, 3,"Power cycle action"},/*watchdog2*/ +{0xffff,0x23, 0xff, 0xff, 0x48,0xff,0xff, 2,"Timer interrupt"}, /*watchdog2*/ +{0xffff,0xf3, 0xff, 0x83, 0x41,0xff,0xff, 0,"SMI de-asserted"}, +{0xffff,0xf3, 0xff, 0x03, 0x41,0xff,0xff, 3,"SMI asserted"}, +{0xffff,0x20, 0x00, 0xff, 0xff,0xff,0xff, 3,"OS Kernel Panic"}, +{0xffff,0x01, 0xff, 0x03, 0x01,0xff,0xff, 2,"Temp Asserted"}, /*Discrete temp*/ +{0xffff,0x01, 0xff, 0x83, 0x01,0xff,0xff, 0,"Temp OK"}, /*Discrete ok*/ +{0xffff,0x01, 0xff, 0x05, 0x01,0xff,0xff, 2,"Temp Asserted"}, /*CPU Hot */ +{0xffff,0x01, 0xff, 0x85, 0x01,0xff,0xff, 0,"Temp OK"}, /*CPU Hot ok*/ +{0xffff,0x01, 0xff, 0x07, 0x01,0xff,0xff, 2,"Temp Asserted"}, /*Discrete temp*/ +{0xffff,0x01, 0xff, 0x87, 0x01,0xff,0xff, 0,"Temp OK"}, /*Discrete ok*/ + /*Thresholds apply to sensor types 1=temp, 2=voltage, 3=current, 4=fan*/ + /*Note that last 2 bytes usu show actual & threshold values*/ + /*evtrg: 0x01=thresh, 0x81=restored/deasserted */ +{0xffff,0xff, 0xff, 0x01, 0x50,0xff,0xff, 1,"Lo Noncrit thresh"}, +{0xffff,0xff, 0xff, 0x01, 0x51,0xff,0xff, 0,"Lo NoncritH OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x52,0xff,0xff, 2,"Lo Crit thresh"}, +{0xffff,0xff, 0xff, 0x01, 0x53,0xff,0xff, 0,"Lo CritHi OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x54,0xff,0xff, 3,"Lo Unrec thresh"}, +{0xffff,0xff, 0xff, 0x01, 0x55,0xff,0xff, 0,"Lo UnrecH OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x56,0xff,0xff, 0,"Hi NoncritL OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x57,0xff,0xff, 1,"Hi Noncrit thresh"}, +{0xffff,0xff, 0xff, 0x01, 0x58,0xff,0xff, 0,"Hi CritLo OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x59,0xff,0xff, 2,"Hi Crit thresh"}, +{0xffff,0xff, 0xff, 0x01, 0x5A,0xff,0xff, 0,"Hi UnrecL OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x5B,0xff,0xff, 3,"Hi Unrec thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x50,0xff,0xff, 0,"LoN thresh OK now"}, +{0xffff,0xff, 0xff, 0x81, 0x51,0xff,0xff, 1,"LoNoncrit thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x52,0xff,0xff, 0,"LoC thresh OK now"}, +{0xffff,0xff, 0xff, 0x81, 0x53,0xff,0xff, 2,"LoCritHi thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x54,0xff,0xff, 0,"LoU thresh OK now"}, +{0xffff,0xff, 0xff, 0x81, 0x55,0xff,0xff, 3,"LoUnrecH thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x56,0xff,0xff, 1,"HiNoncrit thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x57,0xff,0xff, 0,"HiN thresh OK now"}, +{0xffff,0xff, 0xff, 0x81, 0x58,0xff,0xff, 2,"HiCritLo thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x59,0xff,0xff, 0,"HiC thresh OK now"}, +{0xffff,0xff, 0xff, 0x81, 0x5A,0xff,0xff, 3,"HiURecLo thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x5B,0xff,0xff, 0,"HiU thresh OK now"} +}; + +#define NENTID 53 +static struct { char * str; uchar styp; } entitymap[NENTID] = { +/* 00 */ { "unspecified", 0x00 }, +/* 01 */ { "other", 0x00 }, +/* 02 */ { "unknown", 0x00 }, +/* 03 */ { "Processor", 0x07 }, +/* 04 */ { "Disk", 0x00 }, +/* 05 */ { "Peripheral bay", 0x0D }, +/* 06 */ { "Management module", 0x00 }, +/* 07 */ { "System board", 0x00 }, +/* 08 */ { "Memory module", 0x00 }, +/* 09 */ { "Processor module", 0x00 }, +/* 10 */ { "Power supply", 0x08 }, +/* 11 */ { "Add-in card", 0x00 }, +/* 12 */ { "Front panel bd", 0x00 }, +/* 13 */ { "Back panel board", 0x00 }, +/* 14 */ { "Power system bd", 0x00 }, +/* 15 */ { "Drive backplane", 0x00 }, +/* 16 */ { "Expansion board", 0x00 }, +/* 17 */ { "Other system board", 0x15 }, +/* 18 */ { "Processor board", 0x15 }, +/* 19 */ { "Power unit", 0x09 }, +/* 20 */ { "Power module", 0x08 }, +/* 21 */ { "Power distr board", 0x09 }, +/* 22 */ { "Chassis back panel bd", 0x00 }, +/* 23 */ { "System Chassis", 0x00 }, +/* 24 */ { "Sub-chassis", 0x00 }, +/* 25 */ { "Other chassis board", 0x15 }, +/* 26 */ { "Disk Drive Bay", 0x0D }, +/* 27 */ { "Peripheral Bay", 0x00 }, +/* 28 */ { "Device Bay", 0x00 }, +/* 29 */ { "Fan", 0x04 }, +/* 30 */ { "Cooling unit", 0x0A }, +/* 31 */ { "Cable/interconnect", 0x1B }, +/* 32 */ { "Memory device ", 0x0C }, +/* 33 */ { "System Mgt Software", 0x28 }, +/* 34 */ { "BIOS", 0x00 }, +/* 35 */ { "Operating System", 0x1F }, +/* 36 */ { "System bus", 0x00 }, +/* 37 */ { "Group", 0x00 }, +/* 38 */ { "Remote Mgt Comm Device", 0x00 }, +/* 39 */ { "External Environment", 0x00 }, +/* 40 */ { "battery", 0x29 }, +/* 41 */ { "Processing blade", 0x00 }, +/* 43 */ { "Processor/memory module", 0x0C }, +/* 44 */ { "I/O module", 0x15 }, +/* 45 */ { "Processor/IO module", 0x00 }, +/* 46 */ { "Mgt Controller Firmware", 0x0F }, +/* 47 */ { "IPMI Channel", 0x00 }, +/* 48 */ { "PCI Bus", 0x00 }, +/* 49 */ { "PCI Express Bus", 0x00 }, +/* 50 */ { "SCSI Bus", 0x00 }, +/* 51 */ { "SATA/SAS bus", 0x00, }, +/* 52 */ { "Processor FSB", 0x00 } +}; + +char *decode_entity_id(int id) +{ + char *str = NULL; + if (id < 0) id = 0; + if (id > NENTID) { + if (id >= 0x90 && id < 0xB0) str = "Chassis-specific"; + else if (id >= 0xB0 && id < 0xD0) str = "Board-specific"; + else if (id >= 0xD0 && id <= 0xFF) str = "OEM-specific"; + else str = "invalid"; + } else str = entitymap[id].str; + return(str); +} + +uchar entity2sensor_type(uchar ent) +{ + uchar stype = 0x12; + uchar b; + if (ent < NENTID) { + b = entitymap[ent].styp; + if (fdebug) printf("entity2sensor_type(%x,%s), stype=%x\n",ent, + entitymap[ent].str,b); + if (b != 0) stype = b; + } + return(stype); +} + + +static char *mem_str(int off) +{ + char *pstr; + switch(off) { + case 0x00: pstr = "Correctable ECC"; break; + case 0x01: pstr = "Uncorrectable ECC"; break; + case 0x02: pstr = "Parity"; break; + case 0x03: pstr = "Memory Scrub Failed"; break; + case 0x04: pstr = "Memory Device Disabled"; break; + case 0x05: pstr = "ECC limit reached" ; break; + case 0x07: pstr = "SMI Link Lane Fail Over"; break; /*Quanta QSSC_S4R*/ + default: pstr = "Other Memory Error"; break; + } + return(pstr); +} + + +#if defined(METACOMMAND) +/* METACOMMAND is defined for ipmiutil meta-command build. */ +/* These can only be external if linked with non-core objects. */ +extern int GetSDR(int recid, int *recnext, uchar *sdr, int szsdr, int *slen); +extern double RawToFloat(uchar raw, uchar *psdr); +extern char *get_unit_type(uchar iunit, uchar ibase, uchar imod, int flg); +extern int find_sdr_by_snum(uchar *psdr,uchar *pcache, uchar snum, uchar sa); +extern int GetSensorType(int snum, uchar *stype, uchar *rtype); +extern char * get_mfg_str(uchar *rgmfg, int *pmfg); /*from ihealth.c*/ +extern int decode_post_intel(int prod, ushort code, char *outbuf,int szbuf); +extern int decode_sel_kontron(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_kontron.c*/ +extern int decode_sel_fujitsu(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_fujitsu.c*/ +extern int decode_sel_intel(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_intel.c*/ +extern int decode_sel_supermicro(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_supermicro.c*/ +extern int decode_sel_quanta(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_quanta.c*/ +extern int decode_sel_newisys(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_newisys.c*/ +extern int decode_sel_dell(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_dell.c*/ +extern int decode_mem_intel(int prod, uchar b2, uchar b3, char *desc, int *psz); /*oem_intel.c*/ +extern int decode_mem_supermicro(int prod, uchar b2, uchar b3, char *desc, int *psz); /*oem_intel.c*/ +#else +/* else it could be ALONE or for a libipmiutil.a build */ +static int default_mem_desc(uchar b2, uchar b3, char *desc, int *psz) +{ + int array, dimm, n; + uchar bdata; + if (desc == NULL || psz == NULL) return -1; + if (b3 == 0xff) bdata = b2; /*ff is reserved*/ + else bdata = b3; /* normal case */ + array = (bdata & 0xc0) >> 6; + dimm = bdata & 0x3f; + n = sprintf(desc,"DIMM[%d]",dimm); + *psz = n; + return(0); +} +static int decode_mem_intel(int prod, uchar b2, uchar b3, char *desc, int *psz) +{ return(default_mem_desc(b2,b3,desc,psz)); } +static int decode_mem_supermicro(int prod, uchar b2, uchar b3, char *desc, int *psz) +{ return(default_mem_desc(b2,b3,desc,psz)); } +static char * get_mfg_str(uchar *rgmfg, int *pmfg) +{ /* standalone routine here for minimal set of strings*/ + char *mfgstr; + int mfg; + mfg = rgmfg[0] + (rgmfg[1] << 8) + (rgmfg[2] << 16); + if (pmfg != NULL) *pmfg = mfg; + if (mfg == VENDOR_INTEL) mfgstr = "Intel"; + else if (mfg == VENDOR_MICROSOFT) mfgstr = "Microsoft"; + else if (mfg == VENDOR_KONTRON) mfgstr = "Kontron"; + else if (mfg == VENDOR_SUPERMICROX) mfgstr = "SuperMicro"; + else if (mfg == VENDOR_SUPERMICRO) mfgstr = "SuperMicro"; + else mfgstr = " "; + return (mfgstr); +} +#ifdef SENSORS_OK +extern int GetSDR(int recid, int *recnext, uchar *sdr, int szsdr, int *slen); +extern double RawToFloat(uchar raw, uchar *psdr); +extern char *get_unit_type(uchar iunit, uchar ibase, uchar imod, int flg); +extern int find_sdr_by_snum(uchar *psdr,uchar *pcache, uchar snum, uchar sa); +extern int GetSensorType(int snum, uchar *stype, uchar *rtype); +#else +static int GetSDR(int recid, int *recnext, uchar *sdr, int szsdr, int *slen) +{ return(-1); } +static double RawToFloat(uchar raw, uchar *psdr) +{ return((double)raw); } +static char *get_unit_type(uchar iunit, uchar ibase, uchar imod, int flg) +{ return(""); }; +static int find_sdr_by_snum(uchar *psdr,uchar *pcache, uchar snum, uchar sa) +{ return(-1); } +static int GetSensorType(int snum, uchar *stype, uchar *rtype) +{ return(-1); } +#endif +#endif + +#if defined(ALONE) +/* ALONE is defined for ievents standalone build. */ +/* IPMI Spec says that this is an index into the DIMMs. + * Walking through the SDRs dynamically would be too slow, + * but isel -e has an SDR cache which could be leveraged, + * however not all platforms have DIMM slot SDRs. + * The BIOS references the DIMM Locator descriptors from + * SMBIOS type 17, and the descriptions vary for each baseboard. + * We'll just show the index here by default. + * Do the SMBIOS lookup if not standalone build. */ + +int strlen_(const char *s) { return((int)strlen(s)); } +// char * get_iana_str(int vend) { return(""); } *from subs.c*/ +void set_iana(int vend) { return; } +int get_MemDesc(int array, int idimm, char *desc, int *psz) +{ + /* standalone, so use the default method for the DIMM index */ + return(default_mem_desc(array,idimm,desc,psz)); +} + +void get_mfgid(int *vend, int *prod) +{ + if ((vend == NULL) || (prod == NULL)) return; + *vend = VENDOR_INTEL; /*assume a default of Intel*/ + *prod = 0; +} +char is_remote(void) +{ return(1); /* act as if remote with standalone utility */ } +char * decode_rv(int rv) +{ + static char mystr[30]; + char *pstr; + switch(rv) { + case 0: pstr = "completed successfully"; break; + case ERR_BAD_PARAM: pstr = "invalid parameter"; break; + case ERR_USAGE: pstr = "usage or help requested"; break; + case ERR_FILE_OPEN: pstr = "cannot open file"; break; + case ERR_NOT_FOUND: pstr = "item not found"; break; + default: sprintf(mystr,"error = %d",rv); pstr = mystr; break; + } + return(pstr); +} +void dump_buf(char *tag, uchar *pbuf, int sz, char fshowascii) +{ + uchar line[17]; + uchar a; + int i, j; + char *stag; + FILE *fpdbg1; + + fpdbg1 = stdout; + if (tag == NULL) stag = "dump_buf"; /*safety valve*/ + else stag = tag; + fprintf(fpdbg1,"%s (len=%d): ", stag,sz); + line[0] = 0; line[16] = 0; + j = 0; + if (sz < 0) { fprintf(fpdbg1,"\n"); return; } /*safety valve*/ + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { + line[j] = 0; + j = 0; + fprintf(fpdbg1,"%s\n %04x: ",line,i); + } + if (fshowascii) { + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + } + fprintf(fpdbg1,"%02x ",pbuf[i]); + } + if (fshowascii) { + if ((j > 0) && (j < 16)) { + /* space over the remaining number of hex bytes */ + for (i = 0; i < (16-j); i++) fprintf(fpdbg1," "); + } + else j = 16; + line[j] = 0; + } + fprintf(fpdbg1,"%s\n",line); + return; +} +int ipmi_cmdraw(uchar cmd, uchar netfn, uchar sa, uchar bus, uchar lun, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ return(-9); } +#else +/* ipmicmd.h has ipmi_cmdraw() */ +extern int get_MemDesc(int array, int dimm, char *desc, int *psz); /*mem_if.c*/ +extern void get_mfgid(int *vend, int *prod); /*from ipmicmd.c*/ +extern char is_remote(void); /*from ipmicmd.c*/ +extern char * decode_rv(int rv); /*from ipmilan.c*/ +extern void dump_buf(char *tag, uchar *pbuf, int sz, char fshowascii); +#endif + +int new_event(uchar *buf, int len) +{ + int rlen, rv; + uchar idata[8]; + uchar rdata[4]; + uchar cc; + /* + Platform Event Message command, inputs: + offset + 0 = GeneratorID, 0x20 for BMC, 0x21 for SMI/kernel, 0x33 for BIOS + 1 = EVM Rev, 3=IPMI10, 4=IPMI15 + 2 = Sensor Type + 3 = Sensor Number + 4 = Event Type (0x6f = sensor specific) + 5 = data1 + 6 = data2 + 7 = data3 + */ + idata[0] = buf[0]; /*GenID on input is two bytes, but one byte here*/ + idata[1] = buf[2]; + idata[2] = buf[3]; + idata[3] = buf[4]; + idata[4] = buf[5]; + idata[5] = buf[6]; + idata[6] = buf[7]; + idata[7] = buf[8]; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(0x02, NETFN_SEVT, BMC_SA, PUBLIC_BUS, BMC_LUN, + idata,8, rdata,&rlen,&cc, fdebug); + if (fdebug) printf("platform_event: rv = %d, cc = %02x\n",rv,cc); + if ((rv == 0) && (cc != 0)) rv = cc; + return(rv); +} + +char *get_sensor_type_desc(uchar stype) +{ + int i; + static char stype_desc[25]; + char *pstr; + if (stype == 0xF3) i = 0x2D; /*OEM SMI*/ + else if (stype == 0xDC) i = 0x2E; /*NM*/ + else if (stype == SMI_SA) i = BMC_SA; /*SMI -> BMC*/ + else if (stype >= NSTYPES) i = 0; + else i = stype; + if (i == 0) { /* reserved, show the raw sensor_type also */ + if (stype == 0xCF) + strncpy(stype_desc,"OEM Board Reset", sizeof(stype_desc)); + else if (stype >= 0xC0) + sprintf(stype_desc,"OEM(%02x)",stype); + else sprintf(stype_desc,"%s(%02x)",sensor_types[i],stype); /*reserved*/ + pstr = (char *)stype_desc; + } else { + pstr = (char *)sensor_types[i]; + } + return(pstr); +} + +/*------------------------------------------------------------------------ + * get_misc_desc + * Uses the sens_desc array to decode misc entries not otherwise handled. + * Called by decode_sel_entry + *------------------------------------------------------------------------*/ +char * +get_misc_desc(ushort genid, uchar type, uchar num, uchar trig, + uchar data1, uchar data2, uchar data3, uchar *sev) +{ + int i; + char *pstr = NULL; + + /* Use sens_desc array for other misc descriptions */ + data1 &= 0x0f; /*ignore top half of sensor offset for matching */ + for (i = 0; i < NSDESC; i++) { + if ((sens_desc[i].s_typ == 0xff) || + (sens_desc[i].s_typ == type)) { + if (sens_desc[i].s_num != 0xff && + sens_desc[i].s_num != num) + continue; + if (sens_desc[i].genid != 0xffff && + sens_desc[i].genid != genid) + continue; + if (sens_desc[i].evtrg != 0xff && + sens_desc[i].evtrg != trig) + continue; + if (sens_desc[i].data1 != 0xff && + (sens_desc[i].data1 & 0x0f) != (data1 & 0x0f)) + continue; + if (sens_desc[i].data2 != 0xff && + sens_desc[i].data2 != data2) + continue; + if (sens_desc[i].data3 != 0xff && + sens_desc[i].data3 != data3) + continue; + /* have a match, use description */ + pstr = (char *)sens_desc[i].desc; + if (sev != NULL) *sev = sens_desc[i].sev; + break; + } + } /*end for*/ + return(pstr); +} /* end get_misc_desc() */ + +time_t utc2local(time_t t) +{ + struct tm * tm_tmp; + int gt_year,gt_yday,gt_hour,lt_year,lt_yday,lt_hour; + int delta_hour; + time_t lt; + // convert UTC time to local time + // i.e. number of seconds from 1/1/70 0:0:0 1970 GMT + tm_tmp=gmtime(&t); + gt_year=tm_tmp->tm_year; + gt_yday=tm_tmp->tm_yday; + gt_hour=tm_tmp->tm_hour; + tm_tmp=localtime(&t); + lt_year=tm_tmp->tm_year; + lt_yday=tm_tmp->tm_yday; + lt_hour=tm_tmp->tm_hour; + delta_hour=lt_hour - gt_hour; + if ( (lt_year > gt_year) || ((lt_year == gt_year) && (lt_yday > gt_yday)) ) + delta_hour += 24; + if ( (lt_year < gt_year) || ((lt_year == gt_year) && (lt_yday < gt_yday)) ) + delta_hour -= 24; + if (fdebug) printf("utc2local: delta_hour = %d\n",delta_hour); + lt = t + (delta_hour * 60 * 60); + return(lt); +} + +void fmt_time(time_t etime, char *buf, int bufsz) +{ + time_t t; + if (bufsz < 18) printf("fmt_time: buffer size should be >= 18\n"); + if (futc) t = etime; + else t = utc2local(etime); /*assume input time is UTC*/ + strncpy(buf,"00/00/00 00:00:00",bufsz); + strftime(buf,bufsz, "%x %H:%M:%S", gmtime(&t)); /*or "%x %T"*/ + return; +} + +/* + * findmatch + * Finds a matching pattern within a string buffer. + * returns offset of the match if found, or -1 if not found. + */ +int +findmatch(char *buffer, int sbuf, char *pattern, int spattern, char figncase) +{ + int c, i, j, imatch; + + j = 0; + imatch = 0; + for (j = 0; j < sbuf; j++) { + if ((sbuf - j) < spattern && imatch == 0) return(-1); + c = buffer[j]; + if (c == pattern[imatch]) { + imatch++; + } else if ((figncase == 1) && + ((c & 0x5f) == (pattern[imatch] & 0x5f))) { + imatch++; + } else if (pattern[imatch] == '?') { /*wildcard char*/ + imatch++; + } else { + if (imatch > 0) { + if (j > 0) j--; /* try again with the first match char */ + imatch = 0; + } + } + if (imatch == spattern) break; + } + if (imatch == spattern) { + i = (j+1) - imatch; /*buffer[i] is the match */ + return(i); + } else return (-1); /*not found*/ +} /*end findmatch */ + +/* + * file_grep + * Search (grep) for a pattern within a file. + * Inputs: fname = file name to search + * pattn = pattern string to search for + * line = line buffer + * sline = size of line buffer + * bmode = 0 to use last match, + * 1 to use first match, + * 2 to specify starting line number & use first match. + * nret = IN: starting char offset, OUT: num chars read + * Outputs: line = resulting line (stringified) that matches pattn + * nret = resulting line number within file (0-based) + * returns 0 if match, < 0 if error + */ +int file_grep(char *fname, char *pattn, char *line, int sline, + char bmode, int *nret) +{ + FILE *fp; + char buff[1024]; + int ret = ERR_NOT_FOUND; + int i, plen, blen; + int n = 0; + int nstart = 0; + int bufsz; + + if (bmode == 2) nstart = *nret; + bufsz = sizeof(buff); + fp = fopen(fname,"r"); + if (fp == NULL) { + if (fdebug) printf("file_grep: Cannot open %s\n",fname); + ret = ERR_FILE_OPEN; /*cannot open file*/ + } else { + plen = strlen_(pattn); + fseek(fp, nstart, SEEK_SET); + n = nstart; + while (fgets(buff, bufsz, fp) != NULL) + { + blen = strlen_(buff); + /* check for pattern in this line */ + i = findmatch(&buff[0],blen,pattn,plen,0); + if (i >= 0) { + ret = 0; /* found it, success */ + if ((line != NULL) && sline > 1) { + if (blen >= sline) blen = sline - 1; + strncpy(line,buff,blen); + line[blen] = 0; /*stringify*/ + } + if (nret != NULL) *nret = n + i + plen; + if (bmode > 0) break; + /* else keep looking, use last one if multiples */ + } + n += blen; /*number of chars*/ + } /*end while*/ + fclose(fp); + } /*end else file opened*/ + return(ret); +} /*end file_grep*/ + +char *get_sev_str(int val) +{ + if (val >= NSEV) val = SEV_CRIT; + return(sev_str[val]); +} + +/* The htoi() routine is available in subs.c, but ievents.c also + * needs a local copy of it if built with -DALONE. */ +static uchar _htoi(char *inhex) +{ + // char rghex[16] = "0123456789ABCDEF"; + uchar val; + char c; + c = inhex[0] & 0x5f; /* force cap */ + if (c > '9') c += 9; /* c >= 'A' */ + val = (c & 0x0f) << 4; + c = inhex[1] & 0x5f; /* force cap */ + if (c > '9') c += 9; /* c >= 'A' */ + val += (c & 0x0f); + return(val); +} + +/* + * set_sel_opts is used to specify options for showing/decoding SEL events. + * sensdesc : 0 = simple, no sensor descriptions + * 1 = get sensor descriptions from sdr cache + * 2 = get sensor descriptions from sensor file (-s) + * canon : 0 = normal output + * 1 = canonical, delimited output + * sdrs : NULL = no sdr cache, dynamically get sdr cache if sensdesc==1 + * ptr = use this pointer as existing sdr cache if sensdesc==1 + * fdbg : 0 = normal mode + * 1 = debug mode + * futc : 0 = normal mode + * 1 = show raw UTC time + */ +void set_sel_opts(int sensdesc, int canon, void *sdrs, char fdbg, char utc) +{ + fsensdesc = (char)sensdesc; /*get extended sensor descriptions*/ + fcanonical = (char)canon; /*show canonical, delimited output*/ + if (sdrcache == NULL) sdrcache = sdrs; + else printf("Warning: attempted to set_sel_opts(sdrcache) twice\n"); + fdebug = fdbg; + futc = utc; +} + +/* get_sensdesc - get the sensor tag/description from the sensor.out file */ +int get_sensdesc(uchar sa, int snum, char *sensdesc, int *pstyp, int *pidx) +{ + int rv, i, j, len, idx; + char pattn[20]; + char sensline[100]; + int nline = 0; + uchar sa2; + char *sfil; + char *p; + + if (sensdesc == NULL) return ERR_BAD_PARAM; + sensdesc[0] = 0; + if (fdebug) printf("sensdesc(%02x,%02x) with %s\n",sa,snum,sensfil); + sprintf(pattn,"snum %02x",snum); + for (j = 0; j < 3; j++) + { + sfil = sensfil; + /* Use this logic for both Linux and Windows */ + rv = file_grep(sfil,pattn, sensline, sizeof(sensline), 2, &nline); + if (rv != 0) { + if (rv == ERR_FILE_OPEN) { + if (fdebug) fprintf(stdout,"Cannot open file %s\n",sfil); + sfil = sensfil2; + rv = file_grep(sfil, pattn, sensline,sizeof(sensline), 2, &nline); + if (fdebug && rv == ERR_FILE_OPEN) + fprintf(stdout,"Cannot open file %s\n",sfil); + } + if (rv != ERR_FILE_OPEN) { + if (fdebug) printf("Cannot find snum %02x in file %s\n",snum,sfil); + rv = ERR_NOT_FOUND; + } + break; + } + if (rv == 0) { + idx = _htoi(&sensline[2]) + (_htoi(&sensline[0]) << 8); + sa2 = _htoi(&sensline[20]); + if (fdebug) + printf("sensdesc(%02x,%02x) found snum for sa %02x at offset %d\n", sa,snum,sa2,nline); + if (sa == sa2) { + /* truncate the sensor line to omit the reading */ + len = strlen_(sensline); + for (i = 0; i < len; i++) + if (sensline[i] == '=') { sensline[i] = 0; break; } + if (sensline[i-1] != ' ') { + sensline[i] = ' '; sensline[++i] = 0; + } + /* skip to just the sensor description from the SDR */ + p = strstr(sensline,"snum"); + p += 8; /* skip 'snum 11 ' */ + strcpy(sensdesc,p); + if (pstyp != NULL) *pstyp = _htoi(&sensline[25]); + if (pidx != NULL) *pidx = idx; + break; + } + } + } /*end-for j*/ + if (j >= 3) rv = ERR_NOT_FOUND; /*not found*/ + return(rv); +} + +char *get_genid_str(ushort genid) +{ + static char genstr[10]; + char *gstr; + int i; + + sprintf(genstr,"%04x",genid); + gstr = genstr; /* default */ + for (i = 0; i < NGDESC; i++) + { + if (gen_desc[i].g_id == genid) { + gstr = (char *)gen_desc[i].desc; + break; + } + } + return(gstr); +} + +static int is_threshold(uchar evtrg, ushort genid) +{ + int val = 0; /*false*/ + /* It would be better to check the SDR (if Full supports thresholds), + * but we do not always have that available. */ + if ( ((genid == BMC_SA) || /*from BMC*/ + (genid == SMI_SA) || /*from SMI (simulated)*/ + (genid == thr_sa)) && /*from HSC, or other*/ + ((evtrg == 0x01) || /*threshold evt*/ + (evtrg == 0x81))) /*threshold ok*/ + val = 1; + return(val); +} + +static void get_sdr_tag(uchar *sdr, char *tagstr) +{ + int i, j, k, len; + len = sdr[4] + 5; + switch(sdr[3]) { + case 0x01: k = 48; break; /*full sensor*/ + case 0x02: k = 32; break; /*compact sensor*/ + case 0x03: k = 17; break; /*compact sensor*/ + case 0x10: k = 16; break; /*compact sensor*/ + case 0x11: k = 16; break; /*compact sensor*/ + case 0x12: k = 16; break; /*compact sensor*/ + default: k = 0; break; + } + if (k > 0 && k < len) { + i = len - k; + for (j = 0; j < i; j++) { + if (sdr[k+j] == 0) break; + tagstr[j] = sdr[k+j]; + } + tagstr[j++] = ' '; + tagstr[j] = 0; + } +} + +/* + * get_sensor_tag + * + * Get the sensor tag (name) based on the sensor number, etc. + * Use one of 3 methods to get this: + * 1) Parse the sensor_out.txt (sensfil) if fsensdesc==2. + * Use this method if not METACOMMAND or if user-specified. + * 2) Find this SDR in the SDR cache, if available. + * 3) Do a GetSDR command function now (can be slow) + * Input parameters: + * isdr = index of SDR, use 0 if unknown + * genid = genid or sa (slave address) of this sensor + * snum = sensor number of this sensor + * tag = pointer to a buffer for the sensor tag (min 17 bytes) + * sdr = pointer to buffer for the SDR if found (usu <= 65 bytes) + * szsdr = size of the SDR buffer + * Output parameters: + * tag = filled in with sensor tag (name) + * sdr = filled in with SDR, if found. + * Returns: + * 0 if tag and sdr are found. + * ERR_NOT_FOUND if SDR is not found (but tag may be found) + * other errors, see ipmicmd.h + */ +int get_sensor_tag(int isdr, int genid, uchar snum, char *tag, + uchar *sdr, int szsdr) +{ + int rv, i, j = 0; + if (tag == NULL) return(ERR_BAD_PARAM); + if (sdr == NULL) return(ERR_BAD_PARAM); + if (genid == SMS_SA) genid = BMC_SA; /*parse Sms as if BMC*/ + if (genid == SMI_SA) genid = BMC_SA; /*parse SMI as if BMC*/ + tag[0] = 0; + if (fsensdesc == 2) { /*not connected, so do not try to GetSDR*/ + rv = get_sensdesc((uchar)genid, snum, tag,NULL,&isdr); + rv = ERR_NOT_FOUND; /*got tag, but did not get SDR*/ + } else if (sdrcache != NULL) { /*valid sdr cache*/ + rv = find_sdr_by_snum(sdr,sdrcache, snum, (uchar)genid); + if (rv == 0) { + get_sdr_tag(sdr,tag); + } + } else { /* try to get this SDR */ + rv = GetSDR(isdr, &i,sdr,szsdr,&j); + if (fdebug) printf("get_sensor_tag GetSDR[%x] rv=%d sz=%d\n",isdr,rv,j); + if (rv == 0) { + get_sdr_tag(sdr,tag); + } else { /* use a saved sensor.out file */ + rv = get_sensdesc((uchar)genid, snum, tag,NULL,&isdr); + if (rv != 0) tag[0] = 0; + rv = ERR_NOT_FOUND; /*got tag, but did not get SDR*/ + } + } + if (fdebug) printf("get_sensor_tag(%d): find_sdr(%x,%x) rv=%d tag=/%s/\n", + fsensdesc,snum,genid,rv,tag); + return(rv); +} + +static +int decode_post_oem(int vend, int prod, ushort code, char *outbuf,int szbuf) +{ + int rv = -1; + if (outbuf == NULL || szbuf == 0) return(rv); +#if defined(METACOMMAND) + switch(vend) { + case VENDOR_INTEL: + rv = decode_post_intel(prod,code,outbuf,szbuf); + break; + default: + break; + } +#endif + if (rv != 0) snprintf(outbuf,szbuf,"POST Code %04x",code); + return(rv); +} + +static +int decode_sel_oem(int vend, uchar *pevt, char *outbuf,int szbuf, + char fdesc, char fdbg) +{ + int rv = -1; +#ifdef METACOMMAND + switch(vend) { + case VENDOR_KONTRON: + rv = decode_sel_kontron(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_FUJITSU: + /* Fujitsu does an OEM IPMI command to return the decoded string. */ + rv = decode_sel_fujitsu(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_INTEL: + thr_sa = HSC_SA; /* HSC_SA(0xC0) by default */ + rv = decode_sel_intel(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_PEPPERCON: /*SuperMicro AOC-SIMSO*/ + if (pevt[7] == 0x40) pevt[7] = BMC_SA; /*genid broken, fix it*/ + break; + case VENDOR_MAGNUM: + case VENDOR_SUPERMICRO: + case VENDOR_SUPERMICROX: + rv = decode_sel_supermicro(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_QUANTA: + rv = decode_sel_quanta(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_NEWISYS: + rv = decode_sel_newisys(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_DELL: + rv = decode_sel_dell(pevt,outbuf,szbuf,fdesc,fdbg); + break; + default: + break; + } +#endif + if (fdebug) printf("decode_sel_oem(0x%04x) rv=%d\n",vend,rv); + return(rv); +} + +#define N_PWRUNIT 12 +static struct { + uchar trg; uchar data1; uchar sev; char *msg; + } pwrunit_evts[N_PWRUNIT] = { +{ 0x6f, 0x00, 0,"Power Off "}, +{ 0x6f, 0x01, 0,"Power Cycle "}, +{ 0x6f, 0x02, 0,"240VA power down"}, +{ 0x6f, 0x03, 0,"Interlock power down"}, +{ 0x6f, 0x04, 1,"AC Lost"}, +{ 0x6f, 0x05, 2,"Soft Powerup failure"}, +{ 0x6f, 0x06, 2,"Failure detected"}, +{ 0x6f, 0x07, 1,"Predictive failure"}, +{ 0xef, 0x00, 0,"Power Restored"}, +{ 0xef, 0x01, 0,"Power Cycle ok"}, +{ 0xef, 0x04, 0,"AC Regained"}, +{ 0xef, 0x06, 0,"Failure OK now"} +}; +static int decode_pwrunit(uchar trg, uchar data1, char *pstr, uchar *psev) +{ + int rv = -1; + int i, j; + j = data1 & 0x0f; + if (psev == NULL || pstr == NULL) return(rv); + sprintf(pstr,"_"); + for (i = 0; i < N_PWRUNIT; i++) + { + if ((trg == pwrunit_evts[i].trg) && + (j == pwrunit_evts[i].data1)) { + *psev = pwrunit_evts[i].sev; + sprintf(pstr,"%s",pwrunit_evts[i].msg); + rv = 0; + } + } + return(rv); +} + +#define N_REDUN 16 +static struct { + uchar trg; uchar data1; uchar sev; char *msg; + } redund_evts[N_REDUN] = { +{ 0x0B, 0x00, SEV_INFO,"Redundancy OK "}, +{ 0x0B, 0x01, SEV_MAJ, "Redundancy Lost"}, +{ 0x0B, 0x02, SEV_MAJ, "Redundancy Degraded"}, +{ 0x0B, 0x03, SEV_MAJ, "Not Redundant"}, +{ 0x0B, 0x04, SEV_MAJ, "Sufficient Resources"}, +{ 0x0B, 0x05, SEV_CRIT,"Insufficient Resources"}, +{ 0x0B, 0x06, SEV_MAJ, "Fully-to-Degraded"}, +{ 0x0B, 0x07, SEV_MIN, "NonR-to-Degraded"}, +{ 0x8B, 0x00, SEV_MAJ, "Redundancy NOT ok"}, +{ 0x8B, 0x01, SEV_INFO,"Redundancy Regained"}, +{ 0x8B, 0x02, SEV_INFO,"Redundancy Restored"}, +{ 0x8B, 0x03, SEV_INFO,"Redundant"}, +{ 0x8B, 0x04, SEV_MAJ, "Not Sufficient"}, +{ 0x8B, 0x05, SEV_INFO,"Not Insufficient"}, +{ 0x8B, 0x06, SEV_INFO,"Degraded-to-Fully"}, +{ 0x8B, 0x07, SEV_MIN, "Degraded-to-NonR"} +}; +static int decode_redund(uchar trg, uchar data1, char *pstr, uchar *psev) +{ + int rv = -1; + int i, j; + j = data1 & 0x0f; + if (psev == NULL || pstr == NULL) return(rv); + sprintf(pstr,"_"); + for (i = 0; i < N_REDUN; i++) + { + if ((trg == redund_evts[i].trg) && + (j == redund_evts[i].data1)) { + *psev = redund_evts[i].sev; + sprintf(pstr,"%s",redund_evts[i].msg); + rv = 0; + } + } + return(rv); +} + +#define N_PRESENT 2 +static char * present_str[N_PRESENT] = { /* Availability, evtype 0x08 */ + /*00*/ "Absent", /*Absent/Removed*/ + /*01*/ "Present"}; /*Present/Inserted*/ + +static int decode_presence(uchar trg, uchar data1, char *pstr, uchar *psev) +{ + int rv = -1; + int i; + if (psev == NULL || pstr == NULL) return(rv); + sprintf(pstr,"_"); + *psev = SEV_INFO; + i = data1 & 0x0f; + if (trg == 0x08) { + if (i >= N_PRESENT) i = N_PRESENT - 1; + sprintf(pstr,"%s",present_str[i]); + rv = 0; + } else if (trg == 0x88) { + if (data1 & 0x01) i = 0; + else i = 1; + sprintf(pstr,"%s",present_str[i]); + } + return(rv); +} + +void format_event(ushort id, time_t timestamp, int sevid, ushort genid, + char *ptype, uchar snum, char *psens, char *pstr, char *more, + char *outbuf, int outsz) +{ + char sensdesc[36]; + char timestr[40]; + uchar sdr[MAX_BUFFER_SIZE]; /*sdr usu <= 65 bytes*/ + char *gstr; + int isdr = 0; + int rv; + + if (more == NULL) more = ""; + if (psens != NULL) ; /* use what was passed in */ + else { /*psens==NULL, may need to get tag*/ + psens = &sensdesc[0]; + sensdesc[0] = 0; + if (fsensdesc) { + rv = get_sensor_tag(isdr,genid,snum,psens,sdr,sizeof(sdr)); + if (fdebug) printf("get_sensor_tag(%x) rv = %d\n",snum,rv); + } + } + fmt_time(timestamp, timestr, sizeof(timestr)); + gstr = get_genid_str(genid); /*get Generator ID / Source string*/ + + if (fcanonical) { + snprintf(outbuf,outsz,"%04x %c %s %c %s %c %s %c %s %c %s %c %s %s\n", + id, bdelim, timestr, bdelim, + get_sev_str(sevid), bdelim, + gstr, bdelim, ptype, bdelim, + psens, bdelim, pstr, more ); + } else { + snprintf(outbuf,outsz,"%04x %s %s %s %s #%02x %s%s %s\n", + id, timestr, get_sev_str(sevid), + gstr, ptype, snum, psens, pstr, more); + } + return; +} + +/*------------------------------------------------------------------------ + * decode_sel_entry + * Parse and decode the SEL record into readable format. + * This routine is constructed so that it could be used as a library + * function. + * Note that this routine outputs 14 of the 16 bytes in either text or + * raw hex form. For the two bytes not shown: + * . record type: usually = 02, is shown otherwise (e.g. OEM type) + * . event msg revision: =03 if IPMI 1.0, =04 if IPMI 1.5 or IPMI 2.0 + * + * Input: psel, a pointer to the IPMI SEL record (16 bytes) + * Output: outbuf, a description of the event, max 80 chars. + * Called by: ReadSEL() + * Calls: fmt_time() get_misc_desc() + * + * IPMI SEL record format (from IPMI Table 32-1): + * Offset Meaning + * 0-1 Record ID (LSB, MSB) + * 2 Record Type (usu 0x02) + * 3-6 Timestamp (LS byte first) + * 7-8 Generator ID (LS first, usually 20 00) + * 9 Event message format (=0x04, or =0x03 if IPMI 1.0) + * 10 Sensor type + * 11 Sensor number + * 12 Event Dir | Event Type + * 13 Event Data 1 + * 14 Event Data 2 + * 15 Event Data 3 + *------------------------------------------------------------------------*/ +int decode_sel_entry( uchar *pevt, char *outbuf, int szbuf) +{ + char mystr[80] = "panic(123)"; /*used for panic string*/ + char *pstr; + char poststr[80] = "OEM Post Code = %x%x"; + char sensstr[50]; + char datastr[64]; + char cstr[4]; + char *psensstr; + int i, j, k, n; + time_t eventTime; + uchar *evtime; + char timebuf[40]; + uchar *pc; + SEL_RECORD *psel; + uchar fdeassert = 0; + uchar sev = SEV_INFO; + uchar sdr[MAX_BUFFER_SIZE]; /*sdr usu <= 65 bytes*/ + int isdr = 0; + int vend, prod; + int rv = 0; + char fhave_sdr = 0; + char mdesc[80]; /*used for oem memory description*/ + int msz; + + if (outbuf == NULL) return(ERR_BAD_PARAM); + if (pevt == NULL) { + outbuf[0] = 0; + return(ERR_BAD_PARAM); + } + get_mfgid(&vend,&prod); /*saved from ipmi_getdeviceid */ + psel = (SEL_RECORD *)pevt; + + j = decode_sel_oem(vend,pevt,outbuf,szbuf,fsensdesc,fdebug); + if (j == 0) return(0); /*successful, have the description*/ + + if (psel->record_type == 0xDC) { + /* OEM Record: these are usually Microsoft */ + char *mfgstr; + int mfg; + evtime = (uchar *)&psel->timestamp; + eventTime = evtime[0] + (evtime[1] << 8) + + (evtime[2] << 16) + (evtime[3] << 24); + fmt_time(eventTime, timebuf, sizeof(timebuf)); + pc = (uchar *)&psel->generator_id; /* offset 7 */ + mfgstr = get_mfg_str(&pc[0],&mfg); + + if (fcanonical) + sprintf(outbuf,"%04x %c %s %c %s %c %02x %c %06x %c %s %c OEM Event ", + psel->record_id, bdelim, timebuf, bdelim, + get_sev_str(sev), bdelim, psel->record_type, bdelim, + mfg, bdelim, mfgstr, bdelim); + else + sprintf(outbuf,"%04x %s %s %02x %06x %s OEM Event ", + psel->record_id, timebuf, get_sev_str(sev), + psel->record_type, mfg, mfgstr); + j = strlen_(outbuf); + for (i = 3; i < 9; i++) { /* 10:16 = 6 bytes data */ + sprintf(&outbuf[j],"%02x ",pc[i]); + j += 3; + } + outbuf[j++] = '\n'; + outbuf[j++] = 0; + } else if (psel->record_type == 0xDD) { /* usu Intel OEM string */ + char *mfgstr; + int mfg; + int ix = 0; + /* Windows reboot reason string from MS ipmidrv.sys */ + evtime = (uchar *)&psel->timestamp; + eventTime = evtime[0] + (evtime[1] << 8) + + (evtime[2] << 16) + (evtime[3] << 24); + fmt_time(eventTime, timebuf, sizeof(timebuf)); + pc = (uchar *)&psel->generator_id; /* IANA at offset 7 */ + mfgstr = get_mfg_str(&pc[0],&mfg); + if (fcanonical) + sprintf(outbuf,"%04x %c %s %c %s %c %02x %c %06x %c %s %c OEM Event ", + psel->record_id, bdelim, timebuf, bdelim, + get_sev_str(sev), bdelim, psel->record_type, bdelim, + mfg, bdelim, mfgstr, bdelim); + else + sprintf(outbuf,"%04x %s %s %02x %06x %s OEM Event ", + psel->record_id, timebuf, get_sev_str(sev), + psel->record_type, mfg, mfgstr ); + j = strlen_(outbuf); + for (i = 3; i < 9; i++) { /* 10:16 = 6 bytes data */ + if (i == 3 || ix == 0) { + if (i == 3) ix = pc[i]; + sprintf(&outbuf[j],"%02x ",pc[i]); + j += 3; + } else { + if (pc[i] == 0) outbuf[j] = ' '; + else sprintf(&outbuf[j],"%c",pc[i]); + j += 1; + } + } + outbuf[j++] = '\n'; + outbuf[j++] = 0; + } else if (psel->record_type >= 0xe0) { /*OEM Record 26.3*/ + /* 3 bytes header, 13 bytes data, no timestamp */ + pc = (uchar *)&psel->timestamp; /*bytes 4:16*/ + if (fcanonical) + sprintf(outbuf,"%04x %c %s %c %s %c %02x %c %s %c %s %c OEM Event ", + psel->record_id, bdelim, "", bdelim, + get_sev_str(sev), bdelim, psel->record_type, bdelim, + "", bdelim, "", bdelim); + else + sprintf(outbuf,"%04x %s %02x OEM Event ", + psel->record_id,get_sev_str(sev),psel->record_type); + j = strlen_(outbuf); + for (i = 0; i < 13; i++) { /* 5:16 = 11 bytes data */ + if ((psel->record_type == 0xf0) && (i >= 2)) { + /* Linux panic string will be type 0xf0 */ + if (pc[i] == 0) break; + outbuf[j++] = pc[i]; + } else if (psel->record_type == 0xf1) { + /* custom ascii string record, type 0xf1 */ + if (i == 0) { /*linux panic*/ + outbuf[j++] = ':'; + outbuf[j++] = ' '; + } + if (pc[i] == 0) break; + outbuf[j++] = pc[i]; + } else { + sprintf(&outbuf[j],"%02x ",pc[i]); + j += 3; + } + } + outbuf[j++] = '\n'; + outbuf[j++] = 0; + } else if (psel->record_type >= 0xc0) { /*OEM Record 26.3*/ + /* 10 bytes header, 6 bytes data, has timestamp */ + evtime = (uchar *)&psel->timestamp; + eventTime = evtime[0] + (evtime[1] << 8) + + (evtime[2] << 16) + (evtime[3] << 24); + fmt_time(eventTime, timebuf, sizeof(timebuf)); + pc = (uchar *)&psel->generator_id; /* IANA at offset 7 */ + if (fcanonical) + sprintf(outbuf,"%04x %c %s %c %s %c %02x %c %02x%02x%02x %c %s %c OEM Event ", + psel->record_id, bdelim, timebuf, bdelim, + get_sev_str(sev), bdelim, psel->record_type, bdelim, + pc[2],pc[1],pc[0], bdelim, "", bdelim); + else + sprintf(outbuf,"%04x %s %s %02x %02x%02x%02x OEM Event ", + psel->record_id, timebuf, get_sev_str(sev), + psel->record_type, pc[2],pc[1],pc[0] ); + j = strlen_(outbuf); + for (i = 3; i < 9; i++) { /* 10:16 = 6 bytes data */ + sprintf(&outbuf[j],"%02x ",pc[i]); + j += 3; + } + outbuf[j++] = '\n'; + outbuf[j++] = 0; + } else if (psel->record_type == 0x02) { + uchar c = 0; + /* most records are record type 2 */ + /* Interpret the event by sensor type */ + switch(psel->sensor_type) + { + case 0x20: /*OS Crit Stop*/ + i = psel->event_data1 & 0x0f; + switch(i) { + case 0x00: pstr = "Startup Crit Stop"; + sev = SEV_CRIT; break; + case 0x02: pstr = "OS Graceful Stop"; break; + case 0x03: pstr = "OS Graceful Shutdown"; break; + case 0x04: pstr = "PEF Soft-Shutdown"; break; + case 0x05: pstr = "Agent Not Responding"; break; + case 0x01: /*OS Runtime Critical Stop (panic)*/ + default: + sev = SEV_CRIT; + if (psel->sensor_number == 0) { /*Windows*/ + pstr = "Runtime Crit Stop"; + } else { /*Linux panic, get string*/ + /* Show first 3 chars of panic string */ + pstr = mystr; + strcpy(mystr,"panic("); + for (i = 6; i <= 8; i++) { + switch(i) { + case 6: c = psel->sensor_number; break; + case 7: c = psel->event_data2; break; + case 8: c = psel->event_data3; break; + } + c &= 0x7f; + if (c < 0x20) c = '.'; + mystr[i] = c; + } + mystr[9] = ')'; + mystr[10] = 0; + if (psel->sensor_number & 0x80) + strcat(mystr,"Oops!"); + if (psel->event_data2 & 0x80) + strcat(mystr,"Int!"); + if (psel->event_data3 & 0x80) + strcat(mystr,"NullPtr!"); + } + break; + } /*end data1 switch*/ + break; + case 0x01: /*Temperature events*/ + if (is_threshold(psel->event_trigger, + psel->generator_id)) { + pstr = get_misc_desc( psel->generator_id, + psel->sensor_type, + psel->sensor_number, + psel->event_trigger, + psel->event_data1, + psel->event_data2, + psel->event_data3, &sev); + } else { /*else discrete temp event*/ + /* data1 should usually be 0x01 */ + if (psel->event_trigger & 0x80) + strcpy(mystr,"Temp OK"); + else strcpy(mystr,"Temp Asserted"); + pstr = mystr; + } /*end-else discrete*/ + break; + /* case 0X04 for Fan events is further below. */ + case 0x07: /*Processor (CPU)*/ + i = psel->event_data1 & 0x0f; + if (psel->event_trigger == 0x6f) { + /* Processor status sensor */ + if (i >= NPROC) i = NPROC - 1; + if (i == 7) sev = SEV_INFO; + else if (i > 7) sev = SEV_MIN; + else sev = SEV_CRIT; + sprintf(mystr,"%s",proc_str[i]); + pstr = mystr; + } else if (psel->event_trigger == 0xef) { + sev = SEV_CRIT; + if (i >= NPROC) i = NPROC - 1; + sprintf(mystr,"%s deasserted",proc_str[i]); + pstr = mystr; + } else if (psel->sensor_number == 0x80) { /*CATERR*/ + char *p1, *p2; + sev = SEV_CRIT; + switch( psel->event_data2 & 0x0F) + { + case 1: p1 = "CATERR"; break; + case 2: p1 = "CPU Core Error"; break; + case 3: p1 = "MSID Mismatch"; break; + default: p1 = "Unknown Error"; break; + } + if (psel->event_data2 & 0x01) p2 = "CPU0"; + else if (psel->event_data2 & 0x02) p2 = "CPU1"; + else if (psel->event_data2 & 0x04) p2 = "CPU2"; + else if (psel->event_data2 & 0x08) p2 = "CPU3"; + else p2 = "CPU4"; + sprintf(mystr,"%s on %s",p1,p2); + pstr = mystr; + } else if (psel->event_trigger == 0x03) { + if (i) {pstr = "Proc Config Error"; sev = SEV_CRIT;} + else {pstr = "Proc Config OK"; sev = SEV_INFO; } + } else if (psel->event_trigger == 0x83) { + if (i) { pstr = "Proc Config OK"; sev = SEV_INFO; } + else { pstr = "Proc Config Error"; sev = SEV_CRIT; } + } else { /* else other processor sensor */ + i = ((psel->event_trigger & 0x80) >> 7); + if (i) { pstr = "ProcErr Deasserted"; sev = SEV_INFO;} + else { pstr = "ProcErr Asserted"; sev = SEV_CRIT; } + } + break; + case 0x09: /*Power Unit*/ + if ((psel->event_trigger == 0x0b) || + (psel->event_trigger == 0x8b)) { + rv = decode_redund(psel->event_trigger, + psel->event_data1, mystr, &sev); + } else { /*sensor-specific 0x6f/0xef*/ + rv = decode_pwrunit(psel->event_trigger, + psel->event_data1, mystr, &sev); + } + if (rv == 0) pstr = mystr; + else pstr = NULL; /*falls through to unknown*/ + break; + case 0x0C: /*Memory*/ + i = psel->event_data1 & 0x0f; /*memstr index*/ + { /* now get the DIMM index from data2 or data3 */ + uchar b2, b3, bdata; + b2 = psel->event_data2; + b3 = psel->event_data3; + if ((vend == VENDOR_INTEL && prod == 0x4311) || + (vend == VENDOR_NSC)) { /*mini-BMC*/ + bdata = b2; + } else if (b3 == 0xff) { /* FF is reserved */ + bdata = b2; + } else { /* normal case */ + bdata = b3; + } + j = bdata & 0x3f; + /* Now i==data1(lo nib) for memstr, j==DIMM index */ + if (i == 0) sev = SEV_MIN; /*correctable ECC*/ + else sev = SEV_MAJ; + if (fdebug) printf("DIMM(%d) vend=%x prod=%x\n",j,vend,prod); + /* For Intel S5500/S2600 see decode_mem_intel */ + if (vend == VENDOR_INTEL) { + decode_mem_intel(prod,b2,b3,mdesc,&msz); + sprintf(mystr,"%s%c %s",mem_str(i),bcomma,mdesc); + } else if ((vend == VENDOR_SUPERMICRO) || + (vend == VENDOR_SUPERMICROX)) { + decode_mem_supermicro(prod,b2,b3,mdesc,&msz); + sprintf(mystr,"%s%c %s",mem_str(i),bcomma,mdesc); + } else { + sprintf(mystr,"%s%c DIMM[%d]",mem_str(i),bcomma,j); + /* DIMM[2] = 3rd one (zero-based index) */ + } + } + pstr = mystr; + break; + case 0x0F: /*System Firmware events, incl POST Errs*/ + sev = SEV_MAJ; /*usu major, but platform-specific*/ + switch (psel->event_data1) + { + case 0x00: /* System firmware errors */ + i = psel->event_data2; + if (i > NFWERRS) i = NFWERRS; + pstr = fwerrs[i].msg; + break; + case 0x01: /* System firmware hang */ + i = psel->event_data2; + if (i > NFWSTAT) i = NFWSTAT; + sprintf(poststr,"hang%c %s",bcomma, + fwstat[i].msg); + pstr = poststr; + break; + case 0x02: /* System firmware progress */ + sev = SEV_INFO; + i = psel->event_data2; + if (i > NFWSTAT) i = NFWSTAT; + sprintf(poststr,"prog%c %s",bcomma, + fwstat[i].msg); + pstr = poststr; + break; + case 0xa0: /* OEM post codes */ + /* OEM post codes in bytes 2 & 3 (lo-hi) */ + j = psel->event_data2 | + (psel->event_data3 << 8); + /* interpret some OEM post codes if -e */ + i = decode_post_oem(vend,prod,(ushort)j, + poststr,sizeof(poststr)); + pstr = poststr; + break; + default: + pstr = get_misc_desc( psel->generator_id, + psel->sensor_type, + psel->sensor_number, + psel->event_trigger, + psel->event_data1, + psel->event_data2, + psel->event_data3, &sev); + if (pstr == NULL) + pstr = "POST Error"; /*default string*/ + } /*end switch(data1)*/ + break; + case 0x13: /*Crit Int*/ + sev = SEV_CRIT; + i = psel->event_data1 & 0x0f; + if (i >= NCRITS) i = NCRITS - 1; + pstr = crit_int_str[i]; + if ((psel->event_trigger == 0x70) || + (psel->event_trigger == 0x71)) { + uchar bus,dev,func; + /* Intel AER< decode PCI bus:dev.func data */ + bus = psel->event_data2; + dev = ((psel->event_data3 & 0xf8) >> 3); + func = (psel->event_data3 & 0x07); + sprintf(mystr,"%s (on %02x:%02x.%d)", + crit_int_str[i],bus,dev,func); + pstr = mystr; + } + break; + case 0x15: /*Board (e.g. IO Module)*/ + if ((psel->event_trigger == 0x08) || + (psel->event_trigger == 0x88)) { + rv = decode_presence(psel->event_trigger, + psel->event_data1, mystr, &sev); + pstr = mystr; + } else pstr = NULL; /*falls through to unknown*/ + break; + case 0x16: /*Microcontroller (e.g. ME or HDD)*/ + // if (psel->event_trigger == 0x0A) // Availability + { + i = psel->event_data1 & 0x0f; + if (i >= N_AVAIL) i = N_AVAIL - 1; + if (i >= 4) sev = SEV_MIN; + else sev = SEV_INFO; + pstr = avail_str[i]; + } + break; + case 0x1D: /*System Boot Initiated*/ + i = psel->event_data1 & 0x0f; + if (i >= NBOOTI) i = NBOOTI - 1; + pstr = boot_init_str[i]; + break; + case 0x1F: /*OS Boot */ + i = psel->event_data1 & 0x0f; + if (i >= NOSBOOT) i = NOSBOOT - 1; + pstr = osboot_str[i]; + break; + case 0x21: /*Slot/Con*/ + i = psel->event_data1 & 0x0f; + if (i >= NSLOTC) i = NSLOTC - 1; + if (i == 0) sev = SEV_MAJ; /*Fault*/ + else if (i == 8) sev = SEV_MIN; + sprintf(mystr,"%s",slot_str[i]); + /* could also decode data2/data3 here if valid */ + pstr = mystr; + break; + case 0x22: /*ACPI Power state*/ + i = psel->event_data1 & 0x0f; + if (i >= NACPIP) i = NACPIP - 1; + sprintf(mystr,"%s",acpip_str[i]); + pstr = mystr; + break; + case 0x28: /*Management Subsystem Health*/ + i = psel->event_data1 & 0x0f; + if (i == 0x04) /*sensor error*/ + sprintf(mystr,"Sensor %02x fault",psel->event_data2); + else + sprintf(mystr,"Other FW HAL error"); + pstr = mystr; + break; + case 0x29: /*Battery*/ + if (is_threshold(psel->event_trigger, + psel->generator_id)) + { + pstr = get_misc_desc( psel->generator_id, + psel->sensor_type, + psel->sensor_number, + psel->event_trigger, + psel->event_data1, + psel->event_data2, + psel->event_data3, &sev); + } else { + i = psel->event_data1 & 0x0f; + if (i >= NBATT) i = NBATT - 1; + /* sev defaults to SEV_INFO */ + if (psel->event_trigger & 0x80) { /*deasserted*/ + sprintf(mystr,"%s",batt_clr[i]); + } else { /*asserted*/ + sprintf(mystr,"%s",batt_str[i]); + if (i == 0) sev = SEV_MIN; + else if (i == 1) sev = SEV_MAJ; + } + pstr = mystr; + } + break; + case 0x2A: /*Session Audit, new for IPMI 2.0*/ + i = psel->event_data1 & 0x0f; + if (i >= NAUDIT) i = NAUDIT - 1; + sprintf(mystr,"%s User%d",audit_str[i], + psel->event_data2); + /* see also psel->event_data3 for cause/channel*/ + pstr = mystr; + break; + case 0xDC: /*ME Node Manager, for S5500 Urbanna*/ + i = psel->event_trigger; + if (i & 0x80) { fdeassert = 1; i &= 0x7f; } + if (i >= 0x72) i -= 0x72; + if (i >= N_NM) i = N_NM - 1; + sprintf(mystr,"%s",nm_str[i]); + if (fdeassert) strcat(mystr," OK"); + n = strlen_(mystr); + sprintf(cstr,"%c ",bcomma); + j = psel->event_data2; + switch(i) { + case 0x00: /*0x72 NM Exception*/ + j = psel->event_data1; + if ((j & 0x08) == 0) { + k = j & 0x03; + sprintf(&mystr[n], + "%sThreshold %d Exceeded",cstr,k); + } else { /*Policy event*/ + sprintf(&mystr[n], + "%sPolicy Time Exceeded",cstr); + } + sev = SEV_MIN; + break; + case 0x01: /*0x73 NM Health*/ + j &= 0x0f; // if (j >= 0x10) j -= 0x10; + if (j >= N_NMH) j = N_NMH - 1; + if (j != 5) sev = SEV_MAJ; + strcat(mystr,cstr); /*", "*/ + strcat(mystr,nmh_str[j]); + break; + case 0x03: /*0x75 FW Health*/ + if (j >= N_NMFW) j = N_NMFW - 1; + sev = SEV_MAJ; + strcat(mystr,cstr); /*", "*/ + strcat(mystr,nmfw_str[j]); + break; + case 0x02: /*0x74 NM Capabilities*/ + default: + sev = SEV_MIN; + break; + } + pstr = mystr; + break; + case 0x04: /*Fan sensor events */ + if ((psel->event_trigger == 0x0b) || + (psel->event_trigger == 0x8b)) { + rv = decode_redund(psel->event_trigger, + psel->event_data1, mystr, &sev); + pstr = mystr; + break; + } else if ((psel->event_trigger == 0x08) || + (psel->event_trigger == 0x88)) { + rv = decode_presence(psel->event_trigger, + psel->event_data1, mystr, &sev); + pstr = mystr; + break; + } else if (psel->event_trigger == 0x06) { + /* usu psel->event_data1 == 0x01 */ + sev = SEV_MIN; + strcpy(mystr,"Performance Lags"); + pstr = mystr; + break; + } else if (psel->event_trigger == 0x86) { + sev = SEV_INFO; + strcpy(mystr,"Performance OK"); + pstr = mystr; + break; + } + /* else Fan threshold events handled below, trig=01/81*/ + default: /* all other sensor types, see sens_desc */ + pstr = get_misc_desc( psel->generator_id, + psel->sensor_type, + psel->sensor_number, + psel->event_trigger, + psel->event_data1, + psel->event_data2, + psel->event_data3, &sev); + break; + } /*end switch(sensor_type)*/ + + if (pstr == NULL) { /* none found, unknown */ + mystr[0] = '-'; mystr[1] = 0; + pstr = mystr; + } + + + /*firmware timestamp is #seconds since 1/1/1970 localtime*/ + evtime = (uchar *)&psel->timestamp; + eventTime = evtime[0] + (evtime[1] << 8) + + (evtime[2] << 16) + (evtime[3] << 24); + if (fdebug) { + char tbuf[40]; + char *tz; char *lctime; + strftime(timebuf,sizeof(timebuf), "%x %H:%M:%S %Z", + localtime(&eventTime)); + strftime(tbuf,sizeof(tbuf), "%x %H:%M:%S %Z", + gmtime(&eventTime)); + tz = getenv("TZ"); + if (tz == NULL) tz = ""; + lctime = getenv("LC_TIME"); + if (lctime == NULL) lctime = ""; + SELprintf("%s\nTZ=%s, LC_TIME=%s, gmtime=%s\n", + timebuf,tz,lctime,tbuf); + } + psensstr = NULL; + sensstr[0] = 0; + if (fsensdesc) { + rv = get_sensor_tag(isdr,psel->generator_id, + psel->sensor_number, sensstr, + sdr, sizeof(sdr)); + if (rv == 0) { + fhave_sdr = 1; + psensstr = &sensstr[0]; + } else rv = 0; /*no sdr but not an error*/ + } /*endif fsensdesc*/ + + if (is_threshold(psel->event_trigger,psel->generator_id)) { + /* Also usually ((psel->event_data1 & 0x50) == 0x50) */ + /* We know that these two MCs should include the + * actual and threshold raw values in data2 & data3 */ + if (fsensdesc && fhave_sdr) { + double v1, v2; + char *u; + /* if sdrcache, find_sdr_by_snum got the sdr above */ + /* else, GetSDR tried to get the sdr above */ + v1 = RawToFloat(psel->event_data2,sdr); + v2 = RawToFloat(psel->event_data3,sdr); + u = get_unit_type(sdr[20],sdr[21],sdr[22],1); + sprintf(datastr, "actual=%.2f %s, threshold=%.2f %s", + v1,u, v2,u); + } else { // if (fsensdesc == 0 || (rv != 0)) { + sprintf(datastr,"act=%02x thr=%02x", + psel->event_data2, /*actual raw reading*/ + psel->event_data3 ); /*threshold raw value*/ + } + } else { + if (fcanonical) datastr[0] = 0; + else sprintf(datastr,"%02x [%02x %02x %02x]", + psel->event_trigger, + psel->event_data1, + psel->event_data2, + psel->event_data3 ); + } + + format_event(psel->record_id, eventTime, sev, + psel->generator_id, + get_sensor_type_desc(psel->sensor_type), + psel->sensor_number, psensstr, + pstr, datastr, outbuf,szbuf); + + } /*endif type 2 */ + else { /* other misc record type */ + if (fdebug) printf("Unrecognized record type %02x\n", + psel->record_type); + rv = ERR_NOT_FOUND; + pc = (uchar *)&psel->record_type; + sprintf(outbuf,"%04x Type%02x %s ", + psel->record_id,pc[0],get_sev_str(sev)); + j = strlen_(outbuf); + for (i = 1; i < 14; i++) { + sprintf(mystr,"%02x ",pc[i]); + strcat(outbuf,mystr); + } + strcat(outbuf,"\n"); + } /*endif misc type*/ + return(rv); +} /*end decode_sel_entry()*/ + +static void show_usage(void) +{ + printf("Usage: %s [-bdfhprstux] 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10\n",progname); + printf("where -b = interpret Binary raw SEL file, from ipmitool sel writeraw\n"); + printf(" -d = get DeviceID for vendor/product-specific events\n"); + printf(" -f = interpret File with raw ascii SEL data, from ipmiutil sel -r\n"); + printf(" -h = interpret Hex binary raw SEL file (same as -b)\n"); +#ifndef ALONE + printf(" -o = specify the target vendor IANA number.\n"); +#endif + printf(" -n = generate New platform event, use last 9 event bytes\n"); + printf(" -p = decode PET event bytes, use 34 PET data bytes,\n"); + printf(" skipping the first 8 of the 47-byte PET data (-t=all).\n"); + printf(" If not specified, assumes a 16-byte IPMI event.\n"); + printf(" -r = interpret RAW ascii SEL file (same as -f)\n"); + printf(" -s = sensor file with output of 'ipmiutil sensor', used\n"); + printf(" to get the PET sensor_type from the sensor_num.\n"); + printf(" The default is %s\n",sensfil); + printf(" -t = decode PET trap bytes, use all 47 PET data bytes (-p=34)\n"); + printf(" If not specified, assumes a 16-byte IPMI event.\n"); + printf(" -u = use raw UTC time\n"); + printf(" -x = show eXtra debug messages\n"); +} + +/* + * decode_raw_sel + * input parameters: + * raw_file : filename of raw SEL file + * mode : 1 = ascii raw from ipmiutil sel -r + * 2 = binary hex from ipmiutil sel writeraw {raw_file} + */ +int decode_raw_sel(char *raw_file, int mode) +{ + FILE *fp; + char buff[256]; + uchar msg[132]; + uchar hbuf[50]; + int fvalid = 0; + int len, i; + + fp = fopen(raw_file,"r"); + if (fp == NULL) { + printf("Cannot open file %s\n",raw_file); + return(ERR_FILE_OPEN); + } else { + printf("%s",evt_hdr); /*"RecId Date/Time_______*/ + if (mode == 1) { /*ascii raw*/ + if (fdebug) + printf("decoding raw ascii file with IPMI event bytes\n"); + while (fgets(buff, 255, fp)) { + len = strlen_(buff); + fvalid = 0; + if (buff[0] >= '0' && (buff[0] <= '9')) fvalid = 1; + else if (buff[0] >= 'a' && (buff[0] <= 'f')) fvalid = 1; + else if (buff[0] >= 'A' && (buff[0] <= 'F')) fvalid = 1; + if (fvalid == 0) continue; + for (i = 0; i < 16; i++) { + hbuf[i] = _htoi(&buff[i*3]); + } + decode_sel_entry(hbuf,msg,sizeof(msg)); + printf("%s", msg); + } /*end while*/ + } else { /*hex raw*/ + if (fdebug) + printf("decoding binary hex file with IPMI event bytes\n"); + while (fread(hbuf, 1, 16, fp) == 16) { + decode_sel_entry(hbuf,msg,sizeof(msg)); + printf("%s", msg); + } /*end while*/ + } + fclose(fp); + } + return(0); +} + +/* + * The events utility interprets standard 16-byte IPMI events into + * human-readable form by default. + * User must pass raw 16-byte event data from some log text for decoding. + * + * Sample IPMI event usage: + * # ievents fb 07 02 e5 1a b8 44 21 00 03 1d 9a 6f 40 8f ff + * RecId Date/Time_______ SEV Src_ Evt_Type___ Sens# Evt_detail - Trig [Evt_data] + * 07fb 07/14/06 18:29:57 INF SMI System Boot Initiated #9a Power Up 6f [40 8f ff] + * # ievents 14 04 02 BE 35 13 45 33 40 04 0C 08 6F 20 00 04 + * RecId Date/Time_______ SEV Src_ Evt_Type___ Sens# Evt_detail - Trig [Evt_data] + * 0414 09/21/06 21:00:46 MIN 4033 Memory #08 Correctable ECC, DIMM[4] 6f [20 00 04] + * + * If fPET, interpret the SNMP Platform Event Trap hex varbind data. + * For interpreting the 47-byte hex data from SNMP Platform Event Traps, + * specify events -p with the 34 data bytes following the 16-byte GUID. + * + * Sample SNMP PET Data for events: + * 0000: 3C A7 56 85 08 C5 11 D7 C3 A2 00 04 23 BC AC 12 + * 0010: 51 14 11 72 38 58 FF FF 20 20 00 10 83 07 01 41 + * 0020: 0F FF 00 00 00 00 00 19 00 00 01 57 00 22 C1 + * + * Sample events -p command from above data: + * # ievents -p C3 A2 00 04 23 BC AC 12 51 14 11 72 38 58 FF FF 20 20 00 10 83 07 01 41 0F FF 00 00 00 00 + * RecId Date/Time_______ SEV Src_ Evt_Type___ Sens# Evt_detail - Trig [Evt_data] + * 0014 04/11/07 12:03:20 INF BMC System Event #83 OEM System Booted 6f [41 0f ff] + * + * Platform Event Trap Format + * Offset Len Meaning + * 0 16 System GUID + * 16 2 Sequence Number/Cookie + * 18 4 Local Timestamp + * 22 2 UTC Offset + * 24 1 Trap Source Type (usu 0x20) + * 25 1 Event Source Type (usu 0x20) + * 26 1 Event Severity + * 27 1 Sensor Device + * 28 1 Sensor Number + * 29 1 Entity + * 30 1 Entity Instance + * 31 8 Event Data (8 bytes max, 3 bytes used) + * 39 1 Language Code (usu 0x19/25. = English) + * 40 4 Manufacturer IANA number (Intel=0x000157) + * 44 1-N OEM data, C1="No more fields" + * If Intel (0x000157): + * 44 2 Product ID + * 46 1 0xC1 (No more fields) + */ +#if defined(ALONE) +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#else +/* #elif defined(METACOMMAND) or if libipmiutil */ +int i_events(int argc, char **argv) +#endif +{ + uchar buf[50]; + uchar msg[132]; + uchar *pmsg; + int i, j, len; + char fPET = 0; + char frawfile = 0; + char fhexfile = 0; + int rv = 0; + char c; + uchar b = 0; +#ifndef ALONE + uchar devid[16]; +#endif +#if defined(METACOMMAND) + char *p; +#endif + + printf("%s version %s\n",progname,progver); + if (argc > 0) { argc--; argv++; } /*skip argv[0], program name*/ + /* ievents getopt: [ -bdfhnoprstux -NPRUEFJTVY */ + while ((argc > 0) && argv[0][0] == '-') + { + c = argv[0][1]; + switch(c) { + case 'x': fdebug = 1; break; + case 'd': fgetdevid = 1; break; /*get device id (vendor, product)*/ + case 'n': fnewevt = 1; break; /* generate New event */ + case 'p': /* PET format, minus first 8 bytes*/ + /* This is important for some SNMP trap receivers that obscure + * the first 8 bytes of the trap data */ + fPET = 1; /*incoming data is in PET format*/ + break; + case 'u': futc = 1; break; /*use raw UTC time*/ +#ifndef ALONE + case 'o': /*specify OEM IANA manufacturer id */ + if (argc > 1) { /*next argv is IANA number */ + i = atoi(argv[1]); + printf("setting IANA to %d (%s)\n",i,get_iana_str(i)); + set_iana(i); + argc--; argv++; + } else { + printf("option -%c requires an argument\n",c); + rv = ERR_BAD_PARAM; + } + break; +#endif + case 't': /*PET format Trap, use all data*/ + /* This may be helpful if all bytes are available, or if + * the GUID is relevant. */ + fPET = 1; /*incoming data is in PET format*/ + pet_guid = 16; + break; + case 'f': + case 'r': + /* interpret raw ascii SEL file from optarg */ + frawfile = 1; + if (argc > 1) { /*next argv is filename*/ + len = strlen_(argv[1]); + if (len >= sizeof(rawfil)) + len = sizeof(rawfil) - 1; + strncpy(rawfil,argv[1],len); + rawfil[len] = 0; /*stringify*/ + argc--; argv++; + } else { + printf("option -%c requires a filename argument\n",c); + rv = ERR_BAD_PARAM; + } + break; + case 'b': + case 'h': + /* interpret raw binary/hex SEL file from optarg */ + fhexfile = 1; + if (argc > 1) { /*next argv is filename*/ + len = strlen_(argv[1]); + if (len >= sizeof(rawfil)) + len = sizeof(rawfil) - 1; + strncpy(rawfil,argv[1],len); + rawfil[len] = 0; /*stringify*/ + argc--; argv++; + } else { + printf("option -%c requires a filename argument\n",c); + rv = ERR_BAD_PARAM; + } + break; + case 's': /* get sensor file from optarg */ + if (argc > 1) { /*next argv is filename*/ + FILE *fp; + len = strlen_(argv[1]); + if (len >= sizeof(sensfil)) + len = sizeof(sensfil) - 1; + strncpy(sensfil,argv[1],len); + sensfil[len] = 0; /*stringify*/ + fp = fopen(sensfil,"r"); + if (fp == NULL) { + printf("cannot open file %s\n",sensfil); + rv = ERR_FILE_OPEN; + } else fclose(fp); + argc--; argv++; + } else { + printf("option -%c requires a filename argument\n",c); + rv = ERR_BAD_PARAM; + } + fsensdesc = 2; + break; +#if defined(METACOMMAND) + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + if (c == 'Y' || c == 'E') p = NULL; + else if (argc <= 1) { + printf("option -%c requires an argument\n",c); + rv = ERR_BAD_PARAM; + } else { /* has an optarg */ + p = argv[1]; + argc--; argv++; + } + if (rv == 0) parse_lan_options(c,p,fdebug); + break; +#endif + default: /*unknown option*/ + printf("Unknown option -%c\n",c); + show_usage(); + rv = ERR_USAGE; + goto do_exit; + break; + } + argc--; argv++; + } /*end while options*/ + + len = argc; /*number of data bytes*/ + if (!fPET && len > 16) len = 16; /* IPMI event max is 16 */ + if (frawfile || fhexfile) len = 0; + else if (fnewevt) { + if (len < 9) { + printf("Need 9 bytes for a New event, got %d bytes input\n",len); + show_usage(); + rv = ERR_BAD_PARAM; + } + } else if (len < 16) { + printf("Need 16 bytes for an IPMI event, got %d bytes input\n",len); + show_usage(); + rv = ERR_BAD_PARAM; + } + if (rv != 0) goto do_exit; + +#ifndef ALONE + if (fgetdevid || fsensdesc) + rv = ipmi_getdeviceid( devid, sizeof(devid),fdebug); /*sets mfgid*/ +#endif + + for (i = 0; i < len; i++) + { + if (fPET) msg[i] = _htoi(argv[i]); + else buf[i] = _htoi(argv[i]); + } + if (fPET != 0) /*PET, reorder bytes to std event format*/ + { + uchar snum, styp; + int timestamp; + int yrs, time2; + char sensdesc[100]; + int mfg; + + pmsg = &msg[pet_guid]; /*pet_guid=8, skip the GUID*/ + if (fdebug) { + printf("decoding IPMI PET event bytes\n"); + dump_buf("PET buffer",msg,len,1); + } + /* pmsg[ 9] is event source type (gen id, usu 0x20) */ + /* pmsg[10] is event severity */ + /* pmsg[11] is sensor device */ + /* pmsg[12] is sensor number */ + /* pmsg[13] is Entity */ + snum = pmsg[12]; + styp = entity2sensor_type(pmsg[13]); + rv = get_sensdesc(pmsg[9],snum,sensdesc,&i,NULL); + if (rv == 0) { + styp = (uchar)i; + if (fdebug) printf("sensor[%02x]: %s\n",snum,sensdesc); + set_sel_opts(2,0, NULL,fdebug,futc); + } else { + if (rv == ERR_NOT_FOUND) { + printf("Cannot find snum %02x in %s\n",snum,sensfil); + printf("Resolve this by doing 'ipmiutil sensor >sensorX.txt' " + "on a system similar\nto the target, then use " + "'ipmiutil events -s sensorX.txt ...'\n"); + } + /* Try GetSensorType(), which will work if local IPMI. */ + rv = GetSensorType(snum,&b,NULL); + if (fdebug) printf("sensor[%02x]: GetSensorType rv=%d stype=%x\n", + snum,rv,b); + if (rv == 0) styp = b; + } + + buf[0] = pmsg[1]; /*record id (sequence num)*/ + buf[1] = 0; /* was pmsg[0]; */ + buf[2] = 0x02; /*event type*/ +#ifdef RAW + buf[3] = pmsg[5]; /*timestamp*/ + buf[4] = pmsg[4]; /*timestamp*/ + buf[5] = pmsg[3]; /*timestamp*/ + buf[6] = pmsg[2]; /*timestamp*/ +#else + timestamp = pmsg[5] + (pmsg[4] << 8) + (pmsg[3] << 16) + (pmsg[2] << 24); + /* add 28 years, includes 7 leap days, less 1 hour TZ fudge */ + // yrs = ((3600 * 24) * 365 * 28) + (7 * (3600 * 24)) - 3600; + yrs = 0x34aace70; + time2 = timestamp + yrs; + if (fdebug) + printf("timestamp: %08x + %08x = %08x\n",timestamp,yrs,time2); + buf[3] = time2 & 0x000000ff; /*timestamp*/ + buf[4] = (time2 & 0x0000ff00) >> 8; /*timestamp*/ + buf[5] = (time2 & 0x00ff0000) >> 16; /*timestamp*/ + buf[6] = (time2 & 0xff000000) >> 24; /*timestamp*/ +#endif + buf[7] = pmsg[9]; /*generator_id*/ + buf[8] = 0; + buf[9] = 0x04; /*evm_rev*/ + buf[10] = styp; /*derived sensor type, from above */ + buf[11] = snum; /*sensor number*/ + /* set the event trigger based on context */ + switch(styp) { /*set the event trigger*/ + case 0x12: buf[12] = 0x6f; break; /*system event (sensor-specific)*/ + case 0x09: buf[12] = 0x0b; break; /*Power Unit*/ + case 0x01: /*temp*/ + case 0x02: /*voltage*/ + case 0x03: /*current*/ + case 0x04: /*fan*/ + if (pmsg[10] == 0x04) buf[12] = 0x81; /*info severity, ok*/ + else buf[12] = 0x01; /* threshold asserted*/ + break; + default: + buf[12] = pmsg[14]; /*event trigger = Entity Instance */ + /*Note that Entity Instance will not match an event trigger*/ + buf[12] = 0x6f; /*set trigger to sensor-specific*/ + break; + } + memcpy(&buf[13],&pmsg[15],3); /*event data*/ + mfg = pmsg[27] + (pmsg[26] << 8) + (pmsg[25] << 16); + if (fdebug) { + printf("PET severity=%02x, mfgId=%02x%02x%02x%02x\n", + pmsg[10], pmsg[24], pmsg[25], pmsg[26], pmsg[27]); + dump_buf("IPMI event",buf,16,0); + } + if (mfg == VENDOR_SUN) { /* Sun = 0x00002A, extra OEM data */ + j = 28 + pet_guid; /*offset 28+16=44 (OEM data) */ + pmsg = &msg[j]; + for (i = 0; (i+j) < len; ) { + if (pmsg[i] == 0xC1) break; + if (i == 0) i += 2; /* 2-byte header 0x0c 0x01 */ + else if (pmsg[i] == 0x80) { /* 3-byte header, usu strings */ + if (pmsg[i+2] == 0x03) printf(" %s\n",&pmsg[i+3]); + i += (3 + pmsg[i+1]); + } else i++; + } + } + decode_sel_entry(buf,msg,sizeof(msg)); + printf("%s", evt_hdr); /*"RecId Date/Time_______*/ + printf("%s", msg); + } else if (fnewevt) { + rv = new_event(buf,len); /*do new platform event*/ + } else if (frawfile) { + rv = decode_raw_sel(rawfil,1); /*ascii raw data from file */ + } else if (fhexfile) { + rv = decode_raw_sel(rawfil,2); /*binary/hex raw data from file*/ + } else { + if (fdebug) printf("decoding standard IPMI event bytes\n"); + if (fdebug) dump_buf("IPMI event",buf,16,0); + set_sel_opts(2,0, NULL,fdebug,futc); + rv = decode_sel_entry(buf,msg,sizeof(msg)); + /* show header for the event record */ + printf("%s", evt_hdr); /*"RecId Date/Time_______*/ + printf("%s", msg); + } +do_exit: +#ifndef METACOMMAND + printf("%s, %s\n",progname,decode_rv(rv)); +#endif + return(rv); +} +// #endif + +/* end ievents.c */ diff --git a/util/ievents.h b/util/ievents.h new file mode 100644 index 0000000..71bc449 --- /dev/null +++ b/util/ievents.h @@ -0,0 +1,64 @@ +/* + * ievents.h + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2011 Kontron America, Inc. + * + * 12/12/11 Andy Cress - created + */ +/*M* +Copyright (c) 2011 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ + +/* Public routines from ievents.c */ +int decode_sel_entry( uchar *psel, char *outbuf, int sz); +char *decode_entity_id(int id); +char *get_sensor_type_desc(uchar stype); +char *get_sev_str(int val); +void fmt_time(time_t etime, char *buf, int bufsz); +int get_sensor_tag(int isdr, int genid, uchar snum, char *tag, + uchar *sdr, int szsdr); +void format_event(ushort id, time_t timestamp, int sevid, ushort genid, + char *ptype, uchar snum, char *psens, char *pstr, char *more, + char *outbuf, int outsz); +/* + * set_sel_opts is used to specify options for showing/decoding SEL events. + * sensdesc : 0 = simple, no sensor descriptions + * 1 = get sensor descriptions from sdr cache + * 2 = get sensor descriptions from sensor file (-s) + * canon : 0 = normal output + * 1 = canonical, delimited output + * sdrs : NULL = no sdr cache, dynamically get sdr cache if sensdesc==1 + * ptr = use this pointer as existing sdr cache if sensdesc==1 + * fdbg : 0 = normal mode + * 1 = debug mode + * futc : 0 = normal mode + * 1 = show raw UTC time + */ +void set_sel_opts(int sensdsc, int canon, void *sdrs, char fdbg, char futc); + +/*end ievents.h*/ diff --git a/util/ifirewall.c b/util/ifirewall.c new file mode 100644 index 0000000..b92d7d5 --- /dev/null +++ b/util/ifirewall.c @@ -0,0 +1,1154 @@ +/* + * ifirewall.c + * Handle firmware firewall IPMI command functions + * + * Change history: + * 06/04/2010 ARCress - included in source tree + * + *--------------------------------------------------------------------- + * Copyright (c) 2010 Kontron America Inc. All Rights Reserved, + * Copyright (c) 2005 International Business Machines, Inc. All Rights Reserved + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + *--------------------------------------------------------------------- + */ +#ifdef WIN32 +#include <windows.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "getopt.h" +#else +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include "ipmicmd.h" +#include "ifirewall.h" + +/* global variables */ +static char * progname = "ifirewall"; +static char * progver = "2.93"; +static char fdebug = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +extern int verbose; /*see ipmilanplus.c*/ + +extern void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/ + +static void +printf_firewall_usage(void) +{ + printf("Firmware Firewall Commands:\n"); + printf("\tinfo [channel H] [lun L]\n"); + printf("\tinfo [channel H] [lun L [netfn N [command C [subfn S]]]]\n"); + printf("\tenable [channel H] [lun L [netfn N [command C [subfn S]]]]\n"); + printf("\tdisable [channel H] [lun L [netfn N [command C [subfn S]]]] [force])\n"); + printf("\treset [channel H] \n"); + printf("\t\twhere H is a Channel, L is a LUN, N is a NetFn,\n"); + printf("\t\tC is a Command and S is a Sub-Function\n"); +} + +// print n bytes of bit field bf (if invert, print ~bf) +static void print_bitfield(const unsigned char * bf, int n, int invert, int loglevel) { + int i = 0; + if (loglevel < 0) { + while (i<n) { + printf("%02x", (unsigned char) (invert?~bf[i]:bf[i])); + if (++i % 4 == 0) + printf(" "); + } + printf("\n"); + } else { + while (i<n) { + lprintf(loglevel, "%02x", (unsigned char) (invert?~bf[i]:bf[i])); + if (++i % 4 == 0) + lprintf(loglevel, " "); + } + lprintf(loglevel, "\n"); + } + +} + +static int +ipmi_firewall_parse_args(int argc, char ** argv, struct ipmi_function_params * p) +{ + int i; + + if (!p) { + lprintf(LOG_ERR, "ipmi_firewall_parse_args: p is NULL"); + return -1; + } + for (i=0; i<argc; i++) { + if (strncmp(argv[i], "channel", 7) == 0) { + if (++i < argc) + p->channel = atob(argv[i]); + } + else if (strncmp(argv[i], "lun", 3) == 0) { + if (++i < argc) + p->lun = atob(argv[i]); + } + else if (strncmp(argv[i], "force", 5) == 0) { + p->force = 1; + } + else if (strncmp(argv[i], "netfn", 5) == 0) { + if (++i < argc) + p->netfn = atob(argv[i]); + } + else if (strncmp(argv[i], "command", 7) == 0) { + if (++i < argc) + p->command = atob(argv[i]); + } + else if (strncmp(argv[i], "subfn", 5) == 0) { + if (++i < argc) + p->subfn = atob(argv[i]); + } + } + if (p->subfn >= MAX_SUBFN) { + printf("subfn is out of range (0-%d)\n", MAX_SUBFN-1); + return -1; + } + if (p->command >= MAX_COMMAND) { + printf("command is out of range (0-%d)\n", MAX_COMMAND-1); + return -1; + } + if (p->netfn >= MAX_NETFN) { + printf("netfn is out of range (0-%d)\n", MAX_NETFN-1); + return -1; + } + if (p->lun >= MAX_LUN) { + printf("lun is out of range (0-%d)\n", MAX_LUN-1); + return -1; + } + if (p->netfn >= 0 && p->lun < 0) { + printf("if netfn is set, lun must be set also\n"); + return -1; + } + if (p->command >= 0 && p->netfn < 0) { + printf("if command is set, netfn must be set also\n"); + return -1; + } + if (p->subfn >= 0 && p->command < 0) { + printf("if subfn is set, command must be set also\n"); + return -1; + } + return 0; +} + +/* _get_netfn_suport + * + * @intf: ipmi interface + * @channel: ipmi channel + * @lun: a pointer to a 4 byte field + * @netfn: a pointer to a 128-bit bitfield (16 bytes) + * + * returns 0 on success and fills in the bitfield for + * the 32 netfn * 4 LUN pairs that support commands + * returns -1 on error + */ +static int +_get_netfn_support(void * intf, int channel, unsigned char * lun, unsigned char * netfn) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char * d, rqdata; + unsigned int l; + + if (!lun || !netfn) { + lprintf(LOG_ERR, "_get_netfn_suport: lun or netfn is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_NETFN_SUPPORT; + rqdata = (unsigned char) channel; + req.msg.data = &rqdata; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get NetFn Support command failed: %d (0x%02x)\n",rv,rv); + return(rv); + } + + d = &rsp[0]; + for (l=0; l<4; l++) { + lun[l] = (*d)>>(2*l) & 0x3; + } + d++; + + memcpy(netfn, d, 16); + + return 0; +} + +/* _get_command_suport + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @lnfn: a pointer to a struct lun_netfn_support + * + * returns 0 on success and fills in lnfn according to the request in p + * returns -1 on error + */ +static int +_get_command_support(void * intf, + struct ipmi_function_params * p, struct lun_netfn_support * lnfn) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char * d, rqdata[3]; + unsigned int c; + + if (!p || !lnfn) { + lprintf(LOG_ERR, "_get_command_suport: p or lnfn is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_SUPPORT; + rqdata[0] = (unsigned char)p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Support (LUN=%d, NetFn=%d, op=0) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = &rsp[0]; + for (c=0; c<128; c++) { + if (!(d[c>>3] & (1<<(c%8)))) + lnfn->command[c].support |= BIT_AVAILABLE; + } + memcpy(lnfn->command_mask, d, MAX_COMMAND_BYTES/2); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_SUPPORT; + rqdata[0] = (unsigned char)p->channel; + rqdata[1] = (unsigned char)(0x40 | p->netfn); + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Support (LUN=%d, NetFn=%d, op=1) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = &rsp[0]; + for (c=0; c<128; c++) { + if (!(d[c>>3] & (1<<(c%8)))) + lnfn->command[128+c].support |= BIT_AVAILABLE; + } + memcpy(lnfn->command_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2); + return 0; +} + +/* _get_command_configurable + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @lnfn: a pointer to a struct lun_netfn_support + * + * returns 0 on success and fills in lnfn according to the request in p + * returns -1 on error + */ +static int +_get_command_configurable(void * intf, + struct ipmi_function_params * p, struct lun_netfn_support * lnfn) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char * d, rqdata[3]; + unsigned int c; + + if (!p || !lnfn) { + lprintf(LOG_ERR, "_get_command_configurable: p or lnfn is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_CONFIGURABLE_COMMANDS; + rqdata[0] = (unsigned char)p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Configurable Command (LUN=%d, NetFn=%d, op=0) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = rsp; + for (c=0; c<128; c++) { + if (d[c>>3] & (1<<(c%8))) + lnfn->command[c].support |= BIT_CONFIGURABLE; + } + memcpy(lnfn->config_mask, d, MAX_COMMAND_BYTES/2); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_CONFIGURABLE_COMMANDS; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)(0x40 | p->netfn); + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Configurable Command (LUN=%d, NetFn=%d, op=1) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = rsp; + for (c=0; c<128; c++) { + if (d[c>>3] & (1<<(c%8))) + lnfn->command[128+c].support |= BIT_CONFIGURABLE; + } + memcpy(lnfn->config_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2); + return 0; +} + +/* _get_command_enables + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @lnfn: a pointer to a struct lun_netfn_support + * + * returns 0 on success and fills in lnfn according to the request in p + * returns -1 on error + */ +static int +_get_command_enables(void * intf, + struct ipmi_function_params * p, struct lun_netfn_support * lnfn) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char * d, rqdata[3]; + unsigned int c; + + if (!p || !lnfn) { + lprintf(LOG_ERR, "_get_command_enables: p or lnfn is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Enables (LUN=%d, NetFn=%d, op=0) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = rsp; + for (c=0; c<128; c++) { + if (d[c>>3] & (1<<(c%8))) + lnfn->command[c].support |= BIT_ENABLED; + } + memcpy(lnfn->enable_mask, d, MAX_COMMAND_BYTES/2); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)(0x40 | p->netfn); + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Enables (LUN=%d, NetFn=%d, op=1) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = rsp; + for (c=0; c<128; c++) { + if (d[c>>3] & (1<<(c%8))) + lnfn->command[128+c].support |= BIT_ENABLED; + } + memcpy(lnfn->enable_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2); + return 0; +} + +/* _set_command_enables + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @lnfn: a pointer to a struct lun_netfn_support that contains current info + * @enable: a pointer to a 32 byte bitfield that contains the desired enable state + * @gun: here is a gun to shoot yourself in the foot. If this is true + * you are allowed to disable this command + * + * returns 0 on success + * returns -1 on error + */ +static int +_set_command_enables(void * intf, + struct ipmi_function_params * p, struct lun_netfn_support * lnfn, + unsigned char * enable, int gun) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char * d, rqdata[19]; + unsigned int c; + + if (!p || !lnfn) { + lprintf(LOG_ERR, "_set_command_enables: p or lnfn is NULL"); + return -1; + } + + lprintf(LOG_INFO, "support: "); + print_bitfield(lnfn->command_mask, MAX_COMMAND_BYTES, 1, LOG_INFO); + lprintf(LOG_INFO, "configurable: "); + print_bitfield(lnfn->config_mask, MAX_COMMAND_BYTES, 0, LOG_INFO); + lprintf(LOG_INFO, "enabled: "); + print_bitfield(lnfn->enable_mask, MAX_COMMAND_BYTES, 0, LOG_INFO); + lprintf(LOG_INFO, "enable mask before: "); + print_bitfield(enable, MAX_COMMAND_BYTES, 0, LOG_INFO); + + // mask off the appropriate bits (if not configurable, set enable bit + // must be the same as the current enable bit) + for (c=0; c<(MAX_COMMAND_BYTES); c++) { + enable[c] = (lnfn->config_mask[c] & enable[c]) | + (~lnfn->config_mask[c] & lnfn->enable_mask[c]); + } + + // take the gun out of their hand if they are not supposed to have it + if (!gun) { + enable[SET_COMMAND_ENABLE_BYTE] = + (lnfn->config_mask[SET_COMMAND_ENABLE_BYTE] + & SET_COMMAND_ENABLE_BIT) | + (~lnfn->config_mask[SET_COMMAND_ENABLE_BYTE] + & lnfn->enable_mask[SET_COMMAND_ENABLE_BYTE]); + } + lprintf(LOG_INFO, "enable mask after: "); + print_bitfield(enable, MAX_COMMAND_BYTES, 0, LOG_INFO); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_SET_COMMAND_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + memcpy(&rqdata[3], enable, MAX_COMMAND_BYTES/2); + req.msg.data = rqdata; + req.msg.data_len = 19; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Set Command Enables (LUN=%d, NetFn=%d, op=0) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + d = &rsp[0]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_SET_COMMAND_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)(0x40 | p->netfn); + rqdata[2] = (unsigned char)p->lun; + memcpy(&rqdata[3], enable+MAX_COMMAND_BYTES/2, MAX_COMMAND_BYTES/2); + req.msg.data = rqdata; + req.msg.data_len = 19; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Set Command Enables (LUN=%d, NetFn=%d, op=1) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + d = &rsp[0]; + + return 0; +} + +/* _get_subfn_support + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @cmd: a pointer to a struct command_support + * + * returns 0 on success and fills in cmd according to the request in p + * returns -1 on error + */ +static int +_get_subfn_support(void * intf, + struct ipmi_function_params * p, struct command_support * cmd) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char rqdata[4]; + + if (!p || !cmd) { + lprintf(LOG_ERR, "_get_subfn_support: p or cmd is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_SUBFUNCTION_SUPPORT; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + rqdata[3] = (unsigned char)p->command; + req.msg.data = rqdata; + req.msg.data_len = 4; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Subfunction Support (LUN=%d, NetFn=%d, cmd=%d) command failed: %d (0x%02x)\n", p->lun, p->netfn, p->command, rv,rv); + return(rv); + } + + memcpy(cmd->subfn_support, rsp, sizeof(cmd->subfn_support)); + return 0; +} + +/* _get_subfn_configurable + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @cmd: a pointer to a struct command_support + * + * returns 0 on success and fills in cmd according to the request in p + * returns -1 on error + */ +static int +_get_subfn_configurable(void * intf, + struct ipmi_function_params * p, struct command_support * cmd) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char rqdata[4]; + + if (!p || !cmd) { + lprintf(LOG_ERR, "_get_subfn_configurable: p or cmd is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_CONFIGURABLE_COMMAND_SUBFUNCTIONS; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + rqdata[3] = (unsigned char)p->command; + req.msg.data = rqdata; + req.msg.data_len = 4; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Configurable Command Subfunction Support (LUN=%d, NetFn=%d, cmd=%d) command failed: %d (0x%02x)\n", p->lun, p->netfn, p->command, rv,rv); + return(rv); + } + + memcpy(cmd->subfn_config, rsp, sizeof(cmd->subfn_config)); + return 0; +} + +/* _get_subfn_enables + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @cmd: a pointer to a struct command_support + * + * returns 0 on success and fills in cmd according to the request in p + * returns -1 on error + */ +static int +_get_subfn_enables(void * intf, + struct ipmi_function_params * p, struct command_support * cmd) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char rqdata[4]; + + if (!p || !cmd) { + lprintf(LOG_ERR, "_get_subfn_enables: p or cmd is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_SUBFUNCTION_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + rqdata[3] = (unsigned char)p->command; + req.msg.data = rqdata; + req.msg.data_len = 4; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Subfunction Enables (LUN=%d, NetFn=%d, cmd=%d) command failed: %d (0x%02x)\n", p->lun, p->netfn, p->command, rv,rv); + return(rv); + } + + memcpy(cmd->subfn_enable, rsp, sizeof(cmd->subfn_enable)); + return 0; +} + +/* _set_subfn_enables + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @cmd: a pointer to a struct command_support + * @enable: a pointer to a 4 byte bitfield that contains the desired enable state + * + * returns 0 on success (and modifies enable to be the bits it actually set) + * returns -1 on error + */ +static int +_set_subfn_enables(void * intf, + struct ipmi_function_params * p, struct command_support * cmd, + unsigned char * enable) +{ + struct ipmi_rq req; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + unsigned char rqdata[8]; + unsigned int c; + + if (!p || !cmd) { + lprintf(LOG_ERR, "_set_subfn_enables: p or cmd is NULL"); + return -1; + } + + lprintf(LOG_INFO, "support: "); + print_bitfield(cmd->subfn_support, MAX_SUBFN_BYTES, 1, LOG_INFO); + lprintf(LOG_INFO, "configurable: "); + print_bitfield(cmd->subfn_config, MAX_SUBFN_BYTES, 0, LOG_INFO); + lprintf(LOG_INFO, "enabled: "); + print_bitfield(cmd->subfn_enable, MAX_SUBFN_BYTES, 0, LOG_INFO); + lprintf(LOG_INFO, "enable mask before: "); + print_bitfield(enable, MAX_SUBFN_BYTES, 0, LOG_INFO); + // mask off the appropriate bits (if not configurable, set enable bit + // must be the same as the current enable bit) + for (c=0; c<sizeof(cmd->subfn_enable); c++) { + enable[c] = (cmd->subfn_config[c] & enable[c]) | + (~cmd->subfn_config[c] & cmd->subfn_enable[c]); + } + lprintf(LOG_INFO, "enable mask after: "); + print_bitfield(enable, MAX_SUBFN_BYTES, 0, LOG_INFO); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_SET_COMMAND_SUBFUNCTION_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + rqdata[3] = (unsigned char)p->command; + memcpy(&rqdata[4], enable, MAX_SUBFN_BYTES); + req.msg.data = rqdata; + req.msg.data_len = 8; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Set Command Subfunction Enables (LUN=%d, NetFn=%d, cmd=%d) command failed: %d (0x%02x)\n", p->lun, p->netfn, p->command, rv,rv); + return(rv); + } + + return 0; +} + +/* _gather_info + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @bmc: a pointer to a struct bmc_fn_support + * @enable: a pointer to a 4 byte bitfield that contains the desired enable state + * + * returns 0 on success and fills in bmc according to request p + * returns -1 on error + */ +static int _gather_info(void * intf, struct ipmi_function_params * p, struct bmc_fn_support * bmc) +{ + int ret, l, n; + unsigned char lun[MAX_LUN], netfn[16]; + + ret = _get_netfn_support(intf, p->channel, lun, netfn); + if (ret != 0) return (ret); + else { /*success*/ + for (l=0; l<MAX_LUN; l++) { + if (p->lun >= 0 && p->lun != l) + continue; + bmc->lun[l].support = lun[l]; + if (lun[l]) { + for (n=0; n<MAX_NETFN_PAIR; n++) { + int offset = l*MAX_NETFN_PAIR+n; + bmc->lun[l].netfn[n].support = + !!(netfn[offset>>3] & (1<<(offset%8))); + } + } + } + } + if (p->netfn >= 0) { + if (!((p->lun < 0 || bmc->lun[p->lun].support) && + (p->netfn < 0 || bmc->lun[p->lun].netfn[p->netfn>>1].support))) { + lprintf(LOG_ERR, "LUN or LUN/NetFn pair %d,%d not supported", p->lun, p->netfn); + return 0; + } + ret = _get_command_support(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1])); + ret |= _get_command_configurable(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1])); + ret |= _get_command_enables(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1])); + if (!ret && p->command >= 0) { + ret = _get_subfn_support(intf, p, + &(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command])); + ret |= _get_subfn_configurable(intf, p, + &(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command])); + ret |= _get_subfn_enables(intf, p, + &(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command])); + } + } + else if (p->lun >= 0) { + l = p->lun; + if (bmc->lun[l].support) { + for (n=0; n<MAX_NETFN_PAIR; n++) { + p->netfn = n*2; + if (bmc->lun[l].netfn[n].support) { + ret = _get_command_support(intf, p, &(bmc->lun[l].netfn[n])); + ret |= _get_command_configurable(intf, p, &(bmc->lun[l].netfn[n])); + ret |= _get_command_enables(intf, p, &(bmc->lun[l].netfn[n])); + } + if (ret) + bmc->lun[l].netfn[n].support = 0; + } + } + p->netfn = -1; + } else { + for (l=0; l<4; l++) { + p->lun = l; + if (bmc->lun[l].support) { + for (n=0; n<MAX_NETFN_PAIR; n++) { + p->netfn = n*2; + if (bmc->lun[l].netfn[n].support) { + ret = _get_command_support(intf, p, &(bmc->lun[l].netfn[n])); + ret |= _get_command_configurable(intf, p, &(bmc->lun[l].netfn[n])); + ret |= _get_command_enables(intf, p, &(bmc->lun[l].netfn[n])); + } + if (ret) + bmc->lun[l].netfn[n].support = 0; + } + } + } + p->lun = -1; + p->netfn = -1; + } + + return 0; +} + +/* ipmi_firewall_info - print out info for firewall functions + * + * @intf: ipmi inteface + * @argc: argument count + * @argv: argument list + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_firewall_info(void * intf, int argc, char ** argv) +{ + int ret = 0; + struct ipmi_function_params p = {0xe, -1, -1, -1, -1}; + struct bmc_fn_support * bmc_fn_support; + unsigned int l, n, c; + + if ((argc > 0 && strncmp(argv[0], "help", 4) == 0) || ipmi_firewall_parse_args(argc, argv, &p) < 0) + { + printf("info [channel H]\n"); + printf("\tlist all of the firewall information for all LUNs, NetFns, and Commands\n"); + printf("\tthis is a long list and is not very human readable\n"); + printf("info [channel H] lun L\n"); + printf("\tthis also prints a long list that is not very human readable\n"); + printf("info [channel H] lun L netfn N\n"); + printf("\tthis prints out information for a single LUN/NetFn pair\n"); + printf("\tthat is not really very usable, but at least it is short\n"); + printf("info [channel H] lun L netfn N command C\n"); + printf("\tthis is the one you want -- it prints out detailed human\n"); + printf("\treadable information. It shows the support, configurable, and\n"); + printf("\tenabled bits for the Command C on LUN/NetFn pair L,N and the\n"); + printf("\tsame information about each of its Sub-functions\n"); + return 0; + } + + bmc_fn_support = malloc(sizeof(struct bmc_fn_support)); + if (!bmc_fn_support) { + lprintf(LOG_ERR, "malloc struct bmc_fn_support failed"); + return -1; + } + + ret = _gather_info(intf, &p, bmc_fn_support); + + if (p.command >= 0) { + struct command_support * cmd; + if (!((p.lun < 0 || bmc_fn_support->lun[p.lun].support) && + (p.netfn < 0 || bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].support) && + bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].command[p.command].support)) + { + lprintf(LOG_ERR, "Command 0x%02x not supported on LUN/NetFn pair %02x,%02x", + p.command, p.lun, p.netfn); + free(bmc_fn_support); + return 0; + } + cmd = + &bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].command[p.command]; + c = cmd->support; + printf("(A)vailable, (C)onfigurable, (E)nabled: | A | C | E |\n"); + printf("-----------------------------------------------------\n"); + printf("LUN %01d, NetFn 0x%02x, Command 0x%02x: | %c | %c | %c |\n", + p.lun, p.netfn, p.command, + (c & BIT_AVAILABLE) ? 'X' : ' ', + (c & BIT_CONFIGURABLE) ? 'X' : ' ', + (c & BIT_ENABLED) ? 'X': ' '); + + for (n=0; n<MAX_SUBFN; n++) { + printf("sub-function 0x%02x: | %c | %c | %c |\n", n, + (!bit_test(cmd->subfn_support, n)) ? 'X' : ' ', + (bit_test(cmd->subfn_config, n)) ? 'X' : ' ', + (bit_test(cmd->subfn_enable, n)) ? 'X' : ' '); + } + } + else if (p.netfn >= 0) { + if (!((p.lun < 0 || bmc_fn_support->lun[p.lun].support) && + (bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].support))) + { + lprintf(LOG_ERR, "LUN or LUN/NetFn pair %02x,%02x not supported", + p.lun, p.netfn); + free(bmc_fn_support); + return 0; + } + n = p.netfn >> 1; + l = p.lun; + printf("Commands on LUN 0x%02x, NetFn 0x%02x\n", p.lun, p.netfn); + printf("support: "); + print_bitfield(bmc_fn_support->lun[l].netfn[n].command_mask, + MAX_COMMAND_BYTES, 1, -1); + printf("configurable: "); + print_bitfield(bmc_fn_support->lun[l].netfn[n].config_mask, + MAX_COMMAND_BYTES, 0, -1); + printf("enabled: "); + print_bitfield(bmc_fn_support->lun[l].netfn[n].enable_mask, + MAX_COMMAND_BYTES, 0, -1); + } + else { + for (l=0; l<4; l++) { + p.lun = l; + if (bmc_fn_support->lun[l].support) { + for (n=0; n<MAX_NETFN_PAIR; n++) { + p.netfn = n*2; + if (bmc_fn_support->lun[l].netfn[n].support) { + printf("%02x,%02x support: ", p.lun, p.netfn); + print_bitfield(bmc_fn_support->lun[l].netfn[n].command_mask, + MAX_COMMAND_BYTES, 1, -1); + printf("%02x,%02x configurable: ", p.lun, p.netfn); + print_bitfield(bmc_fn_support->lun[l].netfn[n].config_mask, + MAX_COMMAND_BYTES, 0, -1); + printf("%02x,%02x enabled: ", p.lun, p.netfn); + print_bitfield(bmc_fn_support->lun[l].netfn[n].enable_mask, + MAX_COMMAND_BYTES, 0, -1); + } + } + } + } + p.lun = -1; + p.netfn = -1; + } + + free(bmc_fn_support); + return ret; +} + +/* ipmi_firewall_enable_disable - enable/disable BMC functions + * + * @intf: ipmi inteface + * @enable: whether to enable or disable + * @argc: argument count + * @argv: argument list + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_firewall_enable_disable(void * intf, int enable, int argc, char ** argv) +{ + struct ipmi_function_params p = {0xe, -1, -1, -1, -1}; + struct bmc_fn_support * bmc_fn_support; + unsigned int l, n, c; + int ret; + unsigned char enables[MAX_COMMAND_BYTES]; + + if (argc < 1 || strncmp(argv[0], "help", 4) == 0) { + char * s1 = enable?"en":"dis"; + char * s2 = enable?"":" [force]"; + printf("%sable [channel H] lun L netfn N%s\n", s1, s2); + printf("\t%sable all commands on this LUN/NetFn pair\n", s1); + printf("%sable [channel H] lun L netfn N command C%s\n", s1, s2); + printf("\t%sable Command C and all its Sub-functions for this LUN/NetFn pair\n", s1); + printf("%sable [channel H] lun L netfn N command C subfn S\n", s1); + printf("\t%sable Sub-function S for Command C for this LUN/NetFn pair\n", s1); + if (!enable) { + printf("* force will allow you to disable the \"Command Set Enable\" command\n"); + printf("\tthereby letting you shoot yourself in the foot\n"); + printf("\tthis is only recommended for advanced users\n"); + } + return 0; + } + if (ipmi_firewall_parse_args(argc, argv, &p) < 0) + return -1; + + bmc_fn_support = malloc(sizeof(struct bmc_fn_support)); + if (!bmc_fn_support) { + lprintf(LOG_ERR, "malloc struct bmc_fn_support failed"); + return -1; + } + + ret = _gather_info(intf, &p, bmc_fn_support); + if (ret < 0) { + free(bmc_fn_support); + return ret; + } + + l = p.lun; + n = p.netfn>>1; + c = p.command; + if (p.subfn >= 0) { + // firewall (en|dis)able [channel c] lun l netfn n command m subfn s + // (en|dis)able this sub-function for this commnad on this lun/netfn pair + memcpy(enables, + bmc_fn_support->lun[l].netfn[n].command[c].subfn_enable, + MAX_SUBFN_BYTES); + bit_set(enables, p.subfn, enable); + ret = _set_subfn_enables(intf, &p, + &bmc_fn_support->lun[l].netfn[n].command[c], enables); + + } else if (p.command >= 0) { + // firewall (en|dis)able [channel c] lun l netfn n command m + // (en|dis)able all subfn and command for this commnad on this lun/netfn pair + memset(enables, enable?0xff:0, MAX_SUBFN_BYTES); + ret = _set_subfn_enables(intf, &p, + &bmc_fn_support->lun[l].netfn[n].command[c], enables); + memcpy(enables, + &bmc_fn_support->lun[l].netfn[n].enable_mask, sizeof(enables)); + bit_set(enables, p.command, enable); + ret |= _set_command_enables(intf, &p, + &bmc_fn_support->lun[l].netfn[n], enables, p.force); + } else if (p.netfn >= 0) { + // firewall (en|dis)able [channel c] lun l netfn n + // (en|dis)able all commnads on this lun/netfn pair + memset(enables, enable?0xff:0, sizeof(enables)); + ret = _set_command_enables(intf, &p, + &bmc_fn_support->lun[l].netfn[n], enables, p.force); + /* + } else if (p.lun >= 0) { + // firewall (en|dis)able [channel c] lun l + // (en|dis)able all commnads on all netfn pairs for this lun + */ + } + free(bmc_fn_support); + return ret; +} + +/* ipmi_firewall_reset - reset firmware firewall to enable everything + * + * @intf: ipmi inteface + * @argc: argument count + * @argv: argument list + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_firewall_reset(void * intf, int argc, char ** argv) +{ + struct ipmi_function_params p = {0xe, -1, -1, -1, -1}; + struct bmc_fn_support * bmc_fn_support; + unsigned int l, n, c; + int ret; + unsigned char enables[MAX_COMMAND_BYTES]; + + if (argc > 0 || (argc > 0 && strncmp(argv[0], "help", 4) == 0)) { + printf_firewall_usage(); + return 0; + } + if (ipmi_firewall_parse_args(argc, argv, &p) < 0) + return -1; + + bmc_fn_support = malloc(sizeof(struct bmc_fn_support)); + if (!bmc_fn_support) { + lprintf(LOG_ERR, "malloc struct bmc_fn_support failed"); + return -1; + } + + ret = _gather_info(intf, &p, bmc_fn_support); + if (ret < 0) { + free(bmc_fn_support); + return ret; + } + + for (l=0; l<MAX_LUN; l++) { + p.lun = l; + for (n=0; n<MAX_NETFN; n+=2) { + p.netfn = n; + for (c=0; c<MAX_COMMAND; c++) { + p.command = c; + printf("reset lun %d, netfn %d, command %d, subfn\n", l, n, c); + memset(enables, 0xff, MAX_SUBFN_BYTES); + ret = _set_subfn_enables(intf, &p, + &bmc_fn_support->lun[l].netfn[n].command[c], enables); + } + printf("reset lun %d, netfn %d, command\n", l, n); + memset(enables, 0xff, sizeof(enables)); + ret = _set_command_enables(intf, &p, + &bmc_fn_support->lun[l].netfn[n], enables, 0); + } + } + + free(bmc_fn_support); + return ret; +} + +#ifdef METACOMMAND +int i_firewall(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + void *intf = NULL; + int rc = 0; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"m:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'x': fdebug = 1; verbose = 1; + break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + printf_firewall_usage(); + return 0; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + if (argc < 1 || strncmp(argv[0], "help", 4) == 0) { + printf_firewall_usage(); + } + else if (strncmp(argv[0], "info", 4) == 0) { + rc = ipmi_firewall_info(intf, argc-1, &(argv[1])); + } + else if (strncmp(argv[0], "enable", 6) == 0) { + rc = ipmi_firewall_enable_disable(intf, 1, argc-1, &(argv[1])); + } + else if (strncmp(argv[0], "disable", 7) == 0) { + rc = ipmi_firewall_enable_disable(intf, 0, argc-1, &(argv[1])); + } + else if (strncmp(argv[0], "reset", 5) == 0) { + rc = ipmi_firewall_reset(intf, argc-1, &(argv[1])); + } + else { + printf_firewall_usage(); + rc = ERR_BAD_PARAM; + } + + ipmi_close_(); + // show_outcome(progname,rc); + return rc; +} diff --git a/util/ifirewall.h b/util/ifirewall.h new file mode 100644 index 0000000..14a04f4 --- /dev/null +++ b/util/ifirewall.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef IPMI_FIREWALL_H +#define IPMI_FIREWALL_H + +#define uint8_t unsigned char +#define uint16_t unsigned short + +// struct ipmi_rq definition was moved to ipmicmd.h +#define IPMI_NETFN_APP 0x06 + +#define BMC_GET_NETFN_SUPPORT 0x09 +#define BMC_GET_COMMAND_SUPPORT 0x0A +#define BMC_GET_COMMAND_SUBFUNCTION_SUPPORT 0x0B +#define BMC_GET_CONFIGURABLE_COMMANDS 0x0C +#define BMC_GET_CONFIGURABLE_COMMAND_SUBFUNCTIONS 0x0D +#define BMC_SET_COMMAND_ENABLES 0x60 +#define BMC_GET_COMMAND_ENABLES 0x61 +#define BMC_SET_COMMAND_SUBFUNCTION_ENABLES 0x62 +#define BMC_GET_COMMAND_SUBFUNCTION_ENABLES 0x63 +#define BMC_OEM_NETFN_IANA_SUPPORT 0x64 + +#define SET_COMMAND_ENABLE_BYTE (BMC_SET_COMMAND_ENABLES / 8) +#define SET_COMMAND_ENABLE_BIT (BMC_SET_COMMAND_ENABLES % 8) + +#define MAX_LUN 4 +#define MAX_NETFN 64 +#define MAX_NETFN_PAIR (MAX_NETFN/2) +#define MAX_COMMAND 256 +#define MAX_SUBFN 32 +#define MAX_COMMAND_BYTES (MAX_COMMAND>>3) +#define MAX_SUBFN_BYTES (MAX_SUBFN>>3) + +// support is a bitfield with the following bits set... +#define BIT_AVAILABLE 0x01 +#define BIT_CONFIGURABLE 0x02 +#define BIT_ENABLED 0x04 + +struct command_support { + unsigned char support; + unsigned char version[3]; + unsigned char subfn_support[MAX_SUBFN_BYTES]; + unsigned char subfn_config[MAX_SUBFN_BYTES]; + unsigned char subfn_enable[MAX_SUBFN_BYTES]; +}; +struct lun_netfn_support { + unsigned char support; + struct command_support command[MAX_COMMAND]; + unsigned char command_mask[MAX_COMMAND_BYTES]; + unsigned char config_mask[MAX_COMMAND_BYTES]; + unsigned char enable_mask[MAX_COMMAND_BYTES]; +}; +struct lun_support { + unsigned char support; + struct lun_netfn_support netfn[MAX_NETFN_PAIR]; +}; +struct bmc_fn_support { + struct lun_support lun[MAX_LUN]; +}; +struct ipmi_function_params { + int channel; + int lun; + int netfn; + int command; + int subfn; + unsigned char force; +}; + +#ifdef WIN32 +#define INLINE /*nop*/ +#else +#define INLINE inline +#endif +static INLINE int bit_test(const unsigned char * bf, int n) { + return !!(bf[n>>3]&(1<<(n%8))); +} +static INLINE void bit_set(unsigned char * bf, int n, int v) { + bf[n>>3] = (bf[n>>3] & ~(1<<(n%8))) | ((v?1:0)<<(n%8)); +} + +#endif /*IPMI_FIREWALL_H */ diff --git a/util/ifru.c b/util/ifru.c new file mode 100755 index 0000000..ba834e6 --- /dev/null +++ b/util/ifru.c @@ -0,0 +1,2123 @@ +/* + * ifru (was fruconfig.c) + * + * This tool reads the FRU configuration, and optionally sets the asset + * tag field in the FRU data. See IPMI v1.5 spec section 28. + * It can use either the Intel /dev/imb driver or VALinux /dev/ipmikcs. + * + * Author: Andy Cress arcress at users.sourceforge.net + * + * Copyright (c) 2009 Kontron America, Inc. + * + * 10/28/02 Andy Cress - created + * 12/11/02 Andy Cress v0.9 - disable write until checksum fixed. + * 12/13/02 Andy Cress v0.91 - don't abort if cc=c9 in load_fru loop. + * 01/27/03 Andy Cress v0.92 - more debug, do checksums, + * 01/28/03 Andy Cress v1.0 do writes in small chunks, tested w SCB2 & STL2 + * 02/19/03 Andy Cress v1.1 also get System GUID + * 03/10/03 Andy Cress v1.2 do better bounds checking on FRU size + * 04/30/03 Andy Cress v1.3 Board Part# & Serial# reversed + * 05/13/03 Andy Cress v1.4 Added Chassis fields + * 06/19/03 Andy Cress v1.5 added errno.h (email from Travers Carter) + * 05/03/04 Andy Cress v1.6 BladeCenter has no product area, only board area + * 05/05/04 Andy Cress v1.7 call ipmi_close before exit, + * added WIN32 compile options. + * 11/01/04 Andy Cress v1.8 add -N / -R for remote nodes + * 12/10/04 Andy Cress v1.9 add gnu freeipmi interface + * 01/13/05 Andy Cress v1.10 add logic to scan SDRs for all FRU devices, + * and interpret them + * 01/17/05 Andy Cress v1.11 decode SPD Manufacturer + * 01/21/05 Andy Cress v1.12 format SystemGUID display + * 02/03/05 Andy Cress v1.13 fixed fwords bit mask in load_fru, + * decode DIMM size from SPD also. + * 02/04/05 Andy Cress v1.14 decode FRU Board Mfg DateTime + * 03/16/05 Andy Cress v1.15 show Asset Tag Length earlier + * 05/24/05 Andy Cress v1.16 only do write_asset if successful show_fru + * 06/20/05 Andy Cress v1.17 handle Device SDRs also for ATCA + * 08/22/05 Andy Cress v1.18 allow setting Product Serial Number also (-s), + * also add -b option to show only baseboard data. + * 10/31/06 Andy Cress v1.25 handle 1-char asset/serial strings (avoid c1) + */ +/*M* +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <errno.h> +#endif +#endif +#include <time.h> + +#include "ipmicmd.h" +#include "ipicmg.h" +#include "oem_intel.h" +#include "ifru.h" + +#define PICMG_CHILD 1 +#define MIN_SDR_SZ 8 +#ifndef URNLOOPS +#define URNLOOPS 1000 +#endif +extern int get_BiosVersion(char *str); +extern int get_SystemGuid(uchar *guid); +extern void fmt_time(time_t etime, char *buf, int bufsz); /*see ievents.c*/ +extern int get_LastError( void ); /* ipmilan.c */ +extern int GetSDRRepositoryInfo(int *nret, int *fdev); /*isensor.h*/ +#ifdef METACOMMAND +extern int ipmi_kontronoem_main(void * intf, int argc, char ** argv); +#endif + +static char *progname = "ifru"; +static char *progver = "2.93"; +static int vend_id = 0; +static int prod_id = 0; +static char fdebug = 0; +static char fpicmg = 0; +static char fonlybase = 0; +static char fonlyhsc = 0; +static int fwritefru = 0; +static int fdevsdrs = 0; +static char fshowlen = 0; +static char ftestshow = 0; +// static char fgetfru = 0; +static char fdoanyway = 0; +static char fprivset = 0; +static char fset_mc = 0; +static char fcanonical = 0; +static char foemkontron = 0; +static char fbasefru = 1; +static char fdump = 0; +static char frestore = 0; +static char fchild = 0; /* =1 follow child MCs if picmg bladed*/ +static char do_systeminfo = 1; +static char do_guid = 1; +static char bdelim = ':'; +static uchar bmc_sa = BMC_SA; /*defaults to 0x20*/ +static uchar guid[17] = ""; +static char *binfile = NULL; +static uchar *frubuf = NULL; +#define FIELD_LEN 20 +#define SZ_PRODAREA 520 /* product area max is 8*32 + 3 = 259 mod 8 = 264 */ +static int sfru = 0; +static int asset_offset = -1; +static int asset_len = 0; +static int sernum_offset = -1; +static int sernum_len = 0; +static int prodver_offset = -1; +static int prodver_len = 0; +static int chassis_offset = -1; +static int chassis_len = 0; +static char asset_tag[FIELD_LEN] = {0}; +static char serial_num[FIELD_LEN] = {0}; +static char prod_ver[FIELD_LEN] = {0}; +static char chassis_name[FIELD_LEN] = {0}; +static char ps_prod[FIELD_LEN] = {0}; +static int maxprod = 0; +static int ctype; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = 0; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static uchar g_fruid = 0; /* default to fruid 0 */ +static uchar g_frutype = 0; +static uchar lastfru[3] = {0,0,0}; +/* g_frutype values (detected), see also FruTypeString + * --TAG---- FRU IPMB + * Baseboard = 0x0c 0x07 + * PowerSply = 0x0a + * PowerCage = 0x15 + * DIMM = 0x20 + * HotSwapCt = 0x0f + * ME = 0x2e + * SysInfo = 0x40 + * Component = * * (all others) + */ +#ifdef METACOMMAND +extern int verbose; +extern int sdr_get_reservation(uchar *res_id, int fdev); +#else +static int verbose; +static int sdr_get_reservation(uchar *res_id, int fdev) { return(-1); } +#endif + +#define ERR_LENMAX -7 /*same as LAN_ERR_BADLENGTH */ +#define ERR_LENMIN -10 /*same as LAN_ERR_TOO_SHORT */ +#define ERR_OTHER -13 /*same as LAN_ERR_OTHER */ + +#define STRING_DATA_TYPE_BINARY 0x00 +#define STRING_DATA_TYPE_BCD_PLUS 0x01 +#define STRING_DATA_TYPE_SIX_BIT_ASCII 0x02 +#define STRING_DATA_TYPE_LANG_DEPENDENT 0x03 + +#define FRUCHUNK_SZ 16 +#define FRU_END 0xC1 +#define FRU_EMPTY_FIELD 0xC0 +#define FRU_TYPE_MASK 0xC0 +#define FRU_LEN_MASK 0x3F + +#define NUM_BOARD_FIELDS 6 +#define NUM_PRODUCT_FIELDS 8 +#define NUM_CHASSIS_FIELDS 3 +#define MAX_CTYPE 26 +char *ctypes[MAX_CTYPE] = { "", "Other", "Unknown", "Desktop", + "Low Profile Desktop", "Pizza Box", "Mini-Tower", "Tower", + "Portable", "Laptop", "Notebook", "Handheld", "Docking Station", + "All-in-One", "Sub-Notebook", "Space-saving", "Lunch Box", + "Main Server Chassis", "Expansion Chassis", "SubChassis", + "Bus Expansion Chassis", "Peripheral Chassis", + "RAID Chassis", /*0x17=23.*/ "Rack-Mount Chassis", + "New24" , "New25"}; + /* what about bladed chassies? */ +char *ctype_hdr = +"Chassis Type "; +char *chassis[NUM_CHASSIS_FIELDS] = { +"Chassis Part Number ", +"Chassis Serial Num ", +"Chassis OEM Field " }; +char *board[NUM_BOARD_FIELDS] = { +"Board Manufacturer ", +"Board Product Name ", +"Board Serial Number ", +"Board Part Number ", +"Board FRU File ID ", +"Board OEM Field " }; +char *product[NUM_PRODUCT_FIELDS] = { +"Product Manufacturer", +"Product Name ", +"Product Part Number ", +"Product Version ", +"Product Serial Num ", +"Product Asset Tag ", +"Product FRU File ID ", +"Product OEM Field " }; +char *asset_hdr = +" Asset Tag Length "; + +#if 0 +typedef struct { + uchar len :6; + uchar type:2; + } TYPE_LEN; /*old, assumes lo-hi byte order*/ +#else +typedef struct { + uchar len; + uchar type; + } TYPE_LEN; +#endif + +void +free_fru(uchar *pfrubuf) +{ + if (pfrubuf != NULL) { + if (frubuf != NULL) free(frubuf); + frubuf = NULL; + } + return; +} + +int +load_fru(uchar sa, uchar frudev, uchar frutype, uchar **pfrubuf) +{ + int ret = 0; + uchar indata[16]; + uchar resp[18]; + int sresp; + uchar cc; + int sz; + char fwords; + ushort fruoff = 0; + int i, rv; + int chunk; + + if (pfrubuf == NULL) return(ERR_BAD_PARAM); + *pfrubuf = NULL; + indata[0] = frudev; + sresp = sizeof(resp); + if (fdebug) printf("load_fru: sa=%02x, frudev=%02x, addrtype=%d\n", + sa,frudev,g_addrtype); + ret = ipmi_cmd_mc(GET_FRU_INV_AREA,indata,1,resp,&sresp,&cc,fdebug); + if (fdebug) printf("load_fru: inv ret=%d, cc=%x, resp=%02x %02x %02x\n", + ret,cc, resp[0], resp[1], resp[2]); + if (ret != 0) return(ret); + if (cc != 0) { ret = (cc & 0x00ff); return(ret); } + + sz = resp[0] + (resp[1] << 8); + if (resp[2] & 0x01) { fwords = 1; sz = sz * 2; } + else fwords = 0; + + frubuf = malloc(sz); + if (frubuf == NULL) return(get_errno()); + *pfrubuf = frubuf; + sfru = sz; + + /* Loop on READ_FRU_DATA */ + for (i = 0, chunk=FRUCHUNK_SZ; i < sz; i+=chunk) + { + if ((i+chunk) >= sz) chunk = sz - i; + indata[0] = frudev; /* FRU Device ID */ + if (fwords) { + indata[3] = chunk / 2; + fruoff = (i/2); + } else { + indata[3] = (uchar)chunk; + fruoff = (ushort)i; + } + indata[1] = fruoff & 0x00FF; + indata[2] = (fruoff & 0xFF00) >> 8; + sresp = sizeof(resp); + ret = ipmi_cmd_mc(READ_FRU_DATA,indata,4,resp,&sresp,&cc,fdebug); + if (ret != 0) break; + else if (cc != 0) { + if (i == 0) ret = cc & 0x00ff; + if (fdebug) printf("read_fru[%d]: ret = %d cc = %x\n",i,ret,cc); + break; + } + memcpy(&frubuf[i],&resp[1],chunk); + } + + if ((frudev == 0) && (sa == bmc_sa) && do_guid) + { /*main system fru, so get GUID*/ + sresp = sizeof(resp); + rv = ipmi_cmd_mc(GET_SYSTEM_GUID,indata,0,resp,&sresp,&cc,fdebug); + if (fdebug) printf("system_guid: ret = %d, cc = %x\n",rv,cc); + if (rv == 0) rv = cc; + if ((rv != 0) && !is_remote()) { /* get UUID from SMBIOS */ + cc = 0; sresp = 16; + rv = get_SystemGuid(resp); + if (fdebug) printf("get_SystemGuid: ret = %d\n",rv); + } + if (rv == 0 && cc == 0) { + if (fdebug) { + printf("system guid (%d): ",sresp); + for (i=0; i<16; i++) printf("%02x ",resp[i]); + printf("\n"); + } + memcpy(&guid,&resp,16); + guid[16] = 0; + } else { + printf("WARNING: GetSystemGuid error %d, %s\n",rv,decode_rv(rv)); + /*do not pass this error upstream*/ + } + } /*endif*/ + return(ret); +} + +static void decode_string(unsigned char type, + unsigned char language_code, + unsigned char *source, + int slen, + char *target, + int tsize) +{ + static const char bcd_plus[] = "0123456789 -.:,_"; + unsigned char *s = &source[0]; + int len, i, j, k; + union { uint32_t bits; char chars[4]; } u; + + if (slen == 0 || slen == 1) return; + switch(type) { + case STRING_DATA_TYPE_BINARY: /* 00: binary/unspecified */ + len = (slen*2); break; /* hex dump -> 2x length */ + case STRING_DATA_TYPE_SIX_BIT_ASCII: /*type 2 6-bit ASCII*/ + /* 4 chars per group of 1-3 bytes */ + len = ((((slen+2)*4)/3) & ~3); break; + case STRING_DATA_TYPE_LANG_DEPENDENT: /* 03 language dependent */ + case STRING_DATA_TYPE_BCD_PLUS: /* 01b: BCD plus */ + default: + len = slen; break; + } + if (len >= tsize) len = tsize - 1; + memset(target, 0, len); + if (type == STRING_DATA_TYPE_BCD_PLUS) { /*type 1: BCD plus*/ + for (k=0; k<len; k++) + target[k] = bcd_plus[(s[k] & 0x0f)]; + target[k] = '\0'; + } else if (type == STRING_DATA_TYPE_SIX_BIT_ASCII) { /*type 2: 6-bit ASCII*/ + for (i=j=0; i<slen; i+=3) { + u.bits = 0; + k = ((slen-i) < 3 ? (slen-i) : 3); +#if WORDS_BIGENDIAN + u.chars[3] = s[i]; + u.chars[2] = (k > 1 ? s[i+1] : 0); + u.chars[1] = (k > 2 ? s[i+2] : 0); +#define CHAR_IDX 3 +#else + memcpy((void *)&u.bits, &s[i], k); +#define CHAR_IDX 0 +#endif + for (k=0; k<4; k++) { + target[j++] = ((u.chars[CHAR_IDX] & 0x3f) + 0x20); + u.bits >>= 6; + } + } + target[j] = '\0'; + } else if (type == STRING_DATA_TYPE_LANG_DEPENDENT) { /*type 3*/ + if ((language_code == 0x00) || (language_code == 0x25) || + (language_code == 0x19)) { + memcpy(target, source, len); + target[len] = 0; + } else { + printf("Language 0x%x dependent decode not supported\n",language_code); + } + } else if (type == STRING_DATA_TYPE_BINARY) { /* 00: binary/unspecified */ + strncpy(target, buf2str(s, slen), len); + target[len] = '\0'; /* add end-of-string char */ + } else { /* other */ + printf("Unable to decode type 0x%.2x\n",type); + } + return; +} + +uchar calc_cksum(uchar *pbuf,int len) +{ + int i; + uchar cksum; + uchar sum = 0; + + for (i = 0; i < len; i++) sum += pbuf[i]; + cksum = 0 - sum; + return(cksum); +} + +static void dumpbuf(uchar *pbuf,int sz) +{ + uchar line[17]; + uchar a; + int i, j; + + line[0] = 0; line[16] = 0; + j = 0; + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { j = 0; printf("%s\n %04d: ",line,i); } + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + printf("%02x ",pbuf[i]); + } + line[j] = 0; + printf("%s\n",line); + return; +} + +#define NSPDMFG 10 +static struct { + uchar id; char *str; +} spd_mfg[NSPDMFG] = { /* see JEDEC JEP106 doc */ +{ 0x02, "AMI" }, +{ 0x04, "Fujitsu" }, +{ 0x15, "Philips Semi" }, +{ 0x1c, "Mitsubishi" }, +{ 0x2c, "Micron" }, +{ 0x89, "Intel" }, +{ 0x98, "Kingston" }, +{ 0xA8, "US Modular" }, +{ 0xc1, "Infineon" }, +{ 0xce, "Samsung" } +}; + +int ValidTL(uchar typelen) +{ + if (vend_id != VENDOR_INTEL) return 1; + if ((typelen & 0xC0) == 0xC0) return 1; /* validate C type */ + if ((typelen & 0x00) == 0x00) return 1; /* validate 0 type too */ + else return 0; +} + +#define SYS_FRUTYPE 0x40 +char * FruTypeString(uchar frutype, uchar dev) +{ + char *pstr; + switch (frutype) { + case 0x07: /*IPMB*/ + case 0x0c: /*FRU*/ + if (dev == 0) pstr = "Baseboard"; + else pstr = "Board "; + break; + case 0x0a: pstr = "PowerSply"; break; /*FRU*/ + case 0x15: pstr = "PowerCage"; break; /*FRU*/ + case 0x20: pstr = "DIMM "; break; /*FRU*/ + case 0x0f: pstr = "HotSwapCt"; break; /*IPMB*/ + case 0x2e: pstr = "ME "; break; /*IPMB*/ + case SYS_FRUTYPE: pstr = "SysInfo "; break; /*SysInfo*/ + default: pstr = "Component"; break; + } + return(pstr); +} + +static int ChkOverflow(int idx, int sz, uchar len) +{ + if (idx >= sz) { + printf(" ERROR - FRU Buffer Overflow (%d >= %d), last len=%d\n", + idx,sz,len); + return 1; /*overflow error*/ + } + return 0; +} + +static void +show_spd(uchar *spd, int lenspd, uchar frudev, uchar frutype) +{ + int sz; + char *pstr; + int sdcap, ranks, busw, sdw, totcap; + uchar srev, mfgid, mrev1, mrev2, yr, wk; + uchar isdcap, iranks, ibusw, isdw; + uchar iparity, iser, ipart, irev; + int i; + char devstr[24]; + + /* Sample SPD Headers: + 80 08 07 0c 0a 01 48 00 (DDR SDRAM DIMM) + 92 10 0b 01 03 1a 02 00 (DDR3 SDRAM DIMMs) */ + sz = spd[0]; /* sz should == lenspd */ + srev = spd[1]; /* SPD Rev: 8 for DDR, 10 for DDR3 SPD spec */ + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s, %02x] ",FruTypeString(frutype,frudev),frudev); + printf("%sMemory SPD Size %c %d\n", + devstr,bdelim,lenspd); + switch (spd[2]) { + case 0x02: pstr = "EDO"; break; + case 0x04: pstr = "SDRAM"; break; + case 0x05: pstr = "ROM"; break; + case 0x06: pstr = "DDR SGRAM"; break; + case 0x07: pstr = "DDR SDRAM"; break; + case 0x08: pstr = "DDR2 SDRAM"; break; + case 0x09: pstr = "DDR2 SDRAM FB"; break; + case 0x0A: pstr = "DDR2 SDRAM FB PROBE"; break; + case 0x0B: pstr = "DDR3 SDRAM"; break; + default: pstr = "DRAM"; break; /*FPM DRAM or other*/ + } + printf("%sMemory Type %c %s\n", devstr,bdelim,pstr); + if (srev < 0x10) { /*used rev 0.8 of SPD spec*/ + printf("%sModule Density %c %d MB per bank\n", + devstr,bdelim, (spd[31] * 4)); + printf("%sModule Banks %c %d banks\n", + devstr,bdelim,spd[5]); + printf("%sModule Rows, Cols %c %d rows, %d cols\n", + devstr,bdelim, spd[3], spd[4]); + iparity = spd[11]; + mfgid = spd[64]; + } else { /* use 1.0 SPD spec with DDR3 */ + /* SDRAM CAPACITY = SPD byte 4 bits 3~0 */ + /* PRIMARY BUS WIDTH = SPD byte 8 bits 2~0 */ + /* SDRAM WIDTH = SPD byte 7 bits 2~0 */ + /* RANKS = SPD byte 7 bits 5~3 */ + isdcap = (spd[4] & 0x0f); + iranks = (spd[7] & 0x38) >> 3; + isdw = (spd[7] & 0x07); + ibusw = (spd[8] & 0x07); + iparity = (spd[8] & 0x38) >> 3; + mfgid = spd[118]; + switch(isdcap) { + case 0: sdcap = 256; /*MB*/ break; + case 1: sdcap = 512; /*MB*/ break; + case 2: sdcap = 1024; /*MB*/ break; + case 3: sdcap = 2048; /*MB*/ break; + case 4: sdcap = 4096; /*MB*/ break; + case 5: sdcap = 8192; /*MB*/ break; + case 6: sdcap = 16384; /*MB*/ break; + default: sdcap = 32768; /*MB*/ break; + } + switch(iranks) { + case 0: ranks = 1; break; + case 1: ranks = 2; break; + case 2: ranks = 3; break; + case 3: + default: ranks = 4; break; + } + switch(isdw) { + case 0: sdw = 4; break; + case 1: sdw = 8; break; + case 2: sdw = 16; break; + case 3: + default: sdw = 32; break; + } + switch(ibusw) { + case 0: busw = 8; break; + case 1: busw = 16; break; + case 2: busw = 32; break; + case 3: + default: busw = 64; break; + } + totcap = sdcap / 8 * busw / sdw * ranks; + printf("%sModule Density %c %d Mbits\n",devstr,bdelim,sdcap); + printf("%sModule Ranks %c %d ranks\n",devstr,bdelim,ranks); + printf("%sModule Capacity %c %d MB\n",devstr,bdelim,totcap); + } + if (iparity == 0x00) pstr = "Non-parity"; + else /* usu 0x02 */ pstr = "ECC"; + printf("%sDIMM Config Type %c %s\n", devstr,bdelim,pstr); + for (i = 0; i < NSPDMFG; i++) + if (spd_mfg[i].id == mfgid) break; + if (i == NSPDMFG) pstr = ""; /* not found, use null string */ + else pstr = spd_mfg[i].str; + printf("%sManufacturer ID %c %s (0x%02x)\n", devstr,bdelim,pstr,mfgid); + if (srev < 0x10) { + yr = spd[93]; + wk = spd[94]; + iser = 95; + ipart = 73; + irev = 91; + } else { /* 1.0 SPD spec with DDR3 */ + yr = spd[120]; + wk = spd[121]; + iser = 122; + ipart = 128; + irev = 146; + } + mrev1 = spd[irev]; /* save this byte for later */ + mrev2 = spd[irev+1]; + spd[irev] = 0; /*stringify part number */ + printf("%sManufacturer Part# %c %s\n", + devstr,bdelim,&spd[ipart]); + printf("%sManufacturer Rev %c %02x %02x\n", + devstr,bdelim,mrev1,mrev2); + printf("%sManufacturer Date %c year=%02x week=%02x\n", + devstr,bdelim, yr,wk); + printf("%sAssembly Serial Num %c %02x%02x%02x%02x\n", + devstr,bdelim,spd[iser],spd[iser+1],spd[iser+2],spd[iser+3]); + spd[irev] = mrev1; /* restore byte, so ok to repeat later */ + return; +} + +void show_guid(uchar *pguid) +{ + char *s; + int i; + for (i=0; i<16; i++) { + if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) s = "-"; + else s = ""; + printf("%s%02x",s,pguid[i]); + } +} + +static char *volt_desc(uchar b) +{ + char *s; + switch(b) { + case 0x03: s = "5V"; break; + case 0x02: s = "3.3V"; break; + case 0x01: s = "-12V"; break; + case 0x00: + default: s = "12V"; break; + } + return(s); +} + +static char *mgt_type(uchar b) +{ + char *s; + switch(b) { + case 0x01: s = "SysMgt_URL"; break; + case 0x02: s = "SystemName"; break; + case 0x03: s = "SysPingAddr"; break; + case 0x04: s = "Compon_URL"; break; + case 0x05: s = "ComponName"; break; + case 0x06: s = "ComponPing"; break; + case 0x07: + default: s = "SysGUID"; break; + } + return(s); +} + + +static +void show_fru_multi(char *tag, int midx, uchar mtype, uchar *pdata, int dlen) +{ + int vend; + char mystr[256]; + char *s1; + int v1, v2, v3, v4, v5, v6, v7; + uchar b1, b2; + + if (fdebug) dumpbuf(pdata,dlen); /*multi-record area dump*/ + sprintf(mystr,"%sMulti[%d] ",tag,midx); + switch(mtype) { + case 0x00: /*Power Supply*/ + printf("%sPower Supply Record %c \n",mystr,bdelim); + v1 = pdata[0] + ((pdata[1] & 0x0f) << 8); + printf("\t Capacity \t%c %d W\n",bdelim, v1); + v2 = pdata[2] + (pdata[3] << 8); + printf("\t Peak VA \t%c %d VA\n",bdelim, v2); + printf("\t Inrush Current\t%c %d A\n",bdelim, pdata[4]); + printf("\t Inrush Interval\t%c %d ms\n",bdelim, pdata[5]); + v3 = pdata[6] + (pdata[7] << 8); + v4 = pdata[8] + (pdata[9] << 8); + printf("\t Input Voltage Range1\t%c %d-%d V\n", + bdelim,v3/100,v4/100); + v3 = pdata[10] + (pdata[11] << 8); + v4 = pdata[12] + (pdata[13] << 8); + printf("\t Input Voltage Range2\t%c %d-%d V\n", + bdelim,v3/100,v4/100); + printf("\t Input Frequency Range\t%c %d-%d Hz\n", + bdelim,pdata[14],pdata[15]); + printf("\t AC Dropout Tolerance\t%c %d ms\n",bdelim, pdata[16]); + b1 = pdata[17]; + b2 = (b1 & 0x01); + if (b2) { /*predictive fail*/ + if ((b1 & 0x10) != 0) s1 = "DeassertFail "; + else s1 = "AssertFail "; + } else { + if ((b1 & 0x10) != 0) s1 = "2pulses/rot "; + else s1 = "1pulse/rot "; + } + printf("\t Flags \t%c %s%s%s%s%s\n",bdelim, + b2 ? "PredictFail " : "", + ((b1 & 0x02) == 0) ? "" : "PowerFactorCorrect ", + ((b1 & 0x04) == 0) ? "" : "AutoswitchVolt ", + ((b1 & 0x08) == 0) ? "" : "Hotswap ", s1); + v5 = pdata[18] + ((pdata[19] & 0x0f) << 8); + v6 = (pdata[19] & 0xf0) >> 4; + printf("\t Peak Capacity \t%c %d W for %d s\n",bdelim, v5,v6); + if (pdata[20] == 0) { + printf("\t Combined Capacity\t%c not specified\n",bdelim); + } else { + b1 = pdata[20] & 0x0f; + b2 = (pdata[20] & 0xf0) >> 4; + v7 = pdata[21] + (pdata[22] << 8); + printf("\t Combined Capacity\t%c %d W (%s and %s)\n", + bdelim, v7,volt_desc(b1),volt_desc(b2)); + } + if (b2) /*predictive fail*/ + printf("\t Fan low threshold\t%c %d RPS\n",bdelim,pdata[23]); + break; + case 0x01: /*DC Output*/ + b1 = pdata[0] & 0x0f; + b2 = ((pdata[0] & 0x80) != 0); + printf("%sDC Output %c number %d\n",mystr,bdelim,b1); + printf("\t Standby power \t%c %s\n", bdelim, + (b2 ? "Yes" : "No")); + v1 = pdata[1] + (pdata[2] << 8); + printf("\t Nominal voltage \t%c %.2f V\n", bdelim, v1 / 100); + v2 = pdata[3] + (pdata[4] << 8); + v3 = pdata[5] + (pdata[6] << 8); + printf("\t Voltage deviation \t%c + %.2f V / - %.2f V\n", + bdelim, v3/100, v2/100); + v4 = pdata[7] + (pdata[8] << 8); + printf("\t Ripple and noise pk-pk \t%c %d mV\n", bdelim, v4); + v5 = pdata[9] + (pdata[10] << 8); + printf("\t Min current draw \t%c %.3f A\n", bdelim, v5/1000); + v6 = pdata[11] + (pdata[12] << 8); + printf("\t Max current draw \t%c %.3f A\n", bdelim, v6/1000); + break; + case 0x02: /*DC Load*/ + b1 = pdata[0] & 0x0f; + printf("%sDC Load %c number %d\n",mystr,bdelim,b1); + v1 = pdata[1] + (pdata[2] << 8); + printf("\t Nominal voltage \t%c %.2f V\n", bdelim, v1 / 100); + v2 = pdata[3] + (pdata[4] << 8); + v3 = pdata[5] + (pdata[6] << 8); + printf("\t Min voltage allowed \t%c %.2f A\n", bdelim, v2); + printf("\t Max voltage allowed \t%c %.2f A\n", bdelim, v3); + v4 = pdata[7] + (pdata[8] << 8); + printf("\t Ripple and noise pk-pk \t%c %d mV\n", bdelim, v4); + v5 = pdata[9] + (pdata[10] << 8); + printf("\t Min current load \t%c %.3f A\n", bdelim, v5/1000); + v6 = pdata[11] + (pdata[12] << 8); + printf("\t Max current load \t%c %.3f A\n", bdelim, v6/1000); + break; + case 0x03: /*Management Access*/ + b1 = pdata[0]; + printf("%sManagemt Access %c %s ",mystr,bdelim,mgt_type(b1)); + memcpy(mystr,&pdata[1],dlen-1); + mystr[dlen-1] = 0; + printf("%s\n",mystr); + break; + case 0x04: /*Base Compatibility*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + printf("%sBasic Compat %c %06x\n",mystr,bdelim,vend); + break; + case 0x05: /*Extended Compatibility*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + printf("%sExtended Compat %c %06x\n",mystr,bdelim,vend); + break; + case 0xC0: /*OEM Extension*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + if (vend == OEM_PICMG) { + printf("%sOEM PICMG %c \n", mystr,bdelim); + show_fru_picmg(pdata,dlen); + } else + printf("%sOEM Ext %c %06x %02x\n", + mystr,bdelim, vend, pdata[3]); + break; + default: + printf("%s %02x %c %02x\n", mystr,mtype,bdelim, pdata[0]); + break; + } +} + +int +show_fru(uchar sa, uchar frudev, uchar frutype, uchar *pfrubuf) +{ + int ret = 0; + int i, j, n, sz; + uchar *pfru0; + uchar *pfru; + uchar lang; + TYPE_LEN tl; + char newstr[64]; + int iaoff, ialen, bdoff, bdlen; + int proff, prlen, choff, chlen; + int moff, mlen; + char devstr[24]; + char *pstr; + + if ((pfrubuf[0] & 0x80) == 0x80) { /* 0x80 = type for DIMMs (SPD) */ + /* FRU Header: 80 08 07 0c 0a 01 48 00 (DIMM) */ + /* FRU Header: 92 10 0b 01 03 1a 02 00 (DDR3 DIMMs) */ + sz = pfrubuf[0]; + if (fdebug) { + printf("DIMM SPD Body (size=%d/%d): ",sz,sfru); + dumpbuf(pfrubuf,sfru); + } + show_spd(pfrubuf,sfru, frudev,frutype); + return(ret); + } + + pstr = FruTypeString(frutype,frudev); + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s,%02x,%02x] ",pstr,sa,frudev); + printf("%s%s FRU Size %c %d\n",devstr,pstr,bdelim,sfru); + + /* + * FRU header: + * 0 = format_ver (01 is std, usu 0x80 if DIMM) + * 1 = internal_use offset + * 2 = chassis_info offset + * 3 = board_info offset (usu 6 fields) + * 4 = product_info offset (usu 8 fields) + * 5 = multirecord offset + * 6 = pad (00) + * 7 = header checksum (zero checksum) + * FRU Header: 01 01 02 09 13 00 00 e0 (BMC) + * FRU Header: 01 00 00 00 01 07 00 f7 (Power Cage) + */ + pfru0 = &pfrubuf[0]; /*pointer to fru start*/ + pfru = &pfrubuf[0]; + sz = 8; /*minimum for common header*/ + for (i = 1; i < 6; i++) /* walk thru offsets */ + if (pfrubuf[i] != 0) sz = pfrubuf[i] * 8; + if (sz > 8) { /* if have at least one section */ + if (pfrubuf[5] != 0) j = 5 + pfrubuf[sz+2]; /*if multi-record area*/ + else j = pfrubuf[sz+1] * 8; /* else add length of last section */ + sz += j; + } + + /* Now, sz = size used, sfru = total available size */ + if (sz > sfru) { + if (fdebug) { + uchar hsum; + printf("FRU Header: "); + for (i = 0; i < 8; i++) printf("%02x ",pfrubuf[i]); + printf("\n"); + hsum = calc_cksum(&pfrubuf[0],7); + if (pfrubuf[7] != hsum) + printf("FRU Header checksum mismatch (%x != %x)\n",pfrubuf[7],hsum); + } + printf("FRU size used=%d > available=%d\n",sz,sfru); + if (fpicmg || fdoanyway) sz = sfru; /*do it anyway*/ + else { + printf("Please apply the correct FRU/SDR diskette\n"); + return(ERR_OTHER); + } + } + /* internal area offset, length */ + iaoff = pfrubuf[1] * 8; + ialen = pfrubuf[iaoff + 1] * 8; + /* chassis area offset, length */ + choff = pfrubuf[2] * 8; + chlen = pfrubuf[choff + 1] * 8; + /* board area offset, length */ + bdoff = pfrubuf[3] * 8; + bdlen = pfrubuf[bdoff + 1] * 8; + /* product area offset, length */ + proff = pfrubuf[4] * 8; + prlen = pfrubuf[proff + 1] * 8; + /* multi-record area offset, length */ + moff = pfrubuf[5] * 8; + mlen = 0; + if (moff > 0) { + for (i = moff; i < sfru; ) { + j = 5 + pfrubuf[i+2]; + mlen += j; + if (pfrubuf[i+1] & 0x80) break; + i += j; + } + } + + if (fdebug) { + printf("FRU Header: "); + for (i = 0; i < 8; i++) printf("%02x ",pfrubuf[i]); + printf("\n"); + printf("FRU Body (size=%d/%d): ",sz,sfru); + dumpbuf(pfrubuf,sfru); + printf("header, len=%d, cksum0 = %02x, cksum1 = %02x\n", + 8,pfrubuf[7],calc_cksum(&pfrubuf[0],7)); + printf("internal off=%d, len=%d, cksum = %02x\n", + iaoff,ialen,calc_cksum(&pfrubuf[iaoff],ialen-1)); + printf("chassis off=%d, len=%d, cksum = %02x\n", + choff,chlen,calc_cksum(&pfrubuf[choff],chlen-1)); + printf("board off=%d, len=%d, cksum = %02x\n", + bdoff,bdlen,calc_cksum(&pfrubuf[bdoff],bdlen-1)); + printf("prod off=%d, len=%d, cksum = %02x\n", + proff,prlen,calc_cksum(&pfrubuf[proff],prlen-1)); + /* Multi-record area */ + printf("multi off=%d, len=%d, fru sz=%d\n", moff,mlen,sz); + } /*endif fdebug, show header*/ + + if (choff != 0) { + /* show Chassis area fields */ + pfru = &pfrubuf[choff]; + lang = 25; /* English */ + ctype = pfru[2]; /*chassis type*/ + if (fdebug) printf("ctype=%x\n",ctype); + if (ctype >= MAX_CTYPE) ctype = MAX_CTYPE - 1; + printf("%s%s%c %s\n",devstr, ctype_hdr,bdelim,ctypes[ctype]); + pfru += 3; /* skip chassis header */ + tl.len = 0; + for (i = 0; i < NUM_CHASSIS_FIELDS; i++) + { + if (ChkOverflow((int)(pfru - pfru0),sfru,tl.len)) break; + if (pfru[0] == FRU_END) break; /*0xC1 = end of FRU area*/ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],chassis[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + if (i == 2) { /* OEM field for chassis_name */ + chassis_offset = (int)(pfru - pfrubuf); + chassis_len = tl.len; + if (fdebug) printf("chassis oem dtype=%d lang=%d len=%d\n", + tl.type,lang,tl.len); + } + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, chassis[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) printf("num Chassis fields = %d\n",i); + } + + if (bdoff != 0) { + long nMin, nSec; + time_t tsec; + /* show Board area fields */ + pfru = &pfrubuf[bdoff]; + lang = pfru[2]; + /* Decode board mfg date-time (num minutes since 1/1/96) */ + nMin = pfru[3] + (pfru[4] << 8) + (pfru[5] << 16); + /* 820,454,400 sec from 1/1/70 to 1/1/96 */ + nSec = (nMin * 60) + 820454400; + tsec = (time_t)(nSec & 0x0ffffffff); + // fmt_time(tsec,newstr,sizeof(newstr)); + printf("%sBoard Mfg DateTime %c %s",devstr,bdelim,ctime(&tsec)); + pfru += 6; /* skip board header */ + tl.len = 0; + for (i = 0; i < NUM_BOARD_FIELDS; i++) + { + if (ChkOverflow((int)(pfru - pfru0),sfru,tl.len)) break; + if (pfru[0] == FRU_END) break; /*0xC1 = end*/ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],board[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, board[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) printf("num Board fields = %d\n",i); + } + + if (proff != 0) + { + /* show Product area fields */ + pfru = &pfrubuf[proff]; + maxprod = pfru[1] * 8; + lang = pfru[2]; + pfru += 3; /* skip product header */ + tl.len = 0; + for (i = 0; i < NUM_PRODUCT_FIELDS; i++) + { + if (ChkOverflow((int)(pfru - pfru0),sfru,tl.len)) break; + if (*pfru == FRU_END) { /*0xC1 = end*/ + /* Wart for known Kontron 1-byte Product Version anomaly. */ + if (vend_id == VENDOR_KONTRON && i == 3) ; + else break; + } + if (*pfru == 0) *pfru = FRU_EMPTY_FIELD; /* fix a broken table */ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],product[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + if ((frudev == 0) && (sa == bmc_sa)) { /*baseboard FRU*/ + if (i == 5) { /* asset tag */ + asset_offset = (int)(pfru - pfrubuf); + asset_len = tl.len; + if (fdebug) printf("asset off=%d dtype=%d lang=%d len=%d\n", + asset_offset,tl.type,lang,tl.len); + if (fshowlen) /* show asset tag length for main board */ + printf("%s%c %d\n",asset_hdr,bdelim,asset_len); + } else if (i == 4) { /* serial number */ + sernum_offset = (int)(pfru - pfrubuf); + sernum_len = tl.len; + if (fdebug) printf("sernum dtype=%d lang=%d len=%d\n", + tl.type, lang, tl.len); + } else if (i == 3) { /* product version number */ + prodver_offset = (int)(pfru - pfrubuf); + prodver_len = tl.len; + if (fdebug) printf("prodver dtype=%d lang=%d len=%d\n", + tl.type, lang, tl.len); + } + } /*if baseboard sa*/ + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, product[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) + printf("num Product fields = %d, last=%x, max = %d\n", + i,*pfru,maxprod ); + if (*pfru == 0x00) *pfru = FRU_END; /* insert end char if broken */ + } + + if (moff != 0) + { + /* multi-record area may contain several record headers + * 0 = record type id + * 1 = 0x02 or 0x82 if End-of-List + * 2 = record len + * 3 = record chksum + * 4 = header chksum + */ + pfru = &pfrubuf[moff]; + j = moff; + for (i = 0; j < sz ; i++) + { + n = pfru[2]; /* len of this record */ + show_fru_multi(devstr,i,pfru[0],&pfru[5],n); + j += (5 + n); + if (pfru[1] & 0x80) j = sz; /*0x80 = last in list, break*/ + pfru += (5 + n); + } + } + + if ((frudev == 0) && (sa == bmc_sa) && do_guid) { + printf("%sSystem GUID %c ",devstr,bdelim); + show_guid(guid); + printf("\n"); + } + return(ret); +} + +int write_fru_data(uchar id, ushort offset, uchar *data, int dlen, char fdebug) +{ + int ret = -1; + int chunk; + ushort fruoff; + uchar req[25]; + uchar resp[16]; + int sresp; + uchar cc; + int i, j; + + /* Write the buffer in small 16-byte (FRUCHUNK_SZ) chunks */ + req[0] = 0x00; /* override FRU Device ID (fruid) */ + fruoff = offset; + chunk = FRUCHUNK_SZ; + for (i = 0; i < dlen; i += chunk) { + req[1] = fruoff & 0x00ff; + req[2] = (fruoff & 0xff00) >> 8; + if ((i + chunk) > dlen) chunk = dlen - i; + memcpy(&req[3],&data[i],chunk); + if (fdebug) { + printf("write_fru_data[%d] (len=%d): ",i,chunk+3); + for (j = 0; j < chunk+3; j++) printf("%02x ",req[j]); + printf("\n"); + } + sresp = sizeof(resp); + ret = ipmi_cmd_mc(WRITE_FRU_DATA,req,(uchar)(chunk+3),resp,&sresp, + &cc,fdebug); + if ((ret == 0) && (cc != 0)) ret = cc & 0x00ff; + if (fdebug && ret == 0) + printf("write_fru_data[%d]: %d bytes written\n",i,resp[0]); + if (ret != 0) break; + fruoff += (ushort)chunk; + } + return(ret); +} + +/* write_asset updates the FRU Product area only. */ +int +write_asset(char *tag, char *sernum, char *prodver, int flag, uchar *pfrubuf) +{ + int ret = -1; + uchar newdata[SZ_PRODAREA]; + int alen, clen; + int snlen, verlen; + uchar *pfru0; + uchar *pfru; + uchar *pnew; + int i, j, m, n, newlen, max; + int chas_offset; + int prod_offset, prod_len; + int mult_offset, mult_len; + uchar chksum; + char fdoasset = 0; + char fdosernum = 0; + char fdoprodver = 0; + char fdochassis = 0; + + if (flag == 0) return ERR_OTHER; + if (pfrubuf == NULL) pfrubuf = frubuf; + if (pfrubuf == NULL) return ERR_OTHER; + if ((flag & 0x01) != 0) { + fdoasset = 1; + alen = strlen_(tag); /*new*/ + } else { + alen = asset_len; /*old*/ + } + if ((flag & 0x02) != 0) { + fdosernum = 1; + snlen = strlen_(sernum); /*new*/ + } else { + snlen = sernum_len; /*old*/ + } + if ((flag & 0x200) != 0) { + fdochassis = 1; + // clen = strlen(chassis_nm); /*new, ignore*/ + // if (clen <= 1) return ERR_LENMIN; + clen = chassis_len; + } else { + clen = chassis_len; /*old*/ + } + if ((flag & 0x08) != 0) { + fdoprodver = 1; + verlen = strlen_(prodver); /*new*/ + } else verlen = prodver_len; /*old*/ + /* + * Abort if offset is negative or if it would clobber + * fru header (8 bytes). + * Abort if asset tag is too big for fru buffer. + */ + if (fdebug) { + printf("write_asset: asset_off=%d asset_len=%d alen=%d sFRU=%d\n", + asset_offset,asset_len,alen,sfru); + printf(" sernum_off=%d sernm_len=%d snlen=%d maxprod=%d\n", + sernum_offset,sernum_len,snlen,maxprod); + printf(" prodver=%d prodver_len=%d verlen=%d maxprod=%d\n", + prodver_offset,prodver_len,verlen,maxprod); + } + if (fdoasset && (alen <= 1)) return ERR_LENMIN; + if (fdosernum && (snlen <= 1)) return ERR_LENMIN; + if (asset_offset < 8) return ERR_LENMIN; + if (asset_offset + alen > sfru) return ERR_LENMAX; + if (sernum_offset < 8) return ERR_LENMIN; + if (sernum_offset + snlen > sfru) return ERR_LENMAX; + if (prodver_offset < 8) return ERR_LENMIN; + if (prodver_offset + verlen > sfru) return ERR_LENMAX; + + pfru0 = &pfrubuf[0]; + chas_offset = pfrubuf[2] * 8; // offset of chassis data + prod_offset = pfrubuf[4] * 8; // offset of product data + prod_len = pfrubuf[prod_offset+1] * 8; // length of product data + mult_offset = pfrubuf[5] * 8; + mult_len = 0; + if (mult_offset > 0) { + for (i = mult_offset; i < sfru; ) { + mult_len += (5 + pfrubuf[i+2]); + if (pfrubuf[i+1] & 0x80) break; + i = mult_len; + } + } + /* Check if asset tag will fit in product data area of FRU. */ + if (fdebug) + printf("write_asset: fru[4,p]=[%02x,%02x] prod_off=%d plen=%d veroff=%d\n", + pfrubuf[4],pfrubuf[prod_offset+1],prod_offset,prod_len, prodver_offset); + /* asset comes after sernum, so this check works for both */ + if (prod_offset > prodver_offset) return ERR_LENMAX; // offsets wrong + if (prod_len > sizeof(newdata)) return ERR_LENMAX; // product > buffer + + memset(newdata,0,prod_len); + pnew = &newdata[0]; + /* Copy fru data from start to chassis OEM */ + pfru = &pfrubuf[chas_offset]; + + /* Copy fru data before serial number */ + pfru = &pfrubuf[prod_offset]; + j = prodver_offset - prod_offset; + memcpy(pnew,pfru,j); + pfru += j; + pnew += j; + if (fdebug) { + printf("write_asset: fru[4,p]=[%02x,%02x] sernum_off=%d snlen=%d plen=%d\n", + pfrubuf[4],pfrubuf[sernum_offset+1],sernum_offset,snlen,prod_len); + } + if (fdoprodver) { + pnew[0] = (verlen | FRU_TYPE_MASK); /*add type=3 to snlen*/ + memcpy(++pnew,prodver,verlen); + } else { + pnew[0] = (verlen | FRU_TYPE_MASK); /*type/len byte*/ + memcpy(++pnew,&pfrubuf[prodver_offset+1],verlen); + } + j += prodver_len + 1; + pfru += prodver_len + 1; + pnew += verlen; /*already ++pnew above*/ + + /* Copy new or old serial number */ + if (fdebug) printf("pfrubuf[%ld]: %02x %02x %02x, j=%d, snlen=%d/%d\n", + (pfru-pfrubuf),pfru[0],pfru[1],pfru[2],j,snlen,sernum_len); + if (fdosernum) { + pnew[0] = (snlen | FRU_TYPE_MASK); /*add type=3 to snlen*/ + memcpy(++pnew,sernum,snlen); + } else { + pnew[0] = (snlen | FRU_TYPE_MASK); /*type/len byte*/ + memcpy(++pnew,&pfrubuf[sernum_offset+1],snlen); + } + /* increment past serial number, to asset tag */ + j += sernum_len + 1; + pfru += sernum_len + 1; + pnew += snlen; /*already ++pnew above*/ + + /* Copy new or old asset tag */ + if (fdebug) printf("pfrubuf[%ld]: %02x %02x %02x, j=%d, alen=%d/%d\n", + (pfru-pfrubuf),pfru[0],pfru[1],pfru[2],j,alen,asset_len); + if (fdoasset) { + pnew[0] = (alen | FRU_TYPE_MASK); /*add type=3 to len*/ + memcpy(++pnew,tag,alen); + } else { + pnew[0] = (alen | FRU_TYPE_MASK); /*type/len byte*/ + memcpy(++pnew,&pfrubuf[asset_offset+1],alen); + } + j += asset_len + 1; + pfru += asset_len + 1; + pnew += alen; + + /* copy trailing fru data from saved copy */ + n = (int)(pnew - newdata); /* new num bytes used */ + m = (int)(pfru - pfru0); /* old num bytes used */ + if (fdebug) printf("pfrubuf[%d]: %02x %02x %02x, j=%d, n=%d, plen=%d\n", + m,pfru[0],pfru[1],pfru[2],j,n,prod_len); + if (mult_offset > 0) { /* do not expand if multi-record area there */ + max = prod_len - j; + } else /* nothing else, can expand product area, up to sfru */ + max = sfru - (j + prod_offset); + if (fdebug) printf("pfrubuf[%ld]: %02x %02x %02x, j=%d n=%d remainder=%d\n", + (pfru-pfrubuf),pfru[0],pfru[1],pfru[2],j,n,max); + if (max < 0) max = 0; + for (i = 0; i < max; i++) { + pnew[i] = pfru[i]; + if (pfru[i] == FRU_END) { i++; break; } + } + if (i == max) { /*never found 0xC1 FRU_END*/ + pnew[0] = FRU_END; + i = 1; + } + + newlen = n + i; + if (fdebug) printf("newbuf[%d]: %02x %02x %02x, j=%d, newlen=%d\n", + n,pnew[0],pnew[1],pnew[2],j,newlen); + /* round up to next 8-byte boundary */ + /* need one more byte for checksum, so if mod=0, adds 8 anyway */ + j = 8 - (newlen % 8); + for (i = 0; i < j; i++) newdata[newlen++] = 0; + + if (newlen < prod_len) newlen = prod_len; /* don't shrink product area */ + newdata[1] = newlen / 8; // set length of product data + + /* include new checksum (calc over Product area) */ + chksum = calc_cksum(&newdata[0],newlen-1); + newdata[newlen-1] = chksum; + +#ifdef NEEDED + /* This caused a problem on Radisys systems, and is not needed, so skip it.*/ + if (mult_offset > 0) { + /* add on any more data from multi-record area */ + pnew = &newdata[newlen]; + pfru = &pfrubuf[mult_offset]; + memcpy(pnew,pfru,mult_len); + newlen += mult_len; + } +#endif + + if (fdebug) { + printf("old buffer (%d):",prod_len); + dumpbuf(&pfrubuf[prod_offset],prod_len); + printf("new buffer (%d):",newlen); + dumpbuf(newdata,newlen); + } + if (prod_offset + newlen >= sfru) return ERR_LENMAX; + if ((mult_offset > 0) && (newlen > prod_len)) return ERR_LENMAX; +#ifdef TEST + newlen = 0; +#endif + + ret = write_fru_data(0, (ushort)prod_offset, newdata, newlen, fdebug); + return(ret); +} + +#define SDR_CHUNKSZ 16 +#define LAST_REC 0xffff +#define SDR_STR_OFF 16 + +int get_sdr(ushort recid, ushort resid, ushort *recnext, + uchar *sdr, int *slen, uchar *pcc) +{ + uchar idata[6]; + uchar rdata[64]; + int sresp; + ushort cmd; + uchar cc = 0; + int len = 0; + int szsdr, thislen; + int rc; + + memset(sdr,0,*slen); /*clear sdr */ + idata[0] = resid & 0x00ff; + idata[1] = (resid & 0xff00) >> 8; + idata[2] = recid & 0x00ff; + idata[3] = (recid & 0xff00) >> 8; + idata[4] = 0; /*offset*/ + idata[5] = SDR_CHUNKSZ; /*bytes to read*/ + if (fdevsdrs) cmd = GET_DEVICE_SDR; + else cmd = GET_SDR; + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] ret = %d cc = %x sresp = %d\n", + recid,rc,cc,sresp); + if (rc == 0 && cc == 0xCA) { /*cannot read SDR_CHUNKSZ bytes*/ + idata[5] = 8; /*bytes to read*/ + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] ret = %d cc = %x sresp = %d\n", + recid,rc,cc,sresp); + } + *pcc = cc; + if (rc == 0 && cc == 0) { + *recnext = rdata[0] + (rdata[1] << 8); + if (sresp < 2) len = 0; + else len = sresp-2; + if (len > *slen) len = *slen; + memcpy(sdr,&rdata[2],len); + szsdr = sdr[4] + 5; /*get actual SDR size*/ + if (szsdr > *slen) szsdr = *slen; + /* if an SDR locator record, get the rest of it. */ + if (sdr[3] == 0x11 || sdr[3] == 0x12) + if (szsdr > SDR_CHUNKSZ) { + ushort resid2; + rc = sdr_get_reservation((uchar *)&resid2,fdevsdrs); + if (fdebug) printf("2nd sdr_get_reservation ret=%d\n",rc); + thislen = szsdr - SDR_CHUNKSZ; + if (thislen > SDR_CHUNKSZ) thislen = SDR_CHUNKSZ; + idata[0] = resid2 & 0x00ff; + idata[1] = (resid2 & 0xff00) >> 8; + idata[2] = recid & 0x00ff; + idata[3] = (recid & 0xff00) >> 8; + idata[4] = SDR_CHUNKSZ; /*offset*/ + idata[5] = (uchar)thislen; /*bytes to read*/ + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] 2nd ret=%d cc=%x sresp=%d\n", + recid,rc,cc,sresp); + if (rc == 0 && cc == 0) { + if (sresp < 2) sresp = 0; + else sresp -= 2; + if (sresp > thislen) sresp = thislen; + memcpy(&sdr[len],&rdata[2],sresp); + len += sresp; + } else rc = 0; /*ok because got first part*/ + } /*endif got first chunk, need more*/ + *slen = len; + } else *slen = 0; + return(rc); +} + +void show_loadfru_error(uchar sa, uchar fruid, int ret) +{ + if (ret == 0) return; + switch(ret) { + case 0x081: printf("\tFRU(%x,%x) device busy\n",sa,fruid); break; + case 0x0C3: printf("\tFRU(%x,%x) timeout, not found\n",sa,fruid); break; + case 0x0CB: printf("\tFRU(%x,%x) not present\n",sa,fruid); break; + default: printf("load_fru(%x,%x) error = %d (0x%x)\n", + sa,fruid,ret,ret); + break; + } + return; +} + +int get_show_fru(ushort recid, uchar *sdr, int sdrlen) +{ + int ret = 0; + int ilen; + char idstr[32]; + uchar sa, fruid =0; + uchar frutype = 0; + char fgetfru = 0; + char fisbase = 0; + uchar *pfru; + + if (sdrlen > SDR_STR_OFF) { + ilen = sdrlen - SDR_STR_OFF; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[SDR_STR_OFF],ilen); + idstr[ilen] = 0; + } else idstr[0] = 0; + sa = sdr[5]; /* usu 0x20 for bmc_sa */ + if (fbasefru) fisbase = 1; + + /* Get its FRU data */ + if ((sdr[3] == 0x11) && (sdr[7] & 0x80)) { /* FRU SDRs */ + /* It is a logical FRU device */ + if (fcanonical) + printf("SDR[%04x] FRU %c %s\n", recid, bdelim, idstr); + else + printf("SDR[%04x] FRU %02x %02x %02x %02x %s\n", recid, + sdr[5],sdr[6],sdr[12],sdr[13],idstr); + fruid = sdr[6]; + if (sdrlen > 12) frutype = sdr[12]; + if (sa == bmc_sa && fruid == 0) { /*dont repeat base fru */ + frutype = 0x0c; + fisbase = 1; + if (fbasefru) fgetfru = 1; + } else + switch(frutype) /*FRU entity id*/ + { + case 0x0a: /*Power Supply*/ + case 0x20: /*DIMM*/ + case 0x15: /*Power Cage*/ + default: + fgetfru = 1; + break; + } + } else if (sdr[3] == 0x12) { /* IPMB SDRs (DLRs for MCs) */ + if (fcanonical) + printf("SDR[%04x] IPMB %c %s\n", recid, bdelim, idstr); + else + printf("SDR[%04x] IPMB %02x %02x %02x %02x %s\n", recid, + sdr[5],sdr[6],sdr[12],sdr[13],idstr); + fruid = 0; /*every MC must have fruid 0*/ + if (sdrlen > 12) frutype = sdr[12]; + if (sa == bmc_sa && fruid == 0) { /*dont repeat base fru */ + fisbase = 1; + frutype = 0x07; + if (fdebug) printf("do bmc_sa %02x once\n",sa); + g_frutype = frutype; + if (fbasefru) fgetfru = 1; + } else if (frutype == 0x2e) { /*skip ME*/ + if (fdebug) printf("skipping ME sa %02x, %02x\n",sa,fruid); + } else if (sa == 0x28) { /*do nothing for Bridge Ctlr sa=0x28*/ + if (fdebug) printf("skipping IPMB sa %02x, %02x\n",sa,fruid); + } else if (sa == 0xC0) { /* HotSwap Backplane (sa=0xC0) */ + /* Note: Loading sa 0xC0 over ipmi lan gives a timeout + * error, but it works locally. */ + fgetfru = 1; + } else { /* other misc sa,fruid */ + fgetfru = 1; + } + } + + /* Check if matches previous FRU, if so don't repeat */ + if ((sa == lastfru[0]) && (fruid == lastfru[1]) ) + fgetfru = 0; + + if (fgetfru) { + uchar adrtype; + adrtype = g_addrtype; + if (fdebug) printf("set_mc %02x:%02x:%02x type=%d fruid=%02x\n", + g_bus,sa,g_lun,adrtype,fruid); + ipmi_set_mc(g_bus, sa, g_lun,adrtype); + ret = load_fru(sa,fruid,frutype,&pfru); + if (ret != 0) { + show_loadfru_error(sa,fruid,ret); + } else { + ret = show_fru(sa,fruid,frutype,pfru); + if (ret != 0) printf("show_fru error = %d\n",ret); + if (sa == bmc_sa && fruid == 0) fbasefru = 0; + } + free_fru(pfru); + pfru = NULL; + ipmi_restore_mc(); + lastfru[0] = sa; + lastfru[1] = fruid; + lastfru[2] = frutype; + } + return(ret); +} + +/* + * test_show_fru + * + * Reads the FRU buffer dump from a file to test decoding the FRU. + * This file uses the format output from 'ipmiutil fru -x'. + * +[Component,20,00] Component FRU Size : 4096 +FRU Header: 01 0a 00 01 20 00 00 d4 +FRU Body (size=256/4096): + 0000: 01 0a 00 01 20 00 00 d4 01 09 00 c0 3b 7e 83 64 .... .......;~.d + * + */ +static int test_show_fru(char *infile) +{ + int rv = -1; + FILE *fp; + int len, i, idx, sz, off; + uchar buff[256]; + uchar sa = 0x20; + uchar fruid =0; + uchar frutype = 0; + uchar *pfru = NULL; + char *p1; + char *p2; + + fp = fopen(infile,"r"); + if (fp == NULL) { + printf("Cannot open file %s\n",infile); + return(ERR_FILE_OPEN); + } else { + if (fdebug) printf("decoding text file with FRU buffer bytes\n"); + idx = 0; + off = 0; + sz = sizeof(buff); + while (fgets(buff, 255, fp)) { + len = strlen_(buff); + if (fdebug) printf("fgets[%d]: %s",idx,buff); /*has '\n'*/ + if (idx == 0) { /* the FRU Size line*/ + p1 = strstr(buff,"FRU Size"); + if (p1 == NULL) continue; + p1 = strchr(buff,','); + if (p1 == NULL) continue; + p1++; + p2 = strchr(p1,','); + if (p2 == NULL) p2 = &buff[len]; + *p2 = 0; /*stringify*/ + sa = htoi(p1); + p1 = p2 + 1; + p2 = strchr(p1,']'); + if (p2 == NULL) p2 = &buff[len]; + *p2 = 0; /*stringify*/ + fruid = htoi(p1); + frutype = 0; + if (fdebug) printf("read[%d] sa=%x fruid=%x\n",idx,sa,fruid); + idx++; + } else if (idx == 1) { /* the FRU Header line*/ + p1 = strstr(buff,"FRU Header"); + // if (p1 == NULL) continue; + if (fdebug) printf("read[%d] p1=%p\n",idx,p1); + idx++; + } else if (idx == 2) { /* the FRU Bodu line*/ + p1 = strstr(buff,"FRU Body"); + if (p1 == NULL) continue; + p1 = strchr(buff,'='); + if (p1 == NULL) continue; + ++p1; + p2 = strchr(p1,'/'); + if (p2 == NULL) p2 = &buff[len]; + *p2 = 0; /*stringify*/ + sz = atoi(p1); + p1 = p2 + 1; + p2 = strchr(p1,')'); + if (p2 == NULL) p2 = &buff[len]; + *p2 = 0; /*stringify*/ + sfru = atoi(p1); /*global sfru*/ + pfru = malloc(sfru); + if (fdebug) + printf("read[%d] sz=%d/%d pfru=%p\n",idx,sz,sfru,pfru); + idx++; + } else { /*idx==3, this has the FRU buffer data */ + p1 = strchr(buff,':'); + if (p1 == NULL) continue; + p1 += 2; + for (i = 0; i < 16; i++) { + pfru[off+i] = htoi(&p1[i*3]); + } + off += 16; + if (fdebug) printf("read[%d] offset=%d\n",idx,off); + } /*endif */ + if (off >= sz) { rv = 0; break; } + } /*end while*/ + + fclose(fp); + if (rv == 0) { + if (pfru == NULL) { + printf("Invalid input file format (mode %d)\n",idx); + return(ERR_BAD_FORMAT); + } + rv = show_fru(sa,fruid,frutype,pfru); + if (rv != 0) printf("show_fru error = %d\n",rv); + } + free_fru(pfru); + } + return(rv); +} + +#ifdef ALONE +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#else +/* METACOMMAND */ +int i_fru(int argc, char **argv) +#endif +{ + int ret, rv; + int c; + char DevRecord[16]; + ushort recid; + ushort nextid; + ushort rsvid; + uchar sdr[48]; + char biosver[80]; + uchar cc; + uchar sa; + //uchar fruid = 0; + //uchar frutype = 0; + int len, i, j; + char *s1; + uchar *pfru = NULL; + FILE *fp; + int ipass, npass, nsdrs; + char *tag; + char do_reserve = 1; + char devstr[32]; + + printf("%s: version %s\n",progname,progver); + + parse_lan_options('V',"4",0); /*default to admin privilege*/ + while ( (c = getopt( argc, argv,"a:bcd:efhkl:m:n:i:p:r:s:t:v:xyzT:V:J:EYF:P:N:R:U:Z:?")) != EOF ) + switch(c) { + case 'x': fdebug = 1; break; + case 'z': fdebug = 3; break; /*do more LAN debug detail*/ + case 'b': fonlybase = 1; + g_frutype = 0x07; break; + case 'c': fcanonical = 1; bdelim = BDELIM; break; + case 'd': fdump = 1; /*dump fru to a file*/ + binfile = optarg; + break; + case 'e': fchild = 1; break; /*extra child MCs if bladed*/ + case 'f': fchild = 1; break; /*follow child MCs if bladed*/ + case 'h': fonlyhsc = 1; /* show HSC FRU, same as -m00c000s */ + g_frutype = 0x0f; break; + case 'k': foemkontron = 1; break; + case 'n': + fwritefru |= 0x200; + if (optarg) { + len = strlen_(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(chassis_name,optarg,len); + if (len == 1) { /* add a space */ + chassis_name[1] = ' '; + chassis_name[2] = 0; + } + } + break; + case 'p': /*Power Supply Product */ + // fwritefru |= 0x10; + if (optarg) { + len = strlen_(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(ps_prod,optarg,len); + if (len == 1) { /* add a space */ + ps_prod[1] = ' '; + ps_prod[2] = 0; + } + } + break; + case 'r': frestore = 1; /*restore fru from a file*/ + fwritefru = 0x100; + binfile = optarg; + break; + case 't': ftestshow = 1; /*test show_fru from a file*/ + binfile = optarg; + break; + case 'a': + fwritefru |= 0x01; + if (optarg) { + len = strlen_(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(asset_tag,optarg,len); + if (len == 1) { /* add a space */ + asset_tag[1] = ' '; + asset_tag[2] = 0; + } + } + break; + case 's': + fwritefru |= 0x02; + if (optarg) { + len = strlen_(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(serial_num,optarg,len); + if (len == 1) { /* add a space */ + serial_num[1] = ' '; + serial_num[2] = 0; + } + } + break; + case 'v': + fwritefru |= 0x08; + if (optarg) { + len = strlen_(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(prod_ver,optarg,len); + if (len == 1) { /* add a space */ + prod_ver[1] = ' '; + prod_ver[2] = 0; + } + } + break; + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + printf("set MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'l': /* set local IPMB MC sa (same as -Z but sets bmc_sa) */ + sa = htoi(&optarg[0]); /*device slave address*/ + ipmi_set_mymc(g_bus, sa, g_lun,ADDR_IPMB); + bmc_sa = sa; + break; + case 'i': fonlybase = 1; /*specify a fru id*/ + if (strncmp(optarg,"0x",2) == 0) g_fruid = htoi(&optarg[2]); + else g_fruid = htoi(optarg); + printf("Using FRU ID 0x%02x\n",g_fruid); + break; + case 'y': fdoanyway = 1; break; + case 'V': /* priv level */ + fprivset = 1; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-bceikmtvx -a asset_tag -s ser_num -NUPREFTVY]\n", + progname); + printf(" -a tag Sets the Product Asset Tag\n"); + printf(" -b Only show Baseboard FRU data\n"); + printf(" -c show canonical, delimited output\n"); + printf(" -d file Dump the binary FRU data to a file\n"); + printf(" -e walk Every child FRU, for blade MCs\n"); + printf(" -i 00 Get a specific FRU ID\n"); + printf(" -k Kontron setsn, setmfgdate\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -s snum Sets the Product Serial Number\n"); + printf(" -v pver Sets the Product Version Number\n"); + printf(" -x Display extra debug messages\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + if (ftestshow) { + ret = test_show_fru(binfile); + goto do_exit; + } + + if (is_remote() && (!fprivset)) { + /* If priv not specified, not writing, and only targetted FRU, + can default to request user privilege. */ + if (!fwritefru && fonlybase) parse_lan_options('V',"2",0); + } + + ret = ipmi_getdeviceid( DevRecord, sizeof(DevRecord),fdebug); + if (ret == 0) { + uchar ipmi_maj, ipmi_min; + ipmi_maj = DevRecord[4] & 0x0f; + ipmi_min = DevRecord[4] >> 4; + vend_id = DevRecord[6] + (DevRecord[7] << 8) + (DevRecord[8] << 16); + prod_id = DevRecord[9] + (DevRecord[10] << 8); + show_devid( DevRecord[2], DevRecord[3], ipmi_maj, ipmi_min); + if (ipmi_maj < 2) do_systeminfo = 0; + if ((DevRecord[1] & 0x80) == 0x80) fdevsdrs = 1; + if (vend_id == VENDOR_NEC) fdevsdrs = 0; + else if (vend_id == VENDOR_SUN) { + do_guid = 0; /*Sun doesn't support GUID*/ + do_systeminfo = 0; /*Sun doesn't support system info*/ + } else if (vend_id == VENDOR_INTEL) { + if (is_thurley(vend_id,prod_id) || is_romley(vend_id,prod_id)) + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + } + } else { + goto do_exit; + } + + ret = ipmi_getpicmg( DevRecord, sizeof(DevRecord),fdebug); + if (ret == 0) fpicmg = 1; + if (!fpicmg) fdevsdrs = 0; /* override, use SDR repository for FRU */ + if (fdebug) printf("bmc_sa = %02x, fdevsdrs = %d\n",bmc_sa,fdevsdrs); + + if (fset_mc) { + /* target a specific MC via IPMB (usu a picmg blade) */ + if (fdebug) printf("set_mc: %02x:%02x:%02x type=%d\n", + g_bus,g_sa,g_lun,g_addrtype); + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + fonlybase = 1; /*only show this MC*/ + } else { + g_sa = bmc_sa; /* BMC_SA = 0x20 */ + } + if (g_frutype == 0) { + g_frutype = 0x01; /* other = "Component" */ + } + + if (foemkontron) { +#ifdef METACOMMAND + for (i = 0; i < optind; i++) { argv++; argc--; } + if (fdebug) verbose = 1; + ret = ipmi_kontronoem_main(NULL,argc,argv); +#else + ret = LAN_ERR_NOTSUPPORT; +#endif + goto do_exit; + } + npass = 1; + + if (fonlybase || fonlyhsc) fbasefru = 1; + else { + /* find FRU devices from SDRs */ + if (fpicmg && fdevsdrs) { + /* npass = 2 will get both SdrRep & DevSdr passes on CMM */ + npass = 2; + g_addrtype = ADDR_IPMB; + } + + nsdrs = 0; + for (ipass = 0; ipass < npass; ipass++) + { + ret = GetSDRRepositoryInfo(&j,&fdevsdrs); + if (fdebug) printf("GetSDRRepositoryInfo: ret=%x nSDRs=%d fdevsdrs=%d\n", + ret,j,fdevsdrs); + if (j == 0) { + /* this is an error, probably because fdevsdrs is wrong.*/ + fdevsdrs = (fdevsdrs ^ 1); + if (fdebug) printf("nsdrs=0, retrying with fdevsdrs=%d\n",fdevsdrs); + j = 60; /*try some default num SDRs*/ + } + nsdrs = j; + if (fdevsdrs) tag="Device SDRs"; + else tag="SDR Repository"; + printf("--- Scanning %s for %d SDRs ---\n",tag,nsdrs); + + /* loop thru SDRs to find FRU devices */ + recid = 0; + while (recid != LAST_REC) + { + if (do_reserve) { + /* reserve the SDR repository */ + ret = sdr_get_reservation((uchar *)&rsvid,fdevsdrs); + if (fdebug) printf("sdr_get_reservation ret=%d\n",ret); + if (ret == 0) do_reserve = 0; + } + + len = sizeof(sdr); /*sizeof(sdr); get 32 sdr bytes*/ + ret = get_sdr(recid,rsvid,&nextid,sdr,&len,&cc); + if ((ret != 0) || (cc != 0)) { + printf("SDR[%04x] error %d ccode = %x\n",recid,ret,cc); + if ((cc == 0xC5) || (cc == 0x83)) ; /*do not stop (ARC)*/ + else break; /*stop if errors*/ + } + if (len >= MIN_SDR_SZ) { + if ((sdr[3] == 0x11) || (sdr[3] == 0x12)) /*SDR FRU or IPMB type*/ + ret = get_show_fru(recid, sdr,len); + do_reserve = 1; + } /*endif get_show_fru */ +#ifdef PICMG_CHILD + /* + * Special logic for blade child MCs in PICMG ATCA systems + * if fchild, try all child MCs within the chassis. + * SDR type 12 capabilities bits (sdrdata[8]): + * 80 = Chassis Device + * 40 = Bridge + * 20 = IPMB Event Generator + * 10 = IPMB Event Receiver + * 08 = FRU Device + * 04 = SEL Device + * 02 = SDR Repository Device + * 01 = Sensor Device + * But all child MCs use Device SDRs anyway. + */ + if (fpicmg && fchild && (sdr[3] == 0x12)) { /* PICMG MC DLR */ + ushort _recid, _recnext; + int _sz; + uchar _sdrdata[MAX_SDR_SIZE]; + int devsdrs_save; + uchar cc; + + /* save the BMC globals, use IPMB MC */ + devsdrs_save = fdevsdrs; + fdevsdrs = 1; /* use Device SDRs for the children*/ + if (fdebug) + printf(" --- IPMB MC (sa=%02x cap=%02x id=%02x devsdrs=%d):\n", + sdr[5],sdr[8],sdr[12],fdevsdrs); + ipmi_set_mc(PICMG_SLAVE_BUS,sdr[5],sdr[6],g_addrtype); + + _sz = 16; + ret = ipmi_cmd_mc(GET_DEVICE_ID,NULL,0,_sdrdata,&_sz,&cc,fdebug); + if (ret == 0 && cc == 0) { + /* get a new SDR Reservation ID */ + ret = sdr_get_reservation((uchar *)&rsvid,fdevsdrs); + if (fdebug) printf("sdr_get_reservation ret=%d\n",ret); + /* Get the SDRs from the IPMB MC */ + _recid = 0; + while (_recid != 0xffff) + { + _sz = sizeof(_sdrdata); + ret = get_sdr(_recid,rsvid,&_recnext,_sdrdata,&_sz,&cc); + if (fdebug) printf("get_sdr(%x) rv=%d cc=%x rlen=%d\n", + _recid,ret,cc,_sz); + if (ret != 0) { + printf("%04x get_sdr error %d, rlen=%d\n",_recid,ret,_sz); + break; + } + else if (_sz >= MIN_SDR_SZ) { + if ((_sdrdata[3] == 0x11) || (_sdrdata[3] == 0x12)) + ret = get_show_fru(_recid, _sdrdata, _sz); + } + if (_recnext == _recid) _recid = 0xffff; + else _recid = _recnext; + } /*end while*/ + } /*endif ret==0*/ + + /* restore BMC globals */ + fdevsdrs = devsdrs_save; + ipmi_restore_mc(); + do_reserve = 1; /* get a new SDR Reservation ID */ + } /*endif fpicmg && fchild*/ +#endif + + recid = nextid; + } /*end while sdrs*/ + if (npass > 1) { /*npass==2 for PICMG child*/ + /* Switch fdevsdrs from Device to Repository (or vice-versa) */ + if (fdevsdrs == 0) fdevsdrs = 1; + else fdevsdrs = 0; + } + } /*end ipass loop*/ + } /*endif not fonlybase*/ + + /* load the FRU data for Baseboard (address 0x20) */ + printf("\n"); + sa = g_sa; /* bmc_sa = BMC_SA = 0x20 */ + if (fonlyhsc) { sa = 0xC0; g_addrtype = ADDR_SMI; + ipmi_set_mc(g_bus,sa,g_lun,g_addrtype); + } + if (g_addrtype == ADDR_IPMB) + ipmi_set_mc(g_bus,sa,g_lun,g_addrtype); + + if (fbasefru) { + /* get and display the Baseboard FRU data */ + ret = load_fru(sa,g_fruid,g_frutype,&pfru); + if (ret != 0) { + show_loadfru_error(sa,g_fruid,ret); + free_fru(pfru); + pfru = NULL; + goto do_exit; + } + ret = show_fru(sa,g_fruid,g_frutype,pfru); + if (ret != 0) printf("show_fru error = %d\n",ret); + } + + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s,%02x,%02x] ", /*was by g_frutype*/ + FruTypeString(SYS_FRUTYPE,g_fruid),sa,g_fruid); + + if (!is_remote()) { + i = get_BiosVersion(biosver); + if (i == 0) + printf("%sBIOS Version %c %s\n",devstr,bdelim,biosver); + } + + if (do_systeminfo) { + char infostr[64]; + int len; + len = sizeof(infostr); + rv = get_system_info(1,infostr,&len); /*Firmware Version*/ + if (rv == 0) { + len = sizeof(infostr); + rv = get_system_info(2,infostr,&len); + if (rv == 0) printf("%sSystem Name %c %s\n",devstr,bdelim,infostr); + len = sizeof(infostr); + rv = get_system_info(3,infostr,&len); + if (rv == 0) printf("%sPri Operating System%c %s\n",devstr,bdelim,infostr); + len = sizeof(infostr); + rv = get_system_info(4,infostr,&len); + if (rv == 0) printf("%sSec Operating System%c %s\n",devstr,bdelim,infostr); + } else { + if (fdebug && (rv == 0xC1)) /*only supported on later IPMI 2.0 fw */ + printf("GetSystemInfo not supported on this platform\n"); + } + } + + if (fdump && ret == 0) { + /* Dump FRU to a binary file */ + fp = fopen(binfile,"w"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + } else { + printf("Writing FRU size %d to %s ...\n",sfru,binfile); + len = (int)fwrite(frubuf, 1, sfru, fp); + fclose(fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d writing file %s\n",ret,binfile); + } else ret = 0; + } + goto do_exit; + } + else if (frestore) { + uchar cksum; + /* Restore FRU from a binary file */ + fp = fopen(binfile,"r"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + } else { + ret = 0; + /* sfru and frubuf were set from load_fru above. */ + len = (int)fread(frubuf, 1, sfru, fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d reading file %s\n",ret,binfile); + sfru = 0; /*for safety*/ + } + fclose(fp); + if (fdebug) { + printf("FRU buffer from file (%d):",sfru); + dumpbuf(frubuf,sfru); + } + /* Do some validation of the FRU buffer header */ + cksum = calc_cksum(&frubuf[0],7); + if (fdebug) + printf("header, len=8, cksum0 = %02x, cksum1 = %02x\n", + frubuf[7],cksum); + if (frubuf[7] != cksum) { + printf("Not a valid FRU file\n"); + ret = ERR_BAD_FORMAT; + free_fru(frubuf); + } + if (ret == 0) { /*successfully read data*/ + printf("Writing FRU size %d from %s ...\n",sfru,binfile); + ret = write_fru_data(g_fruid, 0, frubuf, sfru, fdebug); + free_fru(frubuf); + if (ret != 0) printf("write_fru error %d (0x%02x)\n",ret,ret); + else { /* successful, show new data */ + ret = load_fru(sa,g_fruid,g_frutype,&pfru); + if (ret != 0) show_loadfru_error(sa,g_fruid,ret); + else ret = show_fru(sa,g_fruid,g_frutype,pfru); + free_fru(pfru); + pfru = NULL; + } + } + } + } /*end-else frestore */ + else if ((fwritefru != 0) && ret == 0) { + if (fbasefru == 0) { + /* if not fbasefru, must reload fru because freed in get_show_fru */ + ret = load_fru(sa,g_fruid,g_frutype,&pfru); + if (ret != 0) { + show_loadfru_error(sa,g_fruid,ret); + free_fru(pfru); + pfru = NULL; + goto do_exit; + } + if (fdebug) printf("Baseboard FRU buffer reloaded (%d):",sfru); + } + printf("\nWriting new product data (%s,%s,%s) ...\n", + prod_ver,serial_num,asset_tag); + ret = write_asset(asset_tag,serial_num,prod_ver,fwritefru,pfru); + free_fru(pfru); + if (ret != 0) printf("write_asset error %d (0x%02x)\n",ret,ret); + else { /* successful, show new data */ + ret = load_fru(sa,g_fruid,g_frutype,&pfru); + if (ret != 0) show_loadfru_error(sa,g_fruid,ret); + else ret = show_fru(sa,g_fruid,g_frutype,pfru); + free_fru(pfru); + } + pfru = NULL; + } + else + free_fru(pfru); + +do_exit: + ipmi_close_(); + // show_outcome(progname,ret); + return(ret); +} + +/* end ifru.c */ diff --git a/util/ifru.h b/util/ifru.h new file mode 100644 index 0000000..f3efaf6 --- /dev/null +++ b/util/ifru.h @@ -0,0 +1,13 @@ +/* + * ifru.h + * common routines from ifru.c + */ +#ifndef uchar +#define uchar unsigned char +#endif + +int load_fru(uchar sa, uchar frudev, uchar frutype, uchar **pfrubuf); +int show_fru(uchar sa, uchar frudev, uchar frutype, uchar *pfrubuf); +void free_fru(uchar *pfrubuf); + +/* end ifru.h */ diff --git a/util/ifru_picmg.c b/util/ifru_picmg.c new file mode 100644 index 0000000..fd6234f --- /dev/null +++ b/util/ifru_picmg.c @@ -0,0 +1,486 @@ +/* + * ifru_picmg.c + * These are helper routines for FRU PICMG decoding. + * + * Author: Andy Cress arcress at users.sourceforge.net + * + * Copyright (c) 2009 Kontron America, Inc. + * + * 09/08/10 Andy Cress - created + */ +/*M* +Copyright (c) 2010 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <string.h> +#endif +#include <time.h> + +#include "ipmicmd.h" +#include "ipicmg.h" + +extern int verbose; +extern void show_guid(uchar *pguid); /*from ifru.c*/ + +static char *picmg_link_type(uchar b) +{ + char *s; + if (b >= 0xf0 && b <= 0xf3) s = "OEM GUID Definition"; + else switch(b) { + case 0x01: s = "PICMG 3.0 Base Interface 10/100/1000"; break; + case 0x02: s = "PICMG 3.1 Ethernet Fabric Interface"; break; + case 0x03: s = "PICMG 3.2 Infiniband Fabric Interface"; break; + case 0x04: s = "PICMG 3.3 Star Fabric Interface"; break; + case 0x05: s = "PICMG 3.4 PCI Express Fabric Interface"; break; + default: s = "Reserved"; break; + } + return(s); +} + +static char *picmg_if_type(uchar b) +{ + char *s; + switch(b) { + case 0x00: s = "Base Interface"; break; + case 0x01: s = "Fabric Interface"; break; + case 0x02: s = "Update Channel"; break; + case 0x03: + default: s = "Reserved"; break; + } + return(s); +} + +static char *picmg_chan_type(uchar b) +{ + char *s; + switch(b) { + case 0x00: + case 0x07: s = "PICMG 2.9"; break; + case 0x08: s = "Single Port Fabric IF"; break; + case 0x09: s = "Double Port Fabric IF"; break; + case 0x0a: s = "Full Port Fabric IF"; break; + case 0x0b: s = "Base IF"; break; + case 0x0c: s = "Update Channel IF"; break; + default: s = "Unknown IF"; break; + } + return(s); +} + +void show_fru_picmg(uchar *pdata, int dlen) +{ + int id, i, j, k, m, n; + float f; + uchar *p; + uchar b0, b1, b2, b3, b4, b5, b6, b7, b8; + char *s1, *s2; + long l1, l2, l3; + + id = pdata[3]; + i = 5; + switch(id) { + case FRU_PICMG_BACKPLANE_P2P: + printf("\tFRU_PICMG_BACKPLANE_P2P\n"); + while (i <= dlen) { + b1 = pdata[i]; + b2 = pdata[i+1]; + b3 = pdata[i+2]; + printf("\t Channel Type : %02x - %s\n",b1, + picmg_chan_type(b1)); + printf("\t Slot Address : %02x\n",b2); + printf("\t Channel Count : %02x\n",b3); + i += 3; + for (j = 0; j < b3; j++) { + if (i > dlen) break; + if (verbose) + printf("\t Channel[%d] : %02x -> %02x in slot %02x\n", + j,pdata[i],pdata[i+1],pdata[i+2]); + i += 3; + } + } + break; + case FRU_PICMG_ADDRESS_TABLE: + printf("\tFRU_PICMG_ADDRESS_TABLE\n"); + printf("\t Type/Len : %02x\n", pdata[i++]); + printf("\t Shelf Addr : "); + for (j = 0; j < 20; j++) + printf("%02x ",pdata[i++]); + printf("\n"); + n = pdata[i++]; + printf("\t AddrTable Entries: %02x\n",n); + for (j = 0; j < n; j++) { + if (i >= dlen) break; + printf("\t HWAddr %02x, SiteNum %02x, SiteType %02x\n", + pdata[i], pdata[i+1], pdata[i+2]); + i += 3; + } + break; + case FRU_PICMG_SHELF_POWER_DIST: + printf("\tFRU_PICMG_SHELF_POWER_DIST\n"); + n = pdata[i++]; + printf("\t Num Power Feeds : %02x\n",n); + for (j = 0; j < n; j++) { + if (i >= dlen) break; + printf("\t Max Ext Current : %04x\n", + (pdata[i] | (pdata[i+1] << 8))); + i += 2; + printf("\t Max Int Current : %04x\n", + (pdata[i] | (pdata[i+1] << 8))); + i += 2; + printf("\t Min Exp Voltage : %02x\n", pdata[i++]); + m = pdata[i++]; /*num entries*/ + printf("\t Feed to FRU count: %02x\n", m); + for (k = 0; k < m; k++) { + if (i >= dlen) break; + printf("\t HW: %02x",pdata[i++]); + printf(" FRU ID: %02x\n",pdata[i++]); + } + } + break; + case FRU_PICMG_SHELF_ACTIVATION: + printf("\tFRU_PICMG_SHELF_ACTIVATION\n"); + printf("\t Allowance for FRU Act Readiness : %02x\n", + pdata[i++]); + n = pdata[i++]; + printf("\t FRU activation and Power desc Cnt: %02x\n",n); + for (j = 0; j < n; j++) { + if (i >= dlen) break; + printf("\t HW Addr: %02x, ", pdata[i++]); + printf(" FRU ID: %02x, ", pdata[i++]); + printf(" Max FRU Power: %04x, ", pdata[i] | (pdata[i+1]<<8)); + i += 2; + printf(" Config: %02x\n", pdata[i++]); + } + break; + case FRU_PICMG_SHMC_IP_CONN: + printf("\tFRU_PICMG_SHMC_IP_CONN\n"); + printf("\t Conn Data: "); + for ( ; i < dlen; i++) { + printf("%02x ",pdata[i]); + } + printf("\n"); + break; + case FRU_PICMG_BOARD_P2P: /*0x14*/ + printf("\tFRU_PICMG_BOARD_P2P\n"); + n = pdata[i++]; /*guid count*/ + printf("\t GUID count : %d\n",n); + for (j = 0; j < n; j++) { + printf("\t GUID[%d] : ",j); + show_guid(&pdata[i]); + printf("\n"); + i += 16; + } + for (j = 1; i < dlen; i += 4) { + p = &pdata[i]; + b1 = (p[0] & 0x3f); /*chan*/ + b2 = (p[0] & 0xc0) >> 6; /*if*/ + b3 = (p[1] & 0x0f); /*port*/ + b4 = ((p[1] & 0xf0) >> 4) + (p[2] & 0xf0); /*type*/ + b5 = (p[2] & 0x0f); /*ext*/ + b6 = p[3]; /*grouping*/ + printf("\t Link%d Grouping : %02x\n",j,b6); + printf("\t Link%d Extension : %02x\n",j,b5); + printf("\t Link%d Type : %02x - %s\n", + j,b4,picmg_link_type(b4)); + printf("\t Link%d Port : %02x\n",j,b3); + printf("\t Link%d Interface : %02x - %s\n", + j,b2,picmg_if_type(b2)); + printf("\t Link%d Channel : %02x\n",j,b1); + j++; + } + break; + case FRU_AMC_CURRENT: + printf("\tFRU_AMC_CURRENT\n"); + b1 = pdata[i]; /*current*/ + f = (float)(b1/10.0); + printf("\t Current draw: %.1f A @ 12V => %.2f Watt\n", + f, (f*12.0)); + break; + case FRU_AMC_ACTIVATION: + printf("\tFRU_AMC_ACTIVATION\n"); + b1 = pdata[i] | (pdata[i+1]<<8); /*max current*/ + i += 2; + f = (float)b1 / 10; + printf("\t Max Internal Current(@12V) : %.2f A [ %.2f Watt ]\n", + f, f*12); + printf("\t Module Activation Readiness: %i sec.\n",pdata[i++]); + n = pdata[i++]; + printf("\t Descriptor Count: %i\n",n); + for (j = 0; i < dlen; i += 3) { + if (j >= n) break; + printf("\t IPMB Address : %02x\n",pdata[i]); + printf("\t Max Module Current: %.2f A\n", + (float)(pdata[i+1]/10)); + j++; + } + break; + case FRU_AMC_CARRIER_P2P: + printf("\tFRU_AMC_CARRIER_P2P\n"); + for ( ; i < dlen; ) { + b1 = pdata[i]; /*resource id*/ + n = pdata[i+1]; /*desc count*/ + i += 2; + b2 = (b1 >> 7); + printf("\t Resource ID: %i, Type: %s\n", + (b1 & 0x07), (b2 == 1 ? "AMC" : "Local")); + printf("\t Descriptor Count: %i\n",n); + for (j = 0; j < n; j++) { + if (i >= dlen) break; + p = &pdata[i]; + b3 = p[0]; /*remote resource id*/ + b4 = (p[1] & 0x1f); /*remote port*/ + b5 = (p[1] & 0xe0 >> 5) + (p[2] & 0x03 << 3); /*local*/ + printf("\t Port %02d -> Remote Port %02d " + "[ %s ID: %02d ]\n", b5, b4, + ((b3 >> 7) == 1)? "AMC " : "local", b3 & 0x0f); + i += 3; + } + } + break; + case FRU_AMC_P2P: + printf("\tFRU_AMC_P2P\n"); + n = pdata[i++]; /*guid count*/ + printf("\t GUID count : %d\n",n); + for (j = 0; j < n; j++) { + printf("\t GUID[%d] : ",j); + show_guid(&pdata[i]); + printf("\n"); + i += 16; + } + b1 = pdata[i] & 0x0f; /*resource id*/ + b2 = (pdata[i] & 0x80) >> 7; /*resource type*/ + i++; + printf("\t Resource ID: %i - %s\n",b1, + b2 ? "AMC Module" : "On-Carrier Device"); + n = pdata[i++]; /*descriptor count*/ + printf("\t Descriptor Count: %i\n",n); + for (j = 0; j < n; j++) { /*channel desc loop*/ + if (i >= dlen) break; + p = &pdata[i]; + b0 = p[0] & 0x1f; + b1 = ((p[0] & 0xe0) >> 5) + ((p[1] & 0x03) << 3); + b2 = ((p[1] & 0x7c) >> 2); + b3 = ((p[1] & 0x80) >> 7) + ((p[2] & 0x0f) << 1); + printf("\t Lane 0 Port: %i\n",b0); + printf("\t Lane 1 Port: %i\n",b1); + printf("\t Lane 2 Port: %i\n",b2); + printf("\t Lane 3 Port: %i\n",b3); + i += 3; + } + for ( ; i < dlen; i += 5) { /*ext descriptor loop*/ + p = &pdata[i]; + b0 = p[0]; /*channel id*/ + b1 = p[1] & 0x01; /*port flag 0*/ + b2 = (p[1] & 0x02) >> 1; /*port flag 1*/ + b3 = (p[1] & 0x04) >> 2; /*port flag 2*/ + b4 = (p[1] & 0x08) >> 3; /*port flag 3*/ + b5 = ((p[1] & 0xf0) >> 4) + ((p[2] & 0x0f) << 4); /*type*/ + b6 = (p[2] & 0xf0) >> 4; /*type ext*/ + b7 = p[3]; /*group id*/ + b8 = (p[4] & 0x03); /*asym match*/ + printf("\t Link Designator: Channel ID: %i, " + "Port Flag 0: %s%s%s%s\n",b0, + b1 ? "o" : "-", + b2 ? "o" : "-", + b3 ? "o" : "-", + b4 ? "o" : "-" ); + switch(b5) { /*link type*/ + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE: + printf("\t Link Type: %02x - %s\n", b5, + "AMC.1 PCI Express"); + switch(b6) { /*link type ext*/ + case AMC_LINK_TYPE_EXT_PCIE_G1_NSSC: + s2 = "Gen 1 capable - non SSC"; break; + case AMC_LINK_TYPE_EXT_PCIE_G1_SSC: + s2 = "Gen 1 capable - SSC"; break; + case AMC_LINK_TYPE_EXT_PCIE_G2_NSSC: + s2 = "Gen 2 capable - non SSC"; break; + case AMC_LINK_TYPE_EXT_PCIE_G2_SSC: + s2 = "Gen 2 capable - SSC"; break; + default: + s2 = "Invalid"; break; + } + printf("\t Link Type Ext: %02x - %s\n", b6,s2); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1: + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2: + printf("\t Link Type: %02x - %s\n", b5, + "AMC.1 PCI Express Advanced Switching"); + printf("\t Link Type Ext: %02x\n", b6); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET: + s1 = "AMC.2 Ethernet"; + printf("\t Link Type: %02x - %s\n", b5,s1); + switch(b6) { /*link type ext*/ + case AMC_LINK_TYPE_EXT_ETH_1000_BX: + s2 = "1000Base-Bx (SerDES Gigabit) Ethernet Link"; + break; + case AMC_LINK_TYPE_EXT_ETH_10G_XAUI: + s2 = "10Gbit XAUI Ethernet Link"; break; + default: + s2 = "Invalid"; break; + } + printf("\t Link Type Ext: %02x - %s\n", b6,s2); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE: + printf("\t Link Type: %02x - %s\n", b5, + "AMC.3 Storage"); + switch(b6) { /*link type ext*/ + case AMC_LINK_TYPE_EXT_STORAGE_FC: + s2 = "Fibre Channel"; break; + case AMC_LINK_TYPE_EXT_STORAGE_SATA: + s2 = "Serial ATA"; break; + case AMC_LINK_TYPE_EXT_STORAGE_SAS: + s2 = "Serial Attached SCSI"; break; + default: + s2 = "Invalid"; break; + } + printf("\t Link Type Ext: %02x - %s\n", b6,s2); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO: + printf("\t Link Type: %02x - %s\n", b5, + "AMC.4 Serial Rapid IO"); + printf("\t Link Type Ext: %02x\n", b6); + break; + default: + printf("\t Link Type: %02x - %s\n", b5, + "reserved or OEM GUID"); + printf("\t Link Type Ext: %02x\n", b6); + break; + } /*end switch(link_type)*/ + printf("\t Link group Id: %i\n", b7); + printf("\t Link Asym Match: %i\n", b8); + } /*end ext descriptor loop*/ + break; + case FRU_AMC_CARRIER_INFO: + printf("\tFRU_AMC_CARRIER_INFO\n"); + b1 = pdata[i++]; /*extVersion*/ + n = pdata[i++]; /*siteCount*/ + printf("\t AMC.0 extension version: R%d.%d\n", + b1 & 0x0f, (b1 >> 4) & 0x0f); + printf("\t Carrier Site Count: %d\n",n); + for (j = 0; j < n; j++) { + if (i >= dlen) break; + printf("\t Site ID: %i\n", pdata[i++]); + } + break; + case FRU_PICMG_CLK_CARRIER_P2P: + printf("\tFRU_PICMG_CLK_CARRIER_P2P\n"); + b0 = pdata[i++]; + n = pdata[i++]; + k = (b0 & 0xC0) >> 6; + switch(k) { + case 0: s1 = "On-Carrier-Device"; break; + case 1: s1 = "AMC slot"; break; + case 2: s1 = "Backplane"; break; + default: s1 = "reserved"; break; + } + printf("\t Clock Resource ID: %02x, Type: %s\n",b0,s1 ); + printf("\t Channel Count : %02x\n",n); + for (j = 0; j < n; j++) { + b1 = pdata[i++]; /*local channel*/ + b2 = pdata[i++]; /*remote channel*/ + b3 = pdata[i++]; /*remote resource*/ + k = (b3 & 0xC0) >> 6; + switch(k) { + case 0: s1 = "Carrier-Dev"; break; + case 1: s1 = "AMC slot "; break; + case 2: s1 = "Backplane "; break; + default: s1 = "reserved "; break; + } + printf("\t CLK-ID: %02x -> %02x [ %s %02x ]\n",b1,b2,s1,b3); + } + break; + case FRU_PICMG_CLK_CONFIG: + printf("\tFRU_PICMG_CLK_CONFIG\n"); + b0 = pdata[i++]; + n = pdata[i++]; + printf("\t Clock Resource ID: %02x\n",b0); + printf("\t Descriptor Count : %02x\n",n); + for (j = 0; j < n; j++) { + b1 = pdata[i++]; /*channel id*/ + b2 = pdata[i++]; /*control*/ + printf("\t CLK-ID: %02x - CTRL %02x [ %12s ]\n", b1, b2, + (b2 & 0x01) == 0 ? "Carrier IPMC":"Application"); + b3 = pdata[i++]; /*indirect_cnt*/ + b4 = pdata[i++]; /*direct_cnt*/ + printf("\t Cnt: Indirect %02x / Direct %02x\n",b3,b4); + for (k = 0; k < b3; k++) { + b5 = pdata[i++]; /*feature*/ + b6 = pdata[i++]; /*dep_chn_id*/ + printf("\t Feature: %02x [%8s] - ", + b5, (b5 & 0x01)==1 ? "Source":"Receiver"); + printf("Dep. CLK-ID: %02x\n",b6); + } + for (k = 0; k < b4; k++) { + b5 = pdata[i++]; /*feature*/ + b6 = pdata[i++]; /*family*/ + b7 = pdata[i++]; /*accuracy*/ + l1 = pdata[i] | (pdata[i+1] << 8) | /*frequency*/ + (pdata[i+2] << 8) | (pdata[i+3] << 8); + i += 4; + l2 = pdata[i] | (pdata[i+1] << 8) | /*min frequency*/ + (pdata[i+2] << 8) | (pdata[i+3] << 8); + i += 4; + l3 = pdata[i] | (pdata[i+1] << 8) | /*max frequency*/ + (pdata[i+2] << 8) | (pdata[i+3] << 8); + i += 4; + printf("\t Feature: %02x - PLL: %x / Asym: %s\n", + b5, (b5 >> 1) & 0x01, (b5 & 1) ? "Source":"Receiver"); + printf("\t Family : %02x - AccLVL: %02x\n", b6, b7); + printf("\t FRQ : %-9d, min: %-9d, max: %-9d\n", + (int)l1, (int)l2, (int)l3); + } + } + break; + case FRU_UTCA_FRU_INFO_TABLE: + case FRU_UTCA_CARRIER_MNG_IP: + case FRU_UTCA_CARRIER_INFO: + case FRU_UTCA_CARRIER_LOCATION: + case FRU_UTCA_SHMC_IP_LINK: + case FRU_UTCA_POWER_POLICY: + case FRU_UTCA_ACTIVATION: + case FRU_UTCA_PM_CAPABILTY: + case FRU_UTCA_FAN_GEOGRAPHY: + case FRU_UTCA_CLOCK_MAPPING: + case FRU_UTCA_MSG_BRIDGE_POLICY: + case FRU_UTCA_OEM_MODULE_DESC: + printf("\tNot yet implemented uTCA record %x\n",id); + break; + default: + printf("\tUnknown PICMG Extension %x\n",id); + break; + } +} /*end show_fru_picmg*/ + +/*end ifru_picmg.c */ diff --git a/util/ifruset.c b/util/ifruset.c new file mode 100644 index 0000000..3e0299a --- /dev/null +++ b/util/ifruset.c @@ -0,0 +1,1658 @@ +/* + * ifruset (copy of ifru.c with extended FRU writing) + * + * This tool reads the FRU configuration, and optionally sets the asset + * tag field in the FRU data. See IPMI v1.5 spec section 28. + * It can use either the Intel /dev/imb driver or VALinux /dev/ipmikcs. + * + * Author: Andy Cress arcress at users.sourceforge.net + * + * Copyright (c) 2009 Kontron America, Inc. + * + * 04/01/10 Andy Cress - created from ifru.c 2.6.1 + */ +/*M* +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include <time.h> + +#include "ipmicmd.h" +#include "ipicmg.h" // #define OEM_PICMG 12634 + +extern int get_LastError( void ); /* ipmilan.c */ +extern int get_BiosVersion(char *str); +extern int get_SystemGuid(uchar *str); +extern void fmt_time(time_t etime, char *buf, int bufsz); /*see ievents.c*/ + +#define FIELD_LEN 24 +#define NUM_BOARD_FIELDS 6 +#define NUM_PRODUCT_FIELDS 8 +#define NUM_CHASSIS_FIELDS 3 +#define ERR_LENMAX -7 /*same as LAN_ERR_BADLENGTH */ +#define ERR_LENMIN -10 /*same as LAN_ERR_TOO_SHORT */ +#define ERR_OTHER -13 /*same as LAN_ERR_OTHER */ + +#define STRING_DATA_TYPE_BINARY 0x00 +#define STRING_DATA_TYPE_BCD_PLUS 0x01 +#define STRING_DATA_TYPE_SIX_BIT_ASCII 0x02 +#define STRING_DATA_TYPE_LANG_DEPENDENT 0x03 + +#define FRUCHUNK_SZ 16 +#define FRU_END 0xC1 +#define FRU_EMPTY_FIELD 0xC0 +#define FRU_TYPE_MASK 0xC0 +#define FRU_LEN_MASK 0x3F +#define IPROD_MANUF 0 +#define IPROD_NAME 1 +#define IPROD_PART 2 +#define IPROD_VERS 3 +#define IPROD_SERNUM 4 +#define IPROD_ASSET 5 +#define IPROD_FRUID 6 +#define IPROD_OEM 7 + +static char *progname = "ifruset"; +static char *progver = "2.93"; +static char fdebug = 0; +static char fpicmg = 0; +static char fonlybase = 0; +static char fonlyhsc = 0; +static char fdevsdrs = 0; +static char fshowlen = 0; +static char fgetfru = 0; +static char fdoanyway = 0; +static char fset_mc = 0; +static char fcanonical = 0; +static char fdump = 0; +static char frestore = 0; +static int fwritefru = 0; +static int prod_id, vend_id = 0; +static char bdelim = ':'; +static char *binfile = NULL; +static uchar bmc_sa = BMC_SA; /*defaults to 0x20*/ +static uchar guid[17] = ""; +static uchar *frubuf = NULL; +static uchar *newdata = NULL; /* new FRU data, including the product area */ + /* usually 4*64 + 3 = 259 bytes */ +static int sfru = 0; +static int chassis_offset = -1; +static int chassis_len = 0; +static char chassis_name[FIELD_LEN] = {0}; +static int product_num = NUM_PRODUCT_FIELDS; +typedef struct { + int offset; + int len; + char tag[FIELD_LEN]; + } FIELDTYPE; +static FIELDTYPE prodarea[NUM_PRODUCT_FIELDS] = { + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0} }; +static FIELDTYPE prodnew[NUM_PRODUCT_FIELDS] = { + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0} }; +static int maxprod = 0; +static int ctype; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = 0; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static uchar g_fruid = 0; /* default to fruid 0 */ +static uchar g_frutype = 0; +/* g_frutype values (detected), see also FruTypeString + * --TAG---- FRU IPMB + * Baseboard = 0x0c 0x07 + * PowerSply = 0x0a + * PowerCage = 0x15 + * DIMM = 0x20 + * HotSwapCt = 0x0f + * ME = 0x2e + * Component = * * (all others) + */ + +#define MAX_CTYPE 26 +char *ctypes[MAX_CTYPE] = { "", "Other", "Unknown", "Desktop", + "Low Profile Desktop", "Pizza Box", "Mini-Tower", "Tower", + "Portable", "Laptop", "Notebook", "Handheld", "Docking Station", + "All-in-One", "Sub-Notebook", "Space-saving", "Lunch Box", + "Main Server Chassis", "Expansion Chassis", "SubChassis", + "Bus Expansion Chassis", "Peripheral Chassis", + "RAID Chassis", /*0x17=23.*/ "Rack-Mount Chassis", + "New24" , "New25"}; + /* what about bladed chassies? */ +char *ctype_hdr = +"Chassis Type "; +char *chassis[NUM_CHASSIS_FIELDS] = { +"Chassis Part Number ", +"Chassis Serial Num ", +"Chassis OEM Field " }; +char *board[NUM_BOARD_FIELDS] = { +"Board Manufacturer ", +"Board Product Name ", +"Board Serial Number ", +"Board Part Number ", +"Board FRU File ID ", +"Board OEM Field " }; +char *product[NUM_PRODUCT_FIELDS] = { +"Product Manufacturer", +"Product Name ", +"Product Part Number ", +"Product Version ", +"Product Serial Num ", +"Product Asset Tag ", +"Product FRU File ID ", +"Product OEM Field " }; +char *asset_hdr = +" Asset Tag Length "; + +#if 0 +typedef struct { + uchar len :6; + uchar type:2; + } TYPE_LEN; /*old, assumes lo-hi byte order*/ +#else +typedef struct { + uchar len; + uchar type; + } TYPE_LEN; +#endif + +void +free_fru(void) +{ + if (frubuf != NULL) { + free(frubuf); + frubuf = NULL; + } + if (newdata != NULL) { + free(newdata); + newdata = NULL; + } + return; +} + +int +load_fru(uchar sa, uchar frudev, uchar frutype) +{ + int ret = 0; + uchar indata[16]; + uchar resp[18]; + int sresp; + uchar cc; + int sz; + char fwords; + ushort fruoff = 0; + int i; + int chunk; + + indata[0] = frudev; + sresp = sizeof(resp); + if (fdebug) printf("load_fru: sa = %02x, frudev = %02x\n",sa,frudev); + ret = ipmi_cmd_mc(GET_FRU_INV_AREA,indata,1,resp,&sresp,&cc,fdebug); + if (fdebug) printf("load_fru: inv ret = %d, cc = %x\n",ret,cc); + if (ret != 0) return(ret); + if (cc != 0) { ret = (cc & 0x00ff); return(ret); } + + sz = resp[0] + (resp[1] << 8); + if (resp[2] & 0x01) { fwords = 1; sz = sz * 2; } + else fwords = 0; + + frubuf = malloc(sz); + if (frubuf == NULL) return(get_errno()); + sfru = sz; + + /* Loop on READ_FRU_DATA */ + for (i = 0, chunk=FRUCHUNK_SZ; i < sz; i+=chunk) + { + if ((i+chunk) >= sz) chunk = sz - i; + indata[0] = frudev; /* FRU Device ID */ + if (fwords) { + indata[3] = chunk / 2; + fruoff = (i/2); + } else { + indata[3] = chunk; + fruoff = i; + } + indata[1] = fruoff & 0x00FF; + indata[2] = (fruoff & 0xFF00) >> 8; + sresp = sizeof(resp); + ret = ipmi_cmd_mc(READ_FRU_DATA,indata,4,resp,&sresp,&cc,fdebug); + if (ret != 0) break; + else if (cc != 0) { + if (i == 0) ret = cc & 0x00ff; + if (fdebug) printf("read_fru[%d]: ret = %d cc = %x\n",i,ret,cc); + break; + } + memcpy(&frubuf[i],&resp[1],chunk); + } + if ((frudev == 0) && (sa == bmc_sa)) { /*main system fru*/ + sresp = sizeof(resp); + ret = ipmi_cmd_mc(GET_SYSTEM_GUID,indata,0,resp,&sresp,&cc,fdebug); + if ((ret != 0) && !is_remote()) { /* get UUID from SMBIOS */ + cc = 0; sresp = 16; + ret = get_SystemGuid(resp); + } + if (fdebug) printf("system_guid: ret = %d, cc = %x\n",ret,cc); + if (ret == 0 && cc == 0) { + if (fdebug) { + printf("system guid (%d): ",sresp); + for (i=0; i<16; i++) printf("%02x ",resp[i]); + printf("\n"); + } + memcpy(&guid,&resp,16); + guid[16] = 0; + } + } /*endif*/ + + return(ret); +} + +static void decode_string(unsigned char type, + unsigned char language_code, + unsigned char *source, + int slen, + char *target, + int tsize) +{ + static const char bcd_plus[] = "0123456789 -.:,_"; + unsigned char *s = &source[0]; + unsigned char *d = &target[0]; + int len, i, j, k; + union { uint32_t bits; char chars[4]; } u; + + if (slen == 0 || slen == 1) return; + switch(type) { + case STRING_DATA_TYPE_BINARY: /* 00: binary/unspecified */ + len = (slen*2); break; /* hex dump -> 2x length */ + case STRING_DATA_TYPE_SIX_BIT_ASCII: /*type 2 6-bit ASCII*/ + /* 4 chars per group of 1-3 bytes */ + len = ((((slen+2)*4)/3) & ~3); break; + case STRING_DATA_TYPE_LANG_DEPENDENT: /* 03 language dependent */ + case STRING_DATA_TYPE_BCD_PLUS: /* 01b: BCD plus */ + default: + len = slen; break; + } + if (len >= tsize) len = tsize - 1; + memset(target, 0, len); + if (type == STRING_DATA_TYPE_BCD_PLUS) { /*type 1 BCD plus*/ + for (k=0; k<len; k++) + target[k] = bcd_plus[(s[k] & 0x0f)]; + target[k] = '\0'; + } else if (type == STRING_DATA_TYPE_SIX_BIT_ASCII) { /*type 2 6-bit ASCII*/ + for (i=j=0; i<slen; i+=3) { + u.bits = 0; + k = ((slen-i) < 3 ? (slen-i) : 3); +#if WORDS_BIGENDIAN + u.chars[3] = s[i]; + u.chars[2] = (k > 1 ? s[i+1] : 0); + u.chars[1] = (k > 2 ? s[i+2] : 0); +#define CHAR_IDX 3 +#else + memcpy((void *)&u.bits, &s[i], k); +#define CHAR_IDX 0 +#endif + for (k=0; k<4; k++) { + target[j++] = ((u.chars[CHAR_IDX] & 0x3f) + 0x20); + u.bits >>= 6; + } + } + target[j] = '\0'; + } else if (type == STRING_DATA_TYPE_LANG_DEPENDENT) { /*type 3*/ + if ((language_code == 0x00) || (language_code == 0x25) || + (language_code == 0x19)) { + memcpy(target, source, len); + target[len] = 0x0; + } else { + printf("Language 0x%x dependent decode not supported\n",language_code); + } + } else if (type == STRING_DATA_TYPE_BINARY) { /* 00: binary/unspecified */ + strncpy(target, buf2str(s, slen), len); + } else { /* other */ + printf("Unable to decode type 0x%.2x\n",type); + } + return; +} + +uchar calc_cksum(uchar *pbuf,int len) +{ + int i; + uchar cksum; + uchar sum = 0; + + for (i = 0; i < len; i++) sum += pbuf[i]; + cksum = 0 - sum; + return(cksum); +} + +static void dumpbuf(uchar *pbuf,int sz) +{ + uchar line[17]; + uchar a; + int i, j; + + line[0] = 0; line[16] = 0; + j = 0; + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { j = 0; printf("%s\n %04d: ",line,i); } + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + printf("%02x ",pbuf[i]); + } + line[j] = 0; + printf("%s\n",line); + return; +} + +#define NSPDMFG 7 +static struct { + uchar id; char *str; +} spd_mfg[NSPDMFG] = { /* see JEDEC JEP106 doc */ +{ 0x2c, "Micron" }, +{ 0x15, "Philips Semi" }, +{ 0x1c, "Mitsubishi" }, +{ 0xce, "Samsung" }, +{ 0xc1, "Infineon" }, +{ 0x98, "Kingston" }, +{ 0x89, "Intel" } +}; + +int ValidTL(uchar typelen) +{ + if (vend_id != VENDOR_INTEL) return 1; + if ((typelen & 0xC0) == 0xC0) return 1; + else return 0; +} + +char * FruTypeString(uchar frutype) +{ + char *pstr; + switch (frutype) { + case 0x07: pstr = "Baseboard"; break; /*IPMB*/ + case 0x0c: pstr = "Baseboard"; break; /*FRU*/ + case 0x0a: pstr = "PowerSply"; break; /*FRU*/ + case 0x15: pstr = "PowerCage"; break; /*FRU*/ + case 0x20: pstr = "DIMM "; break; /*FRU*/ + case 0x0f: pstr = "HotSwapCt"; break; /*IPMB*/ + case 0x2e: pstr = "ME "; break; /*IPMB*/ + default: pstr = "Component"; break; + } + return(pstr); +} + +static void +show_spd(uchar *spd, int lenspd, uchar frudev, uchar frutype) +{ + int sz; + char *pstr; + uchar mrev; + int i; + char devstr[20]; + + sz = spd[0]; /* sz should == lenspd */ + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s,%02x] ",FruTypeString(frutype),frudev); + printf("%sMemory SPD Size %c %d\n", + devstr,bdelim,lenspd); + if (spd[2] == 0x07) pstr = "DDR"; + else /* usu 0x04 */ pstr = "SDRAM"; + printf("%sMemory Type %c %s\n", + devstr,bdelim,pstr); + printf("%sModule Density %c %d MB per bank\n", + devstr,bdelim, (spd[31] * 4)); + printf("%sModule Banks %c %d banks\n", + devstr,bdelim,spd[5]); + printf("%sModule Rows, Cols %c %d rows, %d cols\n", + devstr,bdelim, spd[3], spd[4]); + if (spd[11] == 0x00) pstr = "Non-parity"; + else /* usu 0x02 */ pstr = "ECC"; + printf("%sDIMM Config Type %c %s\n",devstr,bdelim,pstr); + for (i = 0; i < NSPDMFG; i++) + if (spd_mfg[i].id == spd[64]) break; + if (i == NSPDMFG) pstr = ""; /* not found, use null string */ + else pstr = spd_mfg[i].str; + printf("%sManufacturer ID %c %s (0x%02x)\n", + devstr,bdelim, pstr, spd[64]); + mrev = spd[91]; /* save this byte for later */ + spd[91] = 0; /*stringify part number */ + printf("%sManufacturer Part# %c %s\n", + devstr,bdelim,&spd[73]); + printf("%sManufacturer Rev %c %02x %02x\n", + devstr,bdelim,mrev,spd[92]); + printf("%sManufacturer Date %c year=%02d week=%02d\n", + devstr,bdelim,spd[93],spd[94]); + printf("%sAssembly Serial Num %c %02x%02x%02x%02x\n", + devstr,bdelim,spd[95], spd[96], spd[97], spd[98]); + spd[91] = mrev; /* restore byte, so ok to repeat later */ + return; +} + +void show_guid(uchar *pguid) +{ + char *s; + int i; + for (i=0; i<16; i++) { + if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) s = "-"; + else s = ""; + printf("%s%02x",s,pguid[i]); + } +} + +static char *volt_desc(uchar b) +{ + char *s; + switch(b) { + case 0x03: s = "5V"; break; + case 0x02: s = "3.3V"; break; + case 0x01: s = "-12V"; break; + case 0x00: + default: s = "12V"; break; + } + return(s); +} + +static char *mgt_type(uchar b) +{ + char *s; + switch(b) { + case 0x01: s = "SysMgt_URL"; break; + case 0x02: s = "SystemName"; break; + case 0x03: s = "SysPingAddr"; break; + case 0x04: s = "Compon_URL"; break; + case 0x05: s = "ComponName"; break; + case 0x06: s = "ComponPing"; break; + case 0x07: + default: s = "SysGUID"; break; + } + return(s); +} + +static +void show_fru_multi(char *tag, int midx, uchar mtype, uchar *pdata, int dlen) +{ + int vend, i; + char mystr[256]; + char *s1, *s2; + int v1, v2, v3, v4, v5, v6, v7, v8; + uchar b1, b2; + + if (fdebug) dumpbuf(pdata,dlen); /*multi-record area dump*/ + sprintf(mystr,"%sMulti[%d] ",tag,midx); + i = strlen(mystr); + switch(mtype) { + case 0x00: /*Power Supply*/ + printf("%sPower Supply Record %c \n",mystr,bdelim); + v1 = pdata[0] + ((pdata[1] & 0x0f) << 8); + printf("\t Capacity \t%c %d W\n",bdelim, v1); + v2 = pdata[2] + (pdata[3] << 8); + printf("\t Peak VA \t%c %d VA\n",bdelim, v2); + printf("\t Inrush Current\t%c %d A\n",bdelim, pdata[4]); + printf("\t Inrush Interval\t%c %d ms\n",bdelim, pdata[5]); + v3 = pdata[6] + (pdata[7] << 8); + v4 = pdata[8] + (pdata[9] << 8); + printf("\t Input Voltage Range1\t%c %d-%d V\n", + bdelim,v3/100,v4/100); + v3 = pdata[10] + (pdata[11] << 8); + v4 = pdata[12] + (pdata[13] << 8); + printf("\t Input Voltage Range2\t%c %d-%d V\n", + bdelim,v3/100,v4/100); + printf("\t Input Frequency Range\t%c %d-%d Hz\n", + bdelim,pdata[14],pdata[15]); + printf("\t AC Dropout Tolerance\t%c %d ms\n",bdelim, pdata[16]); + b1 = pdata[17]; + b2 = (b1 & 0x01); + if (b2) { /*predictive fail*/ + if (b1 & 0x10 != 0) s1 = "DeassertFail "; + else s1 = "AssertFail "; + } else { + if (b1 & 0x10 != 0) s1 = "2pulses/rot "; + else s1 = "1pulse/rot "; + } + printf("\t Flags \t%c %s%s%s%s%s\n",bdelim, + (b2 ? "PredictFail " : ""), + ((b1 & 0x02 == 0) ? "" : "PowerFactorCorrect "), + ((b1 & 0x04 == 0) ? "" : "AutoswitchVolt "), + ((b1 & 0x08 == 0) ? "" : "Hotswap "), s1); + v5 = pdata[18] + ((pdata[19] & 0x0f) << 8); + v6 = (pdata[19] & 0xf0) >> 4; + printf("\t Peak Capacity \t%c %d W for %d s\n",bdelim, v5,v6); + if (pdata[20] == 0) { + printf("\t Combined Capacity\t%c not specified\n",bdelim); + } else { + b1 = pdata[20] & 0x0f; + b2 = (pdata[20] & 0xf0) >> 4; + v7 = pdata[21] + (pdata[22] << 8); + printf("\t Combined Capacity\t%c %d W (%s and %s)\n", + bdelim, v7,volt_desc(b1),volt_desc(b2)); + } + if (b2) /*predictive fail*/ + printf("\t Fan low threshold\t%c %d RPS\n",bdelim,pdata[23]); + break; + case 0x01: /*DC Output*/ + b1 = pdata[0] & 0x0f; + b2 = (pdata[0] & 0x80 != 0); + printf("%sDC Output %c number %d\n",mystr,bdelim,b1); + printf("\t Standby power \t%c %s\n", bdelim, + (b2 ? "Yes" : "No")); + v1 = pdata[1] + (pdata[2] << 8); + printf("\t Nominal voltage \t%c %.2f V\n", bdelim, v1 / 100); + v2 = pdata[3] + (pdata[4] << 8); + v3 = pdata[5] + (pdata[6] << 8); + printf("\t Voltage deviation \t%c + %.2f V / - %.2f V\n", + bdelim, v3/100, v2/100); + v4 = pdata[7] + (pdata[8] << 8); + printf("\t Ripple and noise pk-pk \t%c %d mV\n", bdelim, v4); + v5 = pdata[9] + (pdata[10] << 8); + printf("\t Min current draw \t%c %.3f A\n", bdelim, v5/1000); + v6 = pdata[11] + (pdata[12] << 8); + printf("\t Max current draw \t%c %.3f A\n", bdelim, v6/1000); + break; + case 0x02: /*DC Load*/ + b1 = pdata[0] & 0x0f; + printf("%sDC Load %c number %d\n",mystr,bdelim,b1); + v1 = pdata[1] + (pdata[2] << 8); + printf("\t Nominal voltage \t%c %.2f V\n", bdelim, v1 / 100); + v2 = pdata[3] + (pdata[4] << 8); + v3 = pdata[5] + (pdata[6] << 8); + printf("\t Min voltage allowed \t%c %.2f A\n", bdelim, v2); + printf("\t Max voltage allowed \t%c %.2f A\n", bdelim, v3); + v4 = pdata[7] + (pdata[8] << 8); + printf("\t Ripple and noise pk-pk \t%c %d mV\n", bdelim, v4); + v5 = pdata[9] + (pdata[10] << 8); + printf("\t Min current load \t%c %.3f A\n", bdelim, v5/1000); + v6 = pdata[11] + (pdata[12] << 8); + printf("\t Max current load \t%c %.3f A\n", bdelim, v6/1000); + break; + case 0x03: /*Management Access*/ + b1 = pdata[0]; + printf("%sManagemt Access %c %s ",mystr,bdelim,mgt_type(b1)); + memcpy(mystr,&pdata[1],dlen-1); + mystr[dlen-1] = 0; + printf("%s\n",mystr); + break; + case 0x04: /*Base Compatibility*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + printf("%sBasic Compat %c %06x\n",mystr,bdelim,vend); + break; + case 0x05: /*Extended Compatibility*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + printf("%sExtended Compat %c %06x\n",mystr,bdelim,vend); + break; + case 0xC0: /*OEM Extension*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + if (vend == OEM_PICMG) { + printf("%sOEM PICMG %c \n", mystr,bdelim); + show_fru_picmg(pdata,dlen); + } else + printf("%sOEM Ext %c %06x %02x\n", + mystr,bdelim, vend, pdata[3]); + break; + default: + printf("%s %02x %c %02x\n", mystr,mtype,bdelim, pdata[0]); + break; + } +} + +int +show_fru(uchar sa, uchar frudev, uchar frutype) +{ + int ret = 0; + int i, j, n, sz; + uchar *pfru; + uchar lang; + TYPE_LEN tl; + char newstr[64]; + int iaoff, ialen, bdoff, bdlen; + int proff, prlen, choff, chlen; + int moff, mlen; + char devstr[24]; + char *pstr; + int extra = 0; + + if (frubuf[0] == 0x80) { /* 0x80 = type for DIMMs (SPD) */ + /* FRU Header: 80 08 07 0c 0a 01 48 00 (DIMM) */ + sz = frubuf[0]; + if (fdebug) { + printf("DIMM SPD Body (size=%d/%d): ",sz,sfru); + dumpbuf(frubuf,sfru); + } + show_spd(frubuf,sfru, frudev,frutype); + return(ret); + } + + pstr = FruTypeString(frutype); + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s,%02x] ",pstr,frudev); + printf("%s%s FRU Size %c %d\n",devstr,pstr,bdelim,sfru); + + /* + * FRU header: + * 0 = format_ver (01 is std, usu 0x80 if DIMM) + * 1 = internal_use offset + * 2 = chassis_info offset + * 3 = board_info offset (usu 6 fields) + * 4 = product_info offset (usu 8 fields) + * 5 = multirecord offset + * 6 = pad (00) + * 7 = header checksum (zero checksum) + * FRU Header: 01 01 02 09 13 00 00 e0 (BMC) + * FRU Header: 01 00 00 00 01 07 00 f7 (Power Cage) + */ + pfru = &frubuf[0]; + sz = 8; /*minimum for common header*/ + for (i = 1; i < 6; i++) /* walk thru offsets */ + if (frubuf[i] != 0) sz = frubuf[i] * 8; + if (sz > 8) /* if have at least one section */ + sz += frubuf[sz+1] * 8; /* add length of last section */ + /* Now, sz = size used, sfru = total available size */ + if (sz > sfru) { + if (fdebug) { + printf("FRU Header: "); + for (i = 0; i < 8; i++) printf("%02x ",frubuf[i]); + printf("\n"); + } + printf("FRU size out of bounds: available=%d used=%d\n",sfru,sz); + printf("Please apply the correct FRU/SDR diskette\n"); + if (fdoanyway) { + extra = sz - sfru; + sz = sfru; + } else return(ERR_OTHER); + } + /* internal area offset, length */ + iaoff = frubuf[1] * 8; + ialen = frubuf[iaoff + 1] * 8; + /* chassis area offset, length */ + choff = frubuf[2] * 8; + chlen = frubuf[choff + 1] * 8; + /* board area offset, length */ + bdoff = frubuf[3] * 8; + bdlen = frubuf[bdoff + 1] * 8; + /* product area offset, length */ + proff = frubuf[4] * 8; + prlen = frubuf[proff + 1] * 8; + if (extra > 0) { /*do fixup of extra in product area*/ + prlen -= extra; + j = prlen / 8; + prlen = j * 8; /*resolve to 8-byte bound*/ + frubuf[proff + 1] = j; + } + /* multi-record area offset, length */ + moff = frubuf[5] * 8; + mlen = 0; + if (moff > 0) { + for (i = moff; i < sfru; ) { + j = 5 + frubuf[i+2]; + mlen += j; + if (frubuf[i+1] & 0x80) break; + i += j; + } + } + + if (fdebug) { + printf("FRU Header: "); + for (i = 0; i < 8; i++) printf("%02x ",frubuf[i]); + printf("\n"); + printf("FRU Body (size=%d/%d): ",sz,sfru); + dumpbuf(frubuf,sfru); + printf("header, len=%d, cksum0 = %02x, cksum1 = %02x\n", + 8,frubuf[7],calc_cksum(&frubuf[0],7)); + printf("internal off=%d, len=%d, cksum = %02x\n", + iaoff,ialen,calc_cksum(&frubuf[iaoff],ialen-1)); + printf("chassis off=%d, len=%d, cksum = %02x\n", + choff,chlen,calc_cksum(&frubuf[choff],chlen-1)); + printf("board off=%d, len=%d, cksum = %02x\n", + bdoff,bdlen,calc_cksum(&frubuf[bdoff],bdlen-1)); + printf("prod off=%d, len=%d, cksum = %02x\n", + proff,prlen,calc_cksum(&frubuf[proff],prlen-1)); + /* Multi-record area */ + printf("multi off=%d, len=%d, fru sz=%d\n", moff,mlen,sz); + } /*endif fdebug, show header*/ + + if (choff != 0) { + /* show Chassis area fields */ + pfru = &frubuf[choff]; + lang = 25; /* English */ + ctype = pfru[2]; /*chassis type*/ + if (fdebug) printf("ctype=%x\n",ctype); + if (ctype >= MAX_CTYPE) ctype = MAX_CTYPE - 1; + printf("%s%s%c %s\n",devstr, ctype_hdr,bdelim,ctypes[ctype]); + pfru += 3; /* skip chassis header */ + for (i = 0; i < NUM_CHASSIS_FIELDS; i++) + { + if (pfru[0] == FRU_END) break; /*0xC1 = end of FRU area*/ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],chassis[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + if (i == 2) { /* OEM field for chassis_name */ + chassis_offset = (int)(pfru - frubuf); + chassis_len = tl.len; + if (fdebug) printf("chassis oem dtype=%d lang=%d len=%d\n", + tl.type,lang,tl.len); + } + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, chassis[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) printf("num Chassis fields = %d\n",i); + } + + if (bdoff != 0) { + long nMin, nSec; + time_t tsec; + /* show Board area fields */ + pfru = &frubuf[bdoff]; + lang = pfru[2]; + /* Decode board mfg date-time (num minutes since 1/1/96) */ + nMin = pfru[3] + (pfru[4] << 8) + (pfru[5] << 16); + /* 13674540 min from 1/1/70 to 1/1/96 */ + nSec = (nMin + 13674540) * 60; + tsec = (time_t)(nSec & 0x0ffffffff); + // fmt_time(tsec,newstr,sizeof(newstr)); + printf("%sBoard Mfg DateTime %c %s",devstr,bdelim,ctime(&tsec)); + pfru += 6; /* skip board header */ + for (i = 0; i < NUM_BOARD_FIELDS; i++) + { + if (pfru[0] == FRU_END) break; /*0xC1 = end*/ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],board[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, board[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) printf("num Board fields = %d\n",i); + } + + if (proff != 0) { + /* show Product area fields */ + pfru = &frubuf[proff]; + maxprod = pfru[1] * 8; + lang = pfru[2]; + pfru += 3; /* skip product header */ + for (i = 0; i < NUM_PRODUCT_FIELDS; i++) + { + if (*pfru == FRU_END) { /*0xC1 = end*/ + /* Wart for known Kontron 1-byte Product Version anomaly. */ + if ((vend_id == VENDOR_KONTRON) && (i == 3)) ; + else break; + } + if (*pfru == 0) *pfru = FRU_EMPTY_FIELD; /* fix a broken table */ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],product[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + n = (int)(pfru - frubuf); + prodarea[i].offset = n; + prodarea[i].len = tl.len; + memcpy(prodarea[i].tag, &frubuf[n+1] ,tl.len); + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, product[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) + printf("num Product fields = %d, last=%x, max = %d\n", + i,*pfru,maxprod ); + product_num = i; /*save number of existing product fields*/ + if (*pfru == 0x00) *pfru = FRU_END; /* insert end char if broken */ + } + + if (moff != 0) + { + /* multi-record area may contain several record headers + * 0 = record type id + * 1 = 0x02 or 0x80 if End-of-List + * 2 = record len + * 3 = record chksum + * 4 = header chksum + */ + pfru = &frubuf[moff]; + j = moff; + for (i = 0; j < sz; i++) + { + n = pfru[2]; /* len of this record */ + show_fru_multi(devstr,i,pfru[0],&pfru[5],n); + j += (5 + n); + if (pfru[1] & 0x80) j = sz; /*0x80 = end of list*/ + pfru += (5 + n); + } + } + + if ((frudev == 0) && (sa == bmc_sa)) { + char *s; + printf("%sSystem GUID %c ",devstr,bdelim); + for (i=0; i<16; i++) { + if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) s = "-"; + else s = ""; + printf("%s%02x",s,guid[i]); + } + printf("\n"); + } + return(ret); +} + +static int +write_fru_data(uchar id, ushort offset, uchar *data, int dlen, char fdebug) +{ + int ret = -1; + int chunk; + ushort fruoff; + uchar req[25]; + uchar resp[16]; + int sresp; + uchar cc; + int i, j; + + /* Write the buffer in small 16-byte (FRUCHUNK_SZ) chunks */ + req[0] = id; /* FRU Device ID (fruid) */ + fruoff = offset; + chunk = FRUCHUNK_SZ; + for (i = 0; i < dlen; i += chunk) { + req[1] = fruoff & 0x00ff; + req[2] = (fruoff & 0xff00) >> 8; + if ((i + chunk) > dlen) chunk = dlen - i; + memcpy(&req[3],&data[i],chunk); + if (fdebug) { + printf("write_fru_data[%d] (len=%d): ",i,chunk+3); + for (j = 0; j < chunk+3; j++) printf("%02x ",req[j]); + printf("\n"); + } + sresp = sizeof(resp); + ret = ipmi_cmd_mc(WRITE_FRU_DATA,req,(uchar)(chunk+3),resp,&sresp, + &cc,fdebug); + if ((ret == 0) && (cc != 0)) ret = cc & 0x00ff; + if (fdebug && ret == 0) + printf("write_fru_data[%d]: %d bytes written\n",i,resp[0]); + if (ret != 0) break; + fruoff += chunk; + } + return(ret); +} + +/* + * write_product + * Updates the FRU Product area only. + * Note that this function will always provide >=8 product fields, + * even if the original had less than 8. + * inputs: prodnew = array of new strings to write + * frubuf = contains existing FRU data + * newdata = new product area buffer, malloc'd + * outputs: returns 0 if successful + */ +int +write_product(void) +{ + int ret = -1; + uchar req[25]; + uchar resp[16]; + int sresp; + uchar cc; + ushort fruoff; + int alen, clen; + int snlen, verlen; + uchar *pfru0; + uchar *pfru; + uchar *pnew; + int i, j, k, n, plen, newlen, max, plimit; + int chas_offset; + int prod_offset; + int mult_offset, mult_len; + uchar chksum; + int chunk; + + chas_offset = frubuf[2] * 8; // offset of chassis data + prod_offset = frubuf[4] * 8; // offset of product data + plen = frubuf[prod_offset+1] * 8; // length of product data + mult_offset = frubuf[5] * 8; + mult_len = 0; + if (mult_offset > 0) { + for (i = mult_offset; i < sfru; ) { + mult_len += (5 + frubuf[i+2]); + if (frubuf[i+1] & 0x80) break; + i = mult_len; + } + } + /* Check if asset tag will fit in product data area of FRU. */ + if (fdebug) + printf("write_product: fru[4,p]=[%02x,%02x] prod_off=%d, plen=%d\n", + frubuf[4],frubuf[prod_offset+1],prod_offset,plen); + if (plen > sfru) return ERR_LENMAX; // product bigger than buffer + if (prodnew[IPROD_ASSET].len > plen) return ERR_LENMAX; + /* if asset bigger than product data, error. */ + /* asset comes after sernum, so this check works for both */ + + newdata = malloc(sfru); /* but should not need more than plen bytes */ + if (newdata == NULL) return(get_errno()); + memset(newdata,0,sfru); + pnew = &newdata[0]; + /* Set pointer to start of chassis area */ + pfru = &frubuf[chas_offset]; + + /* Product Area Header (3 bytes): + [0] = 0x01; * format ver 1 * + [1] = 0x0a; *product area size (in 8-byte mult)* + [2] = 0x00; *lang=english * + Usually max product area is 3 + 8*32 = 259 mod 8 = 264. + */ + pfru0 = &frubuf[prod_offset]; + pfru = &frubuf[prod_offset]; + j = 3; + memcpy(pnew,pfru,j); + pfru += j; + pnew += j; + n = j; + if (mult_offset > 0) plimit = plen; + else plimit = sfru - prod_offset; /*plen can expand*/ + + for (i = 0; i < NUM_PRODUCT_FIELDS; i++) + { + j = prodarea[i].len; /*new len*/ + k = pfru[0] & FRU_LEN_MASK; /*old len*/ + if (k == 1) { /*was 0xC1 FRU_END*/ + if ((vend_id == VENDOR_KONTRON) && (i == 3) && (j == 1)) { + /* fix Kontron 1-byte Version */ + prodarea[i].tag[1] = ' '; + j++; + } else + k = 0; + } + /* check for product area overflow */ + if (n + 2 >= plimit) { + if (fdebug) printf("Field %d is at %d, beyond product area size %d\n", + i+1,n+2,plimit); + break; + } else if ((n + 1 + j) >= plimit) { + if (fdebug) printf("Field %d at %d + %d, truncated, product size %d\n", + i+1,n+1,j,plimit); + j = 0; + } + pnew[0] = (j | FRU_TYPE_MASK); /*add type=3 to len*/ + memcpy(&pnew[1],prodarea[i].tag,j); + if (fdebug) { + printf("i=%d frubuf[%d]: %02x %02x %02x, j=%d k=%d n=%d\n", + i,(pfru-frubuf),pfru[0],pfru[1],pfru[2],j,k,n); + if (i >= product_num) + printf("Field %d is beyond existing %d fields\n",i+1,product_num); + } + pnew += j + 1; + pfru += k + 1; + n += j + 1; + } + + // n = (int)(pnew - newdata); /*new product area index*/ + k = (int)(pfru - pfru0); /*old product area index*/ + if (mult_offset > 0) /* do not expand if multi-record area there */ + max = plen - k; + else /* nothing else, can expand product area, up to sfru */ + max = sfru - (k + prod_offset); + if (fdebug) + printf("frubuf[%d]: %02x %02x %02x, j=%d k=%d n=%d remainder=%d\n", + (pfru-frubuf),pfru[0],pfru[1],pfru[2],j,k,n,max); + if (max < 0) max = 0; + /* copy trailing fru data from saved copy */ + for (i = 0; i < max; i++) { + pnew[i] = pfru[i]; + if (pfru[i] == FRU_END) { i++; break; } /*0xC1*/ + } + if (i == max) { /*never found 0xC1 FRU_END*/ + pnew[0] = FRU_END; /*mark this trailing field as empty*/ + i = 1; + } + newlen = n + i; + if (fdebug) printf("newbuf[%d]: %02x %02x %02x, j=%d newlen=%d plen=%d\n", + n,pnew[0],pnew[1],pnew[2],j,newlen,plen); + + /* round up to next 8-byte boundary */ + /* need one more byte for checksum, so if j=0, add 8 anyway */ + j = 8 - (newlen % 8); + for (i = 0; i < j; i++) newdata[newlen++] = 0; + if (newlen < plen) newlen = plen; /* don't shrink the product area */ + newdata[1] = newlen / 8; // set length of product data + + /* include new checksum (calc over Product area) */ + chksum = calc_cksum(&newdata[0],newlen-1); + newdata[newlen-1] = chksum; + + if (fdebug) { + printf("old prod_area buffer (%d):",plen); + dumpbuf(&frubuf[prod_offset],plen); + printf("new prod_area buffer (%d):",newlen); + dumpbuf(newdata,newlen); + } + if (prod_offset + newlen >= sfru) return ERR_LENMAX; + if ((mult_offset > 0) && (newlen > plen)) return ERR_LENMAX; +#ifdef TEST + newlen = 0; /*don't actually write the new data, if testing*/ +#endif + + ret = write_fru_data(g_fruid, prod_offset, newdata, newlen, fdebug); + return(ret); +} + +#define CHUNKSZ 16 +#define LAST_REC 0xffff +#define STR_OFF 16 + +int get_sdr(ushort recid, ushort resid, ushort *recnext, + uchar *sdr, int *slen, uchar *pcc) +{ + uchar idata[6]; + uchar rdata[64]; + int sresp; + ushort cmd; + uchar cc = 0; + int len = 0; + int rc; + + idata[0] = resid & 0x00ff; + idata[1] = (resid & 0xff00) >> 8; + idata[2] = recid & 0x00ff; + idata[3] = (recid & 0xff00) >> 8; + idata[4] = 0; /*offset*/ + idata[5] = CHUNKSZ; /*bytes to read*/ + if (fdevsdrs) cmd = GET_DEVICE_SDR; + else cmd = GET_SDR; + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] ret = %d cc = %x sresp = %d\n", + recid,rc,cc,sresp); + if (rc == 0 && cc == 0xCA) { + idata[5] = 8; /*bytes to read*/ + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] ret = %d cc = %x sresp = %d\n", + recid,rc,cc,sresp); + } + *pcc = cc; + if (rc == 0 && cc == 0) { + *recnext = rdata[0] + (rdata[1] << 8); + memcpy(sdr,&rdata[2],sresp-2); + *slen = sdr[6] + 5; /*get actual SDR size*/ + len = sresp-2; + /* if an SDR locator record, get the rest of it. */ + if (sdr [3] == 0x11 || sdr[3] == 0x12) + if (*slen > CHUNKSZ) { + idata[0] = resid & 0x00ff; + idata[1] = (resid & 0xff00) >> 8; + idata[2] = recid & 0x00ff; + idata[3] = (recid & 0xff00) >> 8; + idata[4] = CHUNKSZ; /*offset*/ + idata[5] = *slen - CHUNKSZ; /*bytes to read*/ + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] 2nd ret=%d cc=%x sresp=%d\n", + recid,rc,cc,sresp); + if (rc == 0 && cc == 0) { + sresp -= 2; + memcpy(&sdr[len],&rdata[2],sresp); + len += sresp; + } + } + *slen = len; + } + return(rc); +} + +void show_loadfru_error(uchar sa, uchar fruid, int ret) +{ + if (ret == 0) return; + switch(ret) { + case 0x081: printf("\tFRU(%x,%x) device busy\n",sa,fruid); break; + case 0x0C3: printf("\tFRU(%x,%x) timeout, not found\n",sa,fruid); break; + case 0x0CB: printf("\tFRU(%x,%x) not present\n",sa,fruid); break; + default: printf("load_fru(%x,%x) error = %d (0x%x)\n", + sa,fruid,ret,ret); + break; + } + return; +} + +#ifdef METACOMMAND +int i_ifruset(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret; + int c; + char DevRecord[16]; + ushort recid; + ushort nextid; + ushort rsvid; + uchar sdr[40]; + char biosver[80]; + uchar cc; + uchar sa; + uchar fruid = 0; + uchar frutype = 0; + int len, i; + char *s1; + FILE *fp; + + printf("%s: version %s\n",progname,progver); + parse_lan_options('V',"4",0); /*request admin priv by default*/ + while ( (c = getopt( argc, argv,"a:bcd:h:i:f:m:n:o:p:r:s:u:v:xyz:T:V:J:EYF:P:N:R:U:Z:?")) != EOF ) + switch(c) { + case 'x': fdebug = 1; break; + case 'y': fdoanyway = 1; break; + case 'b': fonlybase = 1; + g_frutype = 0x07; break; + case 'c': fcanonical = 1; bdelim = BDELIM; break; +#ifdef TEST + case 'h': + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(chassis_name,optarg,len); + if (len == 1) { /* add a space */ + chassis_name[1] = ' '; + chassis_name[2] = 0; + } + } + break; +#else + case 'h': fonlyhsc = 1; /* can use -m00c000s instead */ + g_frutype = 0x0f; break; +#endif + case 'a': + fwritefru |= 0x01; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_ASSET].tag,optarg,len); + prodnew[IPROD_ASSET].len = len; + } + break; + case 'f': + fwritefru |= 0x04; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_FRUID].tag,optarg,len); + prodnew[IPROD_FRUID].len = len; + } + break; + case 'n': + fwritefru |= 0x20; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_NAME].tag,optarg,len); + prodnew[IPROD_NAME].len = len; + } + break; + case 'o': + fwritefru |= 0x10; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_OEM].tag,optarg,len); + prodnew[IPROD_OEM].len = len; + } + break; + case 'p': + fwritefru |= 0x40; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_PART].tag,optarg,len); + prodnew[IPROD_PART].len = len; + } + break; + case 'u': + fwritefru |= 0x80; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_MANUF].tag,optarg,len); + prodnew[IPROD_MANUF].len = len; + } + break; + case 's': + fwritefru |= 0x02; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_SERNUM].tag,optarg,len); + prodnew[IPROD_SERNUM].len = len; + } + break; + case 'v': + fwritefru |= 0x08; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_VERS].tag,optarg,len); + prodnew[IPROD_VERS].len = len; + } + break; + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + printf("set MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'z': /* set local IPMB MC sa */ + sa = htoi(&optarg[0]); /*device slave address*/ + ipmi_set_mymc(g_bus, sa, g_lun,ADDR_IPMB); + bmc_sa = sa; + case 'i': fonlybase = 1; /*specify a fru id*/ + if (strncmp(optarg,"0x",2) == 0) g_fruid = htoi(&optarg[2]); + else g_fruid = htoi(optarg); + printf("Using FRU ID 0x%02x\n",g_fruid); + break; + case 'd': fdump = 1; /*dump fru to a file*/ + binfile = optarg; + break; + case 'r': frestore = 1; /*restore fru from a file*/ + fwritefru = 0x100; + binfile = optarg; + break; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-bcimx -unpvsafo -NUPREFTVY]\n",progname); + printf(" -u manu Sets Product Manufacturer (0)\n"); + printf(" -n name Sets Product Name (1)\n"); + printf(" -p part Sets Product Part Number (2)\n"); + printf(" -v vers Sets Product Version (3)\n"); + printf(" -s snum Sets Product Serial Num (4)\n"); + printf(" -a tag Sets Product Asset Tag (5)\n"); + printf(" -f fru Sets Product FRU File ID (6)\n"); + printf(" -o oem Sets Product OEM Field (7)\n"); + // printf(" -h chname Sets the Chassis Name \n"); + printf(" -b Only show Baseboard FRU data\n"); + printf(" -c show Canonical, delimited output\n"); + printf(" -d Dump FRU to a file\n"); + printf(" -r Restore FRU from a file\n"); + printf(" -i 00 Get/Set a specific FRU ID\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -x Display extra debug messages\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + // if (is_remote() && fwritefru) parse_lan_options('V',"4",0); + + ret = ipmi_getdeviceid( DevRecord, sizeof(DevRecord),fdebug); + if (ret == 0) { + uchar ipmi_maj, ipmi_min; + ipmi_maj = DevRecord[4] & 0x0f; + ipmi_min = DevRecord[4] >> 4; + vend_id = DevRecord[6] + (DevRecord[7] << 8) + (DevRecord[8] << 16); + prod_id = DevRecord[9] + (DevRecord[10] << 8); + show_devid( DevRecord[2], DevRecord[3], ipmi_maj, ipmi_min); + if ((DevRecord[1] & 0x80) == 0x80) fdevsdrs = 1; + if (vend_id == VENDOR_NEC) fdevsdrs = 0; + else if (vend_id == VENDOR_INTEL) { + if (prod_id == 0x003E) { + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + } + } + } else { + goto do_exit; + } + + ret = ipmi_getpicmg( DevRecord, sizeof(DevRecord),fdebug); + if (ret == 0) fpicmg = 1; + if ((vend_id == VENDOR_INTEL) && (!fpicmg)) + fdevsdrs = 0; /* override, use SDR repository*/ + if (fdebug) printf("bmc_sa = %02x fdevsdrs = %d\n",bmc_sa,fdevsdrs); + + if (fset_mc) { + /* target a specific MC via IPMB (usu a picmg blade) */ + if (fdebug) printf("set_mc: %02x:%02x:%02x type=%d\n", + g_bus,g_sa,g_lun,g_addrtype); + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + fonlybase = 1; /*only show this MC*/ + } else { + g_sa = bmc_sa; /* BMC_SA = 0x20 */ + } + if (g_frutype == 0) { + g_frutype = 0x01; /* other = "Component" */ + } + + if (!fonlybase && !fonlyhsc) { + /* loop thru SDRs to find FRU devices */ +#ifdef NOT_YET + { /* get SDR Repository Info (needs to be copied here)*/ + ret = GetSDRRepositoryInfo(&j,&fdevsdrs); + if (fdebug) printf("GetSDRRepositoryInfo: ret=%x nSDRs=%d\n",ret,j); + } +#endif + { /* reserve the SDR repository */ + uchar resp[16]; + int sresp; + uchar cc; + ushort cmd; + sresp = sizeof(resp); + if (fdevsdrs) cmd = RESERVE_DEVSDR_REP; + else cmd = RESERVE_SDR_REP; + ret = ipmi_cmd_mc(cmd, NULL, 0, resp, &sresp, &cc, 0); + if (fdebug) printf("ipmi_cmd RESERVE status = %d, cc = %x\n",ret,cc); + rsvid = resp[0] + (resp[1] << 8); + } + recid = 0; + while (recid != LAST_REC) + { + char idstr[32]; + int ilen; + + len = sizeof(sdr); /*sizeof(sdr); get 32 sdr bytes*/ + ret = get_sdr(recid,rsvid,&nextid,sdr,&len,&cc); + if ((ret != 0) || (cc != 0)) { + printf("SDR[%04x] error %d ccode = %x\n",recid,ret,cc); + break; + } + fgetfru = 0; + if ((sdr[3] == 0x11) || (sdr[3] == 0x12)) /* SDR FRU or IPMB type */ + { + if (len > STR_OFF) { + ilen = len - STR_OFF; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[STR_OFF],ilen); + idstr[ilen] = 0; + } else idstr[0] = 0; + sa = sdr[5]; /* usu 0x20 for bmc_sa */ + /* Get its FRU data */ + if ((sdr[3] == 0x11) && (sdr[7] & 0x80)) { /* FRU SDRs */ + /* It is a logical FRU device */ + if (fcanonical) + printf("SDR[%04x] FRU %c %s\n", recid, bdelim, idstr); + else + printf("SDR[%04x] FRU %02x %02x %02x %02x %s\n", recid, + sdr[5],sdr[6],sdr[12],sdr[13],idstr); + fruid = sdr[6]; + frutype = sdr[12]; + if (sa == bmc_sa && fruid == 0) /*do this below*/; + else + switch(sdr[12]) /*FRU entity id*/ + { + case 0x0a: /*Power Supply*/ + case 0x20: /*DIMM*/ + case 0x15: /*Power Cage*/ + default: + fgetfru = 1; + break; + } + } else if (sdr[3] == 0x12) { /* IPMB SDRs (DLRs for MCs) */ + if (fcanonical) + printf("SDR[%04x] IPMB %c %s\n", recid, bdelim, idstr); + else + printf("SDR[%04x] IPMB %02x %02x %02x %02x %s\n", recid, + sdr[5],sdr[6],sdr[12],sdr[13],idstr); + fruid = 0; /*every MC must have fruid 0*/ + frutype = sdr[12]; + if (sa == bmc_sa && fruid == 0) { /*do bmc_sa,0 below*/ + if (fdebug) printf("do bmc_sa %02x below\n",sa); + g_frutype = frutype; + } else if (frutype == 0x2e) { /*skip ME*/ + if (fdebug) printf("skipping ME sa %02x, %02x\n",sa,fruid); + } else if (sa == 0x28) { /*do nothing for Bridge Ctlr sa=0x28*/ + if (fdebug) printf("skipping IPMB sa %02x, %02x\n",sa,fruid); + } else if (sa == 0xC0) { /* HotSwap Backplane (sa=0xC0) */ + /* Note: Loading sa 0xC0 over ipmi lan gives a timeout + * error, but it works locally. */ + fgetfru = 1; + } else { /* other misc sa,fruid */ + fgetfru = 1; + } + } + if (fgetfru) { + uchar adrtype; + adrtype = g_addrtype; + if (fdebug) printf("set_mc %02x:%02x:%02x type=%d fruid=%02x\n", + g_bus,sa,g_lun,adrtype,fruid); + ipmi_set_mc(g_bus, sa, g_lun,adrtype); + ret = load_fru(sa,fruid,frutype); + if (ret != 0) { + show_loadfru_error(sa,fruid,ret); + free_fru(); + } else { + ret = show_fru(sa,fruid,frutype); + if (ret != 0) printf("show_fru error = %d\n",ret); + free_fru(); + } + ipmi_restore_mc(); + } + } /*endif FRU/IPMB SDR */ + recid = nextid; + } /*end while sdrs*/ + } /*endif not fonlybase*/ + + /* load the FRU data for Baseboard (address 0x20) */ + printf("\n"); + sa = g_sa; /* bmc_sa = BMC_SA = 0x20 */ + if (fonlyhsc) { sa = 0xC0; g_addrtype = ADDR_SMI; + ipmi_set_mc(g_bus,sa,g_lun,g_addrtype); + } + if (g_addrtype == ADDR_IPMB) + ipmi_set_mc(g_bus,sa,g_lun,g_addrtype); + ret = load_fru(sa,g_fruid,g_frutype); + if (ret != 0) { + show_loadfru_error(sa,g_fruid,ret); + free_fru(); + goto do_exit; + } + + /* display the Baseboard FRU data */ + ret = show_fru(sa,g_fruid,g_frutype); + if (ret != 0) printf("show_fru error = %d\n",ret); + + if (!is_remote()) { + char devstr[24]; + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s,%02x] ",FruTypeString(g_frutype),g_fruid); + i = get_BiosVersion(biosver); + if (i == 0) + printf("%sBIOS Version %c %s\n",devstr,bdelim,biosver); + } + + if (fdump && ret == 0) { + /* Dump FRU to a binary file */ + fp = fopen(binfile,"w"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + } else { + printf("Writing FRU size %d to %s ...\n",sfru,binfile); + len = fwrite(frubuf, 1, sfru, fp); + fclose(fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d writing file %s\n",ret,binfile); + } else ret = 0; + } + } else if (frestore) { + uchar cksum; + /* Restore FRU from a binary file */ + fp = fopen(binfile,"r"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + } else { + ret = 0; + /* sfru and frubuf were set from load_fru above. */ + len = fread(frubuf, 1, sfru, fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d reading file %s\n",ret,binfile); + sfru = 0; /*for safety*/ + } + fclose(fp); + if (fdebug) { + printf("FRU buffer from file (%d):",sfru); + dumpbuf(frubuf,sfru); + } + /* Do some validation of the FRU buffer header */ + cksum = calc_cksum(&frubuf[0],7); + if (fdebug) + printf("header, len=8, cksum0 = %02x, cksum1 = %02x\n", + frubuf[7],cksum); + if (frubuf[7] != cksum) { + printf("Not a valid FRU file\n"); + ret = ERR_BAD_FORMAT; + free_fru(); + } + if (ret == 0) { /*successfully read data*/ + printf("Writing FRU size %d from %s ...\n",sfru,binfile); + ret = write_fru_data(g_fruid, 0, frubuf, sfru, fdebug); + free_fru(); + if (ret != 0) printf("write_fru error %d (0x%02x)\n",ret,ret); + else { /* successful, show new data */ + ret = load_fru(sa,g_fruid,g_frutype); + if (ret != 0) show_loadfru_error(sa,g_fruid,ret); + else ret = show_fru(sa,g_fruid,g_frutype); + free_fru(); + } + } + } + } /*end-else frestore */ + else if ((fwritefru != 0) && ret == 0) { + printf("\nWriting new product data (%s,%s,%s,%s,%s,%s,%s,%s) ...\n", + prodnew[0].tag, prodnew[1].tag, prodnew[2].tag, + prodnew[3].tag, prodnew[4].tag, prodnew[5].tag, + prodnew[6].tag, prodnew[7].tag); + for (i = 0; i < NUM_PRODUCT_FIELDS; i++) { + len = prodnew[i].len; + if (len > 0) { + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + if (len == 1) { + prodnew[i].tag[1] = ' '; + len++; + } + prodarea[i].len = len; + memcpy(prodarea[i].tag,prodnew[i].tag,len); + } + } + ret = write_product(); + free_fru(); + if (ret != 0) printf("write_product error %d (0x%02x)\n",ret,ret); + else { /* successful, show new data */ + ret = load_fru(sa,g_fruid,g_frutype); + if (ret != 0) show_loadfru_error(sa,g_fruid,ret); + else ret = show_fru(sa,g_fruid,g_frutype); + free_fru(); + } + } + else + free_fru(); + +do_exit: + ipmi_close_(); + show_outcome(progname,ret); + return(ret); +} + +/* end ifruset.c */ diff --git a/util/ifwum.c b/util/ifwum.c new file mode 100644 index 0000000..1e7d547 --- /dev/null +++ b/util/ifwum.c @@ -0,0 +1,1697 @@ +/* + * ifwum.c + * Handle firmware update manager IPMI command functions + * + * Change history: + * 08/20/2010 ARCress - ported from ipmitool/lib/ipmi_fwum.c + * + *--------------------------------------------------------------------- + */ +/* + * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved. + * + * Base on code from + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifdef WIN32 +#include <windows.h> +#include "getopt.h" +#elif defined(HPUX) +/* getopt defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <time.h> +#ifdef LINUX +#include <unistd.h> +#endif +#include "ipmicmd.h" +#include "ifwum.h" + +/****************************************************************************** +* HISTORY +* =========================================================================== +* 2007-01-11 [FI] +* - Incremented to version 1.3 +* - Added lan packet size reduction mechanism to workaround fact +* that lan iface will not return C7 on excessive length +* +*****************************************************************************/ + +extern int verbose; /*see ipmilanplus.c*/ +extern void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/ +// extern int ipmi_sendrecv(struct ipmi_rq * req, uint8_t *rsp, int *rsp_len); +extern char * get_mfg_str(uchar *rgmfg, int *pmfg); /*ihealth.c*/ +#ifndef HAVE_LANPLUS +/* define these routines here if no lanplus/helper.c */ +extern uint16_t buf2short(uint8_t * buf); /*ipmilanplus.c*/ +// const char * val2str(uint16_t val, const struct valstr *vs); +#endif + +#define VERSION_MAJ 1 +#define VERSION_MIN 3 + +/* global variables */ +static char * progname = "ifwum"; +static char * progver = "1.3"; +static char fdebug = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + +typedef enum eKFWUM_Task +{ + KFWUM_TASK_INFO, + KFWUM_TASK_STATUS, + KFWUM_TASK_DOWNLOAD, + KFWUM_TASK_UPGRADE, + KFWUM_TASK_START_UPGRADE, + KFWUM_TASK_ROLLBACK, + KFWUM_TASK_TRACELOG +}tKFWUM_Task; + +typedef enum eKFWUM_BoardList +{ + KFWUM_BOARD_KONTRON_UNKNOWN = 0, + KFWUM_BOARD_KONTRON_5002 = 5002, +}tKFWUM_BoardList; + +typedef enum eKFWUM_IanaList +{ + KFWUM_IANA_KONTRON = 15000, +}tKFWUM_IanaList; + +typedef struct sKFWUM_BoardInfo +{ + tKFWUM_BoardList boardId; + tKFWUM_IanaList iana; +}tKFWUM_BoardInfo; + + +#define KFWUM_STATUS_OK 0 +#define KFWUM_STATUS_ERROR -1 +typedef int tKFWUM_Status; +//typedef enum eKFWUM_Status +//{ +// KFWUM_STATUS_OK, +// KFWUM_STATUS_ERROR +//}tKFWUM_Status; + +typedef enum eKFWUM_DownloadType +{ + KFWUM_DOWNLOAD_TYPE_ADDRESS = 0, + KFWUM_DOWNLOAD_TYPE_SEQUENCE, +}tKFWUM_DownloadType; + +typedef enum eKFWUM_DownloadBuffferType +{ + KFWUM_SMALL_BUFFER_TYPE = 0, + KFUMW_BIG_BUFFER_TYPE +}tKFWUM_DownloadBuffferType; + +typedef struct sKFWUM_InFirmwareInfo +{ + unsigned long fileSize; + unsigned short checksum; + unsigned short sumToRemoveFromChecksum; + /* Since the checksum is added in the bin + after the checksum is calculated, we + need to remove the each byte value. This + byte will contain the addition of both bytes*/ + tKFWUM_BoardList boardId; + unsigned char deviceId; + unsigned char tableVers; + unsigned char implRev; + unsigned char versMajor; + unsigned char versMinor; + unsigned char versSubMinor; + unsigned char sdrRev; + tKFWUM_IanaList iana; +}tKFWUM_InFirmwareInfo; + +typedef struct sKFWUM_SaveFirmwareInfo +{ + tKFWUM_DownloadType downloadType; + unsigned char bufferSize; + unsigned char overheadSize; +}tKFWUM_SaveFirmwareInfo; + +#define KFWUM_SMALL_BUFFER 32 /* Minimum size (IPMB/IOL/old protocol) */ +#define KFWUM_BIG_BUFFER 32 /* Maximum size on KCS interface */ + +#define KFWUM_OLD_CMD_OVERHEAD 6 /*3 address + 1 size + 1 checksum + 1 command*/ +#define KFWUM_NEW_CMD_OVERHEAD 4 /*1 sequence+ 1 size + 1 checksum + 1 command*/ +#define KFWUM_PAGE_SIZE 256 + +static unsigned char fileName[512]; +static unsigned char firmBuf[1024*512]; +static tKFWUM_SaveFirmwareInfo saveFirmwareInfo; + +static void KfwumOutputHelp(void); +static int KfwumMain(void * intf, tKFWUM_Task task); +static tKFWUM_Status KfwumGetFileSize(unsigned char * pFileName, + unsigned long * pFileSize); +static tKFWUM_Status KfwumSetupBuffersFromFile(unsigned char * pFileName, + unsigned long fileSize); +static void KfwumShowProgress( const unsigned char * task, + unsigned long current, unsigned long total); +static unsigned short KfwumCalculateChecksumPadding(unsigned char * pBuffer, + unsigned long totalSize); + + +static tKFWUM_Status KfwumGetInfo(void * intf, unsigned char output, + unsigned char *pNumBank); +static tKFWUM_Status KfwumGetDeviceInfo(void * intf, + unsigned char output, tKFWUM_BoardInfo * pBoardInfo); +static tKFWUM_Status KfwumGetStatus(void * intf); +static tKFWUM_Status KfwumManualRollback(void * intf); +static tKFWUM_Status KfwumStartFirmwareImage(void * intf, + unsigned long length,unsigned short padding); +static tKFWUM_Status KfwumSaveFirmwareImage(void * intf, + unsigned char sequenceNumber, unsigned long address, + unsigned char *pFirmBuf, unsigned char * pInBufLength); +static tKFWUM_Status KfwumFinishFirmwareImage(void * intf, + tKFWUM_InFirmwareInfo firmInfo); +static tKFWUM_Status KfwumUploadFirmware(void * intf, + unsigned char * pBuffer, unsigned long totalSize); +static tKFWUM_Status KfwumStartFirmwareUpgrade(void * intf); + +static tKFWUM_Status KfwumGetInfoFromFirmware(unsigned char * pBuf, + unsigned long bufSize, tKFWUM_InFirmwareInfo * pInfo); +static void KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo); + +static tKFWUM_Status KfwumGetTraceLog(void * intf); + +tKFWUM_Status KfwumValidFirmwareForBoard(tKFWUM_BoardInfo boardInfo, + tKFWUM_InFirmwareInfo firmInfo); +static void KfwumOutputInfo(tKFWUM_BoardInfo boardInfo, + tKFWUM_InFirmwareInfo firmInfo); + + +/* ipmi_fwum_main - entry point for this ipmitool mode + * + * @intf: ipmi interface + * @arc : number of arguments + * @argv : point to argument array + * + * returns 0 on success + * returns -1 on error + */ +int ipmi_fwum_main(void * intf, int argc, char ** argv) +{ + int rv = ERR_USAGE; /*1*/ + printf("FWUM extension Version %d.%d\n", VERSION_MAJ, VERSION_MIN); + if ((!argc) || ( !strncmp(argv[0], "help", 4))) + { + KfwumOutputHelp(); + } + else + { + if (!strncmp(argv[0], "info", 4)) + { + rv = KfwumMain(intf, KFWUM_TASK_INFO); + } + else if (!strncmp(argv[0], "status", 6)) + { + rv = KfwumMain(intf, KFWUM_TASK_STATUS); + } + else if (!strncmp(argv[0], "rollback", 8)) + { + rv = KfwumMain(intf, KFWUM_TASK_ROLLBACK); + } + else if (!strncmp(argv[0], "download", 8)) + { + if((argc >= 2) && (strlen(argv[1]) > 0)) + { + /* There is a file name in the parameters */ + if(strlen(argv[1]) < 512) + { + strcpy((char *)fileName, argv[1]); + printf("Firmware File Name : %s\n", fileName); + + rv = KfwumMain(intf, KFWUM_TASK_DOWNLOAD); + } + else + { + fprintf(stderr,"File name must be smaller than 512 bytes\n"); + } + } + else + { + fprintf(stderr,"A path and a file name must be specified\n"); + } + } + else if (!strncmp(argv[0], "upgrade", 7)) + { + if((argc >= 2) && (strlen(argv[1]) > 0)) + { + /* There is a file name in the parameters */ + if(strlen(argv[1]) < 512) + { + strcpy((char *)fileName, argv[1]); + printf("Upgrading using file name %s\n", fileName); + rv = KfwumMain(intf, KFWUM_TASK_UPGRADE); + } + else + { + fprintf(stderr,"File name must be smaller than 512 bytes\n"); + } + } + else + { + rv = KfwumMain(intf, KFWUM_TASK_START_UPGRADE); + } + + } + else if (!strncmp(argv[0], "tracelog", 8)) + { + rv = KfwumMain(intf, KFWUM_TASK_TRACELOG); + } + else + { + printf("Invalid KFWUM command: %s\n", argv[0]); + } + } + return rv; +} + + +static void KfwumOutputHelp(void) +{ + printf("KFWUM Commands: info status download upgrade rollback tracelog\n"); +} + + +/****************************************/ +/** private definitions and macros **/ +/****************************************/ +typedef enum eFWUM_CmdId +{ + KFWUM_CMD_ID_GET_FIRMWARE_INFO = 0, + KFWUM_CMD_ID_KICK_IPMC_WATCHDOG = 1, + KFWUM_CMD_ID_GET_LAST_ANSWER = 2, + KFWUM_CMD_ID_BOOT_HANDSHAKE = 3, + KFWUM_CMD_ID_REPORT_STATUS = 4, + KFWUM_CMD_ID_GET_FIRMWARE_STATUS = 7, + KFWUM_CMD_ID_START_FIRMWARE_UPDATE = 9, + KFWUM_CMD_ID_START_FIRMWARE_IMAGE = 0x0a, + KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE = 0x0b, + KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE = 0x0c, + KFWUM_CMD_ID_READ_FIRMWARE_IMAGE = 0x0d, + KFWUM_CMD_ID_MANUAL_ROLLBACK = 0x0e, + KFWUM_CMD_ID_GET_TRACE_LOG = 0x0f, + KFWUM_CMD_ID_STD_MAX_CMD, + KFWUM_CMD_ID_EXTENDED_CMD = 0xC0 +} tKFWUM_CmdId; + + + +/****************************************/ +/** global/static variables definition **/ +/****************************************/ + +/****************************************/ +/** functions definition **/ +/****************************************/ + +/******************************************************************************* +* +* Function Name: KfwumMain +* +* Description: This function implements the upload of the firware data +* received as parameters. +* +* Restriction: Called only from main +* +* Input: unsigned char * pBuffer[] : The buffers +* unsigned long bufSize : The size of the buffers +* +* Output: None +* +* Global: none +* +* Return: tIFWU_Status (success or failure) +* +*******************************************************************************/ +static int KfwumMain(void * intf, tKFWUM_Task task) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + tKFWUM_BoardInfo boardInfo; + tKFWUM_InFirmwareInfo firmInfo = { 0 }; + unsigned long fileSize = 0; + static unsigned short padding; + + if((status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_INFO)) + { + unsigned char notUsed; + if(verbose) + { + printf("Getting Kontron FWUM Info\n"); + } + status = KfwumGetDeviceInfo(intf, 1, &boardInfo); + status = KfwumGetInfo(intf, 1, ¬Used); + + } + + + if((status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_STATUS)) + { + if(verbose) + { + printf("Getting Kontron FWUM Status\n"); + } + status = KfwumGetStatus(intf); + } + + if( (status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_ROLLBACK) ) + { + status = KfwumManualRollback(intf); + } + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) + ) + ) + { + status = KfwumGetFileSize(fileName, &fileSize); + if(status == KFWUM_STATUS_OK) + { + status = KfwumSetupBuffersFromFile(fileName, fileSize); + if(status == KFWUM_STATUS_OK) + { + padding = KfwumCalculateChecksumPadding(firmBuf, fileSize); + } + } + if(status == KFWUM_STATUS_OK) + { + status = KfwumGetInfoFromFirmware(firmBuf, fileSize, &firmInfo); + } + if(status == KFWUM_STATUS_OK) + { + status = KfwumGetDeviceInfo(intf, 0, &boardInfo); + } + + if(status == KFWUM_STATUS_OK) + { + status = KfwumValidFirmwareForBoard(boardInfo,firmInfo); + } + + if (status == KFWUM_STATUS_OK) + { + unsigned char notUsed; + KfwumGetInfo(intf, 0, ¬Used); + } + + KfwumOutputInfo(boardInfo,firmInfo); + } + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) + ) + ) + { + status = KfwumStartFirmwareImage(intf, fileSize, padding); + } + + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) + ) + ) + { + status = KfwumUploadFirmware(intf, firmBuf, fileSize); + } + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) + ) + ) + { + status = KfwumFinishFirmwareImage(intf, firmInfo); + } + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) + ) + ) + { + status = KfwumGetStatus(intf); + } + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_START_UPGRADE) + ) + ) + { + status = KfwumStartFirmwareUpgrade(intf); + } + + if((status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_TRACELOG)) + { + status = KfwumGetTraceLog(intf); + } + + return(status); +} + +/* KfwumGetFileSize - gets the file size + * + * @pFileName : filename ptr + * @pFileSize : output ptr for filesize + * + * returns KFWUM_STATUS_OK or KFWUM_STATUS_ERROR + */ +static tKFWUM_Status KfwumGetFileSize(unsigned char * pFileName, + unsigned long * pFileSize) +{ + tKFWUM_Status status = KFWUM_STATUS_ERROR; + FILE * pFileHandle; + + pFileHandle = fopen((const char *)pFileName, "rb"); + + if(pFileHandle) + { + if(fseek(pFileHandle, 0L , SEEK_END) == 0) + { + *pFileSize = ftell(pFileHandle); + + if( *pFileSize != 0) + { + status = KFWUM_STATUS_OK; + } + } + fclose(pFileHandle); + } + + return(status); +} + +/* KfwumSetupBuffersFromFile - small buffers are used to store the file data + * + * @pFileName : filename ptr + * unsigned long : filesize + * + * returns KFWUM_STATUS_OK or KFWUM_STATUS_ERROR + */ +#define MAX_FW_BUFFER_SIZE 1024*16 +static tKFWUM_Status KfwumSetupBuffersFromFile(unsigned char * pFileName, + unsigned long fileSize) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + FILE * pFileHandle; + + pFileHandle = fopen((const char *)pFileName, "rb"); + + if(pFileHandle) + { + int count = fileSize / MAX_FW_BUFFER_SIZE; + int modulus = fileSize % MAX_FW_BUFFER_SIZE; + int qty =0; + + rewind(pFileHandle); + + for(qty=0;qty<count;qty++) + { + KfwumShowProgress((const unsigned char *)"Reading Firmware from File", qty, count ); + if(fread(&firmBuf[qty*MAX_FW_BUFFER_SIZE], 1, MAX_FW_BUFFER_SIZE ,pFileHandle) + == MAX_FW_BUFFER_SIZE) + { + status = KFWUM_STATUS_OK; + } + } + if( modulus ) + { + if(fread(&firmBuf[qty*MAX_FW_BUFFER_SIZE], 1, modulus, pFileHandle) == modulus) + { + status = KFWUM_STATUS_OK; + } + } + if(status == KFWUM_STATUS_OK) + { + KfwumShowProgress((const unsigned char *)"Reading Firmware from File", 100, 100); + } + fclose(pFileHandle); + } + return(status); +} + +/* KfwumShowProgress - helper routine to display progress bar + * + * Converts current/total in percent + * + * *task : string identifying current operation + * current: progress + * total : limit + */ +#define PROG_LENGTH 42 +void KfwumShowProgress( const unsigned char * task, unsigned long current , + unsigned long total) +{ + static unsigned long staticProgress=0xffffffff; + unsigned char spaces[PROG_LENGTH + 1]; + unsigned short hash; + float percent = ((float)current/total); + unsigned long progress; + + progress = 100*((unsigned long)percent); + if(staticProgress == progress) + { + /* We displayed the same last time.. so don't do it */ + } + else + { + staticProgress = progress; + + + printf("%-25s : ",task); /* total 20 bytes */ + + hash = ( (unsigned short)percent * PROG_LENGTH ); + memset(spaces,'#', hash); + spaces[ hash ] = '\0'; + printf("%s", spaces ); + + memset(spaces,' ',( PROG_LENGTH - hash ) ); + spaces[ ( PROG_LENGTH - hash ) ] = '\0'; + printf("%s", spaces ); + + + printf(" %3ld %%\r",progress); /* total 7 bytes */ + + if( progress == 100 ) + { + printf("\n"); + } + fflush(stdout); + } +} + +/* KfwumCalculateChecksumPadding + * + * TBD + * + */ +static unsigned short KfwumCalculateChecksumPadding(unsigned char * pBuffer, + unsigned long totalSize) +{ + unsigned short sumOfBytes = 0; + unsigned short padding; + unsigned long counter; + + for(counter = 0; counter < totalSize; counter ++ ) + { + sumOfBytes += pBuffer[counter]; + } + + padding = 0 - sumOfBytes; + return padding; +} + +/****************************************************************************** +******************************* COMMANDS ************************************** +******************************************************************************/ +#pragma pack(1) +struct KfwumGetInfoResp { + unsigned char protocolRevision; + unsigned char controllerDeviceId; + struct + { + unsigned char mode:1; + unsigned char seqAdd:1; + unsigned char res : 6; + } byte; + unsigned char firmRev1; + unsigned char firmRev2; + unsigned char numBank; +}; // __attribute__ ((packed)); +#pragma pack() + + +/* KfwumGetInfo - Get Firmware Update Manager (FWUM) information + * + * * intf : IPMI interface + * output : when set to non zero, queried information is displayed + * pNumBank: output ptr for number of banks + */ +static tKFWUM_Status KfwumGetInfo(void * intf, unsigned char output, + unsigned char *pNumBank) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + static struct KfwumGetInfoResp *pGetInfo; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + int dtype; + uchar bus, sa, lun, mtype; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_GET_FIRMWARE_INFO; + req.msg.data_len = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("FWUM Firmware Get Info returned %d (0x%02x)\n",rv,rv); + status = rv; // KFWUM_STATUS_ERROR + } + + if(status == KFWUM_STATUS_OK) + { + pGetInfo = (struct KfwumGetInfoResp *) rsp; + if(output) + { + printf("\nFWUM info\n"); + printf("=========\n"); + printf("Protocol Revision : %02Xh\n", + pGetInfo->protocolRevision); + printf("Controller Device Id : %02Xh\n", + pGetInfo->controllerDeviceId); + printf("Firmware Revision : %u.%u%u", + pGetInfo->firmRev1, pGetInfo->firmRev2 >> 4, + pGetInfo->firmRev2 & 0x0f); + if(pGetInfo->byte.mode != 0) + { + printf(" - DEBUG BUILD\n"); + } + else + { + printf("\n"); + } + printf("Number Of Memory Bank : %u\n",pGetInfo->numBank); + } + * pNumBank = pGetInfo->numBank; + + /* Determine wich type of download to use: */ + /* Old FWUM or Old IPMC fw (data_len < 7) --> + Address with small buffer size */ + if ( (pGetInfo->protocolRevision) <= 0x05 || (rsp_len < 7 ) ) + { + saveFirmwareInfo.downloadType = KFWUM_DOWNLOAD_TYPE_ADDRESS; + saveFirmwareInfo.bufferSize = KFWUM_SMALL_BUFFER; + saveFirmwareInfo.overheadSize = KFWUM_OLD_CMD_OVERHEAD; + + if(verbose) + { + printf("Protocol Revision :"); + printf(" <= 5 detected, adjusting buffers\n"); + } + } + else /* Both fw are using the new protocol */ + { + saveFirmwareInfo.downloadType = KFWUM_DOWNLOAD_TYPE_SEQUENCE; + saveFirmwareInfo.overheadSize = KFWUM_NEW_CMD_OVERHEAD; + /* Buffer size depending on access type (Local or remote) */ + /* Look if we run remote or locally */ + + if(verbose) + { + printf("Protocol Revision :"); + printf(" > 5 optimizing buffers\n"); + } + + ipmi_get_mc(&bus, &sa, &lun, &mtype); + dtype = get_driver_type(); + if(is_remote()) /* covers lan and lanplus */ + { + saveFirmwareInfo.bufferSize = KFWUM_SMALL_BUFFER; + if(verbose) + { + printf("IOL payload size : %d\r\n" , + saveFirmwareInfo.bufferSize); + } + } else if ( (dtype == DRV_MV) && (sa != IPMI_BMC_SLAVE_ADDR) && + (mtype == ADDR_IPMB) ) + { + saveFirmwareInfo.bufferSize = KFWUM_SMALL_BUFFER; + if(verbose) + { + printf("IPMB payload size : %d\r\n" , + saveFirmwareInfo.bufferSize); + } + } + else + { + saveFirmwareInfo.bufferSize = KFWUM_BIG_BUFFER; + if(verbose) + { + printf("SMI payload size : %d\r\n", + saveFirmwareInfo.bufferSize); + } + } + } + } + return status; +} + +/* KfwumGetDeviceInfo - Get IPMC/Board information + * + * * intf : IPMI interface + * output : when set to non zero, queried information is displayed + * tKFWUM_BoardInfo: output ptr for IPMC/Board information + */ +static tKFWUM_Status KfwumGetDeviceInfo(void * intf, + unsigned char output, tKFWUM_BoardInfo * pBoardInfo) +{ + struct ipm_devid_rsp *pGetDevId; + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + char *mstr; + + /* Send Get Device Id */ + if(status == KFWUM_STATUS_OK) + { + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_DEVICE_ID; + req.msg.data_len = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error in Get Device Id Command %d (0x%02x)\n",rv,rv); + status = rv; // KFWUM_STATUS_ERROR + } + } + + if(status == KFWUM_STATUS_OK) + { + pGetDevId = (struct ipm_devid_rsp *) rsp; + pBoardInfo->iana = IPM_DEV_MANUFACTURER_ID(pGetDevId->manufacturer_id); + pBoardInfo->boardId = buf2short(pGetDevId->product_id); + if(output) + { + mstr = get_mfg_str(pGetDevId->manufacturer_id,NULL); + printf("\nIPMC Info\n"); + printf("=========\n"); + printf("Manufacturer Id : %u \t%s\n",pBoardInfo->iana,mstr); + printf("Board Id : %u\n",pBoardInfo->boardId); + printf("Firmware Revision : %u.%u%u", + pGetDevId->fw_rev1, pGetDevId->fw_rev2 >> 4, + pGetDevId->fw_rev2 & 0x0f); + if( + ( + ( pBoardInfo->iana == KFWUM_IANA_KONTRON) + && + (pBoardInfo->boardId == KFWUM_BOARD_KONTRON_5002) + ) + ) + { + printf(" SDR %u\n", pGetDevId->aux_fw_rev[0]); + } + else + { + printf("\n"); + } + } + } + + return status; +} + +#pragma pack(1) +struct KfwumGetStatusResp { + unsigned char bankState; + unsigned char firmLengthLSB; + unsigned char firmLengthMid; + unsigned char firmLengthMSB; + unsigned char firmRev1; + unsigned char firmRev2; + unsigned char firmRev3; +}; // __attribute__ ((packed)); +#pragma pack() + +const struct valstr bankStateValS[] = { + { 0x00, "Not programmed" }, + { 0x01, "New firmware" }, + { 0x02, "Wait for validation" }, + { 0x03, "Last Known Good" }, + { 0x04, "Previous Good" } +}; + +/* KfwumGetStatus - Get (and prints) FWUM banks information + * + * * intf : IPMI interface + */ +static tKFWUM_Status KfwumGetStatus(void * intf) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct KfwumGetStatusResp *pGetStatus; + unsigned char numBank; + unsigned char counter; + + if(verbose) + { + printf(" Getting Status!\n"); + } + + /* Retreive the number of bank */ + status = KfwumGetInfo(intf, 0, &numBank); + + for( + counter = 0; + (counter < numBank) && (status == KFWUM_STATUS_OK); + counter ++ + ) + { + /* Retreive the status of each bank */ + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_GET_FIRMWARE_STATUS; + req.msg.data = &counter; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("FWUM Firmware Get Status Error %d (0x%02x)\n",rv,rv); + status = rv; // KFWUM_STATUS_ERROR + } + + if(status == KFWUM_STATUS_OK) + { + pGetStatus = (struct KfwumGetStatusResp *) rsp; + printf("\nBank State %d : %s\n", counter, val2str( + pGetStatus->bankState, bankStateValS)); + if(pGetStatus->bankState) + { + unsigned long firmLength; + firmLength = pGetStatus->firmLengthMSB; + firmLength = firmLength << 8; + firmLength |= pGetStatus->firmLengthMid; + firmLength = firmLength << 8; + firmLength |= pGetStatus->firmLengthLSB; + + printf("Firmware Length : %ld bytes\n", firmLength); + printf("Firmware Revision : %u.%u%u SDR %u\n", + pGetStatus->firmRev1, pGetStatus->firmRev2 >> 4, + pGetStatus->firmRev2 & 0x0f, pGetStatus->firmRev3); + } + } + } + printf("\n"); + return status; +} +#pragma pack(1) +struct KfwumManualRollbackReq{ + unsigned char type; +}; // __attribute__ ((packed)); +#pragma pack() + + +/* KfwumManualRollback - Ask IPMC to rollback to previous version + * + * * intf : IPMI interface + */ +static tKFWUM_Status KfwumManualRollback(void * intf) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct KfwumManualRollbackReq thisReq; + + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_MANUAL_ROLLBACK; + + thisReq.type = 0; /* Wait BMC shutdown */ + + req.msg.data = (unsigned char *) &thisReq; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error in FWUM Manual Rollback Command %d (0x%02x)\n",rv,rv); + status = rv; // KFWUM_STATUS_ERROR + } + + if(status == KFWUM_STATUS_OK) + { + printf("FWUM Starting Manual Rollback \n"); + } + return status; +} + +#pragma pack(1) +struct KfwumStartFirmwareDownloadReq{ + unsigned char lengthLSB; + unsigned char lengthMid; + unsigned char lengthMSB; + unsigned char paddingLSB; + unsigned char paddingMSB; + unsigned char useSequence; +}; // __attribute__ ((packed)); +struct KfwumStartFirmwareDownloadResp { + unsigned char bank; +}; // __attribute__ ((packed)); +#pragma pack() + +static tKFWUM_Status KfwumStartFirmwareImage(void * intf, + unsigned long length,unsigned short padding) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct KfwumStartFirmwareDownloadResp *pResp; + struct KfwumStartFirmwareDownloadReq thisReq; + + thisReq.lengthLSB = (uchar)(length & 0x000000ff); + thisReq.lengthMid = (uchar)((length >> 8) & 0x000000ff); + thisReq.lengthMSB = (uchar)((length >> 16) & 0x000000ff); + thisReq.paddingLSB = padding & 0x00ff; + thisReq.paddingMSB = (padding>> 8) & 0x00ff; + thisReq.useSequence = 0x01; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_IMAGE; + req.msg.data = (unsigned char *) &thisReq; + + /* Look for download type */ + if ( saveFirmwareInfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS ) + { + req.msg.data_len = 5; + } + else + { + req.msg.data_len = 6; + } + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("FWUM Firmware Start Firmware Image Download returned %d (0x%02x)\n",rv,rv); + status = rv; // KFWUM_STATUS_ERROR + } + + if(status == KFWUM_STATUS_OK) + { + pResp = (struct KfwumStartFirmwareDownloadResp *) rsp; + printf("Bank holding new firmware : %d\n", pResp->bank); + os_usleep(5,0); + } + return status; +} + +#pragma pack(1) +struct KfwumSaveFirmwareAddressReq +{ + unsigned char addressLSB; + unsigned char addressMid; + unsigned char addressMSB; + unsigned char numBytes; + unsigned char txBuf[KFWUM_SMALL_BUFFER-KFWUM_OLD_CMD_OVERHEAD]; +}; // __attribute__ ((packed)); + +struct KfwumSaveFirmwareSequenceReq +{ + unsigned char sequenceNumber; + unsigned char txBuf[KFWUM_BIG_BUFFER]; +}; // __attribute__ ((packed)); +#pragma pack() + + +#define FWUM_SAVE_FIRMWARE_NO_RESPONSE_LIMIT ((unsigned char)6) + +static tKFWUM_Status KfwumSaveFirmwareImage(void * intf, + unsigned char sequenceNumber, unsigned long address, unsigned char *pFirmBuf, + unsigned char * pInBufLength) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char out = 0; + unsigned char retry = 0; + unsigned char noResponse = 0 ; + + struct KfwumSaveFirmwareAddressReq addressReq; + struct KfwumSaveFirmwareSequenceReq sequenceReq; + + do + { + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE; + + if (saveFirmwareInfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS ) + { + addressReq.addressLSB = (uchar)(address & 0x000000ff); + addressReq.addressMid = (uchar)((address >> 8) & 0x000000ff); + addressReq.addressMSB = (uchar)((address >> 16) & 0x000000ff); + addressReq.numBytes = (* pInBufLength); + memcpy(addressReq.txBuf, pFirmBuf, (* pInBufLength)); + req.msg.data = (unsigned char *) &addressReq; + req.msg.data_len = (* pInBufLength)+4; + } + else + { + sequenceReq.sequenceNumber = sequenceNumber; + memcpy(sequenceReq.txBuf, pFirmBuf, (* pInBufLength)); + req.msg.data = (unsigned char *) &sequenceReq; + req.msg.data_len = (* pInBufLength)+sizeof(unsigned char); /* + 1 => sequenceNumber*/ + } + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf("Error in FWUM Firmware Save Firmware Image Download Command\n"); + + out = 0; + status = KFWUM_STATUS_OK; + + /* With IOL, we don't receive "C7" on errors, instead we receive + nothing */ + if(is_remote()) + { + noResponse++; + + if(noResponse < FWUM_SAVE_FIRMWARE_NO_RESPONSE_LIMIT ) + { + (* pInBufLength) -= 1; + out = 0; + } + else + { + printf("Error, too many commands without response\n"); + (* pInBufLength) = 0 ; + out = 1; + } + } /* For other interface keep trying */ + } + else if (rv > 0) /*ccode*/ + { + if(rv == 0xc0) + { + status = KFWUM_STATUS_OK; + os_usleep(1,0); + } + else if( + (rv == 0xc7) + || + ( + (rv == 0xC3) && + (sequenceNumber == 0) + ) + ) + { + (* pInBufLength) -= 1; + status = KFWUM_STATUS_OK; + retry = 1; + } + else if(rv == 0x82) + { + /* Double sent, continue */ + status = KFWUM_STATUS_OK; + out = 1; + } + else if(rv == 0x83) + { + if(retry == 0) + { + retry = 1; + status = KFWUM_STATUS_OK; + } + else + { + status = rv; // KFWUM_STATUS_ERROR + out = 1; + } + } + else if(rv == 0xcf) /* Ok if receive duplicated request */ + { + retry = 1; + status = KFWUM_STATUS_OK; + } + else if(rv == 0xC3) + { + if(retry == 0) + { + retry = 1; + status = KFWUM_STATUS_OK; + } + else + { + status = rv; // KFWUM_STATUS_ERROR + out = 1; + } + } + else + { + printf("FWUM Firmware Save Firmware Image Download returned %x\n", + rv); + status = rv; // KFWUM_STATUS_ERROR + out = 1; + } + } + else + { + out = 1; + } + }while(out == 0); + return status; +} + +#pragma pack(1) +struct KfwumFinishFirmwareDownloadReq{ + unsigned char versionMaj; + unsigned char versionMinSub; + unsigned char versionSdr; + unsigned char reserved; +}; // __attribute__ ((packed)); +#pragma pack() +static tKFWUM_Status KfwumFinishFirmwareImage(void * intf, + tKFWUM_InFirmwareInfo firmInfo) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct KfwumFinishFirmwareDownloadReq thisReq; + + thisReq.versionMaj = firmInfo.versMajor; + thisReq.versionMinSub = ((firmInfo.versMinor <<4) | firmInfo.versSubMinor); + thisReq.versionSdr = firmInfo.sdrRev; + thisReq.reserved = 0; + /* Byte 4 reserved, write 0 */ + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE; + req.msg.data = (unsigned char *) &thisReq; + req.msg.data_len = 4; + + do + { + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + }while (rv == 0xc0); + + if (rv < 0) + { + printf("Error in FWUM Firmware Finish Firmware Image Download Command\n"); + status = rv; // KFWUM_STATUS_ERROR + } + else if (rv > 0) + { + printf("FWUM Firmware Finish Firmware Image Download returned %x\n", + rv); + status = rv; // KFWUM_STATUS_ERROR + } + + return status; +} + + +#define FWUM_MAX_UPLOAD_RETRY 6 +static tKFWUM_Status KfwumUploadFirmware(void * intf, + unsigned char * pBuffer, unsigned long totalSize) +{ + tKFWUM_Status status = KFWUM_STATUS_ERROR; + unsigned long address = 0x0; + unsigned char writeSize; + unsigned char oldWriteSize; + unsigned long lastAddress = 0; + unsigned char sequenceNumber = 0; + unsigned char retry = FWUM_MAX_UPLOAD_RETRY; + // unsigned char isLengthValid = 1; + + do + { + writeSize = saveFirmwareInfo.bufferSize - saveFirmwareInfo.overheadSize; + + /* Reach the end */ + if( address + writeSize > totalSize ) + { + writeSize = (uchar)(totalSize - address); + } + /* Reach boundary end */ + else if(((address % KFWUM_PAGE_SIZE) + writeSize) > KFWUM_PAGE_SIZE) + { + writeSize = (KFWUM_PAGE_SIZE - (uchar)(address % KFWUM_PAGE_SIZE)); + } + + oldWriteSize = writeSize; + status = KfwumSaveFirmwareImage(intf, sequenceNumber, address, + &pBuffer[address], &writeSize); + + if((status != KFWUM_STATUS_OK) && (retry-- != 0)) + { + address = lastAddress; + status = KFWUM_STATUS_OK; + } + else if( writeSize == 0 ) + { + status = KFWUM_STATUS_ERROR; + } + else + { + if(writeSize != oldWriteSize) + { + printf("Adjusting length to %d bytes \n", writeSize); + saveFirmwareInfo.bufferSize -= (oldWriteSize - writeSize); + } + + retry = FWUM_MAX_UPLOAD_RETRY; + lastAddress = address; + address+= writeSize; + } + + if(status == KFWUM_STATUS_OK) + { + if((address % 1024) == 0) + { + KfwumShowProgress((const unsigned char *)\ + "Writing Firmware in Flash",address,totalSize); + } + sequenceNumber++; + } + + }while((status == KFWUM_STATUS_OK) && (address < totalSize )); + + if(status == KFWUM_STATUS_OK) + { + KfwumShowProgress((const unsigned char *)\ + "Writing Firmware in Flash", 100 , 100 ); + } + + return(status); +} + +static tKFWUM_Status KfwumStartFirmwareUpgrade(void * intf) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char upgType = 0 ; /* Upgrade type, wait BMC shutdown */ + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_UPDATE; + req.msg.data = (unsigned char *) &upgType; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf("Error in FWUM Firmware Start Firmware Upgrade Command\n"); + status = rv; // KFWUM_STATUS_ERROR + } + else if (rv > 0) + { + if(rv == 0xd5) + { + printf("No firmware available for upgrade. Download Firmware first\n"); + } + else + { + printf("FWUM Firmware Start Firmware Upgrade returned %x\n", + rv); + } + status = rv; // KFWUM_STATUS_ERROR + } + + return status; +} + +#define TRACE_LOG_CHUNK_COUNT 7 +#define TRACE_LOG_CHUNK_SIZE 7 +#define TRACE_LOG_ATT_COUNT 3 +/* String table */ +/* Must match eFWUM_CmdId */ +static const char* CMD_ID_STRING[] = { + "GetFwInfo", + "KickWatchdog", + "GetLastAnswer", + "BootHandshake", + "ReportStatus", + "CtrlIPMBLine", + "SetFwState", + "GetFwStatus", + "GetSpiMemStatus", + "StartFwUpdate", + "StartFwImage", + "SaveFwImage", + "FinishFwImage", + "ReadFwImage", + "ManualRollback", + "GetTraceLog" }; + +static const char* EXT_CMD_ID_STRING[] = { + "FwUpgradeLock", + "ProcessFwUpg", + "ProcessFwRb", + "WaitHSAfterUpg", + "WaitFirstHSUpg", + "FwInfoStateChange" }; + + +static const char* CMD_STATE_STRING[] = { + "Invalid", + "Begin", + "Progress", + "Completed" }; + + +static tKFWUM_Status KfwumGetTraceLog(void * intf) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char chunkIdx; + unsigned char cmdIdx; + + if(verbose) + { + printf(" Getting Trace Log!\n"); + } + + for( chunkIdx = 0; (chunkIdx < TRACE_LOG_CHUNK_COUNT) && (status == KFWUM_STATUS_OK); chunkIdx++ ) + { + /* Retreive each log chunk and print it */ + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_GET_TRACE_LOG; + req.msg.data = &chunkIdx; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("FWUM Firmware Get Trace Log returned %d (0x%02x)\n",rv,rv); + status = rv; // KFWUM_STATUS_ERROR + } + + if(status == KFWUM_STATUS_OK) + { + for (cmdIdx=0; cmdIdx < TRACE_LOG_CHUNK_SIZE; cmdIdx++) + { + /* Don't diplay commands with an invalid state */ + if ( (rsp[TRACE_LOG_ATT_COUNT*cmdIdx+1] != 0) && + (rsp[TRACE_LOG_ATT_COUNT*cmdIdx] < KFWUM_CMD_ID_STD_MAX_CMD)) + { + printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", + CMD_ID_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx]], + CMD_STATE_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx+1]], + rsp[TRACE_LOG_ATT_COUNT*cmdIdx+2]); + } + else if ( (rsp[TRACE_LOG_ATT_COUNT*cmdIdx+1] != 0) && + (rsp[TRACE_LOG_ATT_COUNT*cmdIdx] >= KFWUM_CMD_ID_EXTENDED_CMD)) + { + printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", + EXT_CMD_ID_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx] - KFWUM_CMD_ID_EXTENDED_CMD], + CMD_STATE_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx+1]], + rsp[TRACE_LOG_ATT_COUNT*cmdIdx+2]); + } + } + } + } + printf("\n"); + return status; +} + + +/******************************************************************************* +* Function Name: KfwumGetInfoFromFirmware +* +* Description: This function retreive from the firmare the following info : +* +* o Checksum +* o File size (expected) +* o Board Id +* o Device Id +* +* Restriction: None +* +* Input: char * fileName - File to get info from +* +* Output: pInfo - container that will hold all the informations gattered. +* see structure for all details +* +* Global: None +* +* Return: IFWU_SUCCESS - file ok +* IFWU_ERROR - file error +* +*******************************************************************************/ +#define IN_FIRMWARE_INFO_OFFSET_LOCATION 0x5a0 +#define IN_FIRMWARE_INFO_SIZE 20 +#define IN_FIRMWARE_INFO_OFFSET_FILE_SIZE 0 +#define IN_FIRMWARE_INFO_OFFSET_CHECKSUM 4 +#define IN_FIRMWARE_INFO_OFFSET_BOARD_ID 6 +#define IN_FIRMWARE_INFO_OFFSET_DEVICE_ID 8 +#define IN_FIRMWARE_INFO_OFFSET_TABLE_VERSION 9 +#define IN_FIRMWARE_INFO_OFFSET_IMPLEMENT_REV 10 +#define IN_FIRMWARE_INFO_OFFSET_VERSION_MAJOR 11 +#define IN_FIRMWARE_INFO_OFFSET_VERSION_MINSUB 12 +#define IN_FIRMWARE_INFO_OFFSET_SDR_REV 13 +#define IN_FIRMWARE_INFO_OFFSET_IANA0 14 +#define IN_FIRMWARE_INFO_OFFSET_IANA1 15 +#define IN_FIRMWARE_INFO_OFFSET_IANA2 16 + +#define KWUM_GET_BYTE_AT_OFFSET(pBuffer,os) pBuffer[os] + +tKFWUM_Status KfwumGetInfoFromFirmware(unsigned char * pBuf, + unsigned long bufSize, tKFWUM_InFirmwareInfo * pInfo) +{ + tKFWUM_Status status = KFWUM_STATUS_ERROR; + + if(bufSize >= (IN_FIRMWARE_INFO_OFFSET_LOCATION + IN_FIRMWARE_INFO_SIZE)) + { + unsigned long offset = IN_FIRMWARE_INFO_OFFSET_LOCATION; + + /* Now, fill the structure with read informations */ + pInfo->checksum = (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+0+IN_FIRMWARE_INFO_OFFSET_CHECKSUM ) << 8; + pInfo->checksum |= (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+1+IN_FIRMWARE_INFO_OFFSET_CHECKSUM ); + + + pInfo->sumToRemoveFromChecksum= + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_CHECKSUM); + + pInfo->sumToRemoveFromChecksum+= + KWUM_GET_BYTE_AT_OFFSET(pBuf , + offset+IN_FIRMWARE_INFO_OFFSET_CHECKSUM+1); + + pInfo->fileSize = + KWUM_GET_BYTE_AT_OFFSET(pBuf , + offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+0) << 24; + pInfo->fileSize |= + (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+1) << 16; + pInfo->fileSize |= + (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+2) << 8; + pInfo->fileSize |= + (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+3); + + pInfo->boardId = + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_BOARD_ID+0) << 8; + pInfo->boardId |= + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_BOARD_ID+1); + + pInfo->deviceId = + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_DEVICE_ID); + + pInfo->tableVers = + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_TABLE_VERSION); + pInfo->implRev = + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_IMPLEMENT_REV); + pInfo->versMajor = + (KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_VERSION_MAJOR)) & 0x0f; + pInfo->versMinor = + (KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_VERSION_MINSUB)>>4) & 0x0f; + pInfo->versSubMinor = + (KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_VERSION_MINSUB)) & 0x0f; + pInfo->sdrRev = + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_SDR_REV); + pInfo->iana = + KWUM_GET_BYTE_AT_OFFSET(pBuf , + offset+IN_FIRMWARE_INFO_OFFSET_IANA2) << 16; + pInfo->iana |= + (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_IANA1) << 8; + pInfo->iana |= + (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_IANA0); + + KfwumFixTableVersionForOldFirmware(pInfo); + + status = KFWUM_STATUS_OK; + } + return(status); +} + + +void KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo) +{ + switch(pInfo->boardId) + { + case KFWUM_BOARD_KONTRON_UNKNOWN: + pInfo->tableVers = 0xff; + break; + default: + /* pInfo->tableVers is already set for the right version */ + break; + } +} + + +tKFWUM_Status KfwumValidFirmwareForBoard(tKFWUM_BoardInfo boardInfo, + tKFWUM_InFirmwareInfo firmInfo) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + + if(boardInfo.iana != firmInfo.iana) + { + printf("Board IANA does not match firmware IANA\n"); + status = KFWUM_STATUS_ERROR; + } + + if(boardInfo.boardId != firmInfo.boardId) + { + printf("Board IANA does not match firmware IANA\n"); + status = KFWUM_STATUS_ERROR; + } + + if(status == KFWUM_STATUS_ERROR) + { + printf("Firmware invalid for target board. Download of upgrade aborted\n"); + } + return status; +} + + +static void KfwumOutputInfo(tKFWUM_BoardInfo boardInfo, + tKFWUM_InFirmwareInfo firmInfo) +{ + printf("Target Board Id : %u\n",boardInfo.boardId); + printf("Target IANA number : %u\n",boardInfo.iana); + printf("File Size : %lu bytes\n",firmInfo.fileSize); + printf("Firmware Version : %d.%d%d SDR %d\n",firmInfo.versMajor, + firmInfo.versMinor, firmInfo.versSubMinor, firmInfo.sdrRev); +} + +#ifdef METACOMMAND +int i_fwum(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + void *intf = NULL; + int rc = 0; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"m:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'x': fdebug = 1; verbose = 1; + break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + KfwumOutputHelp(); + return ERR_USAGE; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + rc = ipmi_fwum_main(intf, argc, argv); + + ipmi_close_(); + // show_outcome(progname,rc); + return rc; +} diff --git a/util/ifwum.h b/util/ifwum.h new file mode 100644 index 0000000..e6c228c --- /dev/null +++ b/util/ifwum.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef IPMI_KFWUM_H +#define IPMI_KFWUM_H + +// #include <inttypes.h> +// #include <ipmitool/ipmi.h> + +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int + +#define IPMI_NETFN_APP 0x6 +#define IPMI_NETFN_FIRMWARE 0x8 + +#define IPMI_BMC_SLAVE_ADDR 0x20 + +#define BMC_GET_DEVICE_ID 0x1 + +#define IPM_DEV_MANUFACTURER_ID(x) \ + ((uint32_t) ((x[2] & 0x0F) << 16 | x[1] << 8 | x[0])) + +//struct valstr { + // uint16_t val; + // const char * str; +//}; + +#pragma pack(1) +struct ipm_devid_rsp { + uint8_t device_id; + uint8_t device_revision; + uint8_t fw_rev1; + uint8_t fw_rev2; + uint8_t ipmi_version; + uint8_t adtl_device_support; + uint8_t manufacturer_id[3]; + uint8_t product_id[2]; + uint8_t aux_fw_rev[4]; +}; // __attribute__ ((packed)); +#pragma pack() + +/* routines from lib/lanplus/helper.c */ +uint16_t buf2short(uint8_t * buf); +//const char * val2str(uint16_t val, const struct valstr * vs); + +#endif /* IPMI_KFWUM_H */ diff --git a/util/igetevent.c b/util/igetevent.c new file mode 100644 index 0000000..6e2fe27 --- /dev/null +++ b/util/igetevent.c @@ -0,0 +1,1439 @@ +/* + * igetevent.c + * + * This utility waits for IPMI Event Messages. + * Some server management functions want to trigger custom actions or + * alerts when IPMI hardware-related events occur, but do not want to + * track all events, just newly occurring events. + * The IPMI events also include BIOS events such as Memory and POST errors, + * which would not be captured by reading the IPMI sensors. + * This utility waits a specified timeout period for any events, and + * returns interpreted output for each event. It is designed as a + * scriptable command-line utility, but if the timeout is infinite + * (-t 0), then this code could be used for a sample service as well. + * + * There are several methods to do this which are implemented here. + * The SEL method (-s): + * This method polls the SEL once a second, keeps track of the last + * SEL event read, and only new events are processed. This ensures + * that in a series of rapid events, all events are received in order, + * however, some transition-to-OK events may not be configured to + * write to the SEL on certain platforms. + * This method is used if getevent -s is specified. + * The ReadEventMessageBuffer method (-m getmessage option): + * This uses an IPMI Message Buffer in the BMC firmware to read + * each new event. This receives any event, but if two events + * occur nearly simultaneously, only the most recent of the two + * will be returned with this method. An example of simultaneous + * events might be, if a fan stops/fails, both the non-critical + * and critical fan threshold events would occur at that time. + * This is the default method for getevent. It would be used + * locally with the Intel IMB driver or with direct/driverless. + * The OpenIPMI custom method (-m getmessage_mv option if DRV_MV): + * Different IPMI drivers may have varying behavior. For instance, + * the OpenIPMI driver uses the IPMI GetMessage commands internally + * and does not allow client programs to use those commands. It has + * its own custom mechanism, see getevent_mv(). + * This method is used locally if the OpenIPMI driver is detected. + * The Async Event method (-a): + * This only gets certain Asynchronous events, like a shutdown + * request from the BMC to an SMS OS service, and get_software_id. + * This is supported for Intel IMB driver and OpenIPMI driver only. + * This method is only used locally if getevent option -a is used, + * and if either MV (openipmi) or IMB driver is loaded. + * The ipmiutil_asy init script controls the getevent -a service. + * (see DO_ASYNC compile flag comments) + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2005-2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 02/11/05 Andy Cress - created + * 05/18/05 Andy Cress - modified bmc_enable bits + * 05/26/05 Andy Cress - added call to decode_sel_entry + * 09/09/05 Andy Cress - added sensor_type filtering & return type. + * 03/16/05 Andy Cress - added loop, and -o for frunOnce + * 06/27/06 Andy Cress 1.1 - specific message for cc=0x80 (no data) + * 07/18/06 Andy Cress 1.1 - added getevent_mv, etc. + * 07/26/06 Andy Cress 1.1 - added msgout() routine for fflush + * 08/08/06 Andy Cress 1.2 - added -s for SEL method + * 08/08/06 Andy Cress 1.2 - added -s for SEL method + * 08/22/06 Andy Cress 1.3 - direct IOs added with ipmiutil-1.7.5 + * 09/13/06 Andy Cress 1.4 - handle empty SEL (0xCB), + * call syncevent_sel after every new event. + * 09/21/07 Andy Cress 1.21 - implemented IMB Async method for remote + * OS shutdown via SMS requests. + */ +/*M* +Copyright (c) 2009 Kontron America, Inc. +Copyright (c) 2013 Andy Cress <arcress at users.sourceforge.net> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#include <unistd.h> +#endif +#include <pthread.h> +#include <sys/utsname.h> +#endif +#include <string.h> +#ifdef SOLARIS +/* Solaris */ +#define HandleType long +#elif WIN32 +#include "imb_api.h" +#define DO_ASYNC 1 +#elif LINUX +#define LINUX 1 +#include "imb_api.h" +#define DO_ASYNC 1 +#define DO_MVL 1 +#elif BSD +#define DO_MVL 1 +#define HandleType long +#else +/* other OS */ +#define HandleType long +#endif +#include "ipmicmd.h" + +#define THREADS_OK 1 +#define IMBPTIMEOUT 200 /*200 ms*/ +// #define IPMB_CHANNEL 0x00 +// #define LAN_CHANNEL 0x02 +#define ulong unsigned long +#define uint unsigned int +#define ushort unsigned short +#define uchar unsigned char + +#define CMD_GET_SOFTWARE_ID 0x00 +#define CMD_SMS_OS_REQUEST 0x10 + +extern int decode_sel_entry(uchar *evt, char *obuf, int sz); /*see ievents.c*/ +extern void set_sel_opts(int sensdesc, int canon, void *sdrs, char fdbg, char utc); /* ievents.c */ +extern char *get_sensor_type_desc(uchar stype); /*see ievents.c*/ +extern int write_syslog(char *msg); /*see isel.c*/ +extern char *show_driver_type(int idx); /*see ipmicmd.h*/ +extern int get_sdr_cache(uchar **pret); /*see isensor.c*/ +extern void free_sdr_cache(uchar *pret); /*see isensor.c*/ + +/* + * Global variables + */ +static char * progname = "igetevent"; +static char * progver = "2.93"; +static char fdebug = 0; +static char fipmilan = 0; +static char frunonce = 0; +static char futc = 0; +static char fAsync = 0; +static char fAsyncOK = 0; /*=1 if drvtype detected for it*/ +static char fAsyncNOP = 0; /*=1 if skip Async actions*/ +static char fbackground = 0; +static char frunscript = 0; +static char fcanonical = 0; +static char fsettime = 0; /* =1 if timeout is set by -t */ +static uchar evt_stype = 0xff; /* event sensor type, 0xff = get any events */ +static uchar evt_snum = 0xff; /* event sensor num, 0xff = get any events */ +static int timeout = 120; /* 120 seconds default timeout */ +static int wait_interval = 1; /* 1 second between calls */ +static FILE *fdout = NULL; +static char *run_script = NULL; +static uchar ipmi_maj = 0; +static uchar ipmi_min = 0; +static HandleType imb_handle = 0; +static int drvtype = 0; /* driver_type from ipmicmd.h: 1=Intel_imb, 3=MV_OpenIPMI */ +static int vend_id = 0; +static int prod_id = 0; +static char fselevts = 0; +static char fmsgevts = 0; +static ushort sel_recid = 0; +static uint sel_time = 0; +static uchar sms_sa = 0x81; +static uchar *sdrs = NULL; +#define LAST_REC 0xFFFF +#ifdef WIN32 +#define IDXFILE "ipmi_evt.idx" +static char idxfile[80] = IDXFILE; +static char idxfile2[80] = "c:\\ipmi_evt.idx"; +static char outfile[80] = "c:\\ipmiutil_evt.log"; +#define SHUTDOWN_CMD "shutdown -s -d p:01:01 -t 10" +#define REBOOT_CMD "shutdown -r -d p:01:01 -t 10" +#else +static char idxfile[80] = "/var/lib/ipmiutil/evt.idx"; +static char idxfile2[80] = "/usr/share/ipmiutil/evt.idx"; +static char outfile[80] = "/var/log/ipmiutil_evt.log"; +#define SHUTDOWN_CMD "init 0" // or shutdown now +#define REBOOT_CMD "init 6" +#endif +#ifdef METACOMMAND +extern FILE *fpdbg; /*from ipmicmd.c*/ +extern FILE *fperr; /*from ipmicmd.c*/ +#endif +/* prototypes */ +static void iclose(void); +static void ievt_siginit(void); +static void ievt_cleanup(void); + +#define METHOD_UNKNOWN 0 +#define METHOD_SEL_EVTS 1 +#define METHOD_MSG_GET 2 +#define METHOD_MSG_MV 3 +#define METHOD_ASYNC_MV 4 +#define METHOD_ASYNC_IMB 5 +static char *methodstr[6] = { + "unknown", + "SEL_events", + "GetMessage", + "GetMessage_mv", + "Async_mv", + "Async_imb" }; + +static int do_wait(int nsec) +{ + int rv = 0; + if (nsec > 0) os_usleep(nsec,0); /*declared in ipmicmd.h*/ + return(rv); +} + +static int get_event_receiver(uchar *sa, uchar *lun) +{ + uchar rdata[30]; + int rlen; + uchar ccode; + int ret; + + rlen = 2; +#if 0 + ret = ipmi_cmdraw( 0x01,NETFN_SEVT,BMC_SA,PUBLIC_BUS,BMC_LUN, + idata,0, rdata,&rlen,&ccode, fdebug); +#endif + ret = ipmi_cmd(GET_EVENT_RECEIVER,NULL,0, rdata,&rlen,&ccode, 0); + if (ret == 0 && ccode != 0) ret = ccode; + if (ret == 0) { + *sa = rdata[0]; + *lun = rdata[1]; + } + return(ret); +} + +static int get_msg_flags(uchar *flags) +{ + uchar rdata[8]; + int rlen = 1; + uchar ccode; + int ret; + ret = ipmi_cmdraw( 0x31,NETFN_APP,BMC_SA,PUBLIC_BUS,BMC_LUN, + NULL,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + if ((ret == 0) && (flags != NULL)) *flags = rdata[0]; + return(ret); +} + +static int set_bmc_enables(uchar enab) +{ + uchar idata[8]; + uchar rdata[30]; + int rlen; + uchar ccode; + int ret; + + idata[0] = enab; + rlen = 1; + ret = ipmi_cmdraw( 0x2E,NETFN_APP,BMC_SA,PUBLIC_BUS,BMC_LUN, + idata,1, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} + +static int get_bmc_enables(uchar *enab) +{ + uchar rdata[30]; + int rlen; + uchar ccode; + int ret; + + rlen = 1; + ret = ipmi_cmdraw( 0x2F,NETFN_APP,BMC_SA,PUBLIC_BUS,BMC_LUN, + NULL,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + + if (ret == 0) *enab = rdata[0]; + return(ret); +} + +/* + * msgout + * wrapper for printf() to include fflush + */ +void msgout(char *pattn, ...) +{ + va_list arglist; + + if (fdout == NULL) return; + va_start( arglist, pattn ); + vfprintf( fdout, pattn, arglist ); + va_end( arglist ); + fflush( fdout ); +} + +#ifdef DO_ASYNC +/* The DO_ASYNC flag enables the IMB Async Message method via get_imb_event. + * This requires the Intel IMB driver, and is used only for remote shutdown + * and software ID events. */ + +/* The LANDesk library has the same function names as the imbapi.c */ +#ifdef LINK_LANDESK +#define StartAsyncMesgPoll ia_StartAsyncMesgPoll +#define SendAsyncImbpRequest ia_SendAsyncImbpRequest +#define GetAsyncImbpMessage ia_GetAsyncImbpMessage +#define GetAsyncImbpMessage_Ex ia_GetAsyncImbpMessage_Ex +#define IsAsyncMessageAvailable ia_IsAsyncMessageAvailable +#define RegisterForImbAsyncMessageNotification ia_RegisterForImbAsyncMessageNotification +#define UnRegisterForImbAsyncMessageNotification ia_UnRegisterForImbAsyncMessageNotification +#define SendTimedLanMessageResponse_Ex ia_SendTimedLanMessageResponse_Ex +#define SendTimedEmpMessageResponse_Ex ia_SendTimedEmpMessageResponse_Ex +#endif /*endif LINK_LANDESK*/ + +typedef struct { + uchar rsSa; + uchar nfLn; + uchar cSum1; + uchar rqSa; + uchar seqLn; + uchar cmd; + uchar data[1]; +} AsyImbPacket; + +#ifdef THREADS_OK + char message[32]; +#ifdef WIN32 + HANDLE threadid = NULL; +#else + pthread_t threadid = 0; +#endif +#endif + +#ifdef WIN32 +#define ThreadRType DWORD +ThreadRType WINAPI pollThread( LPVOID p) +#else +#define ThreadRType void * +ThreadRType pollThread(void *p) +#endif +{ + int i; + int ret, limit; +#ifdef THREADS_OK + limit = 0; +#else + limit = 30; +#endif + for (i = 0; (limit == 0) || (i < limit); i++) + { + ret = StartAsyncMesgPoll(); + if (fdebug && i < 5) + msgout("StartAsyncMesgPoll [%d] ret = %d\n",i,ret); + // os_usleep(0,5000); /* poll interval 5 msec */ + os_usleep(1,0); /* poll interval 1 sec */ + } + return((ThreadRType)0); +} + +static int GetBmcLanChannel(uchar *chan) +{ + int ret = 0; + int j; + int rlen; + uchar iData[2]; + uchar rData[10]; + uchar cc; + uchar mtype; + uchar chn = 1; + + if (vend_id == VENDOR_INTEL) { + if (prod_id == 0x000C || prod_id == 0x001B) { + *chan = 7; + return(ret); + } + } + for (j = 1; j < 12; j++) { + rlen = sizeof(rData); + iData[0] = (uchar)j; /*channel #*/ + memset(rData,0,9); /*initialize recv data*/ + ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, fdebug); + if (ret == 0xcc || cc == 0xcc) /* special case for ipmi_lan */ + continue; + if (ret != 0) { + if (fdebug) printf("get_chan_info rc = %x\n",ret); + break; + } + mtype = rData[1]; /* channel medium type */ + if (mtype == 4) { /* 802.3 LAN type*/ + if (fdebug) printf("chan[%d] = lan\n",j); + chn = (uchar)j; + break; + } + } + *chan = chn; + return(ret); +} + +int SoftwareIdResponse(uchar *buf, int blen, uchar hnd, uchar chan) +{ + int rv = 0; + uchar resp[12] = {0,0xa6,0,0,0,1,0,0x00,0x01,0x57,0x00,0x01}; +#ifdef WIN32 + /* check OS version & arch (32/64) */ +#else + struct utsname uts; + rv = uname(&uts); + // uts.release=`uname -r` uts.machine=x86_64,ia64,i586,i386 + // kver <= 24 bytes, mach/arch <= 6 bytes +#endif + +#ifdef USE_LANMSG + rv = SendTimedLanMessageResponse_Ex( (ImbPacket *)buf, (char *)(&resp), 12, + IMBPTIMEOUT, hnd, chan); +#else + rv = SendTimedEmpMessageResponse_Ex((ImbPacket *)buf, (char *)(&resp), 12, + IMBPTIMEOUT, hnd,chan); +#endif + if (fdebug) msgout("SoftwareIdResponse(%d) ret = %d\n",chan,rv); + return(rv); +} + + +int SmsOsResponse(uchar *buf, int blen, uchar func, uchar hnd, uchar chan) +{ + int rv = 0; + char cc = 0; + if (frunscript) { + write_syslog("igetevent -a running script\n"); + rv = system(run_script); + if (fdebug) msgout("run(%s) ret = %d\n",run_script,rv); + } + switch(func) /*data byte has function*/ + { + case 0x01: /*shutdown & power down*/ + rv = SendTimedEmpMessageResponse_Ex((ImbPacket *)buf, &cc,1, + IMBPTIMEOUT, hnd,chan); + if (fdebug) msgout("OsResponse(%d) ret = %d\n",chan,rv); + if (!fAsyncNOP) { + write_syslog("igetevent -a initiating OS shutdown\n"); + rv = system(SHUTDOWN_CMD); + if (fdebug) msgout("shutdown ret = %d\n",rv); + } + break; + case 0x02: /*shutdown & reset*/ + rv = SendTimedEmpMessageResponse_Ex((ImbPacket *)buf, &cc,1, + IMBPTIMEOUT, hnd,chan); + if (fdebug) msgout("OsResponse(%d) ret = %d\n",chan,rv); + if (!fAsyncNOP) { + write_syslog("igetevent -a initiating OS reboot\n"); + rv = system(REBOOT_CMD); + if (fdebug) msgout("reboot ret = %d\n",rv); + } + break; + default: + if (fdebug) msgout("igetevent -a unknown function %d\n",func); + rv = 1; + break; + } + return(rv); +} + +/* + * get_imb_event + * This only gets certain IMB events, like + * OS requests (e.g. shutdown), and get_software_id + */ +static int get_imb_event(uchar etype, int timeout, uchar *evt) +{ + int ret = -1; + int i; + int done = 0; + ulong mlen; + uchar buffer[512]; + uchar sendbuf[18]; + static uint asyseqnum = 0; + uchar chan; + uchar sessHandle = 0; + uchar privilege = 0; + uchar cmd, func; + // uchar *pbuf; + + ret = GetBmcLanChannel(&chan); + + /* clean out pre-existing async messages */ + while(1) { + mlen = sizeof(buffer); + if (GetAsyncImbpMessage((ImbPacket *)buffer,&mlen, IMBPTIMEOUT, + &asyseqnum, IPMB_CHANNEL) != 0) + break; + if (fdebug) msgout("cleaned out an IPMB message seq=%d\n",asyseqnum); + } + while(1) { + mlen = sizeof(buffer); + if (GetAsyncImbpMessage((ImbPacket *)buffer,&mlen, IMBPTIMEOUT, + &asyseqnum, LAN_CHANNEL) != 0) + break; + if (fdebug) msgout("cleaned out a LAN message seq=%d\n",asyseqnum); + } + ret = RegisterForImbAsyncMessageNotification(&imb_handle); + if (fdebug) + msgout("RegisterForImbAsync ret=%d, handle=%x\n",ret,imb_handle); + if (ret != 0) { + msgout("RegisterAsync error %d\n",ret); + return(ret); + } + + for (i = 0; (timeout == 0) || (i < timeout); i++) + { /*get one imb event*/ + if (fdebug) msgout("IsAsyncMessageAvailable ...\n"); + if (IsAsyncMessageAvailable(imb_handle) == 0) + { + if (fdebug) msgout("Async Message is Available\n"); + mlen = sizeof(buffer); + ret = GetAsyncImbpMessage_Ex ((ImbPacket *)buffer, &mlen, + IMBPTIMEOUT, &asyseqnum, ANY_CHANNEL, + &sessHandle, &privilege); + /* Hack: buffer contains an extra byte to return channel */ + if (fdebug) + msgout("GetAsync(%d,%d) ret = %d, newchan=%x\n", + asyseqnum,chan,ret,buffer[mlen]); + if (ret == 0) { + /* get the async message command */ + if (fdebug) dump_buf("async msg",buffer,mlen+1,0); + chan = buffer[mlen]; + if (mlen > 16) mlen = 16; + if (buffer[0] == sms_sa) { + memcpy(&sendbuf[0],buffer,mlen); + } else { /* handle shorter format for some BMCs */ + sendbuf[0] = sms_sa; + memcpy(&sendbuf[1],buffer,mlen); + } + cmd = sendbuf[5]; func = sendbuf[6]; + msgout("got async msg: cmd=%02x len=%d\n",cmd,mlen); + memcpy(evt,sendbuf,mlen); + + switch(cmd) { + case CMD_GET_SOFTWARE_ID: /*Get Software ID*/ + ret = SoftwareIdResponse(sendbuf,mlen,sessHandle,chan); + break; + case CMD_SMS_OS_REQUEST: /*SMS OS Request*/ + ret = SmsOsResponse(sendbuf,mlen,func,sessHandle,chan); + if (ret == 0) done = 1; + break; + default: + ret = LAN_ERR_INVPARAM; + msgout("SmsOS cmd %02x unknown, ret = %d\n",cmd,ret); + } + if (fdebug) + msgout("async msg cmd=%02x ret = %d\n",cmd,ret); + if (done == 1) { + if (func == 0x01) msgout("shutting down\n"); + else msgout("rebooting\n"); + ret = 0x81; + break; + } + } + } /*endif have an event*/ + else ret = 0x80; /* no event yet */ + } /*loop for one event*/ + if (fdebug) msgout("Unregister for imb events\n"); + UnRegisterForImbAsyncMessageNotification (imb_handle,0); + return(ret); +} +#endif + /*endif DO_ASYNC*/ + +#ifdef DO_MVL +/* Linux, enable MV OpenIPMI interface */ +extern int register_async_mv(uchar cmd, uchar netfn); /*see ipmimv.c*/ +extern int unregister_async_mv(uchar cmd, uchar netfn); /*see ipmimv.c*/ +extern int getevent_mv(uchar *evt_data, int *evt_len, uchar *cc, int t); +extern int ipmi_rsp_mv(uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *pdata, int sdata, char fdebugcmd); + +static int send_mv_asy_resp(uchar *evt) +{ + uchar cmd, sa, bus, cc; + uchar data0[12] = {0,0xa6,0,0,0,1,0,0x00,0x01,0x57,0x00,0x01}; + uchar data1[1] = { 0x00 }; + uchar rdata[80]; + int sdata, rlen, i; + uchar *pdata; + int rv = -1; + + cmd = evt[2]; + sa = sms_sa; /* sa = SMS_SA (0x81) */ + bus = 0x01; /* usu lan_ch == 1 */ + switch(cmd) { + case CMD_GET_SOFTWARE_ID: /*software id*/ + pdata = &data0[0]; + sdata = sizeof(data0); + break; + case CMD_SMS_OS_REQUEST: /*restart*/ + pdata = &data1[0]; + sdata = sizeof(data1); + break; + default: rv = LAN_ERR_INVPARAM; return (rv); + break; + } + rv = ipmi_rsp_mv(cmd, (NETFN_APP | 0x01), sa, bus, BMC_LUN, + pdata,sdata, fdebug); + if (rv == 0) { + for (i = 0; i < 5; i++) + { + rlen = sizeof(rdata); + rv = getevent_mv(rdata,&rlen,&cc,1); + if (fdebug) msgout("send_mv_asy_resp: rv=%d cc=%x\n",rv,cc); + if (rv == 0 && cc == 0) { + if (fdebug) msgout("got rsp ccode: type=%02x len=%d cc=%x\n", + rdata[0],rlen,rdata[3]); + if (rlen > 0) rv = rdata[3]; /*cc*/ + break; + } + os_usleep(0,5000); /*wait 5 ms*/ + } + } + return (rv); +} + +static int get_mv_asy_event(uchar cmd, int timeout, uchar *evt) +{ + int ret = -1; + int rv = -1; + uchar cc = 0; + uchar rdata[120]; + int rlen, i; + + rv = register_async_mv(cmd,NETFN_APP); /*reserved,GetSoftwareID*/ + if (rv != 0) return(rv); + + for (i = 0; (timeout == 0) || (i < timeout); i++) + { /*get one async event*/ + rv = getevent_mv(rdata,&rlen,&cc,timeout); + if (fdebug) + msgout("get_mv_asy_event: i=%d cmd=%x rv=%d cc=%x\n",i,cmd,rv,cc); + if (rv == 0 && cc == 0) { + msgout("got async msg: type=%02x cmd=%x len=%d\n", + rdata[0],rdata[2],rlen); + if (fdebug) dump_buf("async msg",rdata,rlen,0); + /* check recv_type == 3 (IPMI_CMD_RECV_TYPE) */ + if (rdata[0] == 3 && rdata[2] == cmd) { + if (rlen > 16) rlen = 16; + memcpy(evt,rdata,rlen); + break; + } else { /*else msg, but no match*/ + rv = ERR_BAD_PARAM; + break; + } + } + else do_wait(wait_interval); /*wait 1 sec*/ + } + ret = unregister_async_mv(cmd,NETFN_APP); /*reserved,GetSoftwareID*/ + return(rv); +} +#endif + +static int get_evt_method(char *evtmethod) +{ + int method = METHOD_UNKNOWN; + if (fAsync) { + if (drvtype == DRV_MV) method = METHOD_ASYNC_MV; + else /* if (drvtype == DRV_IMB) */ method = METHOD_ASYNC_IMB; + } else if (fselevts) method = METHOD_SEL_EVTS; + else { /*fmsgevts*/ + if (drvtype == DRV_MV) method = METHOD_MSG_MV; + else method = METHOD_MSG_GET; + } + if (evtmethod != NULL) + strcpy(evtmethod,methodstr[method]); + return(method); +} + +static int get_sel_entry(ushort recid, ushort *nextid, uchar *rec) +{ + uchar ibuf[6]; + uchar rbuf[32]; + int rlen; + ushort xid, id = 0; + uchar cc; + int rv; + + ibuf[0] = 0; + ibuf[1] = 0; + ibuf[2] = (recid & 0x00ff); + ibuf[3] = (recid & 0xff00) >> 8; + ibuf[4] = 0; + ibuf[5] = 0xFF; /*get entire record*/ + rlen = sizeof(rbuf); + rv = ipmi_cmd(GET_SEL_ENTRY, ibuf, 6, rbuf, &rlen, &cc, fdebug); + if (rv == 0) { + if (cc != 0) rv = cc; + else { /*success*/ + xid = rbuf[0] + (rbuf[1] << 8); /*next rec id*/ + memcpy(rec,&rbuf[2],16); + *nextid = xid; + id = rbuf[2] + (rbuf[3] << 8); /*curr rec id*/ + /* recid (requested) should match newid (received) */ + if (fdebug) { + if ((recid != id) && (recid != LAST_REC) && (recid != 0)) { + /* the OpenIPMI driver does this sometimes */ + msgout("get_sel MISMATCH: recid=%x newid=%x next=%x\n", + recid,id,xid); + dump_buf("get_sel cmd",ibuf,6,0); + dump_buf("get_sel rsp",rbuf,rlen,0); + } + } + } + } + if (fdebug) msgout("get_sel(%x) rv=%d cc=%x id=%x next=%x\n", + recid,rv,cc,id,*nextid); + return(rv); +} + +static int startevent_sel(ushort *precid, uint *ptime) +{ + FILE *fd; + uchar rec[24]; + uint t = 0; + ushort r = 0; + ushort r2 = 0; + int rv = -1; + + fd = fopen(idxfile,"r"); + if (fd == NULL) fd = fopen(idxfile2,"r"); /*handle old location*/ + if (fdebug) msgout("start: idxfile=%s fd=%p\n",idxfile,fd); + if (fd != NULL) { + // Read the file, get savtime & savid + rv = fscanf(fd,"%x %x",&t,&r); + fclose(fd); + if (r == LAST_REC) r = 0; + rv = 0; /*read it, success*/ + } else { /* treat as first time */ + r = LAST_REC; + rv = get_sel_entry(r,&r2,rec); + if (rv == 0) { + memcpy(&t,&rec[3],4); + r = rec[0] + (rec[1] << 8); /*use current rec id*/ + } else r = 0; + rv = 1; /*first time*/ + } + if (fdebug) msgout("start: recid=%x time=%x\n",r,t); + *ptime = t; + *precid = r; + return(rv); +} + +static int syncevent_sel(ushort recid, uint itime) +{ + FILE *fd; + int rv; + // Rewrite the saved time & record id + if (fdebug) msgout("sync: recid=%x time=%x\n",recid,itime); + fd = fopen(idxfile,"w"); + if (fd == NULL) { + msgout("syncevent: cannot open %s for writing\n",idxfile); + rv = -1; + } else { + fprintf(fd,"%x %x\n",itime,recid); + fclose(fd); + rv = 0; + } + return(rv); +} + +int getevent_sel(uchar *rdata, int *rlen, uchar *ccode) +{ + uchar rec[24]; + int rv = 0; + ushort newid; + ushort nextid; + ushort recid; + + /* get current last record */ + recid = sel_recid; + rv = get_sel_entry(recid,&nextid,rec); + if (rv == 0xCB && recid == 0) { /* SEL is empty */ + *ccode = (uchar)rv; /* save the real ccode */ + rv = 0x80; /* this is ok, just keep waiting */ + } + if (rv == 0) { + if (fdebug) msgout("sel ok, id=%x next=%x\n",recid,nextid); + if ((nextid == LAST_REC) || (recid == nextid)) { + *ccode = 0x80; /*nothing new*/ + } else { + recid = nextid; /* else get new one */ + rv = get_sel_entry(recid,&nextid,rec); + if (rv == 0) { /* new event */ + newid = rec[0] + (rec[1] << 8); + if (drvtype == DRV_MV && recid != newid) { + /* handle MV driver bug, try to get next one. */ + if (fdebug) msgout("%s bug, record mismatch\n", + show_driver_type(DRV_MV)); + } + if (fdebug) msgout("recid=%x newid=%x next=%x\n", + recid,newid,nextid); + memcpy(rdata,rec,16); + *rlen = 16; + *ccode = 0; + sel_recid = recid; /*or newid*/ + memcpy(&sel_time,&rec[3],4); + } + } + } + else { /* Error reading last recid saved */ + if (fdebug) msgout("sel recid %x error, rv = %d\n",recid,rv); + /* We want to set sel_recid = 0 here for some errors. */ + if (rv == 0xCB || rv == 0xCD) { /* empty, or wrong SDR id */ + sel_recid = 0; + *ccode = (uchar)rv; + rv = 0x80; /* wait again */ + } + } + return(rv); +} + +static int get_event(uchar etype, uchar snum, int timeout, + uchar *evt, uchar *stype) +{ + int ret = 0; + uchar rdata[64]; + int rlen; + uchar ccode; + int fretry; + int i; + + for (i = 0; (timeout == 0) || (i < timeout); i++) + { + rlen = sizeof(rdata); + fretry = 0; ccode = 0; + if (fselevts) { + ret = getevent_sel(rdata,&rlen,&ccode); + } else +#ifdef DO_MVL + if (drvtype == DRV_MV) { /* if MV OpenIPMI driver (Linux only) */ + if (timeout == 0) wait_interval = 0; + /* use special MV API instead (see ipmimv.c) */ + ret = getevent_mv(rdata,&rlen,&ccode,timeout); + } else +#endif + ret = ipmi_cmd(READ_EVENT_MSGBUF,NULL,0,rdata,&rlen,&ccode,fdebug); + /* now we have an event from one of the above methods*/ + + /* IPMI 1.5 spec, section 18.8 says cc 0x80 means + * "data not available (queue/buffer empty)" */ + if (ret == 0 && ccode != 0) { ret = ccode; } + if (ret == 0x80) { + fretry = 1; + do_wait(wait_interval); /*wait 1 sec*/ + } else { + if (ret == 0) { + char ismatch = 0; + /* parse event types for a specified type */ + /* etype param == 0xff means get any event */ + /* rdata[10] is sensor_type, rdata[11] is sensor_num */ + if ((etype == 0xff) || (etype == rdata[10])) ismatch++; + if ((snum == 0xff) || (snum == rdata[11])) ismatch++; + if (ismatch == 2) { + /*event sensor type matches*/ + memcpy(evt,rdata,rlen); + *stype = rdata[10]; /* return sensor type */ + } else { /* keep looking */ + do_wait(wait_interval); + continue; + } + } + /* if here, either got one, or need to return error */ + break; + } + } /*end for loop*/ + return(ret); +} + +int send_nmi(void) +{ + uchar idata[8]; + uchar rdata[30]; + int rlen; + uchar ccode; + int ret; + + idata[0] = 4; /* do NMI */ + rlen = sizeof(rdata); + ret = ipmi_cmdraw( CHASSIS_CTL, NETFN_CHAS, BMC_SA,PUBLIC_BUS,BMC_LUN, + idata,1, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} + +void show_event(uchar *evt,char *obuf, int sz) +{ + int i; + char sysbuf[250]; + /* obuf should be 132 chars or more */ + + msgout("event data: "); + for (i=0; i<16; i++) msgout("%02x ",evt[i]); + msgout("\n"); + + decode_sel_entry(evt,obuf,sz); + msgout(obuf); /*writes to outfile*/ + /* write the message to syslog also. */ + snprintf(sysbuf,sizeof(sysbuf),"%s: %s",progname,obuf); + write_syslog(sysbuf); +} + +static void ievt_cleanup(void) +{ + char obuf[48]; + if (fselevts) syncevent_sel(sel_recid,sel_time); + snprintf(obuf,sizeof(obuf),"%s exiting.\n",progname); + msgout(obuf); + write_syslog(obuf); + free_sdr_cache(sdrs); + iclose(); + exit(EXIT_SUCCESS); +} + +#if defined(WIN32) | defined(DOS) +/* no daemon code */ +static void ievt_siginit(void) { return; } +#else +/* Linux daemon code */ +#include <signal.h> +static void ievt_sighnd(int sig) +{ + ievt_cleanup(); + exit(EXIT_SUCCESS); +} + +static void ievt_siginit(void); +static void ievt_siginit(void) +{ + struct sigaction sact; + + /* handle signals for cleanup */ + sact.sa_handler = ievt_sighnd; + sact.sa_flags = 0; + sigemptyset(&sact.sa_mask); + sigaction(SIGINT, &sact, NULL); + sigaction(SIGQUIT, &sact, NULL); + sigaction(SIGTERM, &sact, NULL); +} + +static int mkdaemon(int fchdir, int fclose); +static int mkdaemon(int fchdir, int fclose) +{ + int fdlimit = sysconf(_SC_OPEN_MAX); /*fdlimit usu = 1024.*/ + int fd = 0; + + + fdlimit = fileno(stderr); /*only close files up to stderr*/ + switch (fork()) { + case 0: break; + case -1: return -1; + default: _exit(0); /* exit the original process */ + } + if (setsid() < 0) return -1; /* shouldn't fail */ + switch (fork()) { + case 0: break; + case -1: return -1; + default: _exit(0); /* exit the original process */ + } + if (fchdir) { + chdir("/"); + /* umask(0022); * leave file creation mask at default (0022) & 0777 */ + } + if (fclose) { + /* Close stdin,stdout,stderr and replace them with /dev/null */ + for (fd = 0; fd < fdlimit; fd++) close(fd); + open("/dev/null",O_RDWR); + dup(0); dup(0); + } + return 0; +} +#endif + +static void iclose() +{ + /* close out any IPMI handles or sessions */ +#ifdef THREADS_OK +#ifdef WIN32 + if (threadid != NULL) CloseHandle(threadid); +#else + /* thread close not needed in Linux */ +#endif +#endif + ipmi_close_(); + if (fbackground && fdout != NULL) fclose(fdout); +} + +#ifdef METACOMMAND +int i_getevt(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret = 0; + int c, j; + uchar devrec[16]; + uchar event[16]; + uchar sa, lun; + uchar enables = 0; + uchar fevmsgok = 0; + uchar sensor_type = 0; + uchar msg_flags = 0; + FILE *fp; + char outbuf[160]; + char tmpout[20]; + char *sdesc; + + fdout = stdout; + msgout("%s ver %s\n", progname,progver); + + while ( (c = getopt(argc,argv,"abce:lmn:or:st:uvT:V:J:YEF:P:N:R:U:Z:x?")) != EOF ) + switch(c) { + case 'a': fAsync = 1; /* imb async message method */ + /* chenge the output log filename */ + sdesc = strstr(outfile,"evt.log"); + if (sdesc != NULL) strcpy(sdesc,"asy.log"); + break; + case 'b': fbackground = 1; break; /* background */ + case 'c': fcanonical = 1; break; /* canonical */ + case 'e': /* event sensor type */ + if (strncmp(optarg,"0x",2) == 0) + evt_stype = htoi(&optarg[2]); + else evt_stype = atob(optarg); + break; + case 'l': fAsyncNOP = 1; break; /* do not reset (for testing)*/ + case 'm': fmsgevts = 1; break; /* use local getmessage method */ + case 'n': /* event sensor num, always hex */ + if (strncmp(optarg,"0x",2) == 0) + evt_snum = htoi(&optarg[2]); + else evt_snum = htoi(&optarg[0]); + break; + case 'o': frunonce = 1; break; /* only run once for first event */ + case 'r': /* run script (or binary) on an event */ + run_script = optarg; + fp = fopen(run_script,"r"); + if (fp == NULL) { + printf("cannot open %s\n",run_script); + ret = ERR_FILE_OPEN; + goto do_exit; + } else { + fclose(fp); + frunscript = 1; + } + break; + case 's': fselevts = 1; break; /* use SEL event method*/ + case 't': timeout = atoi(optarg); fsettime = 1; break; /*timeout*/ + case 'u': futc = 1; break; + case 'x': fdebug = 1; break; /* debug messages */ + case 'v': fdebug = 3; break; /* verbose debug with lan */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-abenorsux -t sec -NPRUEFTVY]\n", progname); + printf(" where -a use Async method\n"); + printf(" -b run in Background\n"); + printf(" -c use Canonical/delimited event format\n"); + printf(" -e T wait for specific event sensor type T\n"); + printf(" -n N wait for specific event sensor num N\n"); + printf(" -o run Once for the first event\n"); + printf(" -r F Run file F when an event occurs\n"); + printf(" -s use SEL event method\n"); + printf(" -t N set timeout to N seconds\n"); + printf(" -u use raw UTC time\n"); + printf(" -x show eXtra debug messages\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + fipmilan = is_remote(); + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + goto do_exit; + } else { + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + prod_id = devrec[9] + (devrec[10] << 8); + if (vend_id == VENDOR_INTEL) { + if (prod_id == 0x003E) /* NSN2U or CG2100 Urbanna */ + sms_sa = 0x41; + } + } + + /* get event receiver */ + ret = get_event_receiver(&sa ,&lun); + if (ret != 0) + msgout("event receiver error %d\n",ret); + else msgout("event receiver sa = %02x lun = %02x\n",sa,lun); + + ret = get_bmc_enables(&enables); + if (ret != 0) msgout("bmc enables error %d\n",ret); + else { + msgout("bmc enables = %02x\n",enables); + if ((enables & 0x02) == 2) fevmsgok = 1; + else fevmsgok = 0; + } + if (fevmsgok == 0 && !fipmilan) { + msgout("Event Message Buffers not enabled.\n"); + enables |= 0x0f; /* 0x08=SEL, 0x02=EvtMsgBuf, rest is gravy */ + ret = set_bmc_enables(enables); + if (ret != 0) { + msgout("set_bmc_enables error 0x%x\n",ret); + } + else msgout("set_bmc_enables success\n"); + } + if (fipmilan && !fselevts) { + msgout("Only the SEL method (-s) is supported over IPMI LAN\n"); + ret = LAN_ERR_NOTSUPPORT; + goto do_exit; + } + ret = get_msg_flags(&msg_flags); + msgout("igetevent reading sensors ...\n"); + write_syslog("igetevent reading sensors ...\n"); + ret = get_sdr_cache(&sdrs); + // if (!fipmilan) set_sel_opts(1,0, NULL,fdebug); + if (fdebug) msgout("get_sdr_cache ret = %d\n",ret); + if (ret == 0) set_sel_opts(1, fcanonical, sdrs,fdebug,futc); + else ret = 0; /*if error, keep going anyway*/ + + if (fselevts) { +#ifdef WIN32 + { /*resolve path of idxfile*/ + char *ipath; + ipath = getenv("ipmiutildir"); /*ipmiutil directory path*/ + if (ipath != NULL) { + if (strlen(ipath)+12 < sizeof(idxfile)) { + sprintf(idxfile,"%s\\%s",ipath,"\\",IDXFILE); + } + } + } +#endif + + if (fipmilan) { + char *node; + node = get_nodename(); + strcat(idxfile,"-"); + strcat(idxfile,node); + strcat(idxfile2,"-"); + strcat(idxfile2,node); + strcat(outfile,"-"); + strcat(outfile,node); + } + ret = startevent_sel(&sel_recid,&sel_time); + ret = 0; /*ignore any earlier errors, keep going*/ + } + + drvtype = get_driver_type(); + if (fdebug) msgout("driver_type = %d (%s)\n", + drvtype,show_driver_type(drvtype)); + + if (evt_stype == 0xFF) sdesc = "any event"; + else sdesc = get_sensor_type_desc(evt_stype); + if (evt_snum == 0xFF) tmpout[0] = 0; + else sprintf(tmpout,"with snum %02x",evt_snum); + if (evt_stype != 0xFF || evt_snum != 0xFF) + msgout("Look for event sensor type %02x (%s) %s\n", evt_stype,sdesc,tmpout); + +#ifdef TEST_SEL + /* This is used to verify that the interface returns valid next ids, + * and that the get_sel_entry is ok. */ + { + int i; + ushort r, r1, r2; + uchar rec[40]; + int rv; + r = 0; + for (i = 0; i < 4; i++) + { + rv = get_sel_entry(r,&r2,rec); + if (rv == 0) { + r1 = rec[0] + (rec[1] << 8); /*get current rec id*/ + if (fdebug) msgout("get_sel: r=%x r1=%x rnext=%x\n",r,r1,r2); + show_event(&rec[0],outbuf,sizeof(outbuf)); + r = r2; + } else break; + } + } +#endif + if (drvtype == DRV_IMB) fAsyncOK = 1; + else if (drvtype == DRV_MV) { + if (fsettime == 0) timeout = 0; /*DRV_MV default to infinite*/ + fAsyncOK = 1; + } else fAsyncOK = 0; + + if (fAsync && (!fAsyncOK)) { + msgout("Cannot open %s or %s driver, required for -a\n", + show_driver_type(DRV_IMB),show_driver_type(DRV_MV)); + ret = ERR_NO_DRV; + goto do_exit; + } + + if (fbackground) { /* convert to a daemon if background */ +#ifdef WIN32 + msgout("Background not implemented for Windows\n"); + ret = LAN_ERR_NOTSUPPORT; + goto do_exit; +#elif defined(DOS) + msgout("Background not implemented for DOS\n"); + ret = LAN_ERR_NOTSUPPORT; + goto do_exit; +#else + /* make sure we can open the log file before doing mkdaemon */ + fdout = fopen(outfile,"a"); + if (fdout == NULL) + printf("%s: Cannot open %s\n", progname,outfile); + else { + pid_t p; + fclose(fdout); + + ret = mkdaemon(1,1); + if (ret != 0) { + msgout("%s: Cannot become daemon, ret = %d\n", progname,ret); + goto do_exit; + } + /* open a log file for messages, set fdout */ + fdout = fopen(outfile,"a"); +#ifdef METACOMMAND + /* make sure driver debug also goes to log */ + fpdbg = fdout; + fperr = fdout; +#endif + p = getpid(); + msgout("PID %d: %s ver %s\n",p,progname,progver); /*log start message*/ + } +#endif + } + ievt_siginit(); + + if (fAsync && (fAsyncOK)) /*use imb/mv async messages*/ + { + msgout("Wait for an async event\n"); /* no timeout */ + if (drvtype == DRV_IMB) + { +#ifdef DO_ASYNC +#ifdef THREADS_OK +#ifdef WIN32 + /* Windows threads */ + threadid = CreateThread(NULL, 0, &pollThread, NULL, 0, NULL); + if (threadid == NULL) pollThread(NULL); +#else + /* Linux threads */ + ret = pthread_create( &threadid, NULL, pollThread, (void*) message); + // if (ret == 0) pthread_join( threadid, NULL); + // if (ret == 0) pthread_detach( threadid); +#endif + if (fdebug) msgout("pollThread create ret=%d handle=%x\n",ret,threadid); +#else + /* no threads */ + pollThread(NULL); +#endif + while (ret == 0) + { /*wait for imb message events*/ + msgout("Waiting %d seconds for an async event ...\n",timeout); + ret = get_imb_event(0xff,timeout,event); + if (ret == 0x81) { /*ok, shutting down OS*/ + ret = 0; + break; + } + if (frunonce) break; + if (timeout == 0 && ret == 0x80) { /*0x80 = no data yet */ + if (fdebug) msgout("get_event timeout, no event yet.\n"); + do_wait(wait_interval); + ret = 0; /*ok, keep going*/ + } + } +#endif + } /*endif DRV_IMB*/ +#ifdef DO_MVL + else { /*DRV_MV*/ + int stage; + stage = 0; + while (stage < 3) + { /*wait for mv message events*/ + if (fdebug) msgout("Waiting for async_mv event, stage %d\n",stage); + if (stage == 0) { + ret = get_mv_asy_event(CMD_GET_SOFTWARE_ID,timeout,event); + if (fdebug) msgout("got SmsOS GetSWID event ret = %d\n",ret); + /* send a reply */ + if (ret == 0) ret = send_mv_asy_resp(event); + if (ret == 0) stage = 1; /* got the SoftwareID request/response */ + else stage = 0; + } + if (stage == 1) { + /* get the reset command */ + memset(event,0,sizeof(event)); + ret = get_mv_asy_event(CMD_SMS_OS_REQUEST,timeout,event); + if (fdebug) msgout("got SmsOS GetSmsOS event ret = %d\n",ret); + if (ret == 0) ret = send_mv_asy_resp(event); + if (ret == 0) stage = 2; + else stage = 0; + } + if (stage == 2) { /* got the SmsOs request in event */ + uchar cmd, func; + cmd = event[2]; + func = event[3]; + if (cmd != CMD_SMS_OS_REQUEST) { /*cmd*/ + ret = LAN_ERR_INVPARAM; + if (fdebug) msgout("SmsOS cmd %x ret = %d\n",cmd,ret); + } else { + if (frunscript) { + write_syslog("igetevent -a running script\n"); + ret = system(run_script); + if (fdebug) msgout("run(%s) ret = %d\n",run_script,ret); + } + if (!fAsyncNOP) + switch(func) { /*subfunction*/ + case 0x01: /*shutdown & power down*/ + write_syslog("igetevent -a OS shutdown\n"); + ret = system(SHUTDOWN_CMD); + msgout("SmsOs shutdown, ret = %d\n",ret); + break; + case 0x02: /*shutdown & reboot*/ + write_syslog("igetevent -a OS reboot\n"); + ret = system(REBOOT_CMD); + msgout("SmsOs reboot, ret = %d\n",ret); + break; + case 0x03: /*send NMI locally*/ + write_syslog("igetevent -a NMI\n"); + ret = send_nmi(); + msgout("SmsOs NMI, ret = %d\n",ret); + default: + ret = LAN_ERR_INVPARAM; + msgout("SmsOS func %02x, ret = %d\n",func,ret); + break; + } + } + if (ret == 0) stage = 3; /*done, exit loop*/ + else { + if (fdebug) msgout("SmsOS error = %d, start over\n",ret); + stage = 0; /*start over*/ + } + } /*endif stage 2*/ + } /*end-while*/ + } /*end else DRV_MV*/ +#endif + + } else { /*not Async, std IPMI events */ + if (fselevts) { + msgout("Get IPMI SEL events after ID %04x\n",sel_recid); + } else + msgout("Get IPMI events from %s driver\n",show_driver_type(drvtype)); + j = get_evt_method(tmpout); + sprintf(outbuf,"igetevent waiting for events via method %d (%s)\n", + j, tmpout); + msgout(outbuf); + write_syslog(outbuf); + + /* loop on events here, like a daemon would. */ + while (ret == 0) + { /*wait for bmc message events*/ + msgout("Waiting %d seconds for an event ...\n",timeout); + /* note: could also get message flags here */ + ret = get_event(evt_stype,evt_snum,timeout,event,&sensor_type); + if (fdebug) msgout("get_event ret = %d\n",ret); + if (ret == 0) { /* got an event successfully */ + msgout("got event id %04x, sensor_type = %02x\n", + sel_recid, sensor_type); + show_event(event,outbuf,sizeof(outbuf)); + if (fselevts) syncevent_sel(sel_recid,sel_time); + if (frunscript) { /*run some script for each event*/ + char run_cmd[256]; + sprintf(run_cmd,"%s \"%s\"\n",run_script,outbuf); + j = system(run_cmd); + msgout("run(%s $1), ret = %d\n",run_script,j); + ret = j; /*if that failed, exit loop*/ + } + } else { + if (ret == 0x80) msgout("get_event timeout\n"); + else msgout("get_event error: ret = 0x%x\n",ret); + } + if (frunonce) break; + if (timeout == 0 && ret == 0x80) { /*0x80 = no data yet */ + if (fdebug) msgout("get_event timeout, no data yet.\n"); + do_wait(wait_interval); + ret = 0; /*ok, keep going*/ + } + } /*end while loop*/ + } + +do_exit: + ievt_cleanup(); + if (ret == 0x80) ret = 0; + // show_outcome(progname,ret); /*inert if background*/ + return(ret); +} /* end main()*/ + +/* end getevent.c */ diff --git a/util/ihealth.c b/util/ihealth.c new file mode 100644 index 0000000..6f6f0e1 --- /dev/null +++ b/util/ihealth.c @@ -0,0 +1,1153 @@ +/* + * ihealth.c (was bmchealth.c) + * + * This tool checks the health of the BMC via IPMI. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 03/22/06 Andy Cress - created + * 06/20/06 Andy Cress 0.6 - more vendor strings, add ping_node() stub for now + * 10/20/06 Andy Cress 1.1 - added -g for guid + * 01/10/07 Andy Cress 1.4 - added product strings + * 02/25/07 Andy Cress 2.8 - added more Chassis Status decoding + */ +/*M* +Copyright (c) 2006, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <stdlib.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include <string.h> +#include "ipmicmd.h" +#include "oem_intel.h" + +#define SELFTEST_STATUS 0x04 +#define GET_POWER_STATE 0x07 +extern int get_BiosVersion(char *str); +extern int get_SystemGuid(uchar *guid); +extern int GetSDR(int id, int *next, uchar *recdata, int srecdata, int *rlen); +extern int get_device_guid(char *pbuf, int *sz); /*subs.c*/ +extern int oem_supermicro_get_health(char *pstr, int sz); /*oem_supermicro.c*/ +extern int oem_supermicro_get_firmware_str(char *pstr, int sz); /*oem_supermicro.c*/ + +/* + * Global variables + */ +static char * progname = "ihealth"; +static char * progver = "2.93"; +static char fdebug = 0; +static char fipmilan = 0; +static char fcanonical = 0; +static char do_hsc = 0; +static char do_me = 0; +static char do_frusdr = 0; +static char do_guid = 0; +static char do_powerstate = 1; +static char do_lanstats = 0; +static char do_session = 0; +static char do_systeminfo = 0; +static char set_restore = 0; +static char set_name = 0; +static char set_os = 0; +static char set_os2 = 0; +static uchar restore_policy = 0; +static uchar bChan = 0x0e; +static char fmBMC = 0; +static char bdelim = '='; /*delimiter to separate name/value pairs*/ +static char bcomma = ','; /*comma delimiter, may change if CSV*/ +static char lan_ch_restrict = 0; +static int kcs_loops = 0; +static int vend_id = 0; +static int prod_id = 0; +static char *pname = NULL; +static char *pos = NULL; +static char *pos2 = NULL; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + + +int oem_get_health(char *pstr, int sz) +{ + int rv; + switch(vend_id) { + case VENDOR_PEPPERCON: + case VENDOR_SUPERMICRO: + rv = oem_supermicro_get_health(pstr, sz); + break; + case VENDOR_SUPERMICROX: + rv = oem_supermicro_get_firmware_str(pstr,sz); + break; + default: + rv = LAN_ERR_NOTSUPPORT; + break; + } + if (fdebug) printf("oem_get_health rv = %d\n",rv); + return rv; +} + +int get_lan_stats(uchar chan) +{ + uchar idata[2]; + uchar rdata[20]; + int rlen, rv; + uchar cc; + ushort *rw; + + /* get BMC LAN Statistics */ + idata[0] = chan; + idata[1] = 0x00; /*do not clear stats*/ + rlen = sizeof(rdata); + rv = ipmi_cmd(GET_LAN_STATS, idata,2, rdata,&rlen, &cc, fdebug); + if (fdebug) printf("get_lan_stats: rv = %d, cc = %02x\n",rv,cc); + if (rv == 0) { + if (cc == 0) { /*success, show BMC LAN stats*/ + rw = (ushort *)&rdata[0]; + printf("IPMI LAN channel %d statistics: \n",chan); + printf(" \tReceived IP Packets %c %d\n",bdelim,rw[0]); + printf(" \tRecvd IP Header errors %c %d\n",bdelim,rw[1]); + printf(" \tRecvd IP Address errors %c %d\n",bdelim,rw[2]); + printf(" \tRecvd IP Fragments %c %d\n",bdelim,rw[3]); + printf(" \tTransmitted IP Packets %c %d\n",bdelim,rw[4]); + printf(" \tReceived UDP Packets %c %d\n",bdelim,rw[5]); + printf(" \tReceived Valid RMCP Pkts %c %d\n",bdelim,rw[6]); + printf(" \tReceived UDP Proxy Pkts %c %d\n",bdelim,rw[7]); + printf(" \tDropped UDP Proxy Pkts %c %d\n",bdelim,rw[8]); + } else if (cc == 0xc1) { + printf("IPMI LAN channel %d statistics: not supported\n",chan); + } + } + return(rv); +} + +int get_session_info(uchar idx, int hnd, uchar *rdata, int *len) +{ + uchar idata[5]; + int ilen, rlen, rv; + uchar cc; + + ilen = 1; + idata[0] = idx; + if (idx == 0xFE) { + idata[1] = (uchar)hnd; + ilen = 2; + } else if (idx == 0xFF) { + idata[1] = (uchar)(hnd & 0x000000FF); + idata[2] = (uchar)((hnd & 0x0000FF00) >> 8); + idata[3] = (uchar)((hnd & 0x00FF0000) >> 16); + idata[4] = (uchar)((hnd & 0xFF000000) >> 24); + ilen = 5; + } + rlen = *len; + *len = 0; + rv = ipmi_cmdraw(CMD_GET_SESSION_INFO,NETFN_APP, + g_sa, g_bus, g_lun, + idata,ilen, rdata,&rlen,&cc, fdebug); + if (fdebug) printf("get_lan_stats: rv = %d, cc = %02x\n",rv,cc); + if (rv == 0) *len = rlen; + if ((rv == 0) && (cc != 0)) rv = cc; + return(rv); +} + +static char *sesstype_str(uchar c) +{ + uchar b; + char *s; + b = ((c & 0xf0) >> 4); + switch(b) { + case 0: s = "IPMIv1.5"; break; + case 1: s = "IPMIv2/RMCP+"; break; + default: s = "Other"; break; + } + return s; +} + +static void show_session_info(uchar idx, uchar *sinfo,int len) +{ + int i; + char lan_type = 1; + if (fdebug) { + printf("Raw Session Info[%d]: ",idx); + for (i = 0; i < len; i++) printf("%02x ",sinfo[i]); + printf("\n"); + } + + printf("Session Info[%d]:\n",idx); + printf("\tSession Handle %c %d\n",bdelim,sinfo[0]); + printf("\tSession Slot Count %c %d\n",bdelim,(sinfo[1] & 0x3f)); + printf("\tActive Sessions %c %d\n",bdelim,(sinfo[2] & 0x3f)); + if (len <= 3) return; + printf("\tUser ID %c %d\n",bdelim,(sinfo[3] & 0x3f)); + printf("\tPrivilege Level %c %d\n",bdelim,(sinfo[4] & 0x0f)); + printf("\tSession Type %c %s\n",bdelim,sesstype_str(sinfo[5])); + printf("\tChannel Number %c %d\n",bdelim,(sinfo[5] & 0x0f)); + if (len <= 6) return; + if (lan_type) { + printf("\tConsole IP %c %d.%d.%d.%d\n",bdelim, + sinfo[6],sinfo[7],sinfo[8],sinfo[9]); + printf("\tConsole MAC %c %02x:%02x:%02x:%02x:%02x:%02x\n",bdelim, + sinfo[10], sinfo[11], sinfo[12], + sinfo[13], sinfo[14], sinfo[15]); + printf("\tConsole Port %c %d\n",bdelim, + sinfo[16]+ (sinfo[17] << 8)); + } +} + +int get_session_info_all(void) +{ + int rv, len, nslots, i; + uchar sinfo[24]; + nslots = 1; + for (i = 1; i <= nslots; i++) { + len = sizeof(sinfo); + rv = get_session_info(i,0,sinfo,&len); + if (fdebug) printf("get_session_info(%d): rv = %d\n",i,rv); + if (rv != 0) { + if ((rv == 0xCB) || (rv == 0xCC)) { + if (len >= 3) show_session_info(i,sinfo,len); + if (i > 1) rv = 0; /*no such idx, end */ + } + break; + } + nslots = (sinfo[1] & 0x3F); + show_session_info(i,sinfo,len); + } + return(rv); +} + +static int get_selftest_status(uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + + ret = ipmi_cmdraw( SELFTEST_STATUS, NETFN_APP, + g_sa, g_bus, g_lun, + idata,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_selftest_status()*/ + +static int get_last_selftest(uchar *val, int vlen) +{ + uchar idata[4]; + uchar rdata[16]; + int rlen; + uchar ccode; + int ret; + + if (val == NULL) return(ERR_BAD_PARAM); + idata[0] = 0; /*0=first, 1=next*/ + memset(rdata,0xFF,2); /*initial value = end-of-list*/ + rlen = sizeof(rdata); + ret = ipmi_cmdraw( 0x16, 0x30, g_sa, g_bus, g_lun, + idata,1, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + if (ret == 0) { + if (rlen <= 0) ret = LAN_ERR_BADLENGTH; + else { + if (rlen > vlen) rlen = vlen; /*truncate if too long*/ + memcpy(val,rdata,rlen); + } + } + return(ret); +} + +static int get_chassis_status(uchar *rdata, int *rsz) +{ + uchar idata[4]; + uchar ccode; + int rlen; + int ret; + + rlen = *rsz; + ret = ipmi_cmdraw( CHASSIS_STATUS, NETFN_CHAS, + g_sa, g_bus, g_lun, + idata,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + if (ret == 0) *rsz = rlen; + return(ret); +} /*end chassis_status()*/ + +static void show_chs_status(uchar *sbuf, int slen) +{ + char chs_strbuf[80]; + char *pstr; + uchar state, b2, b3, b4; + + pstr = &chs_strbuf[0]; + state = sbuf[0] & 0x7f; + b2 = sbuf[1]; + b3 = sbuf[2]; + sprintf(pstr,"%s",(state & 0x01) ? "on" : "off"); + printf("Chassis Status %c %02x %02x %02x %02x (%s, see below)\n", + bdelim,state,sbuf[1],sbuf[2],sbuf[3],pstr); + sprintf(pstr,"\tchassis_power %c ",bdelim); + if (state & 0x01) strcat(pstr,"on"); + else strcat(pstr,"off"); + if (state & 0x02) strcat(pstr,", overload"); + if (state & 0x04) strcat(pstr,", interlock"); + if (state & 0x08) strcat(pstr,", fault"); + if (state & 0x10) strcat(pstr,", control error"); + printf("%s\n",pstr); + + sprintf(pstr,"\tpwr_restore_policy %c ",bdelim); + if (state & 0x20) strcat(pstr,"last_state"); + else if (state & 0x40) strcat(pstr,"turn_on"); + else strcat(pstr,"stay_off"); + printf("%s\n",pstr); + + if (b2 != 0) { + sprintf(pstr,"\tlast_power_event %c ",bdelim); + if (b2 & 0x10) strcat(pstr,"IPMI "); + if (b2 & 0x08) strcat(pstr,"fault "); + if (b2 & 0x04) strcat(pstr,"interlock "); + if (b2 & 0x02) strcat(pstr,"overload "); + if (b2 & 0x01) strcat(pstr,"ACfailed"); + printf("%s\n",pstr); + } + printf("\tchassis_intrusion %c %s\n", bdelim, + (b3 & 0x01) ? "active":"inactive"); + printf("\tfront_panel_lockout %c %s\n", bdelim, + (b3 & 0x02) ? "active":"inactive"); + printf("\tdrive_fault %c %s\n", bdelim, + (b3 & 0x04) ? "true":"false"); + printf("\tcooling_fan_fault %c %s\n", bdelim, + (b3 & 0x08) ? "true":"false"); + if (slen > 3) { + b4 = sbuf[3]; + if (b4 & 0x80) { + printf("\tFP sleep_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x08) ? "disabled":"enabled"); + } + if (b4 & 0x40) { + printf("\tFP diag_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x04) ? "disabled":"enabled"); + } + if (b4 & 0x20) { + printf("\tFP reset_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x02) ? "disabled":"enabled"); + } + if (b4 & 0x10) { + printf("\tFP power_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x01) ? "disabled":"enabled"); + } + } + return; +} + +static int get_power_state(uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + + ret = ipmi_cmdraw( GET_POWER_STATE, NETFN_APP, + g_sa, g_bus, g_lun, + idata,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_power_state()*/ + +static char *pwr_string(uchar pstate) +{ + char *pstr; + switch(pstate) { + case 0x00: pstr = "S0: working"; break; + case 0x01: pstr = "S1: clock stopped, context ok"; break; + case 0x02: pstr = "S2: clock stopped, context lost"; break; + case 0x03: pstr = "S3: suspend-to-RAM"; break; + case 0x04: pstr = "S4: suspend-to-Disk"; break; + case 0x05: pstr = "S5: soft off"; break; + case 0x06: pstr = "S4/S5: soft off, either S4 or S5"; break; + case 0x07: pstr = "G3: mechanical off"; break; + case 0x08: pstr = "S1-S3: sleeping"; break; + case 0x09: pstr = "S1-S4: sleeping"; break; + case 0x0A: pstr = "S5/o: soft off by override"; break; + case 0x20: pstr = "legacy on"; break; + case 0x21: pstr = "legacy soft-off"; break; + case 0x2a: /* not initialized or device lost track of state */ + default: pstr = "unknown"; break; + } + return(pstr); +} + +#ifdef PING_OK +extern int ping_bmc(char *node, char fdebug); + +static int ping_node(char *node) +{ + int rv = 0; + /* verify that the BMC LAN channel is configured & active */ + /* send rmcp_ping to node's BMC */ + rv = ping_bmc(node,fdebug); + return(rv); +} +#endif + +#define MIN_SDR_SZ 8 +static int get_frusdr_version(char *pver, int sver) +{ + ushort recid; + int recnext; + int ret, sz, i, len; + uchar sdr[MAX_BUFFER_SIZE]; + char verstr[30]; + char fIntel; + int verlen; + + recid = 0; + verstr[0] = 0; + verlen = 0; + while (recid != 0xffff) + { + memset(sdr,0,sizeof(sdr)); + ret = GetSDR(recid,&recnext,sdr,sizeof(sdr),&sz); + if (fdebug) + printf("GetSDR[%04x]: ret = %x, next=%x\n",recid,ret,recnext); + if (ret != 0) { + if (ret > 0) { /* ret is a completion code error */ + if (fdebug) + printf("%04x GetSDR error 0x%02x %s, rlen=%d\n",recid,ret, + decode_cc((ushort)0,(uchar)ret),sz); + } else printf("%04x GetSDR error %d, rlen = %d\n", recid,ret,sz); + if (sz < MIN_SDR_SZ) { /* don't have recnext, so abort */ + break; + } /* else fall through & continue */ + } else { /*got SDR */ + len = sdr[4] + 5; + if (sdr[3] == 0xC0) { /* OEM SDR */ + /* check for Intel mfg id */ + if ((sdr[5] == 0x57) && (sdr[6] == 0x01) && (sdr[7] == 0x00)) + fIntel = 1; + else fIntel = 0; + if (sdr[8] == 0x53) { /*Intel OEM subtype, ASCII 'S' */ + verlen = 0; + for (i = 8; i < len; i++) { + if (sdr[i] == 0) break; + if (i >= sizeof(verstr)) break; + verstr[verlen++] = sdr[i]; + } + verstr[verlen] = 0; /*stringify*/ + /* continue on past SDR File, get SDR Package version */ + // break; + } + } /*endif OEM SDR*/ + } + if (recnext == recid) recid = 0xffff; /*break;*/ + else recid = (ushort)recnext; + } + if (verlen > sver) verlen = sver; + if (fdebug) + printf("get_frusdr_version: verstr=%s, verlen=%d\n",verstr,verlen); + strncpy(pver,verstr,verlen); + return(ret); +} + +static int get_hsc_devid(uchar *rdata, int rlen) +{ + uchar ccode; + int ret; + + ret = ipmi_cmdraw( 0x01, /*(GET_DEVICEID & 0x00ff)*/ + NETFN_APP, 0xC0,PUBLIC_BUS,BMC_LUN, + NULL,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_hsc_devid*/ + +static int get_chan_auth(uchar chan, uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + + idata[0] = chan; /*0x0e = this channel*/ + idata[1] = 0x02; /*priv level = user*/ + ret = ipmi_cmdraw( 0x38, NETFN_APP, /*CMD_GET_CHAN_AUTH_CAP*/ + g_sa, g_bus, g_lun, + idata,2, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_chan_auth*/ + +void show_chan_auth(char *tag, uchar *rec, int srec) +{ + char pstr[40]; + pstr[0] = 0; + if (rec[1] & 0x01) strcat(pstr,"None "); + if (rec[1] & 0x02) strcat(pstr,"MD2 "); + if (rec[1] & 0x04) strcat(pstr,"MD5 "); + if (rec[1] & 0x10) strcat(pstr,"Straight_Passwd "); + if (rec[1] & 0x20) strcat(pstr,"OEM "); + printf("Chan %d AuthTypes %c %s\n",rec[0],bdelim,pstr); + if (do_hsc) /*only show this if extra output*/ + printf("Chan %d Status %c %02x, OEM ID %02x%02x%02x OEM Aux %02x\n", + rec[0],bdelim,rec[2],rec[4],rec[5],rec[6],rec[7]); +} + +#define BMC 1 +#define HSC 2 + +#ifdef MOVED +/* moved to subs.c*/ +#define N_MFG 41 +struct { int val; char *pstr; } mfgs[N_MFG] = { }; +char * get_iana_str(int mfg); +#endif + +char * get_mfg_str(uchar *rgmfg, int *pmfg) +{ + char *mfgstr = ""; + int mfg; + mfg = rgmfg[0] + (rgmfg[1] << 8) + (rgmfg[2] << 16); + if (pmfg != NULL) *pmfg = mfg; /*vend_id*/ + mfgstr = get_iana_str(mfg); + return(mfgstr); +} + +/* int get_system_info(uchar parm, char *pbuf, int *szbuf); *see subs.c*/ +/* int set_system_info(uchar parm, uchar *pbuf, int *szbuf); *see subs.c*/ + +void show_devid_all(int dtype, uchar *devrec, int sdevrec) +{ + uchar ipmi_maj = 0; + uchar ipmi_min = 0; + char *tag; + int mfg, prod; + char *mfgstr = ""; + char *prodstr = ""; + char prodoem[40]; + char extraver[32]; + int i, j, k, l, rv; + + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + prod = devrec[9] + (devrec[10] << 8); + mfgstr = get_mfg_str(&devrec[6],&mfg); + vend_id = mfg; + prod_id = prod; + extraver[0] = 0; + if (dtype == HSC) tag = "HSC"; + else { + tag = "BMC"; + /* The product ids below only apply to BMCs */ + switch(mfg) { + case VENDOR_NSC: /*=0x000322*/ + fmBMC = 1; + if (dtype == BMC) tag="mBMC"; + if (prod == 0x4311) prodstr = "(TIGPT1U)"; /*Intel*/ + break; + case VENDOR_SUN: /*=0x00002a*/ + if (prod == 0x4701) prodstr = "(X4140)"; + break; + case VENDOR_TYAN: /*=0x0019fd*/ + switch(prod) { /* show product names for some */ + case 0x0b41: prodstr = "(M3289)"; break; + case 0x0f98: prodstr = "(M3291)"; break; + case 0x137d: prodstr = "(S4989)"; break; + case 0x13ee: prodstr = "(S5102)"; break; + case 0x14fc: prodstr = "(S5372)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_FUJITSU: /*=0x002880*/ + if (prod >= 0x200) prodstr = "(iRMC S2)"; + else prodstr = ""; + break; + case VENDOR_CISCO: /*=0x00168b*/ + if (prod == 0x0005) prodstr = "(UCS C200)"; + else prodstr = ""; + if (fipmilan) lan_ch_restrict = 1; /*fw bug, gets 0xC1 on ipmilan*/ + break; + case VENDOR_INTEL: /*=0x000157*/ + if (do_hsc && (dtype == BMC)) /*if HSC option, also show extra*/ + sprintf(extraver," (Boot %x.%x PIA %x.%x)", /*BMC extra*/ + devrec[11],devrec[12],devrec[13],devrec[14]); + switch(prod) { /* show product names for some */ + case 0x000C: prodstr = "(TSRLT2)"; /*SCB2*/ + bChan = 7; break; + case 0x001B: prodstr = "(TIGPR2U)"; /*SWV2*/ + bChan = 7; break; + case 0x0022: prodstr = "(TIGI2U)"; break; /*SJR2*/ + case 0x0026: prodstr = "(Bridgeport)"; break; + case 0x0028: prodstr = "(S5000PAL)"; break; /*Alcolu*/ + case 0x0029: prodstr = "(S5000PSL)"; break; /*StarLake*/ + case 0x002B: prodstr = "(S5000VSA)"; break; + case 0x002D: prodstr = "(MFSYS25)"; break; /*ClearBay*/ + case 0x003E: prodstr = "(S5520UR)"; /*CG2100 or NSN2U*/ + do_me = 1; kcs_loops = URNLOOPS; + bChan = 1; break; + case 0x0040: prodstr = "(QSSC-S4R)"; /*Stoutland*/ + do_me = 1; kcs_loops = URNLOOPS; + bChan = 1; break; + case 0x0100: prodstr = "(Tiger4)"; break; + case 0x0103: prodstr = "(McCarran)"; /*BladeCenter*/ + do_powerstate = 0; break; + case 0x0800: prodstr = "(ZT5504)"; /*ZiaTech*/ + do_powerstate = 0; break; + case 0x0808: prodstr = "(MPCBL0001)"; /*ATCA Blade*/ + do_powerstate = 0; break; + case 0x0841: prodstr = "(MPCMM0001)"; /*ATCA CMM*/ + do_powerstate = 0; break; + case 0x0811: prodstr = "(TIGW1U)"; break; /*S5000PHB*/ + case 0x4311: prodstr = "(NSI2U)"; /*SE7520JR23*/ + if (dtype == BMC) tag="mBMC"; + fmBMC = 1; break; + default: prodstr = ""; break; + } + if (is_romley(mfg,prod)) { + intel_romley_desc(mfg,prod,&prodstr); + snprintf(prodoem,sizeof(prodoem),"(%s)",prodstr); + prodstr = prodoem; + do_me = 1; kcs_loops = URNLOOPS; + do_hsc = 1; /*the HSC is embedded, so not the same*/ + sprintf(extraver,".%d (Boot %x.%x)", /*BMC extra*/ + (devrec[13] + (devrec[14] << 8)),devrec[11],devrec[12]); + } + break; + case VENDOR_KONTRON: /*=0x003A98=15000.*/ + i = devrec[11] + (devrec[12] << 8); + j = devrec[13] + (devrec[14] << 8); + k = 0; l = 0; + { /* get Kontron firmware version with OEM cmd */ + int rlen; + uchar idata[4]; + uchar rdata[16]; + uchar cc; + rlen = sizeof(rdata); + idata[0] = 0; + idata[1] = 0; + idata[2] = 1; + rv = ipmi_cmdraw(0x2f, 0x2c, g_sa, g_bus, g_lun, + idata,3,rdata,&rlen,&cc,fdebug); + if (rv == 0 && cc == 0) { + k = rdata[1]; + l = rdata[2]; + } + } + sprintf(extraver,".%02d.%02d (FW %x.%x)",i,j,k,l); + switch(prod) { /* show product names for some */ + case 0x1590: prodstr = "(KTC5520)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_PEPPERCON: /*=0x0028c5 Peppercon/Raritan */ + if (prod == 0x0004) prodstr = "(AOC-IPMI20)"; /*SuperMicro*/ + else if (prod == 0x0007) prodstr = "(RMM2)"; /*Intel RMM2*/ + break; + case VENDOR_HP: /*=0x00000B*/ + switch(prod) { /* show product names for some */ + case 0x2000: prodstr = "(Proliant ML/DL)"; break; /*DL380*/ + case 0x2020: prodstr = "(Proliant BL)"; break; + default: if ((prod & 0xff00) == 0x8300) + prodstr = "(Proliant SL)"; + else prodstr = ""; + break; + } + do_powerstate = 0; /*HP does not support get_power_state cmd*/ + break; + case VENDOR_DELL: /*=0x0002A2*/ + switch(prod) { /* show product names for some */ + case 0x0100: prodstr = "(PE R610)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_MAGNUM: /* =5593. used by SuperMicro*/ + switch(prod) { /* show product names for some */ + case 6: prodstr = "(X8DTL)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_SUPERMICRO: /* =10876. used by SuperMicro*/ + case VENDOR_SUPERMICROX: /* =47488. used by Winbond/SuperMicro*/ + switch(prod) { /* decode some SuperMicro product ids */ + case 4: prodstr = "(X7DBR)"; break; + case 6: prodstr = "(X8DTL)"; break; + case 1037: prodstr = "(X8SIE)"; break; + case 1541: prodstr = "(X8SIL)"; break; + case 1547: prodstr = "(X8SIA)"; break; /*0x060b*/ + case 1549: prodstr = "(X8DTU)"; break; + case 1551: prodstr = "(X8DTN)"; break; + case 1562: prodstr = "(X8SIU-F)"; break; /*0x061a*/ + case 1572: prodstr = "(X9SCM)"; break; /*or X9SCL*/ + case 1576: prodstr = "(X9DRi)"; break; + case 1585: prodstr = "(X9SCA)"; break; + case 1603: prodstr = "(X9SPU)"; break; /*0x0643*/ + case 1643: prodstr = "(X9SRL)"; break; /*0x066b*/ + case 1797: prodstr = "(X9DR7)"; break; /*0x0705*/ + case 43025: prodstr = "(H8DGU)"; break; + case 43707: prodstr = "(X8DTH)"; break; + default: prodstr = ""; break; + } + if (!fipmilan) lan_ch_restrict = 1; /*fw bug, gets 0xd4 locally*/ + break; + case VENDOR_QUANTA: /*=7244.*/ + switch(prod) { /* show product names for some */ + case 21401: prodstr = "(S99Q)"; break; + default: prodstr = ""; break; + } + break; + default: + prodstr = ""; + break; + } /*end switch(prod)*/ + if (kcs_loops != 0) set_max_kcs_loops(kcs_loops); + } /*end-else BMC*/ + + printf("%s manufacturer %c %06x (%s)%c product %c %04x %s\n", + tag, bdelim,mfg,mfgstr,bcomma,bdelim,prod,prodstr); + { /* BMC version */ + printf("%s version %c %x.%02x%s%c IPMI v%d.%d\n", tag,bdelim, + devrec[2],devrec[3],extraver,bcomma,ipmi_maj,ipmi_min); + } + /* could show product rev, if available (sdevrec > 14) */ + return; +} + +int GetPowerOnHours(unsigned int *val) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar cc; + int rc = -1; + int i; + unsigned int hrs; + + *val = 0; + if (fmBMC) return(rc); + sresp = MAX_BUFFER_SIZE; + memset(resp,0,6); /* default response size is 5 */ + rc = ipmi_cmd_mc(GET_POWERON_HOURS, NULL, 0, resp, &sresp, &cc, fdebug); + if (rc == 0 && cc == 0) { + /* show the hours (32-bits) */ + hrs = resp[1] | (resp[2] << 8) | (resp[3] << 16) | (resp[4] << 24); + if (resp[0] == 60) /*normal*/ i = 1; + else { + i = 60 / resp[0]; + hrs = hrs / i; + } + *val = hrs; + } + return(rc); +} + +char *decode_selftest(int stat) +{ + uchar *s; + uchar b; + if (stat == 0x0055) s = "(OK)"; + else { + s = "(Error)"; + if ((stat & 0x00ff) == 0x0057) { + b = ((stat & 0xff00) >> 8); + if (b & 0x80) s = "(No SEL Access)"; + if (b & 0x40) s = "(No SDR Access)"; + if (b & 0x20) s = "(No FRU Access)"; + if (b & 0x10) s = "(IPMB Error)"; + if (b & 0x08) s = "(SDR Empty)"; + if (b & 0x02) s = "(BootCode Corrupt)"; + if (b & 0x01) s = "(OpCode Corrupt)"; + } + } + return(s); +} + +#ifdef METACOMMAND +int i_health(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret = 0; + int c; + uchar selfbuf[16]; + uchar devrec[30]; + char biosver[80]; + uchar cc; + int selfstatus; + uchar pwr_state; + char selfstr[36]; + char *s; + char *s1; + int i, sresp; + uint n; + int rlen, len; + uchar idata[4]; + uchar rdata[16]; + + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"cfghiln:o:p:q:sT:V:J:YEF:P:N:R:U:Z:x?")) != EOF ) + switch(c) { + case 'c': fcanonical = 1; + bdelim = BDELIM; break; /* canonical output */ + case 'f': do_frusdr = 1; break; /* check the FRUSDR too */ + case 'g': do_guid = 1; break; /* get the System GUID also */ + case 'h': do_hsc = 1; break; /* check the HSC too */ + case 'i': do_systeminfo = 1; break; /* get system info too */ + case 'l': do_lanstats = 1; break; /* get the LAN stats too */ + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'n': set_name = 1; /* set the system name*/ + pname = optarg; + break; + case 'o': set_os = 1; /* set the Operating System*/ + pos = optarg; + break; + case 'q': set_os2 = 1; /* set the Operating System*/ + pos2 = optarg; + break; + case 'p': set_restore = 1; /* set the restore policy */ + restore_policy = atob(optarg); + if (restore_policy > 2) restore_policy = 1; + break; + case 's': do_session = 1; break; /* get session info too */ + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-cfghilnopsx -N node -U user -P/-R pswd -EFTVY]\n", progname); + printf(" where -x show eXtra debug messages\n"); + printf(" -c canonical output\n"); + printf(" -f get the FRUSDR version also\n"); + printf(" -g get the System GUID also\n"); + printf(" -h check the HotSwap Controller also\n"); + printf(" -i get System Info also: Name and OS\n"); + printf(" -l get the IPMI LAN statistics also\n"); + printf(" -n set System Name to this string \n"); + printf(" -o set Operating System to this string\n"); + printf(" -p1 set restore policy: 0=off, 1=last, 2=on\n"); + printf(" -s get the IPMI Session info also\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto health_end; + } + + fipmilan = is_remote(); + if (fipmilan && set_restore) + parse_lan_options('V',"4",0); /*if set, request admin priv*/ + + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + goto health_end; + } else { + show_devid_all(BMC,devrec,16); + } + + if (!fipmilan) { /*get local BIOS version*/ + biosver[0] = 0; + ret = get_BiosVersion(biosver); + if (ret == 0) printf("BIOS Version %c %s\n",bdelim,biosver); + } + if (do_me) { /* ME version for Intel S5500 motherboards */ + rlen = sizeof(rdata); + ret = ipmi_cmdraw((GET_DEVICE_ID & 0xff), NETFN_APP,ME_SA,ME_BUS,0x00, + idata,0,rdata,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + if (ret == 0) { + uchar m,n; + m = (rdata[3] & 0xf0) >> 4; + n = (rdata[3] & 0x0f); + printf("ME Firmware Ver %c %02x.%02x.%02x.%02x%02x\n",bdelim, + rdata[2],m,n,rdata[12],rdata[13]); + /* If rdata[2] has 0x80 bit on, ME is in update/recovery mode. + That can be cleared by removing input power. */ + } else + if (fdebug) printf("GetDeviceID(ME) error ret = %d\n",ret); + } + + if (do_hsc) { + if (fmBMC) printf("No HSC present\n"); + else { + /* Get HSC status */ + if (is_romley(vend_id, prod_id)) { + uchar maj, min; + ret = get_hsbp_version_intel(&maj, &min); + if (fdebug) printf("get_hsbp_version_intel ret = %d\n",ret); + if (ret == 0) + printf("HSC version %c %d.%02d\n", bdelim,maj,min); + } else { + ret = get_hsc_devid(&devrec[0],sizeof(devrec)); + if (fdebug) printf("get_hsc_devid ret = %d\n",ret); + if (ret == 0) /* only if HSC is detected */ + show_devid_all(HSC,devrec,14); + } + } + } + + i = get_driver_type(); + printf("IPMI driver type %c %d (%s)\n",bdelim,i,show_driver_type(i)); + + if (do_powerstate) + { /* Some BMCs dont support get_power_state*/ + ret = get_power_state(selfbuf,4); + if (ret != 0) { + printf("ipmi_getpowerstate error, ret = %d\n",ret); + goto health_end; + } else { + pwr_state = selfbuf[0] & 0x7f; + printf("Power State %c %02x (%s)\n", + bdelim,pwr_state,pwr_string(pwr_state)); + } + } + + ret = get_selftest_status(&selfbuf[0],sizeof(selfbuf)); + if (ret != 0) { + printf("get_selftest_status error, ret = %x\n",ret); + goto health_end; + } else { + selfstatus = selfbuf[0] + (selfbuf[1] << 8); + s = decode_selftest(selfstatus); + if (fmBMC) { + sprintf(selfstr,"%s",s); + } else { + ret = get_last_selftest(&selfbuf[0],sizeof(selfbuf)); + if (fdebug) printf("get_last_selftest ret = %x, %02x%02x\n", + ret, selfbuf[1],selfbuf[0]); + if (ret == 0 && (selfbuf[0] != 0xFF)) { + sprintf(selfstr,"%s, last = %02x%02x",s,selfbuf[1],selfbuf[0]); + } else sprintf(selfstr,"%s",s); + ret = 0; /*ignore any errors with get_last_selftest*/ + } + printf("Selftest status %c %04x %s\n",bdelim,selfstatus,selfstr); + } + + ret = oem_get_health(&selfstr[0],sizeof(selfstr)); + if (ret == 0) { + printf("%s\n",selfstr); + } + + rlen = 4; + ret = get_chassis_status(selfbuf,&rlen); + if (ret != 0) { + printf("Cannot do get_chassis_status, ret = %d\n",ret); + goto health_end; + } else { + show_chs_status(selfbuf,rlen); + } + + if (vend_id == VENDOR_INTEL) { + int pwr_delay = 0; + ret = get_power_restore_delay_intel(&pwr_delay); + if (fdebug) printf("get_power_restore_delay_intel ret = %d\n",ret); + if (ret == 0) { + printf("PowerRestoreDelay %c %d seconds\n",bdelim,pwr_delay); + } else ret = 0; + } + + if (do_guid) { + sresp = sizeof(devrec); + ret = ipmi_cmd(GET_SYSTEM_GUID,NULL,0,devrec,&sresp,&cc,fdebug); + if (ret != 0) { + if (!is_remote()) { /* get UUID from SMBIOS */ + cc = 0; sresp = 16; + ret = get_SystemGuid(devrec); + } else { + cc = 0; + sresp = sizeof(devrec); + ret = get_device_guid(devrec,&sresp); + } + } + if (fdebug) printf("system_guid: ret = %d, cc = %x\n",ret,cc); + if (ret == 0 && cc == 0) { + printf("System GUID %c ",bdelim); + for (i=0; i<16; i++) { + if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) s = "-"; + else s = ""; + printf("%s%02x",s,devrec[i]); + } + printf("\n"); + } + } + + if (bChan != 7) /* do not get first lan chan if set above */ + ret = get_lan_channel(1,&bChan); + + if (fmBMC == 0) { + ret = GetPowerOnHours(&n); + if (ret == 0) + printf("Power On Hours %c %d hours (%d days)\n",bdelim,n,(n/24)); + if (ret == 0xC1) ret = 0; /* not supporting poweron hours is ok. */ + + printf("BMC LAN Channels %c ",bdelim); + for (i = 1; i<= 16; ) { + c = get_lan_channel(i,&cc); + if (c != 0) break; + printf("%d ",cc); + i = cc+1; + } + printf("\n"); + + if (lan_ch_restrict) ; /*skip if vendor fw bug*/ + else { + ret = get_chan_auth(bChan,&devrec[0],sizeof(devrec)); + if (ret == 0) + show_chan_auth("Channel Auth Cap",devrec,8); + else + printf("get_chan_auth error: ret = %x\n",ret); + } + } + + if (do_systeminfo) { + char infostr[64]; + len = sizeof(infostr); + ret = get_system_info(1,infostr,&len); /*Firmware Version*/ + len = sizeof(infostr); + ret = get_system_info(2,infostr,&len); + if (ret == 0) { + printf("System Name %c %s\n",bdelim,infostr); + len = sizeof(infostr); + ret = get_system_info(3,infostr,&len); + if (ret == 0) printf("Pri Operating System %c %s\n",bdelim,infostr); + len = sizeof(infostr); + ret = get_system_info(4,infostr,&len); + if (ret == 0) printf("Sec Operating System %c %s\n",bdelim,infostr); + } else { + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("GetSystemInfo not supported on this platform\n"); + } + } + + if (do_frusdr) { + ret = get_frusdr_version((char *)&devrec[0],sizeof(devrec)); + if (ret == 0) printf("FRU/SDR Version %c %s\n",bdelim,devrec); + else printf("FRU/SDR Version %c error %d\n",bdelim,ret); + } + + if (do_lanstats) { + ret = get_lan_stats(bChan); + } + + if (do_session) { + i = get_session_info_all(); + if (i != 0) printf("get_session_info error %d, %s\n",i,decode_rv(i)); + } + +#ifdef PING_OK + { + char *node; + /* Currently some problems with this: + * works first time, but locks up BMC LAN on subsequent attempts. + */ + node = get_nodename(); + ret = ping_node(node); + printf("ping_node(%s): ret = %d\n",node,ret); + } +#endif + + if (set_name) { + len = (int)strlen(pname); + ret = set_system_info(2,pname,len); + printf("Set System Name to '%s', ret = %d\n",pname,ret); + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("SetSystemInfo not supported on this platform\n"); + } + + if (set_os) { + len = (int)strlen(pos); + ret = set_system_info(3,pos,len); + printf("Set Pri Operating System to '%s', ret = %d\n",pos,ret); + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("SetSystemInfo not supported on this platform\n"); + } + + if (set_os2) { + len = (int)strlen(pos2); + ret = set_system_info(4,pos2,len); + printf("Set Sec Operating System to '%s', ret = %d\n",pos2,ret); + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("SetSystemInfo not supported on this platform\n"); + } + + if (set_restore) { + idata[0] = restore_policy; /* 1=last_state, 2=turn_on, 0=stay_off*/ + rlen = sizeof(rdata); + ret = ipmi_cmdraw(0x06 , NETFN_CHAS, g_sa, g_bus, g_lun, + idata,1,rdata,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + printf("set_restore_policy(%x): ret = %d\n",restore_policy,ret); + } + +health_end: + ipmi_close_(); + // show_outcome(progname,ret); + return (ret); +} /* end main()*/ + +/* end bmchealth.c */ diff --git a/util/ihpm.c b/util/ihpm.c new file mode 100644 index 0000000..740ab74 --- /dev/null +++ b/util/ihpm.c @@ -0,0 +1,4003 @@ +/* + * ihpm.c + * Hardware Platform Management, IPM Controller Firmware Upgrade Procedure + * + * Change history: + * 08/25/2010 ARCress - ported from ipmitool/lib/ipmi_hpmfwupg.c + * 08/24/2011 ARcress - updated to Kontron 1.08 (K17) version, + * added hpm_decode_cc(), etc. + * + *--------------------------------------------------------------------- + */ +/* + * Copyright (c) 2006 Kontron Canada, Inc. All Rights Reserved. + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifdef WIN32 +#include <windows.h> +#include <winsock.h> +#include <stdlib.h> +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +typedef uint32_t socklen_t; +#include "getopt.h" +#else +#include <arpa/inet.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <ctype.h> /*for toupper*/ +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> + +#include "ipmicmd.h" +#include "ihpm.h" + +/**************************************************************************** +* +* Copyright (c) 2006 Kontron Canada, Inc. All Rights Reserved. +* +* HPM.1 +* Hardware Platform Management +* IPM Controller Firmware Upgrade Procedure +* +* This module implements an Upgrade Agent for the IPM Controller +* Firmware Upgrade Procedure (HPM.1) specification version 1.0. +* +* author: +* Frederic.Lelievre@ca.kontron.com +* Francois.Isabelle@ca.kontron.com +* Jean-Michel.Audet@ca.kontron.com +* MarieJosee.Blais@ca.kontron.com +* +***************************************************************************** +* +* HISTORY +* =========================================================================== +* 2007-01-11 +* +* - Incremented to version 0.2 +* - Added lan packet size reduction mechanism to workaround fact +* that lan iface will not return C7 on excessive length +* - Fixed some typos +* - now uses lprintf() +* +* - Incremented to version 0.3 +* - added patch for openipmi si driver V39 (send message in driver does not +* retry on 82/83 completion code and return 82/83 as response from target +* [conditionnaly built with ENABLE_OPENIPMI_V39_PATCH] +* +* see: ipmi-fix-send-msg-retry.pacth in openipmi-developer mailing list +* +* 2007-01-16 +* +* - Incremented to version 0.4 +* - Fixed lan iface inaccesiblity timeout handling. Waiting for firmware +* activation completion (fixed sleep) before re-opening a session and +* get the final firmware upgrade status. +* - Fixed some user interface stuff. +* +* 2007-05-09 +* +* - Incremented to version 1.0 +* - Modifications for compliancy with HPM.1 specification version 1.0 +* +* 2007-06-05 +* +* - Modified the display of upgrade of Firmware version. +* - Added new options like "check" and "component" and "all" to hpm commands. +* - By default we skip the upgrade if we have the same firmware version +* as compared to the Image file (*.hpm).This will ensure that user does +* not update the target incase its already been updated +* +* 2008-01-25 +* - Reduce buffer length more aggressively when no response from iol. +* - Incremented version to 1.02 +* +* 2009-02-11 +* - With multi-component HPM file, if one component need to be skipped because +* the component is already up-to-date, ipmitool sends "Initiate upgrade +* action / Upload for upgrade" anyway. +* +* If the component needs to be skipped, ipmitool will not send "Initiate +* upgrade action / Upload for upgrade" +* +* - Incremented version to 1.03 +* +* 2009-02-11 +* - Fixed side effect introduced by last version, "forced" update didn't +* work anymore +* - Incremented version to 1.04 +* +* 2009-03-25 +* - Fix the case where ipmitool loses the iol connection during the upload +* block process. Once IPMITool was successfully sent the first byte, +* IPMITool will not resize the block size. +* +* 2009-03-26 +* - Fix the problem when we try to upgrade specific component and the component +* is already updated, IPMITool sends a "prepare action" but IPMITool skips +* the upload firmware block process. +* So, if we specify a specific component, we want to force to upload this +* specific component. +* - Incremented version to 1.05 +* +* 2009-04-20 +* - Reworked previous update, when 'component' is specified, the other +* components are now skipped. +* - Incremented version to 1.06 +* +* =========================================================================== +* TODO +* =========================================================================== +* 2007-01-11 +* - Add interpretation of GetSelftestResults +* - Add interpretation of component ID string +* +*****************************************************************************/ + +extern int verbose; + +/* + * Agent version + */ +#define HPMFWUPG_VERSION_MAJOR 1 +#define HPMFWUPG_VERSION_MINOR 0 +#define HPMFWUPG_VERSION_SUBMINOR 9 +static char * progname = "ihpm"; +static char * progver = "1.09"; /* HPMFWUPG_VERSION */ +extern char fdebug; /*from ipmicmd.c*/ +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static int g_channel_buf_size = 0; + +/* + * HPM.1 FIRMWARE UPGRADE COMMANDS (part of PICMG) + */ + +#define HPMFWUPG_GET_TARGET_UPG_CAPABILITIES 0x2E +#define HPMFWUPG_GET_COMPONENT_PROPERTIES 0x2F +#define HPMFWUPG_ABORT_UPGRADE 0x30 +#define HPMFWUPG_INITIATE_UPGRADE_ACTION 0x31 +#define HPMFWUPG_UPLOAD_FIRMWARE_BLOCK 0x32 +#define HPMFWUPG_FINISH_FIRMWARE_UPLOAD 0x33 +#define HPMFWUPG_GET_UPGRADE_STATUS 0x34 +#define HPMFWUPG_ACTIVATE_FIRMWARE 0x35 +#define HPMFWUPG_QUERY_SELFTEST_RESULT 0x36 +#define HPMFWUPG_QUERY_ROLLBACK_STATUS 0x37 +#define HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK 0x38 + +/* + * HPM.1 SPECIFIC COMPLETION CODES + */ +#define HPMFWUPG_ROLLBACK_COMPLETED 0x00 +#define HPMFWUPG_COMMAND_IN_PROGRESS 0x80 +#define HPMFWUPG_NOT_SUPPORTED 0x81 +#define HPMFWUPG_SIZE_MISMATCH 0x81 +#define HPMFWUPG_ROLLBACK_FAILURE 0x81 +#define HPMFWUPG_INV_COMP_MASK 0x81 +#define HPMFWUPG__ABORT_FAILURE 0x81 +#define HPMFWUPG_INV_COMP_ID 0x82 +#define HPMFWUPG_INT_CHECKSUM_ERROR 0x82 +#define HPMFWUPG_INV_UPLOAD_MODE 0x82 +#define HPMFWUPG_ROLLBACK_OVERRIDE 0x82 +#define HPMFWUPG_INV_COMP_PROP 0x83 +#define HPMFWUPG_FW_MISMATCH 0x83 +#define HPMFWUPG_ROLLBACK_DENIED 0x83 +#define HPMFWUPG_NOT_SUPPORTED_NOW 0xd5 + +/* + * This error code is used as a temporary PATCH to + * the latest Open ipmi driver. This PATCH + * will be removed once a new Open IPMI driver is released. + * (Buggy version = 39) + */ +#define ENABLE_OPENIPMI_V39_PATCH + +#ifdef ENABLE_OPENIPMI_V39_PATCH + +#define RETRY_COUNT_MAX 3 + +static int errorCount; + +#define HPMFWUPG_IS_RETRYABLE(error) \ +((((error==0x83)||(error==0x82)||(error==0x80)) && (errorCount++<RETRY_COUNT_MAX))?TRUE:FALSE) +#else +#define HPMFWUPG_IS_RETRYABLE(error) FALSE +#endif + +/* + * HPM FIRMWARE UPGRADE GENERAL DEFINITIONS + */ + +#define HPMFWUPG_PICMG_IDENTIFIER 0 +#define HPMFWUPG_VERSION_SIZE 6 +#define HPMFWUPG_DESC_STRING_LENGTH 12 +#define HPMFWUPG_DEFAULT_INACCESS_TIMEOUT 60 /* sec */ +#define HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT 60 /* sec */ +#define HPMFWUPG_MD5_SIGNATURE_LENGTH 16 + +/* Component IDs */ +typedef enum eHpmfwupgComponentId +{ + HPMFWUPG_COMPONENT_ID_0 = 0, + HPMFWUPG_COMPONENT_ID_1, + HPMFWUPG_COMPONENT_ID_2, + HPMFWUPG_COMPONENT_ID_3, + HPMFWUPG_COMPONENT_ID_4, + HPMFWUPG_COMPONENT_ID_5, + HPMFWUPG_COMPONENT_ID_6, + HPMFWUPG_COMPONENT_ID_7, + HPMFWUPG_COMPONENT_ID_MAX +} tHpmfwupgComponentId; + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgComponentBitMask +{ + union + { + unsigned char byte; + struct + { + #ifdef WORDS_BIGENDIAN + unsigned char component7 : 1; + unsigned char component6 : 1; + unsigned char component5 : 1; + unsigned char component4 : 1; + unsigned char component3 : 1; + unsigned char component2 : 1; + unsigned char component1 : 1; + unsigned char component0 : 1; + #else + unsigned char component0 : 1; + unsigned char component1 : 1; + unsigned char component2 : 1; + unsigned char component3 : 1; + unsigned char component4 : 1; + unsigned char component5 : 1; + unsigned char component6 : 1; + unsigned char component7 : 1; + #endif + }ATTRIBUTE_PACKING bitField; + }ATTRIBUTE_PACKING ComponentBits; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + + +static const int HPMFWUPG_SUCCESS = 0; +static const int HPMFWUPG_ERROR = -1; +/* Upload firmware specific error codes */ +static const int HPMFWUPG_UPLOAD_BLOCK_LENGTH = 1; +static const int HPMFWUPG_UPLOAD_RETRY = 2; + + +/* + * TARGET UPGRADE CAPABILITIES DEFINITIONS + */ + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetTargetUpgCapabilitiesReq +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetTargetUpgCapabilitiesResp +{ + unsigned char picmgId; + unsigned char hpmVersion; + union + { + unsigned char byte; + struct + { + #if WORDS_BIGENDIAN + unsigned char fwUpgUndesirable : 1; + unsigned char autRollbackOverride : 1; + unsigned char ipmcDegradedDurinUpg: 1; + unsigned char deferActivation : 1; + unsigned char servAffectDuringUpg : 1; + unsigned char manualRollback : 1; + unsigned char autRollback : 1; + unsigned char ipmcSelftestCap : 1; + #else + unsigned char ipmcSelftestCap : 1; + unsigned char autRollback : 1; + unsigned char manualRollback : 1; + unsigned char servAffectDuringUpg : 1; + unsigned char deferActivation : 1; + unsigned char ipmcDegradedDurinUpg: 1; + unsigned char autRollbackOverride : 1; + unsigned char fwUpgUndesirable : 1; + #endif + }ATTRIBUTE_PACKING bitField; + }ATTRIBUTE_PACKING GlobalCapabilities; + unsigned char upgradeTimeout; + unsigned char selftestTimeout; + unsigned char rollbackTimeout; + unsigned char inaccessTimeout; + struct HpmfwupgComponentBitMask componentsPresent; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetTargetUpgCapabilitiesCtx +{ + struct HpmfwupgGetTargetUpgCapabilitiesReq req; + struct HpmfwupgGetTargetUpgCapabilitiesResp resp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +/* + * COMPONENT PROPERTIES DEFINITIONS + */ + +typedef enum eHpmfwupgCompPropertiesSelect +{ + HPMFWUPG_COMP_GEN_PROPERTIES = 0, + HPMFWUPG_COMP_CURRENT_VERSION, + HPMFWUPG_COMP_DESCRIPTION_STRING, + HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION, + HPMFWUPG_COMP_DEFERRED_FIRMWARE_VERSION, + HPMFWUPG_COMP_RESERVED, + HPMFWUPG_COMP_OEM_PROPERTIES = 192 +} tHpmfwupgCompPropertiesSelect; + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetComponentPropertiesReq +{ + unsigned char picmgId; + unsigned char componentId; + unsigned char selector; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetGeneralPropResp +{ + unsigned char picmgId; + union + { + unsigned char byte; + struct + { + #if WORDS_BIGENDIAN + unsigned char reserved : 2; + unsigned char payloadColdReset : 1; + unsigned char deferredActivation : 1; + unsigned char comparisonSupport : 1; + unsigned char preparationSupport : 1; + unsigned char rollbackBackup : 2; + #else + unsigned char rollbackBackup : 2; + unsigned char preparationSupport : 1; + unsigned char comparisonSupport : 1; + unsigned char deferredActivation : 1; + unsigned char payloadColdReset : 1; + unsigned char reserved : 2; + #endif + }ATTRIBUTE_PACKING bitfield; + }ATTRIBUTE_PACKING GeneralCompProperties; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetCurrentVersionResp +{ + unsigned char picmgId; + unsigned char currentVersion[HPMFWUPG_VERSION_SIZE]; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetDescStringResp +{ + unsigned char picmgId; + char descString[HPMFWUPG_DESC_STRING_LENGTH]; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetRollbackFwVersionResp +{ + unsigned char picmgId; + unsigned char rollbackFwVersion[HPMFWUPG_VERSION_SIZE]; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetDeferredFwVersionResp +{ + unsigned char picmgId; + unsigned char deferredFwVersion[HPMFWUPG_VERSION_SIZE]; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +/* + * GetComponentProperties - OEM properties (192) + */ +#define HPMFWUPG_OEM_LENGTH 4 +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetOemProperties +{ + unsigned char picmgId; + unsigned char oemRspData[HPMFWUPG_OEM_LENGTH]; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetComponentPropertiesResp +{ + union + { + struct HpmfwupgGetGeneralPropResp generalPropResp; + struct HpmfwupgGetCurrentVersionResp currentVersionResp; + struct HpmfwupgGetDescStringResp descStringResp; + struct HpmfwupgGetRollbackFwVersionResp rollbackFwVersionResp; + struct HpmfwupgGetDeferredFwVersionResp deferredFwVersionResp; + struct HpmfwupgGetOemProperties oemProperties; + }ATTRIBUTE_PACKING Response; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetComponentPropertiesCtx +{ + struct HpmfwupgGetComponentPropertiesReq req; + struct HpmfwupgGetComponentPropertiesResp resp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + + +/* + * ABORT UPGRADE DEFINITIONS + */ +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgAbortUpgradeReq +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgAbortUpgradeResp +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgAbortUpgradeCtx +{ + struct HpmfwupgAbortUpgradeReq req; + struct HpmfwupgAbortUpgradeResp resp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +/* + * UPGRADE ACTIONS DEFINITIONS + */ +typedef enum eHpmfwupgUpgradeAction +{ + HPMFWUPG_UPGRADE_ACTION_BACKUP = 0, + HPMFWUPG_UPGRADE_ACTION_PREPARE, + HPMFWUPG_UPGRADE_ACTION_UPGRADE, + HPMFWUPG_UPGRADE_ACTION_COMPARE, + HPMFWUPG_UPGRADE_ACTION_INVALID = 0xff +} tHpmfwupgUpgradeAction; + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgInitiateUpgradeActionReq +{ + unsigned char picmgId; + struct HpmfwupgComponentBitMask componentsMask; + unsigned char upgradeAction; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgInitiateUpgradeActionResp +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgInitiateUpgradeActionCtx +{ + struct HpmfwupgInitiateUpgradeActionReq req; + struct HpmfwupgInitiateUpgradeActionResp resp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +/* + * UPLOAD FIRMWARE BLOCK DEFINITIONS + */ + +#define HPMFWUPG_SEND_DATA_COUNT_MAX 256 +#define HPMFWUPG_SEND_DATA_COUNT_KCS 30 +#define HPMFWUPG_SEND_DATA_COUNT_LAN 25 +#define HPMFWUPG_SEND_DATA_COUNT_IPMB 26 +#define HPMFWUPG_SEND_DATA_COUNT_IPMBL 26 + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgUploadFirmwareBlockReq +{ + unsigned char picmgId; + unsigned char blockNumber; + unsigned char data[HPMFWUPG_SEND_DATA_COUNT_MAX]; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgUploadFirmwareBlockResp +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgUploadFirmwareBlockCtx +{ + struct HpmfwupgUploadFirmwareBlockReq req; + struct HpmfwupgUploadFirmwareBlockResp resp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + + +/* + * FINISH FIRMWARE UPLOAD DEFINITIONS + */ + +#define HPMFWUPG_IMAGE_SIZE_BYTE_COUNT 4 + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgFinishFirmwareUploadReq +{ + unsigned char picmgId; + unsigned char componentId; + unsigned char imageLength[HPMFWUPG_IMAGE_SIZE_BYTE_COUNT]; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgFinishFirmwareUploadResp +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgFinishFirmwareUploadCtx +{ + struct HpmfwupgFinishFirmwareUploadReq req; + struct HpmfwupgFinishFirmwareUploadResp resp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +/* + * ACTIVATE FW DEFINITIONS + */ +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgActivateFirmwareReq +{ + unsigned char picmgId; + unsigned char rollback_override; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgActivateFirmwareResp +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgActivateFirmwareCtx +{ + struct HpmfwupgActivateFirmwareReq req; + struct HpmfwupgActivateFirmwareResp resp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + + +/* + * GET UPGRADE STATUS DEFINITIONS + */ +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetUpgradeStatusReq +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetUpgradeStatusResp +{ + unsigned char picmgId; + unsigned char cmdInProcess; + unsigned char lastCmdCompCode; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgGetUpgradeStatusCtx +{ + struct HpmfwupgGetUpgradeStatusReq req; + struct HpmfwupgGetUpgradeStatusResp resp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +/* + * MANUAL FW ROLLBACK DEFINITIONS + */ + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgManualFirmwareRollbackReq +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgManualFirmwareRollbackResp +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif +struct HpmfwupgManualFirmwareRollbackCtx +{ + struct HpmfwupgManualFirmwareRollbackReq req; + struct HpmfwupgManualFirmwareRollbackResp resp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +/* + * QUERY ROLLBACK STATUS DEFINITIONS + */ +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgQueryRollbackStatusReq +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgQueryRollbackStatusResp +{ + unsigned char picmgId; + struct HpmfwupgComponentBitMask rollbackComp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgQueryRollbackStatusCtx +{ + struct HpmfwupgQueryRollbackStatusReq req; + struct HpmfwupgQueryRollbackStatusResp resp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +/* + * QUERY SELF TEST RESULT DEFINITIONS + */ +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgQuerySelftestResultReq +{ + unsigned char picmgId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgQuerySelftestResultResp +{ + unsigned char picmgId; + unsigned char result1; + unsigned char result2; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgQuerySelftestResultCtx +{ + struct HpmfwupgQuerySelftestResultReq req; + struct HpmfwupgQuerySelftestResultResp resp; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif +/* + * HPM.1 IMAGE DEFINITIONS + */ + +#define HPMFWUPG_HEADER_SIGNATURE_LENGTH 8 +#define HPMFWUPG_MANUFATURER_ID_LENGTH 3 +#define HPMFWUPG_PRODUCT_ID_LENGTH 2 +#define HPMFWUPG_TIME_LENGTH 4 +#define HPMFWUPG_TIMEOUT_LENGTH 1 +#define HPMFWUPG_COMP_REVISION_LENGTH 2 +#define HPMFWUPG_FIRM_REVISION_LENGTH 6 +#define HPMFWUPG_IMAGE_HEADER_VERSION 0 +#define HPMFWUPG_IMAGE_SIGNATURE "PICMGFWU" + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgImageHeader +{ + char signature[HPMFWUPG_HEADER_SIGNATURE_LENGTH]; + unsigned char formatVersion; + unsigned char deviceId; + unsigned char manId[HPMFWUPG_MANUFATURER_ID_LENGTH]; + unsigned char prodId[HPMFWUPG_PRODUCT_ID_LENGTH]; + unsigned char time[HPMFWUPG_TIME_LENGTH]; + union + { + struct + { + #if WORDS_BIGENDIAN + unsigned char imageSelfTest : 1; + unsigned char autRollback : 1; + unsigned char manRollback : 1; + unsigned char servAffected : 1; + unsigned char reserved : 4; + #else + unsigned char reserved : 4; + unsigned char servAffected : 1; + unsigned char manRollback : 1; + unsigned char autRollback : 1; + unsigned char imageSelfTest : 1; + #endif + } ATTRIBUTE_PACKING bitField; + unsigned char byte; + }ATTRIBUTE_PACKING imageCapabilities; + struct HpmfwupgComponentBitMask components; + unsigned char selfTestTimeout; + unsigned char rollbackTimeout; + unsigned char inaccessTimeout; + unsigned char compRevision[HPMFWUPG_COMP_REVISION_LENGTH]; + unsigned char firmRevision[HPMFWUPG_FIRM_REVISION_LENGTH]; + unsigned short oemDataLength; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + + +#define HPMFWUPG_DESCRIPTION_LENGTH 21 + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgActionRecord +{ + unsigned char actionType; + struct HpmfwupgComponentBitMask components; + unsigned char checksum; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#define HPMFWUPG_FIRMWARE_SIZE_LENGTH 4 + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgFirmwareImage +{ + unsigned char version[HPMFWUPG_FIRM_REVISION_LENGTH]; + char desc[HPMFWUPG_DESCRIPTION_LENGTH]; + unsigned char length[HPMFWUPG_FIRMWARE_SIZE_LENGTH]; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct HpmfwupgUpgradeCtx +{ + struct HpmfwupgComponentBitMask compUpdateMask; + unsigned int imageSize; + unsigned char* pImageData; + unsigned char componentId; + struct HpmfwupgGetTargetUpgCapabilitiesResp targetCap; + struct HpmfwupgGetGeneralPropResp genCompProp[HPMFWUPG_COMPONENT_ID_MAX]; + struct ipm_devid_rsp devId; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +typedef enum eHpmfwupgActionType +{ + HPMFWUPG_ACTION_BACKUP_COMPONENTS = 0, + HPMFWUPG_ACTION_PREPARE_COMPONENTS, + HPMFWUPG_ACTION_UPLOAD_FIRMWARE, + HPMFWUPG_ACTION_RESERVED = 0xFF +} tHpmfwupgActionType; + +/* + * FUNCTIONS PROTOTYPES + */ +#define HPMFWUPG_MAJORMINOR_VERSION_SIZE 2 + + +#define DEFAULT_COMPONENT_UPLOAD 0x0F + +/* + * Options added for user to check the version and to view both the FILE and TARGET Version + */ +#define VERSIONCHECK_MODE 0x01 +#define VIEW_MODE 0x02 +#define DEBUG_MODE 0x04 +#define FORCE_MODE_ALL 0x08 +#define FORCE_MODE_COMPONENT 0x10 +#define FORCE_MODE (FORCE_MODE_ALL|FORCE_MODE_COMPONENT) + +typedef struct _VERSIONINFO +{ + unsigned char componentId; + unsigned char targetMajor; + unsigned char targetMinor; + unsigned char targetAux[4]; + unsigned char rollbackMajor; + unsigned char rollbackMinor; + unsigned char rollbackAux[4]; + unsigned char imageMajor; + unsigned char imageMinor; + unsigned char imageAux[4]; + unsigned char coldResetRequired; + unsigned char rollbackSupported; + unsigned char skipUpgrade; + char descString[15]; +}VERSIONINFO, *PVERSIONINFO; + +VERSIONINFO gVersionInfo[HPMFWUPG_COMPONENT_ID_MAX]; + +#define TARGET_VER (0x01) +#define ROLLBACK_VER (0x02) +#define IMAGE_VER (0x04) + + + + +static int HpmfwupgPreUpgradeCheck(void *intf, + struct HpmfwupgUpgradeCtx* pFwupgCtx,int componentToUpload,int option); +static int HpmfwupgUpgrade(void *intf, char* imageFilename, int activate, int,int); +static int HpmfwupgValidateImageIntegrity(struct HpmfwupgUpgradeCtx* pFwupgCtx); +static int HpmfwupgPreparationStage( void *intf, + struct HpmfwupgUpgradeCtx* pFwupgCtx, int option); +static int HpmfwupgUpgradeStage ( void *intf, + struct HpmfwupgUpgradeCtx* pFwupgCtx, int compToUpload ,int option); +static int HpmfwupgActivationStage(void *intf, + struct HpmfwupgUpgradeCtx* pFwupgCtx); +static int HpmfwupgGetTargetUpgCapabilities(void *intf, + struct HpmfwupgGetTargetUpgCapabilitiesCtx* pCtx); +static int HpmfwupgGetComponentProperties(void *intf, + struct HpmfwupgGetComponentPropertiesCtx* pCtx); +static int HpmfwupgQuerySelftestResult(void *intf, + struct HpmfwupgQuerySelftestResultCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx); +static int HpmfwupgQueryRollbackStatus(void *intf, + struct HpmfwupgQueryRollbackStatusCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx); +static int HpmfwupgAbortUpgrade(void *intf, + struct HpmfwupgAbortUpgradeCtx* pCtx); +static int HpmfwupgInitiateUpgradeAction(void *intf, + struct HpmfwupgInitiateUpgradeActionCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx); +static int HpmfwupgUploadFirmwareBlock(void *intf, + struct HpmfwupgUploadFirmwareBlockCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx, int count , + unsigned int *pOffset, unsigned int *blockLen); +static int HpmfwupgFinishFirmwareUpload(void *intf, + struct HpmfwupgFinishFirmwareUploadCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx); +static int HpmfwupgActivateFirmware(void *intf, + struct HpmfwupgActivateFirmwareCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx); +static int HpmfwupgGetUpgradeStatus(void *intf, + struct HpmfwupgGetUpgradeStatusCtx* pCtxstruct, + struct HpmfwupgUpgradeCtx* pFwupgCtx); +static int HpmfwupgManualFirmwareRollback(void *intf, + struct HpmfwupgManualFirmwareRollbackCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx); +static void HpmfwupgPrintUsage(void); +static unsigned char HpmfwupgCalculateChecksum(unsigned char* pData, unsigned int length); +static int HpmfwupgGetDeviceId(void *intf, struct ipm_devid_rsp* pGetDevId); +static int HpmfwupgGetBufferFromFile(char* imageFilename, struct HpmfwupgUpgradeCtx* pFwupgCtx); +static int HpmfwupgWaitLongDurationCmd(void *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx); + +static struct ipmi_rs * HpmfwupgSendCmd(void *intf, struct ipmi_rq req, + struct HpmfwupgUpgradeCtx* pFwupgCtx); + + +static int HpmFwupgActionUploadFirmware +( + struct HpmfwupgComponentBitMask components, + struct HpmfwupgUpgradeCtx* pFwupgCtx, + unsigned char** pImagePtr, + int componentToUpload, + void *intf, + int option, + int* pFlagColdReset +); + +static char * hpm_decode_cc( uchar cmd, uchar cc ) +{ + char *pstr; + switch(cc) { + case 0x80: pstr = "Command in progress"; break; + case 0x81: pstr = "HPM not supported"; break; + case 0x82: pstr = "Checksum error"; break; + case 0x83: pstr = "Firmware mismatch"; break; + default: pstr = decode_cc(cmd,cc); + } + return(pstr); +} + +/**************************************************************************** +* +* Function Name: HpmGetuserInput +* +* Description: This function gets input from user and returns TRUE if its Yes +* or FALSE if its No +* +*****************************************************************************/ +int HpmGetUserInput(char *str) +{ + char userInput[2]; + printf("%s",str); + scanf("%s",userInput); + if (toupper(userInput[0]) == 'Y') + { + return 1; + } + return 0; +} +/**************************************************************************** +* +* Function Name: HpmDisplayLine +* +* Description: This is to display the line with the given character. +* +*****************************************************************************/ +void HpmDisplayLine(char *s, int n) +{ + while (n--) printf ("%c",*s); + printf("\n"); +} + +/**************************************************************************** +* +* Function Name: HpmDisplayUpgradeHeader +* +* Description: This function the displays the Upgrade header information +* +*****************************************************************************/ +void HpmDisplayUpgradeHeader(int option) +{ + printf("\n"); + HpmDisplayLine("-",78 ); + printf("|ID | Name | Versions | %% |\n"); + printf("| | | Active | Backup | File | |\n"); + printf("|---|-----------|-----------------|-----------------|-----------------|------|\n"); +} + +/**************************************************************************** +* +* Function Name: HpmDisplayUpgrade +* +* Description: This function displays the progress of the upgrade it prints the "." +* every 5% of its completion. +* +*****************************************************************************/ +void HpmDisplayUpgrade( int skip, unsigned int totalSent, + unsigned int displayFWLength,time_t timeElapsed) +{ + int percent; + static int old_percent=1; + if (skip) + { + printf(" Skip |\n"); + return; + } + fflush(stdout); + + percent = (int)((totalSent * 100)/displayFWLength); + if (percent != old_percent) + { + if ( percent == 0 ) printf(" 0 %% |"); + else if (percent == 100) printf("\b\b\b\b\b\b\b100 %% |\n"); + else printf("\b\b\b\b\b\b\b%3d %% |", percent); + old_percent = percent; + } + + if (totalSent== displayFWLength) + { + /* Display the time taken to complete the upgrade */ + printf("| | Upload Time: %02d.%02d | Image Size: %05x |\n", + timeElapsed/60,timeElapsed%60,totalSent); + } +} + +/**************************************************************************** +* +* Function Name: HpmDisplayVersionHeader +* +* Description: This function displays the information about version header +* +*****************************************************************************/ +int HpmDisplayVersionHeader(int mode) +{ + if ( mode & IMAGE_VER) + { + HpmDisplayLine("-",71 ); + printf("|ID | Name | Versions |\n"); + printf("| | | Active | Backup | File |\n"); + HpmDisplayLine("-",71 ); + } + else + { + HpmDisplayLine("-",53 ); + printf("|ID | Name | Versions |\n"); + printf("| | | Active | Backup |\n"); + HpmDisplayLine("-",53 ); + } + return 0; +} + +/**************************************************************************** +* +* Function Name: HpmDisplayVersion +* +* Description: This function displays the version of the image and target +* +*****************************************************************************/ +int HpmDisplayVersion(int mode,VERSIONINFO *pVersion) +{ + char descString[12]; + memset(&descString,0x00,12); + /* + * Added this to ensure that even if the description string + * is more than required it does not give problem in displaying it + */ + strncpy(descString,pVersion->descString,11); + /* + * If the cold reset is required then we can display * on it + * so that user is aware that he needs to do payload power + * cycle after upgrade + */ + printf("|%c%-2d|%-11s|",pVersion->coldResetRequired?'*':' ',pVersion->componentId,descString); + + if (mode & TARGET_VER) + { + if (pVersion->targetMajor == 0xFF && pVersion->targetMinor == 0xFF) + printf(" ---.-- -------- |"); + else + printf(" %3d.%02x %02X%02X%02X%02X |", + pVersion->targetMajor, + pVersion->targetMinor, + pVersion->targetAux[0], + pVersion->targetAux[1], + pVersion->targetAux[2], + pVersion->targetAux[3] + ); + + if (mode & ROLLBACK_VER) + { + if (pVersion->rollbackMajor == 0xFF && pVersion->rollbackMinor == 0xFF) + printf(" ---.-- -------- |"); + else + printf(" %3d.%02x %02X%02X%02X%02X |", + pVersion->rollbackMajor, + pVersion->rollbackMinor, + pVersion->rollbackAux[0], + pVersion->rollbackAux[1], + pVersion->rollbackAux[2], + pVersion->rollbackAux[3]); + } + else + { + printf(" ---.-- -------- |"); + } + } + + if (mode & IMAGE_VER) + { + if (pVersion->imageMajor == 0xFF && pVersion->imageMinor == 0xFF) + printf(" ---.-- |"); + else + printf(" %3d.%02x %02X%02X%02X%02X |", + pVersion->imageMajor, + pVersion->imageMinor, + pVersion->imageAux[0], + pVersion->imageAux[1], + pVersion->imageAux[2], + pVersion->imageAux[3]); + } + return 0; +} + + +/**************************************************************************** +* +* Function Name: HpmfwupgTargerCheck +* +* Description: This function gets the target information and displays it on the +* screen +* +*****************************************************************************/ +int HpmfwupgTargetCheck(void * intf, int option) +{ + // struct HpmfwupgUpgradeCtx fwupgCtx; + struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; + int rc = HPMFWUPG_SUCCESS; + int componentId = 0; + int flagColdReset = FALSE; + struct ipm_devid_rsp devIdrsp; + struct HpmfwupgGetComponentPropertiesCtx getCompProp; + int mode = 0; + + + rc = HpmfwupgGetDeviceId(intf, &devIdrsp); + + if (rc != HPMFWUPG_SUCCESS) + { + lprintf(LOG_NOTICE,"Verify whether the Target board is present \n"); + return rc; + } + + rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); + if (rc != HPMFWUPG_SUCCESS) + { + /* + * That indicates the target is not responding to the command + * May be that there is no HPM support + */ + lprintf(LOG_NOTICE,"Board might not be supporting the HPM.1 Standards\n"); + return rc; + } + if (option & VIEW_MODE) + { + lprintf(LOG_NOTICE,"-------Target Information-------"); + lprintf(LOG_NOTICE,"Device Id : 0x%x", devIdrsp.device_id); + lprintf(LOG_NOTICE,"Device Revision : 0x%x", devIdrsp.device_revision); + lprintf(LOG_NOTICE,"Product Id : 0x%04x", buf2short(devIdrsp.product_id)); + lprintf(LOG_NOTICE,"Manufacturer Id : 0x%04x (%s)\n\n", + buf2short(devIdrsp.manufacturer_id), + get_mfg_str(devIdrsp.manufacturer_id,NULL)); + HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER); + } + + for ( componentId = HPMFWUPG_COMPONENT_ID_0; componentId < HPMFWUPG_COMPONENT_ID_MAX; + componentId++ ) + { + /* If the component is supported */ + if ( ((1 << componentId) & targetCapCmd.resp.componentsPresent.ComponentBits.byte) ) + { + memset((PVERSIONINFO)&gVersionInfo[componentId],0x00,sizeof(VERSIONINFO)); + + getCompProp.req.componentId = componentId; + getCompProp.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES; + rc = HpmfwupgGetComponentProperties(intf, &getCompProp); + if (rc != HPMFWUPG_SUCCESS) + { + lprintf(LOG_NOTICE,"Get CompGenProp Failed for component Id %d\n",componentId); + return rc; + } + + gVersionInfo[componentId].rollbackSupported = getCompProp.resp.Response. + generalPropResp.GeneralCompProperties.bitfield.rollbackBackup; + gVersionInfo[componentId].coldResetRequired = getCompProp.resp.Response. + generalPropResp.GeneralCompProperties.bitfield.payloadColdReset; + + getCompProp.req.selector = HPMFWUPG_COMP_DESCRIPTION_STRING; + rc = HpmfwupgGetComponentProperties(intf, &getCompProp); + if (rc != HPMFWUPG_SUCCESS) + { + lprintf(LOG_NOTICE,"Get CompDescString Failed for component Id %d\n",componentId); + return rc; + } + strcpy((char *)&gVersionInfo[componentId].descString, + getCompProp.resp.Response.descStringResp.descString); + + getCompProp.req.selector = HPMFWUPG_COMP_CURRENT_VERSION; + rc = HpmfwupgGetComponentProperties(intf, &getCompProp); + if (rc != HPMFWUPG_SUCCESS) + { + lprintf(LOG_NOTICE,"Get CompCurrentVersion Failed for component Id %d\n",componentId); + return rc; + } + + gVersionInfo[componentId].componentId = componentId; + gVersionInfo[componentId].targetMajor = getCompProp.resp.Response. + currentVersionResp.currentVersion[0]; + gVersionInfo[componentId].targetMinor = getCompProp.resp.Response. + currentVersionResp.currentVersion[1]; + gVersionInfo[componentId].targetAux[0] = getCompProp.resp.Response. + currentVersionResp.currentVersion[2]; + gVersionInfo[componentId].targetAux[1] = getCompProp.resp.Response. + currentVersionResp.currentVersion[3]; + gVersionInfo[componentId].targetAux[2] = getCompProp.resp.Response. + currentVersionResp.currentVersion[4]; + gVersionInfo[componentId].targetAux[3] = getCompProp.resp.Response. + currentVersionResp.currentVersion[5]; + mode = TARGET_VER; + + if (gVersionInfo[componentId].rollbackSupported) + { + getCompProp.req.selector = HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION; + rc = HpmfwupgGetComponentProperties(intf, &getCompProp); + if (rc != HPMFWUPG_SUCCESS) + { + lprintf(LOG_NOTICE,"Get CompRollbackVersion Failed for component Id %d\n",componentId); + } else { + gVersionInfo[componentId].rollbackMajor = getCompProp.resp + .Response.rollbackFwVersionResp.rollbackFwVersion[0]; + gVersionInfo[componentId].rollbackMinor = getCompProp.resp + .Response.rollbackFwVersionResp.rollbackFwVersion[1]; + gVersionInfo[componentId].rollbackAux[0] = getCompProp.resp.Response. + rollbackFwVersionResp.rollbackFwVersion[2]; + gVersionInfo[componentId].rollbackAux[1] = getCompProp.resp.Response. + rollbackFwVersionResp.rollbackFwVersion[3]; + gVersionInfo[componentId].rollbackAux[2] = getCompProp.resp.Response. + rollbackFwVersionResp.rollbackFwVersion[4]; + gVersionInfo[componentId].rollbackAux[3] = getCompProp.resp.Response. + rollbackFwVersionResp.rollbackFwVersion[5]; + } + mode |= ROLLBACK_VER; + } + + if (gVersionInfo[componentId].coldResetRequired) + { + /* + * If any of the component indicates that the Payload Cold reset is required + * then set the flag + */ + flagColdReset = TRUE; + } + if (option & VIEW_MODE) + { + HpmDisplayVersion(mode,&gVersionInfo[componentId]); + printf("\n"); + } + } + } + + if (option & VIEW_MODE) + { + HpmDisplayLine("-",53 ); + if (flagColdReset) + { + fflush(stdout); + lprintf(LOG_NOTICE,"(*) Component requires Payload Cold Reset"); + } + printf("\n\n"); + } + return HPMFWUPG_SUCCESS; +} + +/***************************************************************************** +* Function Name: HpmfwupgUpgrade +* +* Description: This function performs the HPM.1 firmware upgrade procedure as +* defined the IPM Controller Firmware Upgrade Specification +* version 1.0 +* +*****************************************************************************/ +int HpmfwupgUpgrade(void *intf, char* imageFilename, + int activate,int componentToUpload, int option) +{ + int rc = HPMFWUPG_SUCCESS; + // struct HpmfwupgImageHeader imageHeader; + struct HpmfwupgUpgradeCtx fwupgCtx; + + /* + * GET IMAGE BUFFER FROM FILE + */ + + rc = HpmfwupgGetBufferFromFile(imageFilename, &fwupgCtx); + + /* + * VALIDATE IMAGE INTEGRITY + */ + + if ( rc == HPMFWUPG_SUCCESS ) + { + printf("Validating firmware image integrity..."); + fflush(stdout); + rc = HpmfwupgValidateImageIntegrity(&fwupgCtx); + if ( rc == HPMFWUPG_SUCCESS ) + { + printf("OK\n"); + fflush(stdout); + } + else + { + free(fwupgCtx.pImageData); + } + } + + /* + * PREPARATION STAGE + */ + + if ( rc == HPMFWUPG_SUCCESS ) + { + printf("Performing preparation stage..."); + fflush(stdout); + rc = HpmfwupgPreparationStage(intf, &fwupgCtx, option); + if ( rc == HPMFWUPG_SUCCESS ) + { + printf("OK\n"); + fflush(stdout); + } + else + { + free(fwupgCtx.pImageData); + } + } + + /* + * UPGRADE STAGE + */ + + if ( rc == HPMFWUPG_SUCCESS ) + { + if (option & VIEW_MODE) + { + lprintf(LOG_NOTICE,"\nComparing Target & Image File version"); + } + else + { + lprintf(LOG_NOTICE,"\nPerforming upgrade stage:"); + } + if (option & VIEW_MODE) + { + rc = HpmfwupgPreUpgradeCheck(intf, &fwupgCtx,componentToUpload,VIEW_MODE); + } + else + { + rc = HpmfwupgPreUpgradeCheck(intf, &fwupgCtx,componentToUpload,option); + if (rc == HPMFWUPG_SUCCESS ) + { + if( verbose ) { + printf("Component update mask : 0x%02x\n", fwupgCtx.compUpdateMask.ComponentBits.byte); + } + rc = HpmfwupgUpgradeStage(intf, &fwupgCtx,componentToUpload,option); + } + } + + if ( rc != HPMFWUPG_SUCCESS ) + { + if (verbose) printf("HPM Upgrade error %d\n",rc); + free(fwupgCtx.pImageData); + } + } + + /* + * ACTIVATION STAGE + */ + if ( rc == HPMFWUPG_SUCCESS && activate ) + { + lprintf(LOG_NOTICE,"Performing activation stage: "); + rc = HpmfwupgActivationStage(intf, &fwupgCtx); + if ( rc != HPMFWUPG_SUCCESS ) + { + if (verbose) printf("HPM Activation error %d\n",rc); + free(fwupgCtx.pImageData); + } + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + if (option & VIEW_MODE) + { + // Dont display anything here in case we are just viewing it + lprintf(LOG_NOTICE," "); + } + else + { + lprintf(LOG_NOTICE,"\nFirmware upgrade procedure successful\n"); + } + free(fwupgCtx.pImageData); + } + else + { + lprintf(LOG_NOTICE,"Firmware upgrade procedure failed\n"); + } + + return rc; +} + +/**************************************************************************** +* +* Function Name: HpmfwupgValidateImageIntegrity +* +* Description: This function validates a HPM.1 firmware image file as defined +* in section 4 of the IPM Controller Firmware Upgrade +* Specification version 1.0 +* +*****************************************************************************/ +int HpmfwupgValidateImageIntegrity(struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) + pFwupgCtx->pImageData; + md5_state_t ctx; + static unsigned char md[HPMFWUPG_MD5_SIGNATURE_LENGTH]; + unsigned char* pMd5Sig = pFwupgCtx->pImageData + + (pFwupgCtx->imageSize - + HPMFWUPG_MD5_SIGNATURE_LENGTH); + + /* Validate MD5 checksum */ + memset(md, 0, HPMFWUPG_MD5_SIGNATURE_LENGTH); + memset(&ctx, 0, sizeof(md5_state_t)); + md5_init(&ctx); + md5_append(&ctx, pFwupgCtx->pImageData, pFwupgCtx->imageSize - + HPMFWUPG_MD5_SIGNATURE_LENGTH); + md5_finish(&ctx, md); + if ( memcmp(md, pMd5Sig,HPMFWUPG_MD5_SIGNATURE_LENGTH) != 0 ) + { + lprintf(LOG_NOTICE,"\n Invalid MD5 signature"); + rc = HPMFWUPG_ERROR; + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Validate Header signature */ + if( strncmp(pImageHeader->signature, HPMFWUPG_IMAGE_SIGNATURE, HPMFWUPG_HEADER_SIGNATURE_LENGTH) == 0 ) + { + /* Validate Header image format version */ + if ( pImageHeader->formatVersion == HPMFWUPG_IMAGE_HEADER_VERSION ) + { + /* Validate header checksum */ + if ( HpmfwupgCalculateChecksum((unsigned char*)pImageHeader, + sizeof(struct HpmfwupgImageHeader) + + pImageHeader->oemDataLength + + sizeof(unsigned char)/*checksum*/) != 0 ) + { + lprintf(LOG_NOTICE,"\n Invalid header checksum"); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"\n Unrecognized image version"); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"\n Invalid image signature"); + rc = HPMFWUPG_ERROR; + } + } + return rc; +} + +/**************************************************************************** +* +* Function Name: HpmfwupgPreparationStage +* +* Description: This function the preperation stage of a firmware upgrade +* procedure as defined in section 3.2 of the IPM Controller +* Firmware Upgrade Specification version 1.0 +* +*****************************************************************************/ +int HpmfwupgPreparationStage(void *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx, int option) +{ + int rc = HPMFWUPG_SUCCESS; + struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) + pFwupgCtx->pImageData; + + /* Get device ID */ + rc = HpmfwupgGetDeviceId(intf, &pFwupgCtx->devId); + + /* Match current IPMC IDs with upgrade image */ + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Validate device ID */ + if ( pImageHeader->deviceId == pFwupgCtx->devId.device_id ) + { + /* Validate product ID */ + if ( memcmp(pImageHeader->prodId, pFwupgCtx->devId.product_id, HPMFWUPG_PRODUCT_ID_LENGTH ) == 0 ) + { + /* Validate man ID */ + if ( memcmp(pImageHeader->manId, pFwupgCtx->devId.manufacturer_id, + HPMFWUPG_MANUFATURER_ID_LENGTH ) != 0 ) + { + lprintf(LOG_NOTICE,"\n Invalid image file for manufacturer %u", + buf2short(pFwupgCtx->devId.manufacturer_id)); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"\n Invalid image file for product %u", + buf2short(pFwupgCtx->devId.product_id)); + rc = HPMFWUPG_ERROR; + } + + } + else + { + lprintf(LOG_NOTICE,"\n Invalid device ID %x", pFwupgCtx->devId.device_id); + rc = HPMFWUPG_ERROR; + } + + if (rc != HPMFWUPG_SUCCESS) + { + /* + * Giving one more chance to user to check whether its OK to continue even if the + * product ID does not match. This is helpful as sometimes we just want to update + * and dont care whether we have a different product Id. If the user says NO then + * we need to just bail out from here + */ + if ( (option & FORCE_MODE) || (option & VIEW_MODE) ) + { + printf("\n Image Information"); + printf("\n Device Id : 0x%x",pImageHeader->deviceId); + printf("\n Prod Id : 0x%02x%02x",pImageHeader->prodId[1], pImageHeader->prodId[0]); + printf("\n Manuf Id : 0x%02x%02x%02x",pImageHeader->manId[2], + pImageHeader->manId[1],pImageHeader->manId[0]); + printf("\n Board Information"); + printf("\n Device Id : 0x%x", pFwupgCtx->devId.device_id); + printf("\n Prod Id : 0x%02x%02x",pFwupgCtx->devId.product_id[1], pFwupgCtx->devId.product_id[0]); + printf("\n Manuf Id : 0x%02x%02x%02x",pFwupgCtx->devId.manufacturer_id[2], + pFwupgCtx->devId.manufacturer_id[1],pFwupgCtx->devId.manufacturer_id[0]); + if (HpmGetUserInput("\n Continue ignoring DeviceID/ProductID/ManufacturingID (Y/N) :")) + rc = HPMFWUPG_SUCCESS; + } + else + { + /* + * If you use all option its kind of FORCE command where we need to upgrade all the components + */ + printf("\n\n Use \"all\" option for uploading all the components\n"); + } + } + } + + /* Validate earliest compatible revision */ + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Validate major & minor revision */ + if ( pImageHeader->compRevision[0] < pFwupgCtx->devId.fw_rev1 ) + { + /* Do nothing, upgrade accepted */ + } + else if ( pImageHeader->compRevision[0] == pFwupgCtx->devId.fw_rev1 ) + { + /* Must validate minor revision */ + if ( pImageHeader->compRevision[1] > pFwupgCtx->devId.fw_rev2 ) + { + /* Version not compatible for upgrade */ + lprintf(LOG_NOTICE,"\n Version: Major: %d", pImageHeader->compRevision[0]); + lprintf(LOG_NOTICE," Minor: %x", pImageHeader->compRevision[1]); + lprintf(LOG_NOTICE," Not compatible with "); + lprintf(LOG_NOTICE," Version: Major: %d", pFwupgCtx->devId.fw_rev1); + lprintf(LOG_NOTICE," Minor: %x", pFwupgCtx->devId.fw_rev2); + rc = HPMFWUPG_ERROR; + } + } + else + { + /* Version not compatible for upgrade */ + lprintf(LOG_NOTICE,"\n Version: Major: %d", pImageHeader->compRevision[0]); + lprintf(LOG_NOTICE," Minor: %x", pImageHeader->compRevision[1]); + lprintf(LOG_NOTICE," Not compatible with "); + lprintf(LOG_NOTICE," Version: Major: %d", pFwupgCtx->devId.fw_rev1); + lprintf(LOG_NOTICE," Minor: %x", pFwupgCtx->devId.fw_rev2); + rc = HPMFWUPG_ERROR; + } + + if (rc != HPMFWUPG_SUCCESS) + { + /* Confirming it once again */ + if ( (option & FORCE_MODE) || (option & VIEW_MODE) ) + { + if( HpmGetUserInput("\n Continue IGNORING Earliest compatibility (Y/N) :")) + rc = HPMFWUPG_SUCCESS; + } + } + } + + /* Get target upgrade capabilities */ + if ( rc == HPMFWUPG_SUCCESS ) + { + struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; + + rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Copy response to context */ + memcpy(&pFwupgCtx->targetCap, + &targetCapCmd.resp, + sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp)); + + if (option & VIEW_MODE) + { + return rc; + } + else + { + /* Make sure all component IDs defined in the upgrade + image are supported by the IPMC */ + if ( (pImageHeader->components.ComponentBits.byte & + pFwupgCtx->targetCap.componentsPresent.ComponentBits.byte ) != + pImageHeader->components.ComponentBits.byte ) + { + lprintf(LOG_NOTICE,"\n Some components present in the image file are not supported by the IPMC"); + rc = HPMFWUPG_ERROR; + } + + /* Make sure the upgrade is desirable rigth now */ + if ( pFwupgCtx->targetCap.GlobalCapabilities.bitField.fwUpgUndesirable == 1 ) + { + lprintf(LOG_NOTICE,"\n Upgrade undesirable at this moment"); + rc = HPMFWUPG_ERROR; + } + + /* Get confimation from the user if he wants to continue when service + affected during upgrade */ + if ( pFwupgCtx->targetCap.GlobalCapabilities.bitField.servAffectDuringUpg == 1 || + pImageHeader->imageCapabilities.bitField.servAffected == 1 ) + { + if (HpmGetUserInput("\nServices may be affected during upgrade. Do you wish to continue? y/n ")) + { + rc = HPMFWUPG_SUCCESS; + } + else + { + rc = HPMFWUPG_ERROR; + } + } + } + } + } + + /* Get the general properties of each component present in image */ + if ( rc == HPMFWUPG_SUCCESS ) + { + int componentId; + + for ( componentId = HPMFWUPG_COMPONENT_ID_0; + componentId < HPMFWUPG_COMPONENT_ID_MAX; + componentId++ ) + { + /* Reset component properties */ + memset(&pFwupgCtx->genCompProp[componentId], 0, sizeof (struct HpmfwupgGetGeneralPropResp)); + + if ( (1 << componentId & pImageHeader->components.ComponentBits.byte) ) + { + struct HpmfwupgGetComponentPropertiesCtx getCompPropCmd; + + /* Get general component properties */ + getCompPropCmd.req.componentId = componentId; + getCompPropCmd.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES; + + rc = HpmfwupgGetComponentProperties(intf, &getCompPropCmd); + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Copy response to context */ + memcpy(&pFwupgCtx->genCompProp[componentId], + &getCompPropCmd.resp, + sizeof(struct HpmfwupgGetGeneralPropResp)); + } + } + } + } + + return rc; +} + +/**************************************************************************** +* +* Function Name: HpmfwupgPreUpgradeCheck +* +* Description: This function the pre Upgrade check, this mainly helps in checking +* which all version upgrade is skippable because the image version +* is same as target version. +* +*****************************************************************************/ +int HpmfwupgPreUpgradeCheck(void *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx, + int componentToUpload,int option) +{ + int rc = HPMFWUPG_SUCCESS; + unsigned char* pImagePtr; + struct HpmfwupgActionRecord* pActionRecord; + unsigned int actionsSize; + int flagColdReset = FALSE; + struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) + pFwupgCtx->pImageData; + + /* Put pointer after image header */ + pImagePtr = (unsigned char*) + (pFwupgCtx->pImageData + sizeof(struct HpmfwupgImageHeader) + + pImageHeader->oemDataLength + sizeof(unsigned char)/*checksum*/); + + /* Deternime actions size */ + actionsSize = pFwupgCtx->imageSize - sizeof(struct HpmfwupgImageHeader); + + if (option & VIEW_MODE) + { + HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER|IMAGE_VER); + } + + /* Perform actions defined in the image */ + while( ( pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize - + HPMFWUPG_MD5_SIGNATURE_LENGTH)) && + ( rc == HPMFWUPG_SUCCESS) ) + { + /* Get action record */ + pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr; + + /* Validate action record checksum */ + if ( HpmfwupgCalculateChecksum((unsigned char*)pActionRecord, + sizeof(struct HpmfwupgActionRecord)) != 0 ) + { + lprintf(LOG_NOTICE," Invalid Action record."); + rc = HPMFWUPG_ERROR; + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + switch( pActionRecord->actionType ) + { + case HPMFWUPG_ACTION_BACKUP_COMPONENTS: + { + pImagePtr += sizeof(struct HpmfwupgActionRecord); + } + break; + + case HPMFWUPG_ACTION_PREPARE_COMPONENTS: + { + if (componentToUpload != DEFAULT_COMPONENT_UPLOAD) + { + if (!(1<<componentToUpload & pActionRecord->components.ComponentBits.byte)) + { + lprintf(LOG_NOTICE,"\nComponent Id given is not supported\n"); + return HPMFWUPG_ERROR; + } + } + pImagePtr += sizeof(struct HpmfwupgActionRecord); + } + break; + + case HPMFWUPG_ACTION_UPLOAD_FIRMWARE: + /* Upload all firmware blocks */ + { + struct HpmfwupgFirmwareImage* pFwImage; + unsigned char* pData; + unsigned int firmwareLength = 0; + unsigned char mode = 0; + unsigned char componentId = 0x00; + unsigned char componentIdByte = 0x00; + VERSIONINFO *pVersionInfo; + // struct HpmfwupgGetComponentPropertiesCtx getCompProp; + + /* Save component ID on which the upload is done */ + componentIdByte = pActionRecord->components.ComponentBits.byte; + + while ((componentIdByte>>=1)!=0) + { + componentId++; + } + pFwupgCtx->componentId = componentId; + + pFwImage = (struct HpmfwupgFirmwareImage*)(pImagePtr + + sizeof(struct HpmfwupgActionRecord)); + + pData = ((unsigned char*)pFwImage + sizeof(struct HpmfwupgFirmwareImage)); + + /* Get firmware length */ + firmwareLength = pFwImage->length[0]; + firmwareLength |= (pFwImage->length[1] << 8) & 0xff00; + firmwareLength |= (pFwImage->length[2] << 16) & 0xff0000; + firmwareLength |= (pFwImage->length[3] << 24) & 0xff000000; + + pVersionInfo = &gVersionInfo[componentId]; + + pVersionInfo->imageMajor = pFwImage->version[0]; + pVersionInfo->imageMinor = pFwImage->version[1]; + pVersionInfo->imageAux[0] = pFwImage->version[2]; + pVersionInfo->imageAux[1] = pFwImage->version[3]; + pVersionInfo->imageAux[2] = pFwImage->version[4]; + pVersionInfo->imageAux[3] = pFwImage->version[5]; + + mode = TARGET_VER | IMAGE_VER; + + if (pVersionInfo->coldResetRequired) + { + flagColdReset = TRUE; + } + pVersionInfo->skipUpgrade = FALSE; + + if (option & FORCE_MODE_ALL) + { + /* user has given all to upload all the components on the command line */ + if(verbose) { + lprintf(LOG_NOTICE,"Forcing ALL components"); + } + } + else if( option & FORCE_MODE_COMPONENT ) + { + if( componentToUpload != componentId ) + { + if(verbose) { + lprintf(LOG_NOTICE,"Forcing component %d skip", componentId); + } + /* user has given the component Id to upload on the command line */ + pVersionInfo->skipUpgrade = TRUE; + } + else if(verbose) + { + lprintf(LOG_NOTICE,"Forcing component %d update", componentId); + /* user has given the component Id to upload on the command line */ + } + } + else + { + if + ( + (pVersionInfo->imageMajor == pVersionInfo->targetMajor) + && + (pVersionInfo->imageMinor == pVersionInfo->targetMinor)) + { + if (pVersionInfo->rollbackSupported) + { + /*If the Image Versions are same as Target Versions then check for the + * rollback version*/ + if + ( + (pVersionInfo->imageMajor == pVersionInfo->rollbackMajor) + && + (pVersionInfo->imageMinor == pVersionInfo->rollbackMinor) + ) + { + /* This indicates that the Rollback version is also same as + * Image version -- So now we must skip it */ + pVersionInfo->skipUpgrade = TRUE; + } + mode |= ROLLBACK_VER; + } + else + { + pVersionInfo->skipUpgrade = TRUE; + } + } + if ( verbose ) { + lprintf(LOG_NOTICE,"Component %d: %s", componentId , (pVersionInfo->skipUpgrade?"skipped":"to update")); + } + } + if( pVersionInfo->skipUpgrade == FALSE ) + { + pFwupgCtx->compUpdateMask.ComponentBits.byte |= 1<<componentId; + } + if (option & VIEW_MODE) + { + HpmDisplayVersion(mode,pVersionInfo); + printf("\n"); + } + pImagePtr = pData + firmwareLength; + } + break; + default: + lprintf(LOG_NOTICE," Invalid Action type. Cannot continue"); + rc = HPMFWUPG_ERROR; + break; + } + } + } + if (option & VIEW_MODE) + { + HpmDisplayLine("-",71); + if (flagColdReset) + { + fflush(stdout); + lprintf(LOG_NOTICE,"(*) Component requires Payload Cold Reset"); + } + } + return rc; +} + + +/**************************************************************************** +* +* Function Name: HpmfwupgUpgradeStage +* +* Description: This function the upgrade stage of a firmware upgrade +* procedure as defined in section 3.3 of the IPM Controller +* Firmware Upgrade Specification version 1.0 +* +*****************************************************************************/ +int HpmfwupgUpgradeStage(void *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx, + int componentToUpload, int option) +{ + struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) + pFwupgCtx->pImageData; + struct HpmfwupgActionRecord* pActionRecord; + + int rc = HPMFWUPG_SUCCESS; + unsigned char* pImagePtr; + unsigned int actionsSize; + int flagColdReset = FALSE; + // time_t start,end; + + /* Put pointer after image header */ + pImagePtr = (unsigned char*) + (pFwupgCtx->pImageData + sizeof(struct HpmfwupgImageHeader) + + pImageHeader->oemDataLength + sizeof(unsigned char)/*checksum*/); + + /* Deternime actions size */ + actionsSize = pFwupgCtx->imageSize - sizeof(struct HpmfwupgImageHeader); + + if (option & VERSIONCHECK_MODE || option & FORCE_MODE) + { + HpmDisplayUpgradeHeader(0); + } + + /* Perform actions defined in the image */ + while( ( pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize - + HPMFWUPG_MD5_SIGNATURE_LENGTH)) && + ( rc == HPMFWUPG_SUCCESS) ) + { + /* Get action record */ + pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr; + + /* Validate action record checksum */ + if ( HpmfwupgCalculateChecksum((unsigned char*)pActionRecord, + sizeof(struct HpmfwupgActionRecord)) != 0 ) + { + lprintf(LOG_NOTICE," Invalid Action record."); + rc = HPMFWUPG_ERROR; + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + switch( pActionRecord->actionType ) + { + case HPMFWUPG_ACTION_BACKUP_COMPONENTS: + { + /* Send prepare components command */ + struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; + + initUpgActionCmd.req.componentsMask = pFwupgCtx->compUpdateMask; + /* Action is prepare components */ + initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_BACKUP; + rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); + pImagePtr += sizeof(struct HpmfwupgActionRecord); + + } + break; + case HPMFWUPG_ACTION_PREPARE_COMPONENTS: + { + int componentId; + /* Make sure every components specified by this action + supports the prepare components */ + + /* Component 'filtering' is done in PreUpdateCheck() and pFwupgCtx is set accordiongly */ + + for ( componentId = HPMFWUPG_COMPONENT_ID_0; + componentId < HPMFWUPG_COMPONENT_ID_MAX; + componentId++ ) + { + if ( (1 << componentId & pFwupgCtx->compUpdateMask.ComponentBits.byte) ) + { + if ( pFwupgCtx->genCompProp[componentId].GeneralCompProperties.bitfield.preparationSupport == 0 ) + { + lprintf(LOG_NOTICE," Prepare component not supported by component ID %d", componentId); + rc = HPMFWUPG_ERROR; + break; + } + } + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + if ( pFwupgCtx->compUpdateMask.ComponentBits.byte != 0x00 ) + { + /* Send prepare components command */ + struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; + initUpgActionCmd.req.componentsMask = pFwupgCtx->compUpdateMask; + /* Action is prepare components */ + initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_PREPARE; + rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); + + } + pImagePtr += sizeof(struct HpmfwupgActionRecord); + } + } + break; + + case HPMFWUPG_ACTION_UPLOAD_FIRMWARE: + /* Upload all firmware blocks */ + rc = HpmFwupgActionUploadFirmware + ( + pActionRecord->components, + pFwupgCtx, + &pImagePtr, + componentToUpload, + intf, + option, + &flagColdReset + ); + + break; + default: + lprintf(LOG_NOTICE," Invalid Action type. Cannot continue"); + rc = HPMFWUPG_ERROR; + break; + } + } + } + + HpmDisplayLine("-",78); + + if (flagColdReset) + { + fflush(stdout); + lprintf(LOG_NOTICE,"(*) Component requires Payload Cold Reset"); + } + return rc; +} + +static int HpmFwupgActionUploadFirmware +( + struct HpmfwupgComponentBitMask components, + struct HpmfwupgUpgradeCtx* pFwupgCtx, + unsigned char** pImagePtr, + int componentToUpload, + void *intf, + int option, + int *pFlagColdReset +) +{ + struct HpmfwupgFirmwareImage* pFwImage; + struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; + struct HpmfwupgUploadFirmwareBlockCtx uploadCmd; + struct HpmfwupgFinishFirmwareUploadCtx finishCmd; + // struct HpmfwupgGetComponentPropertiesCtx getCompProp; + VERSIONINFO *pVersionInfo; + time_t start,end; + + int rc = HPMFWUPG_SUCCESS; + int skip = TRUE; + unsigned char* pData, *pDataInitial; + unsigned char count; + unsigned int totalSent = 0; + unsigned char bufLength = 0; + unsigned int firmwareLength = 0; + + unsigned int displayFWLength = 0; + unsigned char *pDataTemp; + unsigned int imageOffset = 0x00; + unsigned int blockLength = 0x00; + unsigned int lengthOfBlock = 0x00; + unsigned int numTxPkts = 0; + unsigned int numRxPkts = 0; + unsigned char mode = 0; + unsigned char componentId = 0x00; + unsigned char componentIdByte = 0x00; + + /* Save component ID on which the upload is done */ + componentIdByte = components.ComponentBits.byte; + while ((componentIdByte>>=1)!=0) + { + componentId++; + } + pFwupgCtx->componentId = componentId; + + pVersionInfo = (VERSIONINFO*) &gVersionInfo[componentId]; + + pFwImage = (struct HpmfwupgFirmwareImage*)((*pImagePtr) + + sizeof(struct HpmfwupgActionRecord)); + + pDataInitial = ((unsigned char*)pFwImage + sizeof(struct HpmfwupgFirmwareImage)); + pData = pDataInitial; + + /* Get firmware length */ + firmwareLength = pFwImage->length[0]; + firmwareLength |= (pFwImage->length[1] << 8) & 0xff00; + firmwareLength |= (pFwImage->length[2] << 16) & 0xff0000; + firmwareLength |= (pFwImage->length[3] << 24) & 0xff000000; + + mode = TARGET_VER | IMAGE_VER; + + if (pVersionInfo->rollbackSupported) + { + mode |= ROLLBACK_VER; + } + + if ((option & DEBUG_MODE)) + { + printf("\n\n Comp ID : %d [%-20s]\n",pVersionInfo->componentId,pFwImage->desc); + } + else + { + HpmDisplayVersion(mode,pVersionInfo); + } + + if( (1 << componentId) & pFwupgCtx->compUpdateMask.ComponentBits.byte) + { + if( verbose ) { + lprintf(LOG_NOTICE,"Do not skip %d" , componentId); + } + skip = FALSE; + } + + if(!skip) + { + /* Initialize parameters */ + uploadCmd.req.blockNumber = 0; + + /* Check if we receive size in parameters */ + if(g_channel_buf_size != 0) + { + if (g_sa == BMC_SA) + { + bufLength = g_channel_buf_size - 9; /* Plan for overhead */ + } + else + { + bufLength = g_channel_buf_size - 11; /* Plan for overhead */ + } + } + else + { + /* Find max buffer length according the connection parameters */ + if ( is_remote() ) /*IPMI LAN*/ + { + bufLength = HPMFWUPG_SEND_DATA_COUNT_LAN - 2; + if (g_sa != BMC_SA) + bufLength -= 8; + } + else + { + int i; + i = get_driver_type(); + if ((i == DRV_MV || i == DRV_KCS) && /*open driver*/ + (g_sa == BMC_SA) ) + { + bufLength = HPMFWUPG_SEND_DATA_COUNT_KCS - 2; + } + else + { + if ( g_bus == 7 ) + { + bufLength = HPMFWUPG_SEND_DATA_COUNT_IPMBL; + } + else + { + bufLength = HPMFWUPG_SEND_DATA_COUNT_IPMB; + } + } + } + } + if (verbose) + printf("Upgrade buffer size = %d (%d)\n",bufLength,g_channel_buf_size); + + /* Send Initiate Upgrade Action */ + initUpgActionCmd.req.componentsMask = components; + /* Action is upgrade */ + initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_UPGRADE; + rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); + + if (rc != HPMFWUPG_SUCCESS) + { + skip = TRUE; + } + + if ( (pVersionInfo->coldResetRequired) && (!skip)) + { + *pFlagColdReset = TRUE; + } + /* pDataInitial is the starting pointer of the image data */ + /* pDataTemp is one which we will move across */ + pData = pDataInitial; + pDataTemp = pDataInitial; + lengthOfBlock = firmwareLength; + totalSent = 0x00; + displayFWLength= firmwareLength; + time(&start); + + + while ( (pData < (pDataTemp+lengthOfBlock)) && (rc == HPMFWUPG_SUCCESS) ) + { + if ( (pData+bufLength) <= (pDataTemp+lengthOfBlock) ) + { + count = bufLength; + } + else + { + count = (unsigned char)((pDataTemp+lengthOfBlock) - pData); + } + memcpy(&uploadCmd.req.data, pData, bufLength); + + imageOffset = 0x00; + blockLength = 0x00; + numTxPkts++; + rc = HpmfwupgUploadFirmwareBlock(intf, &uploadCmd, pFwupgCtx, count, + &imageOffset,&blockLength); + numRxPkts++; + + if ( rc != HPMFWUPG_SUCCESS) + { + if ( rc == HPMFWUPG_UPLOAD_BLOCK_LENGTH ) + { + /* Retry with a smaller buffer length */ + if ( is_remote() ) // strstr(intf->name,"lan") != NULL + { + bufLength -= (unsigned char)8; + lprintf(LOG_INFO,"Trying reduced buffer length: %d", bufLength); + } + else + { + bufLength -= (unsigned char)1; + lprintf(LOG_INFO,"Trying reduced buffer length: %d", bufLength); + } + rc = HPMFWUPG_SUCCESS; + } + else if ( rc == HPMFWUPG_UPLOAD_RETRY ) + { + rc = HPMFWUPG_SUCCESS; + } + else + { + fflush(stdout); + lprintf(LOG_NOTICE,"\n Error in Upload FIRMWARE command [rc=%d]\n",rc); + lprintf(LOG_NOTICE,"\n TotalSent:0x%x ",totalSent); + /* Exiting from the function */ + rc = HPMFWUPG_ERROR; + } + } + else + { + if (blockLength > firmwareLength) + { + /* + * blockLength is the remaining length of the firmware to upload so + * if its greater than the firmware length then its kind of error + */ + lprintf(LOG_NOTICE,"\n Error in Upload FIRMWARE command [rc=%d]\n",rc); + lprintf(LOG_NOTICE,"\n TotalSent:0x%x Img offset:0x%x Blk length:0x%x Fwlen:0x%x\n", + totalSent,imageOffset,blockLength,firmwareLength); + rc = HPMFWUPG_ERROR; + } + totalSent += count; + if (imageOffset != 0x00) + { + /* block Length is valid */ + lengthOfBlock = blockLength; + pDataTemp = pDataInitial + imageOffset; + pData = pDataTemp; + if ( displayFWLength == firmwareLength) + { + /* This is basically used only to make sure that we display uptil 100% */ + displayFWLength = blockLength + totalSent; + } + } + else + { + pData += count; + } + time(&end); + /* + * Just added debug mode in case we need to see exactly how many bytes have + * gone through - Its a hidden option used mainly should be used for debugging + */ + if ( option & DEBUG_MODE) + { + fflush(stdout); + printf(" Blk Num : %02x Bytes : %05x \r\n", + uploadCmd.req.blockNumber,totalSent); + if (imageOffset || blockLength) + { + printf("\r--> ImgOff : %x BlkLen : %x\n",imageOffset,blockLength); + } + if (displayFWLength == totalSent) + { + printf(" Time Taken %02d:%02d\n",(end-start)/60, (end-start)%60); + printf("\n"); + } + } + else + { + HpmDisplayUpgrade(0,totalSent,displayFWLength,(end-start)); + } + uploadCmd.req.blockNumber++; + } + } + } + + if (skip) + { + + HpmDisplayUpgrade(1,0,0,0); + *pImagePtr = pDataInitial + firmwareLength; + } + + if + ( + (rc == HPMFWUPG_SUCCESS) + && + (!skip) + ) + { + /* Send finish component */ + /* Set image length */ + finishCmd.req.componentId = componentId; + /* We need to send the actual data that is sent + * not the comlete firmware image length + */ + finishCmd.req.imageLength[0] = totalSent & 0xFF; + finishCmd.req.imageLength[1] = (totalSent >> 8) & 0xFF; + finishCmd.req.imageLength[2] = (totalSent >> 16) & 0xFF; + finishCmd.req.imageLength[3] = (totalSent >> 24) & 0xFF; + rc = HpmfwupgFinishFirmwareUpload(intf, &finishCmd, pFwupgCtx); + if ( option & DEBUG_MODE) + printf("HpmfwupgFinishFirmwareUpload rc = %d sent = %d\n",rc,totalSent); + *pImagePtr = pDataInitial + firmwareLength; + } + + return rc; +} + +/**************************************************************************** +* +* Function Name: HpmfwupgActivationStage +* +* Description: This function the validation stage of a firmware upgrade +* procedure as defined in section 3.4 of the IPM Controller +* Firmware Upgrade Specification version 1.0 +* +*****************************************************************************/ +static int HpmfwupgActivationStage(void *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct HpmfwupgActivateFirmwareCtx activateCmd; + struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) + pFwupgCtx->pImageData; + + /* Print out stuf...*/ + printf(" "); + fflush(stdout); + /* Activate new firmware */ + rc = HpmfwupgActivateFirmware(intf, &activateCmd, pFwupgCtx); + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Query self test result if supported by target and new image */ + if ( (pFwupgCtx->targetCap.GlobalCapabilities.bitField.ipmcSelftestCap == 1) || + (pImageHeader->imageCapabilities.bitField.imageSelfTest == 1) ) + { + struct HpmfwupgQuerySelftestResultCtx selfTestCmd; + rc = HpmfwupgQuerySelftestResult(intf, &selfTestCmd, pFwupgCtx); + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Get the self test result */ + if ( selfTestCmd.resp.result1 != 0x55 ) + { + /* Perform manual rollback if necessary */ + /* BACKUP/ MANUAL ROLLBACK not supported by this UA */ + lprintf(LOG_NOTICE," Self test failed:"); + lprintf(LOG_NOTICE," Result1 = %x", selfTestCmd.resp.result1); + lprintf(LOG_NOTICE," Result2 = %x", selfTestCmd.resp.result2); + rc = HPMFWUPG_ERROR; + } + } + else + { + /* Perform manual rollback if necessary */ + /* BACKUP / MANUAL ROLLBACK not supported by this UA */ + lprintf(LOG_NOTICE," Self test failed."); + } + } + } + + /* If activation / self test failed, query rollback status if automatic rollback supported */ + if ( rc == HPMFWUPG_ERROR ) + { + if ( (pFwupgCtx->targetCap.GlobalCapabilities.bitField.autRollback == 1) && + (pFwupgCtx->genCompProp[pFwupgCtx->componentId].GeneralCompProperties.bitfield.rollbackBackup != 0x00) ) + { + struct HpmfwupgQueryRollbackStatusCtx rollCmd; + lprintf(LOG_NOTICE," Getting rollback status..."); + fflush(stdout); + rc = HpmfwupgQueryRollbackStatus(intf, &rollCmd, pFwupgCtx); + } + } + + return rc; +} + +int HpmfwupgGetBufferFromFile(char* imageFilename, struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + FILE* pImageFile = fopen(imageFilename, "rb"); + + if ( pImageFile == NULL ) + { + lprintf(LOG_NOTICE,"Cannot open image file %s", imageFilename); + rc = HPMFWUPG_ERROR; + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Get the raw data in file */ + fseek(pImageFile, 0, SEEK_END); + pFwupgCtx->imageSize = ftell(pImageFile); + pFwupgCtx->pImageData = malloc(sizeof(unsigned char)*pFwupgCtx->imageSize); + pFwupgCtx->compUpdateMask.ComponentBits.byte = 0; + rewind(pImageFile); + if ( pFwupgCtx->pImageData != NULL ) + { + fread(pFwupgCtx->pImageData, sizeof(unsigned char), pFwupgCtx->imageSize, pImageFile); + } + else + { + rc = HPMFWUPG_ERROR; + } + + fclose(pImageFile); + } + + return rc; +} + +int HpmfwupgGetDeviceId(void *intf, struct ipm_devid_rsp* pGetDevId) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_DEVICE_ID; + req.msg.data_len = 0; + + rsp = HpmfwupgSendCmd(intf, req, NULL); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + memcpy(pGetDevId, rsp->data, sizeof(struct ipm_devid_rsp)); + } + else + { + lprintf(LOG_NOTICE,"Error getting device ID, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting device ID\n"); + rc = HPMFWUPG_ERROR; + } + return rc; +} + +int HpmfwupgGetTargetUpgCapabilities(void *intf, + struct HpmfwupgGetTargetUpgCapabilitiesCtx* pCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_GET_TARGET_UPG_CAPABILITIES; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgGetTargetUpgCapabilitiesReq); + + rsp = HpmfwupgSendCmd(intf, req, NULL); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"TARGET UPGRADE CAPABILITIES"); + lprintf(LOG_NOTICE,"-------------------------------"); + lprintf(LOG_NOTICE,"HPM.1 version............%d ", pCtx->resp.hpmVersion); + lprintf(LOG_NOTICE,"Component 0 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component0 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 1 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component1 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 2 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component2 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 3 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component3 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 4 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component4 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 5 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component5 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 6 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component6 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 7 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component7 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Upgrade undesirable.....[%c] ", pCtx->resp.GlobalCapabilities. + bitField.fwUpgUndesirable ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Aut rollback override...[%c] ", pCtx->resp.GlobalCapabilities. + bitField.autRollbackOverride ? 'y' : 'n'); + lprintf(LOG_NOTICE,"IPMC degraded...........[%c] ", pCtx->resp.GlobalCapabilities. + bitField.ipmcDegradedDurinUpg ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Defered activation......[%c] ", pCtx->resp.GlobalCapabilities. + bitField.deferActivation ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Service affected........[%c] ", pCtx->resp.GlobalCapabilities. + bitField.servAffectDuringUpg ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Manual rollback.........[%c] ", pCtx->resp.GlobalCapabilities. + bitField.manualRollback ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Automatic rollback......[%c] ", pCtx->resp.GlobalCapabilities. + bitField.autRollback ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Self test...............[%c] ", pCtx->resp.GlobalCapabilities. + bitField.ipmcSelftestCap ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Upgrade timeout.........[%d sec] ", pCtx->resp.upgradeTimeout*5); + lprintf(LOG_NOTICE,"Self test timeout.......[%d sec] ", pCtx->resp.selftestTimeout*5); + lprintf(LOG_NOTICE,"Rollback timeout........[%d sec] ", pCtx->resp.rollbackTimeout*5); + lprintf(LOG_NOTICE,"Inaccessibility timeout.[%d sec] \n", pCtx->resp.inaccessTimeout*5); + } + } + else + { + lprintf(LOG_NOTICE,"Error getting target upgrade capabilities\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting target upgrade capabilities\n"); + rc = HPMFWUPG_ERROR; + } + + + + return rc; +} + + +int HpmfwupgGetComponentProperties(void *intf, struct HpmfwupgGetComponentPropertiesCtx* pCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_GET_COMPONENT_PROPERTIES; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgGetComponentPropertiesReq); + + rsp = HpmfwupgSendCmd(intf, req, NULL); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + switch ( pCtx->req.selector ) + { + case HPMFWUPG_COMP_GEN_PROPERTIES: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetGeneralPropResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"GENERAL PROPERTIES"); + lprintf(LOG_NOTICE,"-------------------------------"); + lprintf(LOG_NOTICE,"Payload cold reset req....[%c] ", pCtx->resp.Response.generalPropResp. + GeneralCompProperties.bitfield.payloadColdReset ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Def. activation supported.[%c] ", pCtx->resp.Response.generalPropResp. + GeneralCompProperties.bitfield.deferredActivation ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Comparison supported......[%c] ", pCtx->resp.Response.generalPropResp. + GeneralCompProperties.bitfield.comparisonSupport ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Preparation supported.....[%c] ", pCtx->resp.Response.generalPropResp. + GeneralCompProperties.bitfield.preparationSupport ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Rollback supported........[%c] \n", pCtx->resp.Response.generalPropResp. + GeneralCompProperties.bitfield.rollbackBackup ? 'y' : 'n'); + } + break; + case HPMFWUPG_COMP_CURRENT_VERSION: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetCurrentVersionResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"Current Version: "); + lprintf(LOG_NOTICE," Major: %d", pCtx->resp.Response.currentVersionResp.currentVersion[0]); + lprintf(LOG_NOTICE," Minor: %x", pCtx->resp.Response.currentVersionResp.currentVersion[1]); + lprintf(LOG_NOTICE," Aux : %03d %03d %03d %03d\n", pCtx->resp.Response.currentVersionResp.currentVersion[2], + pCtx->resp.Response.currentVersionResp.currentVersion[3], + pCtx->resp.Response.currentVersionResp.currentVersion[4], + pCtx->resp.Response.currentVersionResp.currentVersion[5]); + } + break; + case HPMFWUPG_COMP_DESCRIPTION_STRING: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetDescStringResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"Description string: %s\n", pCtx->resp.Response.descStringResp.descString); + } + break; + case HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetRollbackFwVersionResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"Rollback FW Version: "); + lprintf(LOG_NOTICE," Major: %d", pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[0]); + lprintf(LOG_NOTICE," Minor: %x", pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[1]); + lprintf(LOG_NOTICE," Aux : %03d %03d %03d %03d\n", pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[2], + pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[3], + pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[4], + pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[5]); + } + break; + case HPMFWUPG_COMP_DEFERRED_FIRMWARE_VERSION: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetDeferredFwVersionResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"Deferred FW Version: "); + lprintf(LOG_NOTICE," Major: %d", pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[0]); + lprintf(LOG_NOTICE," Minor: %x", pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[1]); + lprintf(LOG_NOTICE," Aux : %03d %03d %03d %03d\n", pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[2], + pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[3], + pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[4], + pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[5]); + } + break; + // OEM Properties command + case HPMFWUPG_COMP_OEM_PROPERTIES: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetOemProperties)); + if ( verbose ) + { + unsigned char i = 0; + lprintf(LOG_NOTICE,"OEM Properties: "); + for (i=0; i < HPMFWUPG_OEM_LENGTH; i++) + { + lprintf(LOG_NOTICE," 0x%x ", pCtx->resp.Response.oemProperties.oemRspData[i]); + } + } + break; + default: + lprintf(LOG_NOTICE,"Unsupported component selector"); + rc = HPMFWUPG_ERROR; + break; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting component properties, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting component properties\n"); + rc = HPMFWUPG_ERROR; + } + + + return rc; +} + +int HpmfwupgAbortUpgrade(void *intf, struct HpmfwupgAbortUpgradeCtx* pCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_ABORT_UPGRADE; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgAbortUpgradeReq); + + rsp = HpmfwupgSendCmd(intf, req, NULL); + + if ( rsp ) + { + if ( rsp->ccode != 0x00 ) + { + lprintf(LOG_NOTICE,"Error aborting upgrade, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error aborting upgrade\n"); + rc = HPMFWUPG_ERROR; + } + return rc; +} + +int HpmfwupgInitiateUpgradeAction(void *intf, struct HpmfwupgInitiateUpgradeActionCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_INITIATE_UPGRADE_ACTION; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgInitiateUpgradeActionReq); + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + /* Long duration command handling */ + if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ) + { + rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); + } + else if ( rsp->ccode != 0x00 ) + { + lprintf(LOG_NOTICE,"Error initiating upgrade action, compcode = %x %s\n", + rsp->ccode, hpm_decode_cc(req.msg.cmd,rsp->ccode)); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error initiating upgrade action\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +int HpmfwupgUploadFirmwareBlock(void *intf, struct HpmfwupgUploadFirmwareBlockCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx, int count + ,unsigned int *imageOffset, unsigned int *blockLength ) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_UPLOAD_FIRMWARE_BLOCK; + req.msg.data = (unsigned char*)&pCtx->req; + /* 2 is the size of the upload struct - data */ + req.msg.data_len = 2 + count; + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS || + rsp->ccode == 0x00 ) + { + /* + * We need to check if the response also contains the next upload firmware offset + * and the firmware length in its response - These are optional but very vital + */ + if ( rsp->data_len > 1 ) + { + /* + * If the response data length is greater than 1 it should contain both the + * the Section offset and section length. Because we cannot just have + * Section offset without section length so the length should be 9 + */ + if ( rsp->data_len == 9 ) + { + /* rsp->data[1] - LSB rsp->data[2] - rsp->data[3] = MSB */ + *imageOffset = (rsp->data[4] << 24) + (rsp->data[3] << 16) + (rsp->data[2] << 8) + rsp->data[1]; + *blockLength = (rsp->data[8] << 24) + (rsp->data[7] << 16) + (rsp->data[6] << 8) + rsp->data[5]; + } + else + { + /* + * The Spec does not say much for this kind of errors where the + * firmware returned only offset and length so currently returning it + * as 0x82 - Internal CheckSum Error + */ + lprintf(LOG_NOTICE,"Error wrong rsp->datalen %d for Upload Firmware block command\n",rsp->data_len); + rsp->ccode = HPMFWUPG_INT_CHECKSUM_ERROR; + } + } + } + /* Long duration command handling */ + if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ) + { + rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); + } + else if (rsp->ccode != 0x00) + { + /* + * PATCH --> This validation is to handle retryables errors codes on IPMB bus. + * This will be fixed in the next release of open ipmi and this + * check will have to be removed. (Buggy version = 39) + */ + if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) + { + lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); + rc = HPMFWUPG_UPLOAD_RETRY; + } + /* + * If completion code = 0xc7, we will retry with a reduced buffer length. + * Do not print error. + */ + else if ( rsp->ccode == IPMI_CC_REQ_DATA_INV_LENGTH ) + { + rc = HPMFWUPG_UPLOAD_BLOCK_LENGTH; + } + else + { + lprintf(LOG_NOTICE,"Error uploading firmware block, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + } + else + { + lprintf(LOG_NOTICE,"Error uploading firmware block\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +int HpmfwupgFinishFirmwareUpload(void *intf, struct HpmfwupgFinishFirmwareUploadCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_FINISH_FIRMWARE_UPLOAD; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgFinishFirmwareUploadReq); + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + /* Long duration command handling */ + if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) + { + rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); + } + else if ( rsp->ccode != IPMI_CC_OK ) + { + lprintf(LOG_NOTICE,"Error finishing firmware upload, compcode = %x %s\n", + rsp->ccode, hpm_decode_cc(req.msg.cmd,rsp->ccode)); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error finishing firmware upload\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +int HpmfwupgActivateFirmware(void *intf, struct HpmfwupgActivateFirmwareCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_ACTIVATE_FIRMWARE; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgActivateFirmwareReq) - + (!pCtx->req.rollback_override ? 1 : 0); + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + /* Long duration command handling */ + if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) + { + printf("Waiting firmware activation..."); + fflush(stdout); + + rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); + + if ( rc == HPMFWUPG_SUCCESS ) + { + lprintf(LOG_NOTICE,"OK"); + } + else + { + lprintf(LOG_NOTICE,"Failed"); + } + } + else if (rsp->ccode == HPMFWUPG_NOT_SUPPORTED_NOW) /*0xd5*/ + { + printf("Activation already completed.\n"); + rc = HPMFWUPG_SUCCESS; + } + else if ( rsp->ccode != IPMI_CC_OK ) + { + lprintf(LOG_NOTICE,"Error activating firmware, compcode = %x\n", + rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error activating firmware\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +int HpmfwupgGetUpgradeStatus(void *intf, struct HpmfwupgGetUpgradeStatusCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_GET_UPGRADE_STATUS; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgGetUpgradeStatusReq); + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetUpgradeStatusResp)); + if ( verbose > 1 ) + { + lprintf(LOG_NOTICE,"Upgrade status:"); + lprintf(LOG_NOTICE," Command in progress: %x", pCtx->resp.cmdInProcess); + lprintf(LOG_NOTICE," Last command completion code: %x", pCtx->resp.lastCmdCompCode); + } + } + /* + * PATCH --> This validation is to handle retryables errors codes on IPMB bus. + * This will be fixed in the next release of open ipmi and this + * check will have to be removed. (Buggy version = 39) + */ + else if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) + { + lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); + + pCtx->resp.lastCmdCompCode = HPMFWUPG_COMMAND_IN_PROGRESS; + } + else + { + if ( verbose ) + { + lprintf(LOG_NOTICE,"Error getting upgrade status, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + } + else + { + if ( verbose ) + { + lprintf(LOG_NOTICE,"Error getting upgrade status"); + rc = HPMFWUPG_ERROR; + } + } + + return rc; +} + +int HpmfwupgManualFirmwareRollback(void *intf, struct HpmfwupgManualFirmwareRollbackCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgManualFirmwareRollbackReq); + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + /* Long duration command handling */ + if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ) + { + struct HpmfwupgQueryRollbackStatusCtx resCmd; + printf("Waiting firmware rollback..."); + fflush(stdout); + rc = HpmfwupgQueryRollbackStatus(intf, &resCmd, pFwupgCtx); + } + else if ( rsp->ccode != 0x00 ) + { + lprintf(LOG_NOTICE,"Error sending manual rollback, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error sending manual rollback\n"); + rc = HPMFWUPG_ERROR; + } + return rc; +} + +int HpmfwupgQueryRollbackStatus(void *intf, struct HpmfwupgQueryRollbackStatusCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + unsigned int rollbackTimeout = 0; + unsigned int timeoutSec1, timeoutSec2; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_QUERY_ROLLBACK_STATUS; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgQueryRollbackStatusReq); + + /* + * If we are not in upgrade context, we use default timeout values + */ + if ( pFwupgCtx != NULL ) + { + rollbackTimeout = pFwupgCtx->targetCap.rollbackTimeout*5; + } + else + { + struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; + verbose--; + rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); + verbose++; + if ( rc == HPMFWUPG_SUCCESS ) + { + rollbackTimeout = targetCapCmd.resp.rollbackTimeout *5; + } + else + { + rollbackTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; + } + } + + /* Poll rollback status until completion or timeout */ + timeoutSec1 = (uint32_t)time(NULL); + timeoutSec2 = (uint32_t)time(NULL); + do + { + /* Must wait at least 100 ms between status requests */ + os_usleep(0,100000); + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + /* + * PATCH --> This validation is to handle retryables errors codes on IPMB bus. + * This will be fixed in the next release of open ipmi and this + * check will have to be removed. (Buggy version = 39) + */ + if ( rsp ) + { + if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) + { + lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); + rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS; + } + } + timeoutSec2 = (uint32_t)time(NULL); + + }while( rsp && + (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) && + (timeoutSec2 - timeoutSec1 < rollbackTimeout ) ); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgQueryRollbackStatusResp)); + if ( pCtx->resp.rollbackComp.ComponentBits.byte != 0 ) + { + /* Rollback occured */ + lprintf(LOG_NOTICE,"Rollback occured on component mask: 0x%02x", + pCtx->resp.rollbackComp.ComponentBits.byte); + } + else + { + lprintf(LOG_NOTICE,"No Firmware rollback occured"); + } + } + else if ( rsp->ccode == 0x81 ) + { + lprintf(LOG_NOTICE,"Rollback failed on component mask: 0x%02x", + pCtx->resp.rollbackComp.ComponentBits.byte); + rc = HPMFWUPG_ERROR; + } + else + { + lprintf(LOG_NOTICE,"Error getting rollback status, compcode = %x", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting upgrade status\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +int HpmfwupgQuerySelftestResult(void *intf, struct HpmfwupgQuerySelftestResultCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + unsigned char selfTestTimeout = 0; + unsigned int timeoutSec1, timeoutSec2; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + /* + * If we are not in upgrade context, we use default timeout values + */ + if ( pFwupgCtx != NULL ) + { + /* Getting selftest timeout from new image */ + struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) + pFwupgCtx->pImageData; + selfTestTimeout = pImageHeader->selfTestTimeout; + } + else + { + selfTestTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_QUERY_SELFTEST_RESULT; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgQuerySelftestResultReq); + + + /* Poll rollback status until completion or timeout */ + timeoutSec1 = (uint32_t)time(NULL); + timeoutSec2 = (uint32_t)time(NULL); + do + { + /* Must wait at least 100 ms between status requests */ + os_usleep(0,100000); + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + /* + * PATCH --> This validation is to handle retryables errors codes on IPMB bus. + * This will be fixed in the next release of open ipmi and this + * check will have to be removed. (Buggy version = 39) + */ + if ( rsp ) + { + if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) + { + lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); + rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS; + } + } + timeoutSec2 = (uint32_t)time(NULL); + + }while( rsp && + (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) && + (timeoutSec2 - timeoutSec1 < selfTestTimeout ) ); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgQuerySelftestResultResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"Self test results:"); + lprintf(LOG_NOTICE,"Result1 = %x", pCtx->resp.result1); + lprintf(LOG_NOTICE,"Result2 = %x", pCtx->resp.result2); + } + } + else + { + lprintf(LOG_NOTICE,"Error getting self test results, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting upgrade status\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +struct ipmi_rs * HpmfwupgSendCmd(void *intf, struct ipmi_rq req, + struct HpmfwupgUpgradeCtx* pFwupgCtx ) +{ + struct ipmi_rs * rsp; + unsigned int inaccessTimeout = 0, inaccessTimeoutCounter = 0; + unsigned int upgradeTimeout = 0, upgradeTimeoutCounter = 0; + unsigned int timeoutSec1, timeoutSec2; + unsigned char retry = 0; + static struct ipmi_rs fakeRsp; + int rv, rsp_len; + + /* + * If we are not in upgrade context, we use default timeout values + */ + if ( pFwupgCtx != NULL ) + { + inaccessTimeout = pFwupgCtx->targetCap.inaccessTimeout*5; + upgradeTimeout = pFwupgCtx->targetCap.upgradeTimeout*5; + } + else + { + /* keeping the inaccessTimeout to 60 seconds results in almost 2900 retries + * So if the target is not available it will be retrying the command for 2900 + * times which is not effecient -So reducing the Timout to 5 seconds which is + * almost 200 retries if it continuously recieves 0xC3 as completion code. + */ + inaccessTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; + upgradeTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; + } + + timeoutSec1 = (uint32_t)time(NULL); + + do + { + static unsigned char isValidSize = FALSE; + rv = ipmi_sendrecv(&req, fakeRsp.data, &rsp_len); + if( rv < 0) + { + #define HPM_LAN_PACKET_RESIZE_LIMIT 6 + + if(is_remote()) /* also covers lanplus */ + { + static int errorCount=0; + + lprintf(LOG_DEBUG,"HPM: no response available"); + lprintf(LOG_DEBUG,"HPM: the command may be rejected for " \ + "security reasons"); + + if + ( + req.msg.netfn == IPMI_NETFN_PICMG + && + req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK + && + errorCount < HPM_LAN_PACKET_RESIZE_LIMIT + && + (!isValidSize) + ) + { + lprintf(LOG_DEBUG,"HPM: upload firmware block API called"); + lprintf(LOG_DEBUG,"HPM: returning length error to force resize"); + + fakeRsp.ccode = IPMI_CC_REQ_DATA_INV_LENGTH; + rv = fakeRsp.ccode; + rsp = &fakeRsp; + errorCount++; + } + else if + ( + req.msg.netfn == IPMI_NETFN_PICMG + && + ( req.msg.cmd == HPMFWUPG_ACTIVATE_FIRMWARE || + req.msg.cmd == HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK ) + ) + { + /* + * rsp == NULL and command activate firmware or manual firmware + * rollback most likely occurs when we have sent a firmware activation + * request. Fake a command in progress response. + */ + lprintf(LOG_DEBUG,"HPM: activate/rollback firmware API called"); + lprintf(LOG_DEBUG,"HPM: returning in progress to handle IOL session lost"); + + fakeRsp.ccode = HPMFWUPG_COMMAND_IN_PROGRESS; + rv = fakeRsp.ccode; + rsp = &fakeRsp; + } + else if + ( + req.msg.netfn == IPMI_NETFN_PICMG + && + ( req.msg.cmd == HPMFWUPG_QUERY_ROLLBACK_STATUS || + req.msg.cmd == HPMFWUPG_GET_UPGRADE_STATUS ) + ) + { + /* + * rsp == NULL and command get upgrade status or query rollback + * status most likely occurs when we are waiting for firmware + * activation. Try to re-open the IOL session (re-open will work + * once the IPMC recovers from firmware activation. + */ + + lprintf(LOG_DEBUG,"HPM: upg/rollback status firmware API called"); + lprintf(LOG_DEBUG,"HPM: try to re-open IOL session"); + + { + /* force session re-open */ + ipmi_close_(); + os_usleep(inaccessTimeout,0); + + /* Fake timeout to retry command */ + fakeRsp.ccode = 0xc3; + rv = fakeRsp.ccode; + rsp = &fakeRsp; + } + } + } + } + + /* Handle inaccessibility timeout (rsp = NULL if IOL) */ + if ( rv < 0 || rv == 0xff || rv == 0xc3 || rv == 0xd3 ) + { + if ( inaccessTimeoutCounter < inaccessTimeout ) + { + timeoutSec2 = (uint32_t)time(NULL); + if ( timeoutSec2 > timeoutSec1 ) + { + inaccessTimeoutCounter += timeoutSec2 - timeoutSec1; + timeoutSec1 = (uint32_t)time(NULL); + } + os_usleep(0,100000); + retry = 1; + } + else + { + retry = 0; + } + } + /* Handle node busy timeout */ + else if ( rv == 0xc0 ) + { + if ( upgradeTimeoutCounter < upgradeTimeout ) + { + timeoutSec2 = (uint32_t)time(NULL); + if ( timeoutSec2 > timeoutSec1 ) + { + timeoutSec1 = (uint32_t)time(NULL); + // upgradeTimeoutCounter += timeoutSec2 - timeoutSec1; + upgradeTimeoutCounter += 1; + } + os_usleep(0,100000); + retry = 1; + } + else + { + retry = 0; + } + } + else + { + #ifdef ENABLE_OPENIPMI_V39_PATCH + if( rv == IPMI_CC_OK ) + { + errorCount = 0 ; + } + #endif + retry = 0; + + if + ( + req.msg.netfn == IPMI_NETFN_PICMG + && + req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK + && + (!isValidSize) + ) + { + lprintf(LOG_INFO,"Buffer length is now considered valid" ); + + isValidSize = TRUE; + } + } + }while( retry ); + + if (rv < 0) rsp = NULL; + else { + rsp = &fakeRsp; /*has data already*/ + rsp->ccode = (uchar)rv; + rsp->session.payloadtype = 0; /*IPMI_PAYLOAD_TYPE_IPMI*/ + rsp->data_len = rsp_len; + } + return rsp; +} + +int HpmfwupgWaitLongDurationCmd(void *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + unsigned int upgradeTimeout = 0; + unsigned int timeoutSec1, timeoutSec2; + struct HpmfwupgGetUpgradeStatusCtx upgStatusCmd; + + /* + * If we are not in upgrade context, we use default timeout values + */ + if ( pFwupgCtx != NULL ) + { + upgradeTimeout = pFwupgCtx->targetCap.upgradeTimeout*5; + if ( verbose ) + printf("Use File Upgrade Capabilities: %i seconds\n", upgradeTimeout); + } + else + { + /* Try to retreive from Caps */ + struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; + + if(HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd) != HPMFWUPG_SUCCESS) + { + upgradeTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; + + if ( verbose ) + printf("Use default timeout: %i seconds\n", upgradeTimeout); + } + else + { + upgradeTimeout = (targetCapCmd.resp.upgradeTimeout * 5); + if ( verbose ) + printf("Use Command Upgrade Capabilities Timeout: %i seconds\n", upgradeTimeout); + } + } + + if(rc == HPMFWUPG_SUCCESS) + { + /* Poll upgrade status until completion or timeout*/ + timeoutSec1 = (uint32_t)time(NULL); + timeoutSec2 = (uint32_t)time(NULL); + rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd, pFwupgCtx); + } + + while( + (upgStatusCmd.resp.lastCmdCompCode == HPMFWUPG_COMMAND_IN_PROGRESS ) && + (timeoutSec2 - timeoutSec1 < upgradeTimeout ) && + (rc == HPMFWUPG_SUCCESS) + ) + { + /* Must wait at least 1000 ms between status requests */ + os_usleep(0,1000000); + rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd, pFwupgCtx); + //printf("Get Status: %x - %x = %x _ %x [%x]\n", timeoutSec2, timeoutSec1,(timeoutSec2 - timeoutSec1),upgradeTimeout, rc); + } + + if ( upgStatusCmd.resp.lastCmdCompCode != 0x00 ) + { + if ( verbose ) + { + lprintf(LOG_NOTICE,"Error waiting for command %x, compcode = %x", + upgStatusCmd.resp.cmdInProcess, + upgStatusCmd.resp.lastCmdCompCode, + hpm_decode_cc(upgStatusCmd.resp.cmdInProcess, + upgStatusCmd.resp.lastCmdCompCode)); + } + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +unsigned char HpmfwupgCalculateChecksum(unsigned char* pData, unsigned int length) +{ + unsigned char checksum = 0; + int dataIdx = 0; + + for ( dataIdx = 0; dataIdx < (int)length; dataIdx++ ) + { + checksum += pData[dataIdx]; + } + return checksum; +} + +static void HpmfwupgPrintUsage(void) +{ + lprintf(LOG_NOTICE,"help - This help menu"); + lprintf(LOG_NOTICE,"check - Check the target information"); + lprintf(LOG_NOTICE,"check <file> - If the user is unsure of what update is going to be "); + lprintf(LOG_NOTICE," This will display the existing target version and image "); + lprintf(LOG_NOTICE," version on the screen"); + lprintf(LOG_NOTICE,"upgrade <file> - Upgrade the firmware using a valid HPM.1 image <file>"); + lprintf(LOG_NOTICE," This checks the version from the file and image and "); + lprintf(LOG_NOTICE," if it differs then only updates else skips"); + lprintf(LOG_NOTICE,"upgrade <file> all - Updates all the components present in the file on the target board"); + lprintf(LOG_NOTICE," without skipping (use this only after using \"check\" command"); + lprintf(LOG_NOTICE,"upgrade <file> component x - Upgrade only component <x> from the given <file>"); + lprintf(LOG_NOTICE," component 0 - BOOT"); + lprintf(LOG_NOTICE," component 1 - RTK"); + lprintf(LOG_NOTICE,"upgrade <file> activate - Upgrade the firmware using a valid HPM.1 image <file>"); + lprintf(LOG_NOTICE," If activate is specified, activate new firmware rigth"); + lprintf(LOG_NOTICE," away"); + lprintf(LOG_NOTICE,"activate [norollback] - Activate the newly uploaded firmware"); + lprintf(LOG_NOTICE,"targetcap - Get the target upgrade capabilities"); + lprintf(LOG_NOTICE,"compprop <id> <select> - Get the specified component properties"); + lprintf(LOG_NOTICE," Valid component <ID> 0-7 "); + lprintf(LOG_NOTICE," Properties <select> can be one of the following: "); + lprintf(LOG_NOTICE," 0- General properties"); + lprintf(LOG_NOTICE," 1- Current firmware version"); + lprintf(LOG_NOTICE," 2- Description string"); + lprintf(LOG_NOTICE," 3- Rollback firmware version"); + lprintf(LOG_NOTICE," 4- Deferred firmware version"); + lprintf(LOG_NOTICE,"abort - Abort the on-going firmware upgrade"); + lprintf(LOG_NOTICE,"upgstatus - Returns the status of the last long duration command"); + lprintf(LOG_NOTICE,"rollback - Performs a manual rollback on the IPM Controller"); + lprintf(LOG_NOTICE," firmware"); + lprintf(LOG_NOTICE,"rollbackstatus - Query the rollback status"); + lprintf(LOG_NOTICE,"selftestresult - Query the self test results\n"); +} + +int ipmi_hpmfwupg_main(void * intf, int argc, char ** argv) +{ + int rc = HPMFWUPG_SUCCESS; + int activateFlag = 0x00; + int componentId = DEFAULT_COMPONENT_UPLOAD; + int option = VERSIONCHECK_MODE; + + lprintf(LOG_DEBUG,"ipmi_hpmfwupg_main()"); + + + lprintf(LOG_NOTICE,"\nPICMG HPM.1 Upgrade Agent %d.%d.%d: \n", + HPMFWUPG_VERSION_MAJOR, HPMFWUPG_VERSION_MINOR, HPMFWUPG_VERSION_SUBMINOR); + + if ( (argc == 0) || (strcmp(argv[0], "help") == 0) ) + { + HpmfwupgPrintUsage(); + return ERR_USAGE; + } + if ( (strcmp(argv[0], "check") == 0) ) + { + /* hpm check */ + if (argv[1] == NULL) + { + rc = HpmfwupgTargetCheck(intf,VIEW_MODE); + } + else + { + /* hpm check <filename> */ + rc = HpmfwupgTargetCheck(intf,0); + if (rc == HPMFWUPG_SUCCESS) + { + rc = HpmfwupgUpgrade(intf, argv[1],0,DEFAULT_COMPONENT_UPLOAD,VIEW_MODE); + } + } + } + + else if ( strcmp(argv[0], "upgrade") == 0) + { + int i =0; + if (fdebug) option |= DEBUG_MODE; + if (g_channel_buf_size > 0) + printf("Large buffer size %d specified\n", g_channel_buf_size ); + for (i=1; i< argc ; i++) + { + if (strcmp(argv[i],"activate") == 0) + { + activateFlag = 1; + } + /* hpm upgrade <filename> all */ + if (strcmp(argv[i],"all") == 0) + { + option &= ~(VERSIONCHECK_MODE); + option &= ~(VIEW_MODE); + option |= FORCE_MODE_ALL; + } + /* hpm upgrade <filename> component <comp Id> */ + if (strcmp(argv[i],"component") == 0) + { + if (i+1 < argc) + { + componentId = atoi(argv[i+1]); + option &= ~(VERSIONCHECK_MODE); + option &= ~(VIEW_MODE); + option |= FORCE_MODE_COMPONENT; + + if( verbose ) { + lprintf(LOG_NOTICE,"Component Id %d provided",componentId ); + } + + /* Error Checking */ + if (componentId >= HPMFWUPG_COMPONENT_ID_MAX) + { + lprintf(LOG_NOTICE,"Given component ID %d exceeds Max Comp ID %d\n", + componentId, HPMFWUPG_COMPONENT_ID_MAX-1); + return HPMFWUPG_ERROR; + } + } + if (componentId == DEFAULT_COMPONENT_UPLOAD) + { + /* That indicates the user has given component on console but not + * given any ID */ + lprintf(LOG_NOTICE,"No component Id provided\n"); + return HPMFWUPG_ERROR; + } + } + if (strcmp(argv[i],"debug") == 0) + { + option |= DEBUG_MODE; + } + } + rc = HpmfwupgTargetCheck(intf,0); + if (rc == HPMFWUPG_SUCCESS) + { + /* Call the Upgrade function to start the upgrade */ + rc = HpmfwupgUpgrade(intf, argv[1],activateFlag,componentId,option); + } + } + + else if ( (argc >= 1) && (strcmp(argv[0], "activate") == 0) ) + { + struct HpmfwupgActivateFirmwareCtx cmdCtx; + if ( (argc == 2) && (strcmp(argv[1], "norollback") == 0) ) + cmdCtx.req.rollback_override = 1; + else + cmdCtx.req.rollback_override = 0; + rc = HpmfwupgActivateFirmware(intf, &cmdCtx, NULL); + } + else if ( (argc == 1) && (strcmp(argv[0], "targetcap") == 0) ) + { + struct HpmfwupgGetTargetUpgCapabilitiesCtx cmdCtx; + verbose++; + rc = HpmfwupgGetTargetUpgCapabilities(intf, &cmdCtx); + } + else if ( (argc == 3) && (strcmp(argv[0], "compprop") == 0) ) + { + struct HpmfwupgGetComponentPropertiesCtx cmdCtx; + cmdCtx.req.componentId = atob(argv[1]); + cmdCtx.req.selector = atob(argv[2]); + verbose++; + rc = HpmfwupgGetComponentProperties(intf, &cmdCtx); + } + else if ( (argc == 1) && (strcmp(argv[0], "abort") == 0) ) + { + struct HpmfwupgAbortUpgradeCtx cmdCtx; + verbose++; + rc = HpmfwupgAbortUpgrade(intf, &cmdCtx); + } + else if ( (argc == 1) && (strcmp(argv[0], "upgstatus") == 0) ) + { + struct HpmfwupgGetUpgradeStatusCtx cmdCtx; + verbose++; + rc = HpmfwupgGetUpgradeStatus(intf, &cmdCtx, NULL); + } + else if ( (argc == 1) && (strcmp(argv[0], "rollback") == 0) ) + { + struct HpmfwupgManualFirmwareRollbackCtx cmdCtx; + verbose++; + rc = HpmfwupgManualFirmwareRollback(intf, &cmdCtx, NULL); + } + else if ( (argc == 1) && (strcmp(argv[0], "rollbackstatus") == 0) ) + { + struct HpmfwupgQueryRollbackStatusCtx cmdCtx; + verbose++; + rc = HpmfwupgQueryRollbackStatus(intf, &cmdCtx, NULL); + } + else if ( (argc == 1) && (strcmp(argv[0], "selftestresult") == 0) ) + { + struct HpmfwupgQuerySelftestResultCtx cmdCtx; + verbose++; + rc = HpmfwupgQuerySelftestResult(intf, &cmdCtx, NULL); + } + else + { + HpmfwupgPrintUsage(); + } + + return rc; +} + +#ifdef METACOMMAND +int i_hpm(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + void *intf = NULL; + int rc = 0; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + set_loglevel(LOG_NOTICE); + + while ( (c = getopt( argc, argv,"m:z:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'z': + g_channel_buf_size = atoi(optarg); + if (g_channel_buf_size < HPMFWUPG_SEND_DATA_COUNT_LAN) + rc = ERR_BAD_LENGTH; + else if (g_channel_buf_size > IPMI_REQBUF_SIZE) + rc = LAN_ERR_BADLENGTH; + if (rc != 0) { + printf("Invalid buffer size %d\n",g_channel_buf_size); + return rc; + } + break; + case 'x': fdebug = 1; verbose = 1; + set_loglevel(LOG_DEBUG); + break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + HpmfwupgPrintUsage(); + return ERR_USAGE; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + rc = ipmi_hpmfwupg_main(intf, argc, argv); + + ipmi_close_(); + // show_outcome(progname,rc); + return rc; +} +/* end ihpm.c */ + diff --git a/util/ihpm.h b/util/ihpm.h new file mode 100644 index 0000000..00d6dc9 --- /dev/null +++ b/util/ihpm.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef IPMI_HPMFWUPG_H +#define IPMI_HPMFWUPG_H + +#define IPMI_BUF_SIZE 1024 +#ifdef HAVE_LANPLUS +#include "../lib/lanplus/lanplus_defs.h" +#else +#define _IPMI_RS_ +struct ipmi_rs { + uint8_t ccode; + uint8_t data[IPMI_BUF_SIZE]; + + /* + * Looks like this is the length of the entire packet, including the RMC +P + * stuff, then modified to be the length of the extra IPMI message data + */ + int data_len; + + struct { + uint8_t netfn; + uint8_t cmd; + uint8_t seq; + uint8_t lun; + } msg; + struct { + uint8_t authtype; + uint32_t seq; + uint32_t id; + uint8_t bEncrypted; /* IPMI v2 only */ + uint8_t bAuthenticated; /* IPMI v2 only */ + uint8_t payloadtype; /* IPMI v2 only */ + uint16_t msglen; + } session; +}; +#endif + +#define TRUE 1 +#define FALSE 0 + +#define IPMI_NETFN_APP 0x06 +#define IPMI_NETFN_PICMG 0x2C + +#define IPMI_BMC_SLAVE_ADDR 0x20 + +#define BMC_GET_DEVICE_ID 0x1 + +#define IPMI_CC_OK 0x00 +#define IPMI_CC_REQ_DATA_INV_LENGTH 0xc7 + +#define ATTRIBUTE_PACKING /* */ +#define PRAGMA_PACK 1 + +#pragma pack(1) +struct ipm_devid_rsp { + uint8_t device_id; + uint8_t device_revision; + uint8_t fw_rev1; + uint8_t fw_rev2; + uint8_t ipmi_version; + uint8_t adtl_device_support; + uint8_t manufacturer_id[3]; + uint8_t product_id[2]; + uint8_t aux_fw_rev[4]; +}; +#pragma pack() + +typedef struct md5_state_s { + uint count[2]; /* message length in bits, lsw first */ + uint abcd[4]; /* digest buffer */ + uchar buf[64]; /* accumulate block */ +} md5_state_t; + +void md5_init(md5_state_t *pms); /*md5.c*/ +void md5_append(md5_state_t *pms, const uchar *data, int nbytes); /*md5.c*/ +void md5_finish(md5_state_t *pms, uchar digest[16]); /*md5.c*/ + +void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/ +void set_loglevel(int level); +char * get_mfg_str(uchar *rgmfg, int *pmfg); +ushort buf2short(uchar * buf); + +int ipmi_hpmfwupg_main(void *, int, char **); + +#endif /* IPMI_KFWUM_H */ diff --git a/util/ilan.c b/util/ilan.c new file mode 100644 index 0000000..a1ed76a --- /dev/null +++ b/util/ilan.c @@ -0,0 +1,5149 @@ +/*--------------------------------------------------------------------------- + * Filename: ilan.c (was pefconfig.c) + * + * Author: arcress at users.sourceforge.net + * Copyright (c) 2009 Kontron America, Inc. + * + * Abstract: + * This tool sets up the custom Platform Event Filter for the panicSEL + * record (0x20, OS Critical Stop) to send a PEF SNMP alert for Linux + * panics. It also configures the BMC LAN parameters, which are needed + * to support PEF alerts. + * + * ----------- Change History ----------------------------------------------- + * 10/16/01 Andy Cress - created + * 10/24/01 Andy Cress - mods for SetPefEntry(0c) + * 11/02/01 Andy Cress - added option to disable a given PefEntry + * 11/15/01 Andy Cress - added function to GetLanEntry + * 11/19/01 Andy Cress - added function to SetLanEntry + * 01/18/02 Andy Cress - added GetCfgData function + * 01/31/02 Andy Cress - converted to use ipmi_cmd_ia + * 02/06/02 Andy Cress - removed GetCfgData + * 02/06/02 Andy Cress - added ipmi_cmd_va + * 02/08/02 Andy Cress - added GetChanAcc + * 02/14/02 Andy Cress - added Get_IPMac_Addr() + * 02/21/02 Andy Cress - added Alert IP/MAC logic to Get_IPMac_Addr() + * 03/21/02 Andy Cress - do SetChanAcc(0x80) with every SetChanAcc(0x40) + * 04/15/02 Andy Cress v1.2 - fix bug with user-specified Alert IP: + * (ccode=c7 on SetLanEntry(16 & 18), also + * added Get_Mac() for user-specified Alert IP. + * 04/16/02 Andy Cress v1.3 added SetUser() to set password if specified, + * also changed unset mac[0] to be 0xFF, not 0. + * 05/09/02 Andy Cress v1.4 fixed bug 504 gwymac[0]=00 (mymac overwrote it), + * also fixed alert scan to pick last trapsink + * 05/31/02 Andy Cress v1.5 for gwy mac, changed arping -c 1 to -c 2, + * also get com2sec community from snmpd.conf, + * set dest type for no ack, no retry, + * special handling to set preset PEF entries + * 07/02/02 Andy Cress v1.6 added more Usage text + * 07/08/02 Andy Cress v1.7 SetUserAccess length change + * 08/02/02 Andy Cress v1.8 moved common ipmi_cmd() code to ipmicmd.c + * 08/27/02 Andy Cress v1.9 fixed 0xc7 on SETUSER_ACCESS with pefconfig -P "", + * show message if alert dest not found + * 09/10/02 Andy Cress v1.10 make channel nums into defines (16) + * 09/17/02 Andy Cress v1.11 decode Dest Addr IP (19) in decimal, + * fix enable user padding in SetUser, + * display new community string when setting + * 12/09/02 Andy Cress v1.12 fix error w -C & snmpd.conf conflict + * 01/29/03 Andy Cress v1.13 added MV OpenIPMI support + * 02/05/03 Andy Cress v1.14 show pef entry descriptions, + * added EnablePef routine + * show correct Alert dest mac if -A only + * 04/04/03 Andy Cress v1.15 add eth interface option (-i) + * 05/13/03 Andy Cress v1.16 fix EnablePef if startup delay not supported + * 06/19/03 Andy Cress v1.17 added errno.h (email from Travers Carter) + * 07/25/03 Andy Cress v1.18 add SerialOverLan configuration + * mod to SetUser, added GetBmcEthDevice, + * use 'arping -I' if eth1. + * 08/18/03 Andy Cress v1.19 Don't abort if IPMI 1.0, just skip PEF, + * SetLanEntry(10 & 11) for bmc grat arp, + * SetLanEntry(2) to 0x17 for auth priv + * 09/10/03 Andy Cress v1.20 Don't enable a PEF entry if it is empty, + * added -L lan_ch parameter, + * scan for lan_ch in GetBmcEthDevice + * 09/22/03 Andy Cress v1.21 Add DHCP option (-D), from Jerry Yu. + * 12/05/03 Andy Cress v1.22 Fix auth type enables for ServerConfig + * 12/16/03 Andy Cress v1.23 Allow flexible auth types via authmask + * 03/19/04 Andy Cress v1.24 Change default pefnum for mBMC to 10 + * 04/15/04 Andy Cress v1.25 Init each response for channel info, avoids + * 0xcc error with /dev/ipmi0 due to wrong lan_ch + * 05/05/04 Andy Cress v1.26 call ipmi_close before exit. Note that + * Get_IPMac_Addr and GetBmcEthDevice + * routines need more work for WIN32. + * 05/24/04 Andy Cress v1.27 added CHAN_ACC params for ia64 + * 06/28/04 Andy Cress v1.28 added parsing to get community from trapsink + * 07/23/04 Andy Cress v1.29 use lan_ch variable to set Alert Policy Table + * 08/23/04 Andy Cress v1.30 fixed decoding of PE Table entries, + * added -e option (same as no params) + * 08/25/04 Andy Cress v1.31 added some WIN32 logic to Get_Mac, Get_IPMac_Addr + * 11/01/04 Andy Cress v1.32 add -N / -R for remote nodes + * added -U for remote username + * 11/18/04 Andy Cress v1.33 added -u to configure a lan username (user 2) + * 11/23/04 Andy Cress v1.34 added pef_defaults if first 11 empty + * 01/11/05 Andy Cress v1.35 allow scan for BMC LAN if fIPMI10 + * 01/20/05 Andy Cress v1.36 fix to allow IPMI 2.0 + * 02/16/05 Andy Cress v1.37 added IPMI 2.0 VLAN parameters, + * if DHCP, can set DHCP Server via -I param + * 03/02/05 Andy Cress v1.38 show Serial-Over-Lan params, + * fix -L with lan_ch_parm. mods to GetBmcEthDevice + * 03/18/05 Andy Cress v1.39 fix GetBmcEthDevice for invalid MAC compares + * 06/03/05 Andy Cress v1.40 For my MAC in BMC, check user-specified, then + check existing BMC MAC, then check OS MAC. + * 06/10/05 Andy Cress v1.41 Display multiple Alert Destinations, + * handle fSOL20 commands + * 07/07/05 Andy Cress v1.42 Fix GetBmcEthDevice for TIGI2U to skip GCM ch 3 + * 07/08/05 Andy Cress v1.43 Mods to handle Intel NSI2U miniBMC, + * 08/01/05 Andy Cress v1.44 added -t option to test if BMC LAN configured + * 08/10/05 Andy Cress v1.45 truncate extra string chars, + * decode more PEF params + * 09/07/05 Andy Cress v1.46 enable mBMC PEF entries 26 thru 30 + * 04/06/06 Andy Cress v1.47 show "gcm" as ifname if -L 3. + * 06/20/06 Andy Cress v1.48 fix strcmp(gcm), show all 4 alert policies, + * add PefDesc() for misc vendor pefdesc, add -a. + * 08/08/06 Andy Cress v1.49 add Alcolu to fsharedMAC + * 09/29/06 Andy Cress v1.52 use bmcmymac if valid, use bmcmyip if ok, + * added -q for user number, + * enhanced Get_IPMac_Addr for Windows + * 10/12/06 Andy Cress v1.53 FindEthNum updates, always use gwy iface for mac + * 11/02/06 Andy Cress v1.55 add user names, EnablePef mods for non-Intel. + * 05/02/07 Brian Johnson v1.65 add fpefenable flag to not do SetPefEntry + * if no Alert Destination. Previously did + * SetPefEntry but not EnablePef in this case. + * 05/04/07 Andy Cress v1.65 Use 0x02 for DHCP source instead of 0x03, + * fix 1714748 missing "X:" in getopt line + * 05/23/07 Jakub Gorgolewski + * v1.66 Use iphlpapi for Windows detection + * 10/31/07 Andy Cress v2.3 Fixed PEF entry for Power Redundancy Lost + * 11/15/07 Andy Cress v2.4 Move custom PEF to #14, add to usage, + * Allow broadcast MAC for -X + * 12/17/07 Andy Cress v2.5 Add fSetPEFOks & secondary Gateway + */ +/*M* + *--------------------------------------------------------------------------- +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *--------------------------------------------------------------------------- + *M*/ +#ifdef WIN32 +#include <winsock2.h> +#include <iphlpapi.h> +#include <windows.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#else +/* Linux or similar */ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#include <string.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <errno.h> +#endif +#ifdef LINUX +#include <unistd.h> +#endif +#ifdef SOLARIS +#include <sys/sockio.h> +#define SIOCGIFHWADDR SIOCGENADDR +#define ifr_netmask ifr_ifru.ifru_addr +// #define ifr_hwaddr.sa_data ifr_ifru.ifru_enaddr +#elif defined(BSD) +#include <sys/sockio.h> +#define SIOCGIFHWADDR SIOCGIFMAC +#define ifr_netmask ifr_ifru.ifru_addr +// #define ifr_hwaddr.sa_data ifr_ifru.ifru_addr +#elif defined(MACOS) +#include <sys/sockio.h> +#define ifr_netmask ifr_ifru.ifru_addr +#endif +#include "ipmicmd.h" +#include "oem_intel.h" +#include "oem_supermicro.h" + +#define SELprintf printf +#define RTF_UP 0x0001 /* route usable */ + +#define SOL_ENABLE_FLAG 0x01 +#define SOL_DISABLE_FLAG 0x00 +#define SOL_PRIVILEGE_LEVEL_USER 0x02 +#define SOL_PRIVILEGE_LEVEL_OPERATOR 0x03 +#define SOL_PRIVILEGE_LEVEL_ADMIN 0x04 +#define SOL_PREFERRED_BAUD_RATE 0x0a /*115.2k*/ +/* For IPMI 1.5, use Intel SOL commands & subfunctions */ +#define SOL_ENABLE_PARAM 0x01 +#define SOL_AUTHENTICATION_PARAM 0x02 +#define SOL_ACC_INTERVAL_PARAM 0x03 +#define SOL_RETRY_PARAM 0x04 +#define SOL_BAUD_RATE_PARAM 0x05 /*non-volatile*/ +#define SOL_VOL_BAUD_RATE_PARAM 0x06 /*volatile*/ +/* For IPMI 2.0, use IPMI SOL commands & subfunctions */ +#define SOL_ENABLE_PARAM2 0x08 +#define SOL_AUTHENTICATION_PARAM2 0x09 +#define SOL_BAUD_RATE_PARAM2 0x11 + +/* IPMI 2.0 SOL PAYLOAD commands */ +#define SET_PAYLOAD_ACCESS 0x4C +#define GET_PAYLOAD_ACCESS 0x4D +#define GET_PAYLOAD_SUPPORT 0x4E + +/* Channel Access values */ +#define CHAN_ACC_DISABLE 0x20 /* PEF off, disabled*/ +#define CHAN_ACC_PEFON 0x02 /* PEF on, always avail */ +#define CHAN_ACC_PEFOFF 0x22 /* PEF off, always avail*/ +/* special channel access values for ia64 */ +#define CHAN_ACC_PEFON64 0x0A /* PEF on, always avail, UserLevelAuth=off */ +#define CHAN_ACC_PEFOFF64 0x2A /* PEF off, always avail, UserLevelAuth=off */ +#define OS_LINUX 1 +#define OS_WINDOWS 2 +#define OS_SOLARIS 3 +#define OS_BSD 4 +#define OS_HPUX 5 + + /* TSRLT2 Channels: 0=IPMB, 1=Serial/EMP, 6=LAN2, 7=LAN1 */ + /* S5000 Channels: 0=IPMB, 1=LAN1, 2=LAN2, 3=RMM2, 4=Serial, 6=pci, 7=sys */ + /* For TIGPT1U/mBMC: 1=LAN channel, no serial */ +#define LAN_CH 1 +#define SER_CH 4 +#define MAXCHAN 12 /*was 16, reduced for gnu ipmi_lan*/ +#define NUM_DEVICES_TO_CHECK 32 /*for GetBmcEthDevice()*/ +#define MAC_LEN 6 /*length of MAC Address*/ +#define PSW_LEN 16 /* see also PSW_MAX =20 in ipmicmd.h*/ +/* Note: The optional IPMI 2.0 20-byte passwords are not supported here, + * due to back-compatibility issues. */ + + /* IP address source values */ +#define SRC_STATIC 0x01 +#define SRC_DHCP 0x02 /* BMC running DHCP */ +#define SRC_BIOS 0x03 /* BIOS, sometimes DHCP */ +#define SRC_OTHER 0x04 + +/* PEF event severities */ +#define PEF_SEV_UNSPEC 0x00 +#define PEF_SEV_MON 0x01 +#define PEF_SEV_INFO 0x02 +#define PEF_SEV_OK 0x04 +#define PEF_SEV_WARN 0x08 +#define PEF_SEV_CRIT 0x10 +#define PEF_SEV_NORECOV 0x20 +#define FLAG_INIT 99 /*initial value of char flag, beyond scope*/ +#define PARM_INIT 0xff + +typedef struct +{ /* See IPMI Table 15-2 */ + uchar rec_id; + uchar fconfig; + uchar action; + uchar policy; + uchar severity; + uchar genid1; + uchar genid2; + uchar sensor_type; + uchar sensor_no; + uchar event_trigger; + uchar data1; + uchar mask1; + uchar res[9]; +} PEF_RECORD; + +typedef struct +{ /* See IPMI Table 19-3 */ + uchar data[36]; +} LAN_RECORD; /*LanRecord*/ + +#ifdef METACOMMAND +extern int get_lan_stats(uchar chan); /*see bmchealth.c */ +extern char *get_sensor_type_desc(uchar stype); /*from ievents.c*/ +#endif + +#define MYIP 0x01 +#define GWYIP 0x02 +#define DESTIP 0x04 +#define MAXPEF 41 /* max pefnum offset = 40 (41 entries) */ +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "ilan"; +static char fdebug = 0; +static char fipmilan = 0; +static char fIPMI10 = 0; /* =1 if IPMI v1.0 or less */ +static char fIPMI20 = 0; /* =1 if IPMI v2.0 or greater */ +static char fSOL20 = 1; /* =1 if use Serial-Over-Lan 2.0 w IPMI 2.0 */ +static char fsharedMAC = 0; /* =1 if special shared-MAC BMC LAN port */ +static char fAdjustPefNum = 0; /* =1 adjust pefnum to first empty index */ +static char fUserPefNum = 0; /* =1 if user specified a valid pefnum value*/ +static char freadonly = 1; /* =1 to only read LAN & PEF parameters */ +static char fcanonical = 0; /* =1 to show only canonical output */ +static char bdelim = BCOLON; /* delimiter ':' or '|' if canonical output*/ +static char ftestonly = 0; +static char fprivset = 0; +static char flanstats = 0; /* =1 to show the IPMI LAN statistics */ +static char foptmsg = 0; /* =1 to show the option warning msg */ +static char fshowchan = 0; /* =1 to show the IPMI channels */ +static char nopts = 0; /* number of pefconfig options specified*/ +static int nerrs = 0; /* number of errors during processing */ +static int ngood = 0; /* number of good results */ +static int lasterr = 0; /* value of the last error */ +static char fCustomPEF = 0; /* =1 if -j to input a custom PEF record */ +static char fSetPEFOks = 0; /* =1 if -k to set PEF OK rules */ +static char fdisable = 0; +static char fenable = 0; /* =1 to config BMC LAN and PEF */ +static char fpefenable = 0; /* =1 enable PEF if Alert Dest is specified*/ +static char fdisableSOL = 0; +static char fgetser = 0; +static char fsetifn = 0; /* =1 if user specified ifname[] with -i */ +static char fethfound = 0; /* =1 if FindEthNum successful */ +static char fset_ip = 0; /* !=0 if options used to specify an IP addr*/ +static char fpassword = 0; /* =1 user-specified a password, so set it. */ +static uchar fmBMC = 0; /* =1 mini-BMC, =0 Sahalee BMC */ +static uchar fiBMC = 0; /* =1 Intel iBMC */ +static uchar fRomley = 0; /* =1 Intel Romley BMC */ +static uchar fipv6 = 0; /* =1 if BMC supports IPv6 */ +static uchar bmcpefctl = 0; /* existing BMC PEF Control, !0 = enabled */ +static char alertnum = 1; /* alert dest num (usu 1 thru 4) */ +static char alertmax = 9; /* alert dest num max (usu 4, error if >9) */ +static char pefnum = 12; /* 11 pre-defined entries, adding 12th */ +static char pefadd = 0; /* num PEF rules added (usu 2, could be 5 */ +static char pefmax = MAXPEF; /* 20 for Sahalee, 30 for miniBMC */ +static char *myuser = NULL; /* username to set, specified by -u */ +static uchar usernum = 0; /* set non-zero to specify user number */ +static uchar rgmyip[4] = {0,0,0,0}; +static uchar rggwyip[4] = {0,0,0,0}; +static uchar rggwy2ip[4] = {0,0,0,0}; +static uchar rgdestip[4] = {0,0,0,0}; +static uchar rgsubnet[4] = {0,0,0,0}; +static uchar bmcsubnet[4] = {255,255,255,0}; /* default subnet */ +static uchar ossubnet[4] = {0,0,0,0}; +static uchar osmyip[4] = {0,0,0,0}; +static uchar bmcmyip[4] = {0,0,0,0}; +static uchar bmcdestip[4] = {0,0,0,0}; +static uchar bmcdestmac[6]= {0xff,0,0,0,0,0}; +static uchar bmcmymac[6] = {0xff,0,0,0,0,0}; +static uchar rgmymac[6] = {0xff,0,0,0,0,0}; +static uchar osmymac[6] = {0xff,0,0,0,0,0}; +static uchar rggwymac[6] = {0xff,0,0,0,0,0}; +static uchar rggwy2mac[6] = {0xff,0,0,0,0,0}; +static uchar rgdestmac[6] = {0xff,0,0,0,0,0}; +static uchar rgdhcpmac[6] = {0xff,0,0,0,0,0}; +static char rghostname[32] = {'\0'}; +static uchar custPEF[20]; /* max used = 18 bytes */ +static char rgcommunity[19] = "public"; /* default community */ +static char fsetcommunity = 0; /* =1 if user-specified community */ +static char passwordData[PSW_MAX+1] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static uchar authmask = 0; /* usu 0x17, mBMC = 0x15 */ +static uchar bAuth = 0x16; /*exclude auth=None for security*/ +static uchar lan_access = 0x04; /* usu 4=Admin, 3=Operator, 2=User */ +static uchar lan_user = 0x02; /* if -u specified, use user 2 for lan */ +static uchar arp_interval = 0x04; /* in 500 ms increments, 0-based */ +static uchar arp_ctl = 0x01; /* 01=grat arp, 02=arp resp, 03=both*/ +static uchar fsetarp = 0; /* 1=user-specified arp_ctl */ +#ifdef WIN32 +static uchar ostype = OS_WINDOWS; /*windows*/ +static char ifname[64] = "Local Area Connection "; /* interface name */ +static char ifpattn[25] = "Local Area Connection "; +#elif SOLARIS +/* for i86pc use "e1000g0", but for sun4u(sparc) this might be "eri0" */ +static uchar ostype = OS_SOLARIS; +#ifdef __SPARC__ +static char ifname[16] = "eri0"; /* SPARC interface name */ +static char ifname0[16] = "eri0"; +static char ifpattn[14] = "eri"; +#else +static char ifname[16] = "e1000g0"; /* Solaris x86 interface name */ +static char ifname0[16] = "e1000g0"; +static char ifpattn[14] = "e1000g"; +#endif +#elif defined(BSD) +static uchar ostype = OS_BSD; +static char ifname[16] = "em0"; /* interface name */ +static char ifname0[16] = "em0"; +static char ifpattn[14] = "em"; +#elif defined(HPUX) +static uchar ostype = OS_HPUX; +static char ifname[16] = "lan0"; /* interface name */ +static char ifname0[16] = "lan0"; +static char ifpattn[14] = "lan"; +#else +static uchar ostype = OS_LINUX; +static char ifname[16] = "eth0"; /* interface name */ +static char ifname0[16] = "eth0"; +static char ifpattn[14] = "eth"; +#endif +static char *pspace1 = "\t"; /*used for fcanonical output*/ +static char *pspace2 = "\t\t"; +static char *pspace3 = "\t\t\t"; +static char *pspace4 = "\t\t\t\t"; +static int vend_id; +static int prod_id; +static int lan_dhcp = 0; /*=1 if using DHCP for bmc lan channel*/ +static uchar ser_ch = SER_CH; +static uchar lan_ch = LAN_CH; +static uchar lan_ch_parm = PARM_INIT; +static uchar gcm_ch = PARM_INIT; +static uchar vlan_enable = PARM_INIT; +static uchar failover_enable = PARM_INIT; +static uchar vlan_prio = 0; /*default = 0*/ +static ushort vlan_id = 0; /*max 12 bits used*/ +static uchar max_users = 5; /* set in GetUser(1); */ +static uchar enabled_users = 0; /* set in GetUser(1); */ +static uchar show_users = 5; /* default, adjusted based on DeviceID */ +static uchar fnewbaud = 0; /* =1 if user specified baud */ +static uchar sol_baud = SOL_PREFERRED_BAUD_RATE; /*115.2k default*/ +static uchar sol_accum[2] = { 0x04, 0x32 }; +static uchar sol_retry[2] = { 0x06, 0x14 }; +static uchar sol_bvalid = 0; /* =1 if SOL baud is valid */ +static uchar chan_pefon = CHAN_ACC_PEFON; +static uchar chan_pefoff = CHAN_ACC_PEFOFF; +static uchar SessInfo[18]; /* Session Info data */ +// static uchar bparm7[3] = {0x00, 0x00, 0x00}; /*ipv4 header before*/ +static uchar iparm7[3] = {0x1E, 0x00, 0x00}; /*intel ipv4 TTL,Flags,Service*/ +static uchar oparm7[3] = {0x40, 0x40, 0x10}; /*other ipv4 TTL,Flags,Service*/ +static uchar *parm7 = &oparm7[0]; +#define MAX_PEFPARAMS 14 /* max pef params = 14 */ +uchar peflen[MAX_PEFPARAMS] = {0,1,1,1,1,1,21,2,1,4,17,1,3,18}; /*for ShowPef*/ +uchar pef_array[MAXPEF][21]; /* array of all PEF entries read, */ + /* sizeof(PEF_RECORD) = 21 */ +uchar pef_defaults[11][21] = { /* array of first 11 default PEF entries */ +{0x01,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x01,0xff,0x01,0x95,0x0a,0,0,0,0,0,0,0,0,0}, /*Temp*/ +{0x02,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x02,0xff,0x01,0x95,0x0a,0,0,0,0,0,0,0,0,0}, /*Volt*/ +{0x03,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x04,0xff,0x01,0x95,0x0a,0,0,0,0,0,0,0,0,0}, /*Fan*/ +{0x04,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x05,0x05,0x03,0x01,0x00,0,0,0,0,0,0,0,0,0}, /*Chass*/ +{0x05,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x08,0xff,0x6f,0x06,0x00,0,0,0,0,0,0,0,0,0}, /*PS*/ +{0x06,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x0c,0x08,0x6f,0x02,0x00,0,0,0,0,0,0,0,0,0}, /*ECC*/ +{0x07,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x0f,0x06,0x6f,0x01,0x00,0,0,0,0,0,0,0,0,0}, /*FRB*/ +{0x08,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x07,0xff,0x6f,0x1c,0x00,0,0,0,0,0,0,0,0,0}, /*POST*/ +{0x09,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x13,0xff,0x6f,0x3e,0x03,0,0,0,0,0,0,0,0,0}, /*NMI*/ +{0x0a,0x80,1,1,PEF_SEV_INFO,0xff,0xff,0x23,0x03,0x6f,0x0e,0x00,0,0,0,0,0,0,0,0,0}, /*WDT*/ +{0x0b,0x80,1,1,PEF_SEV_MON,0xff,0xff,0x12,0xff,0x6f,0x02,0x00,0,0,0,0,0,0,0,0,0} };/*Restart*/ + +char **pefdesc; +char *pefdesc1[MAXPEF] = { /* for Sahalee BMC */ +/* 0 0x00 */ "", +/* 1 0x01 */ "Temperature Sensor", +/* 2 0x02 */ "Voltage Sensor", +/* 3 0x04 */ "Fan Failure", +/* 4 0x05 */ "Chassis Intrusion", +/* 5 0x08 */ "Power Supply Fault", +/* 6 0x0c */ "Memory ECC Error", +/* 7 0x0f */ "BIOS POST Error", +/* 8 0x07 */ "FRB Failure", +/* 9 0x13 */ "Fatal NMI", +/*10 0x23 */ "Watchdog Timer Reset", +/*11 0x12 */ "System Restart", +/*12 0x20 */ "OS Critical Stop", +/*13 0x09 */ "Power Redundancy Lost", +/*14 0x00 */ "reserved", +/*15 0x00 */ "reserved", +/*16 0x00 */ "reserved", +/*17 */ "reserved", +/*18 */ "reserved", +/*19 */ "reserved", +/*20 */ "reserved", +/*21 */ "reserved", +/*22 */ "reserved", +/*23 */ "reserved", +/*24 */ "reserved", +/*25 */ "reserved", +/*26 */ "reserved", +/*27 */ "reserved", +/*28 */ "reserved", +/*29 */ "unused", +/*30 */ "unused" }; + +char *pefdesc2[MAXPEF] = { /* for NSC miniBMC */ +/* 0 */ "", +/* 1 0x02*/ "Voltage Sensor Assert", +/* 2 0x23*/ "Watchdog FRB Timeout", /* was "Proc FRB Thermal", */ +/* 3 0x02*/ "Voltage Sensor Deassert", +/* 4 0x07*/ "Proc1 IERR", +/* 5 0xff*/ "Digital Sensor OK", +/* 6 0x14*/ "Chassis Identify", +/* 7 0x13*/ "NMI Button", +/* 8 0x14*/ "Clear CMOS via Panel", +/* 9 0x0f*/ "OS Load POST Code", +/*10 0x20*/ "OS Critical Stop", +/*11 0x09 */ "Power Redundancy Lost", +/*12 0x00*/ "reserved", +/*13 */ "reserved", +/*14 */ "reserved", +/*15 */ "reserved", +/*16 */ "reserved", +/*17 */ "reserved", +/*18 */ "reserved", +/*19 */ "reserved", +/*20 */ "reserved", +/*21 */ "reserved", +/*22 */ "reserved", +/*23 */ "reserved", +/*24 */ "reserved", +/*25 */ "reserved", +/*26 0x05*/ "Chassis Intrusion", +/*27 0x0f*/ "POST Code Error", +/*28 0x02*/ "Voltage Failure", +/*29 0x04*/ "Fan Failure", +/*30 0x01*/ "Temperature Failure"}; + +#define NLAN 39 +char canon_param[NLAN] = { 0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,1,0,0,1, + 0,0,0,0,0,0,1,1,1,1}; +struct { + int cmd; + int sz; + char desc[28]; +} lanparams[NLAN] = { /* see IPMI Table 19-4 */ + /* 0 */ { 0, 1, "Set in progress"}, + /* 1 */ { 1, 1, "Auth type support"}, + /* 2 */ { 2, 5, "Auth type enables"}, + /* 3 */ { 3, 4, "IP address"}, + /* 4 */ { 4, 1, "IP addr src"}, /* (DHCP/Static) */ + /* 5 */ { 5, 6, "MAC addr"}, + /* 6 */ { 6, 4, "Subnet mask"}, + /* 7 */ { 7, 3, "IPv4 header"}, + /* 8 */ { 8, 2, "Prim RMCP port"}, + /* 9 */ { 9, 2, "Sec RMCP port"}, + /* 10 */ {10, 1, "BMC grat ARP"}, + /* 11 */ {11, 1, "grat ARP interval"}, + /* 12 */ {12, 4, "Def gateway IP"}, + /* 13 */ {13, 6, "Def gateway MAC"}, + /* 14 */ {14, 4, "Sec gateway IP"}, + /* 15 */ {15, 6, "Sec gateway MAC"}, + /* 16 */ {16,18, "Community string"}, + /* 17 */ {17, 1, "Num dest"}, + /* 18 */ {18, 5, "Dest type"}, + /* 19 */ {19, 13, "Dest address"}, + /* 20 */ {20, 2, "VLAN ID"}, + /* 21 */ {21, 1, "VLAN Priority"}, + /* 22 */ {22, 1, "Cipher Suite Support"}, + /* 23 */ {23,17, "Cipher Suites "}, + /* 24 */ {24, 9, "Cipher Suite Priv"}, + /* 25 */ {25, 4, "VLAN Dest Tag"}, + /* 26 */ {96, 28, "OEM Alert String"}, + /* 27 */ {97, 1, "Alert Retry Algorithm"}, + /* 28 */ {98, 3, "UTC Offset"}, + /* 29 */ {102, 1, "IPv6 Enable"}, + /* 30 */ {103, 1, "IPv6 Addr Source"}, + /* 31 */ {104,16, "IPv6 Address"}, + /* 32 */ {105, 1, "IPv6 Prefix Len"}, + /* 33 */ {106,16, "IPv6 Default Gateway"}, + /* 34 */ {108,17, "IPv6 Dest address"}, + /* 35 */ {192, 4, "DHCP Server IP"}, + /* 36 */ {193, 6, "DHCP MAC Address"}, + /* 37 */ {194, 1, "DHCP Enable"}, + /* 38 */ {201, 2, "Channel Access Mode(Lan)"} +}; + +#define NSER 22 /* max=32 */ +struct { + int cmd; + int sz; + char desc[28]; +} serparams[NSER] = { /* see IPMI Table 20-4 */ + /* 0 */ { 0, 1, "Set in progress"}, + /* 1 */ { 1, 1, "Auth type support"}, + /* 2 */ { 2, 5, "Auth type enables"}, + /* 3 */ { 3, 1, "Connection Mode"}, + /* 4 */ { 4, 1, "Sess Inactiv Timeout"}, + /* 5 */ { 5, 5, "Channel Callback"}, + /* 6 */ { 6, 1, "Session Termination"}, + /* 7 */ { 7, 2, "IPMI Msg Comm"}, + /* 8 */ { 8, 2, "Mux Switch"}, + /* 9 */ { 9, 2, "Modem Ring Time"}, + /* 10 */ {10,17, "Modem Init String"}, + /* 11 */ {11, 5, "Modem Escape Seq"}, + /* 12 */ {12, 8, "Modem Hangup Seq"}, + /* 13 */ {13, 8, "Modem Dial Command"}, + /* 14 */ {14, 1, "Page Blackout Interval"}, + /* 15 */ {15,18, "Community String"}, + /* 16 */ {16, 1, "Num of Alert Dest"}, + /* 17 */ {17, 5, "Destination Info"}, + /* 18 */ {18, 1, "Call Retry Interval"}, + /* 19 */ {19, 3, "Destination Comm Settings"}, + /* 20 */ {29, 2, "Terminal Mode Config"}, + /* 21 */ {201, 2,"Channel Access Mode (Ser)"} +}; + +static void getauthstr(uchar auth, char *s) +{ + if (s == NULL) return; + s[0] = 0; + if (auth & 0x01) strcat(s,"None "); + if (auth & 0x02) strcat(s,"MD2 "); + if (auth & 0x04) strcat(s,"MD5 "); + if (auth & 0x10) strcat(s,"Pswd "); + if (auth & 0x20) strcat(s,"OEM "); + return; +} + +static int GetDeviceID(LAN_RECORD *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (pLanRecord == NULL) return(-1); + + status = ipmi_cmd(GET_DEVICE_ID, inputData, 0, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("GetDeviceID: completion code=%x\n", + completionCode); + status = completionCode; + } else { + memcpy(pLanRecord,&responseData[0],responseLength); + set_mfgid(&responseData[0],responseLength); + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*end GetDeviceID() */ + +static int GetChanAcc(uchar chan, uchar parm, LAN_RECORD *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (pLanRecord == NULL) return(-1); + responseLength = 3; + inputData[0] = chan; + inputData[1] = parm; /* 0x80 = active, 0x40 = non-volatile */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_CHANNEL_ACC, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("GetChanAcc: completion code=%x\n", + completionCode); + status = completionCode; + } else { + // dont copy first byte (Parameter revision, usu 0x11) + memcpy(pLanRecord,&responseData[0],responseLength); + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*GetChanAcc()*/ + +static int SetChanAcc(uchar chan, uchar parm, uchar val) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (fmBMC) return(0); /* mBMC doesn't support this */ + /* parm: 0x80 = active, 0x40 = set non-vol*/ + responseLength = 1; + inputData[0] = chan; /* channel */ + inputData[1] = (parm & 0xc0) | (val & 0x3F); + inputData[2] = (parm & 0xc0) | lan_access; /* set priv level to Admin */ + + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_CHANNEL_ACC, inputData, 3, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("SetChanAcc: completion code=%x\n", + completionCode); + status = completionCode; + } else { + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*SetChanAcc()*/ + +int +SetPasswd(int unum, char *uname, char *upswd) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status, i, psw_len; + uchar completionCode; + char inputData[24]; + int ret = 0; + + inputData[0] = (uchar)unum; /*user 1 = null user */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_USER_NAME, inputData, 1, responseData, + &responseLength, &completionCode, fdebug); + SELprintf("GET_USERNAME: %x %x %x, status = %x, ccode=%x\n", + responseData[0],responseData[1],responseData[2], + status,completionCode); + if (fdebug) { + char aname[17]; + printf("User %d: ",unum); + for (i = 0; i < responseLength; i++) { + printf("%02x ",responseData[i]); + if (responseData[i] < 0x20) aname[i] = '.'; + else aname[i] = responseData[i]; + } + aname[16] = 0; + printf(" %s\n",aname); + } + + if (unum != 1) + { /* user specified a lan username */ + if (fiBMC && (unum == 2)) { + /* cannot set user 2 name */ + if (uname != NULL) { + if (strcmp(uname,"root") != 0) + printf("SETUSERNAME - user2 name %s must be root\n",uname); + } + } else if (unum == 2 && (vend_id == VENDOR_SUPERMICROX || + vend_id == VENDOR_SUPERMICRO) ) { + /* cannot set user 2 name */ + if (uname != NULL) { + if (strcmp(uname,"ADMIN") != 0) + printf("SETUSERNAME - user2 name %s must be ADMIN\n",uname); + } + } else { + inputData[0] = (uchar)unum; + memset(&inputData[1],0,16); + if (uname != NULL) + memcpy(&inputData[1],uname,strlen(uname)); + status = ipmi_cmd(SET_USER_NAME, inputData, 17, responseData, + &responseLength, &completionCode, fdebug); + if (completionCode == 0xCC) + status = 0; /*setting username to previous gives 0xCC, ok*/ + else { + SELprintf("SETUSERNAME - %x %x %x status = %x, ccode=%x\n", + inputData[0],inputData[1],inputData[2], + status,completionCode); + if (status == 0) status = completionCode; + if (status != 0) ret = status; + } + } + } + + if ((unum != 1) && (uname == NULL)) { + ; /* if no username, do not enable user */ + } else { + inputData[0] = (uchar)unum; /*user 1 = null user */ + inputData[1] = 0x01; /*enable user*/ + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_USER_PASSWORD, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + printf("SETUSERENAB - inputData %x %x %x, status = %x, ccode=%x\n", + inputData[0],inputData[1],inputData[2], + status,completionCode); + if (status == 0) status = completionCode; + if (status != 0) ret = status; + } + + inputData[0] = (uchar)unum; /*user 1 = null user */ + inputData[1] = 0x02; /*set password*/ + psw_len = PSW_LEN; /*=16 change if 20-byte passwords supported */ + memset(&inputData[2],0,psw_len); + if (upswd != NULL) + strcpy(&inputData[2],upswd); + if (fdebug) { + char apsw[PSW_MAX+1]; + char c; + printf("Pswd %d: ",unum); + for (i = 0; i < psw_len; i++) { + c = inputData[i+2]; + printf("%02x ",(unsigned char)c); + if (c < 0x20) apsw[i] = '.'; + else apsw[i] = c; + } + apsw[psw_len] = 0; + printf(" %s\n",apsw); + } + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_USER_PASSWORD, inputData, 2+psw_len, + responseData,&responseLength, &completionCode,fdebug); + SELprintf("SETUSERPSW - inputData %x %x %x, status = %x, ccode=%x\n", + inputData[0],inputData[1],inputData[2], + status,completionCode); + if (status == 0) status = completionCode; + if (status != 0) ret = status; + + inputData[0] = (uchar)unum; /*user 1 = null user */ + inputData[1] = 0x03; /*test password*/ + memset(&inputData[2],0,psw_len); + if (upswd != NULL) + strcpy(&inputData[2],upswd); + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_USER_PASSWORD, inputData, 2+psw_len, + responseData,&responseLength, &completionCode,fdebug); + SELprintf("TESTUSERPSW - inputData %x %x %x, status = %x, ccode=%x\n", + inputData[0],inputData[1],inputData[2], + status,completionCode); + + if (fiBMC && (unum == 2)) { /*iBMC doesn't support this on user 2*/ + if (fdebug) + printf("skipping SETUSER_ACCESS on iBMC for user %d\n",unum); + } else { + inputData[0] = 0x90 | lan_ch; /* = 0x97 */ + inputData[1] = (uchar)unum; /* user num */ + inputData[2] = lan_access; /* usu admin */ + inputData[3] = 0x00; /* User Session Limit, 0=not limited*/ + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_USER_ACCESS, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + printf("SETUSER_ACCESS - inputData %x %x %x, status = %x ccode=%x\n", + (uchar)inputData[0],inputData[1],inputData[2], + status,completionCode); + if (status == 0) status = completionCode; + if (status != 0) ret = status; + } + + return(ret); +} /*end SetPswd()*/ + +int SetUser(int unum, char *uname, char *passwd) +{ + int ret = 0; + /* if the user specified a username or password, set it. */ + if ((fpassword) || (uname != NULL)) { + ret = SetPasswd(unum, uname,passwd); /*set username and password*/ + } + return(ret); +} /*end SetUser()*/ + +int +DisableUser(int unum) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar completionCode; + char inputData[24]; + + inputData[0] = 0x80 | lan_ch; /* = 0x87, no IPMI */ + inputData[1] = (uchar)unum; /* user 1 */ + inputData[2] = 0x0F; /* No access */ + inputData[3] = 0x00; /* User Session Limit, 0=not limited*/ + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_USER_ACCESS, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + if (status == 0) status = completionCode; + return(status); +} + +static char *parse_priv(uchar c) +{ + char *p; + c = (c & 0x0f); + switch(c) { + case 1: p = "Callback"; break; + case 2: p = "User "; break; + case 3: p = "Operator"; break; + case 4: p = "Admin "; break; + case 5: p = "OEM "; break; + case 0x0f: p = "No access"; break; + default: p = "Reserved"; + } + return(p); +} + +static void show_priv(uchar c) +{ + char *privstr; + privstr = parse_priv(c); + printf("%s",privstr); +} + +static int valid_priv(int c) +{ + int rv; + switch(c) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 0x0f: + rv = 1; + break; + default: + rv = 0; + break; + } + return rv; +} + +int GetUser(uchar user_num) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar completionCode; + char inputData[24]; + + inputData[0] = lan_ch; + inputData[1] = user_num; /* usually = 1 for BMC LAN */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_USER_ACCESS, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + if (status == 0 && completionCode == 0) { + uchar c; + if (user_num == 1) { /*get max_users and enabled_users*/ + max_users = responseData[0] & 0x3f; + enabled_users = responseData[1] & 0x3f; + if (enabled_users > show_users) show_users = enabled_users; + if (show_users > max_users) show_users = max_users; + if (!fcanonical) + SELprintf("Users: showing %d of max %d users (%d enabled)\n", + show_users,max_users,enabled_users); + } + if (fcanonical) + SELprintf("Channel %d User %d Access %s%c ", lan_ch, user_num, + pspace2,bdelim); + else + SELprintf("User Access(chan%d,user%d): %02x %02x %02x %02x : ", + lan_ch, user_num, (uchar)responseData[0], + responseData[1],responseData[2], responseData[3]); + c = responseData[3]; + inputData[0] = user_num; /* usually = 1 for BMC LAN */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_USER_NAME, inputData, 1, responseData, + &responseLength, &completionCode, fdebug); + if (status != 0 || completionCode != 0) + responseData[0] = 0; + if (c & 0x10) printf("IPMI, "); + show_priv(c); + printf(" (%s)\n",responseData); /*show user name */ + } else + SELprintf("Get User Access(%d,%d), status=%x, ccode=%x\n", + lan_ch, user_num, status, completionCode); + return(status); +} /*end GetUser()*/ + +static int GetSerEntry(uchar subfunc, LAN_RECORD *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + uchar chan; uchar bset; + + if (pLanRecord == NULL) + { + if (fdebug) + printf("GetSerEntry(%d): error, output buffer is NULL\n",subfunc); + return (-1); + } + + chan = ser_ch; /* 1=EMP, 0=IPMB, 6=LAN2, 7=LAN1 */ + bset = 0; + + inputData[0] = chan; // flags, channel 3:0 (1=EMP) + inputData[1] = subfunc; // Param selector + inputData[2] = bset; // Set selector + inputData[3] = 0; // Block selector + if (subfunc == 10) { + inputData[2] = 0; + inputData[3] = 1; + } + + status = ipmi_cmd(GET_SER_CONFIG, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetSerEntry(%d,%d): completion code=%x\n", + chan,subfunc,completionCode); + } else { + // dont copy first byte (Parameter revision, usu 0x11) + memcpy(pLanRecord,&responseData[1],responseLength-1); + pLanRecord->data[responseLength-1] = 0; + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetSerEntry(%d,%d): ipmi_cmd status=%x ccode=%x\n", + chan,subfunc,status,completionCode); + return -1; +} + +static int GetLanEntry(uchar subfunc, uchar bset, LAN_RECORD *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status, n; + uchar completionCode; + uchar chan; + + if (pLanRecord == NULL) + { + if (fdebug) + printf("GetLanEntry: error, output buffer is NULL\n"); + return (-1); + } + + chan = lan_ch; /* LAN 1 = 7 */ + + inputData[0] = chan; // flags, channel 3:0 (LAN 1) + inputData[1] = subfunc; // Param selector (3 = ip addr) + inputData[2] = bset; // Set selector + inputData[3] = 0; // Block selector + + status = ipmi_cmd(GET_LAN_CONFIG, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetLanEntry: completion code=%x\n", + completionCode); + status = completionCode; + } else { + // dont copy first byte (Parameter revision, usu 0x11) + if (responseLength > 0) { + n = responseLength-1; + memcpy(pLanRecord,&responseData[1],n); + } else n = 0; + pLanRecord->data[n] = 0; + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetLanEntry: ipmi_cmd status=%d completionCode=%x\n", + status,completionCode); + return status; +} /* end GetLanEntry() */ + +static int SetLanEntry(uchar subfunc, LAN_RECORD *pLanRecord, int reqlen) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + + if (pLanRecord == NULL) + { + if (fdebug) + printf("SetLanEntry(%d): error, input buffer is NULL\n",subfunc); + return (-1); + } + if (vend_id == VENDOR_SUPERMICROX || vend_id == VENDOR_SUPERMICRO) { + /* SUPERMICRO cannot set grat arp or grat arp interval */ + if (subfunc == 10 || subfunc == 11) return(0); + } + + inputData[0] = lan_ch; // flags, channel 3:0 (LAN 1) + inputData[1] = subfunc; // Param selector (3 = ip addr) + memcpy(&inputData[2],pLanRecord,reqlen); + + status = ipmi_cmd(SET_LAN_CONFIG, inputData, (uchar)(reqlen+2), + responseData, &responseLength,&completionCode,fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("SetLanEntry(%d): completion code=%x\n", + subfunc,completionCode); // responseData[0]); + return(completionCode); + } else { + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("SetLanEntry(%d): ipmi_cmd status=%d ccode=%x\n", + subfunc,status,completionCode); + return status; +} /* end SetLanEntry() */ + +int GetPefEntry(uchar subfunc, ushort rec_id, PEF_RECORD *pPefRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; /* only use 3 bytes for input */ + int status, n; + uchar completionCode; + + if (pPefRecord == NULL) + { + if (fdebug) + printf("GetPefEntry(%d): error, output buffer is NULL\n",subfunc); + return (-1); + } + + inputData[0] = subfunc; // Parameter = Evt Filter Table + inputData[1] = (uchar)rec_id; + inputData[2] = 0; + + status = ipmi_cmd(GET_PEF_CONFIG, inputData, 3, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetPefEntry(%d/%d): completion code=%x\n", + subfunc,rec_id,completionCode); + status = completionCode; + } else { + /* expect PEF record to be >=21 bytes */ + if (responseLength > 1) n = responseLength-1; + else n = 0; + if (n > 21) n = 21; /*only use 21 bytes*/ + if ((subfunc == 6) && (n < 21)) { + if (fdebug) + printf("GetPefEntry(%d/%d): length %d too short\n", + subfunc,rec_id,responseLength); + } + // dont copy first byte (Parameter revision, usu 0x11) + if (n == 0) memset(pPefRecord,0,21); + else memcpy(pPefRecord,&responseData[1],n); + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetPefEntry: ipmi_cmd status=%x completionCode=%x\n", + status, completionCode); + return status; +} /* end GetPefEntry() */ + +int SetPefEntry(PEF_RECORD *pPefRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[32]; /* sizeof(PEF_RECORD) = 21 +1=22 */ + int status; + uchar completionCode; + uchar subfunc; + + subfunc = 0x06; // Parameter = Evt Filter Table + + if (pPefRecord == NULL) { + if (fdebug) + printf("SetPefEntry: error, output buffer is NULL\n"); + return (-1); + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + // 06 0c 80 01 01 00 ff ff 20 ff 6f ff 00 00 00 00 00 00 00 00 00 00 + // memset(&inputData[0],0,requestData.dataLength); + inputData[0] = subfunc; + memcpy(&inputData[1],pPefRecord,sizeof(PEF_RECORD)); + + status = ipmi_cmd(SET_PEF_CONFIG, inputData, sizeof(PEF_RECORD)+1, + responseData, &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("SetPefEntry: completion code=%x\n", + completionCode); // responseData[0]); + status = completionCode; + } else { + //successful, done + return(0); + } + + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("SetPefEntry: ipmi_cmd status=%d completion code=%x\n", + status,completionCode); + return(status); + +} /* end SetPefEntry() */ + +int DisablePef(int anum) +{ + uchar iData[24]; /* sizeof(PEF_RECORD) = 21 +1=22 */ + uchar rData[MAX_BUFFER_SIZE]; + int rLength = MAX_BUFFER_SIZE; + uchar cc; + int status; + + if (fmBMC) { + SELprintf("mini-BMC does not support disabling BMC LAN\n"); + return(-1); + } else { + status = SetChanAcc(lan_ch, 0x80, CHAN_ACC_DISABLE); + if (fdebug) SELprintf("SetChanAcc(lan/active), ret = %d\n",status); + status = SetChanAcc(lan_ch, 0x40, CHAN_ACC_DISABLE); + SELprintf("SetChanAcc(lan), ret = %d\n",status); + if (status != 0) return(status); + } + + iData[0] = 0x01; /* PEF Control Param */ + iData[1] = 0x00; /* PEF disable */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(SET_PEF_CONFIG, iData, 2, rData, &rLength, + &cc, fdebug); + if (status != 0) return(status); + if( cc ) { + SELprintf("DisablePef[%d]: completion code=%x\n",iData[0],cc); + return(-1); + } + + if (anum != 0) { + iData[0] = 0x09; /* PEF Alert Policy Table */ + iData[1] = (uchar)anum; /* Policy number (default 0x01) */ + iData[2] = 0x10; /* PEF LAN, policy disable */ + iData[3] = 0x00; /* LAN_CH=00, default dest=00 */ + iData[4] = 0x00; /* No alert string */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(SET_PEF_CONFIG, iData, 5, rData, &rLength, + &cc, fdebug); + if (status != 0) return(status); + if( cc ) { + SELprintf("DisablePef[%d]: completion code=%x\n",iData[0],cc); + return(-1); + } + } + return(status); +} + +int ShowPef(void) +{ + uchar iData[24]; /* sizeof(PEF_RECORD) = 21 +1=22 */ + uchar rData[MAX_BUFFER_SIZE]; + int rLength = MAX_BUFFER_SIZE; + uchar cc; + int status, i,j; + + for (j = 1; j < MAX_PEFPARAMS; j++) { + if (j == 4 && fmBMC) { + /* fmBMC gets cc=0x80 for param 4, so skip it. */ + continue; + } + iData[0] = (uchar)j; /* PEF Control Param */ + if (j == 6 || j == 7 || j == 9) iData[1] = 1; + else iData[1] = 0x00; /* PEF Set Selector */ + if (j == 13) iData[2] = 1; + else iData[2] = 0x00; /* PEF Block Selector */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(GET_PEF_CONFIG, iData, 3, rData, &rLength, + &cc, fdebug); + if (status == 0 && cc == 0) { + SELprintf("PefParam[%d]: ",iData[0]); + if (rLength > 0) + for (i=0;i<peflen[j];i++) SELprintf("%02x ", rData[1+i]); + SELprintf("\n"); + } else + SELprintf("PefParam[%d]: GET_PEF status=%d cc=%x\n", + iData[0],status,cc); + } + return(status); +} + +int EnablePef(int anum) +{ + uchar iData[24]; /* sizeof(PEF_RECORD) = 21 +1=22 */ + uchar rData[MAX_BUFFER_SIZE]; + int rLength = MAX_BUFFER_SIZE; + uchar cc; + int status; + uchar sdelay; + + status = SetChanAcc(lan_ch, 0x80, chan_pefon); + if (fdebug) SELprintf("SetChanAcc(lan/active), ret = %d\n",status); + status = SetChanAcc(lan_ch, 0x40, chan_pefon); + SELprintf("SetChanAcc(lan), ret = %d\n",status); + if (status != 0) return(status); + + { + iData[0] = 0x01; /* PEF Control Param */ + iData[1] = 0x00; /* PEF Set Selector */ + iData[2] = 0x00; /* PEF Block Selector */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(GET_PEF_CONFIG, iData, 3, rData, &rLength, + &cc, fdebug); + if (status != 0 || cc != 0) sdelay = 0; + else sdelay = rData[1]; + if (fdebug) SELprintf("EnablePef[%d]: get cc=%x, control=%02x\n", + iData[0],cc,sdelay); + iData[0] = 0x01; /* PEF Control Param (0x01 or 0x05) */ + iData[1] = 0x01; /* PEF enable, & no startup delay */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(SET_PEF_CONFIG, iData, 2, rData, &rLength, + &cc, fdebug); + if (status != 0) return(status); + if( cc ) { + SELprintf("EnablePef[%d]: completion code=%x\n",iData[0],cc); + return(-1); + } + +#ifdef TEST + iData[0] = 0x01; /* Serial Channel */ + iData[1] = 0x13; /* Dest Com settings = 19. */ + iData[2] = 0x01; /* POL Default Dest */ + iData[3] = 0x60; + iData[4] = 0x07; + status = ipmi_cmd(SET_SER_CONFIG, iData, 5, rData, &rLength, + &cc, fdebug); +#endif + + iData[0] = 0x02; /* PEF Action Param */ + iData[1] = 0x00; /* PEF Set Selector */ + iData[2] = 0x00; /* PEF Block Selector */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(GET_PEF_CONFIG, iData, 3, rData, &rLength, + &cc, fdebug); + if (fdebug) SELprintf("EnablePef[%d]: get cc=%x, val=%02x\n", + iData[0],cc,rData[1]); + iData[0] = 0x02; /* PEF Action Param */ + if (vend_id == VENDOR_INTEL) + iData[1] = 0x2f; /* enable alerts, reset, power cycle/down, diag*/ + else + iData[1] = 0x0f; /* enable alerts, reset, power cycle/down */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(SET_PEF_CONFIG, iData, 2, rData, &rLength, + &cc, fdebug); + if (status != 0) return(status); + if( cc ) { + SELprintf("EnablePef[%d]: completion code=%x\n",iData[0],cc); + return(-1); + } + + if ((sdelay & 0x04) != 0) { /* startup delay is supported */ + iData[0] = 0x03; /* PEF Startup Delay Param */ + iData[1] = 0x00; /* 0 seconds, default is 0x3c (60 sec) */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(SET_PEF_CONFIG, iData, 2, rData, &rLength, + &cc, fdebug); + if (fdebug) SELprintf("EnablePef[%d]: set val=%02x cc=%x\n", + iData[0],iData[1],cc); + if (status != 0) return(status); + if( cc ) { + SELprintf("EnablePef[%d]: completion code=%x\n",iData[0],cc); + // return(-1); + } + iData[0] = 0x04; /* PEF Alert Startup Delay Param */ + iData[1] = 0x00; /* 0 seconds, default is 0x3c (60 sec) */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(SET_PEF_CONFIG, iData, 2, rData, &rLength, + &cc, fdebug); + if (fdebug) SELprintf("EnablePef[%d]: set val=%02x cc=%x\n", + iData[0],iData[1],cc); + if (status != 0) return(status); + if( cc ) { + SELprintf("EnablePef[%d]: completion code=%x\n",iData[0],cc); + // return(-1); + } + } /*endif sdelay*/ + + iData[0] = 0x09; /* PEF Alert Policy Table */ + iData[1] = (uchar)anum; /* Policy number (default 0x01) */ + iData[2] = 0x18; /* PEF LAN, always alert, policy enable */ + iData[3] = (lan_ch << 4) + anum; /* LAN_CH=70, default dest=01 */ + iData[4] = 0x00; /* No alert string */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(SET_PEF_CONFIG, iData, 5, rData, &rLength, + &cc, fdebug); + if (fdebug) SELprintf("EnablePef[%d]: set val=%02x cc=%x\n", + iData[0],iData[1],cc); + if (status != 0) return(status); + if( cc ) { + SELprintf("EnablePef[%d]: completion code=%x\n",iData[0],cc); + return(-1); + } + } /*endif IPMI 1.5 */ + + return(status); +} /* end EnablePef */ + +#define NBAUDS 10 +static struct { + unsigned char val; + char str[8]; + } mapbaud[NBAUDS] = { + { 6, "9600" }, + { 6, "9.6K" }, + { 7, "19.2K" }, + { 7, "19200" }, + { 8, "38.4K" }, + { 8, "38400" }, + { 9, "57.6K" }, + { 9, "57600" }, + { 10, "115.2K" }, + { 10, "115200" } + }; + +static unsigned char Str2Baud(char * str) +{ + unsigned char baud = 0; + int i, n, len; + len = strlen_(str); + for (i = 0; i < len; i++) /*toupper*/ + if (str[i] >= 'a' && str[i] <= 'z') str[i] &= 0x5F; + for (i = 0; i < NBAUDS; i++) { + n = strlen_(mapbaud[i].str); + if (strncmp(str,mapbaud[i].str,n) == 0) { + baud = mapbaud[i].val; + break; + } + } + if (i == NBAUDS || baud == 0) { + printf("Invalid -B parameter value (%s), using 19.2K.\n",str); + i = 1; /* default is 19.2K */ + baud = mapbaud[i].val; /* =7 */ + } + if (fdebug) printf("new baud = %02x (%s)\n",baud,mapbaud[i].str); + return(baud); +} + +static char *Baud2Str(unsigned char bin) +{ + char *baudstr; + unsigned char b; + b = bin & 0x0f; + switch(b) { + case 6: baudstr = "9600 "; break; + case 7: baudstr = "19.2k"; break; + case 8: baudstr = "38.4k"; break; + case 9: baudstr = "57.6k"; break; + case 10: baudstr = "115.2k"; break; + default: baudstr = "nobaud"; + } + return(baudstr); +} + +static int BaudValid(unsigned char b) +{ + int val = 0; + switch(b) { + case 6: val = 1; break; + case 7: val = 1; break; + case 8: val = 1; break; + case 9: val = 1; break; + case 10: val = 1; break; + default: val = 0; break; + } + return(val); +} + +/* + * atomac - converts ASCII string to binary MAC address (array). + * Accepts input formatted as 11:22:33:44:55:66 or 11-22-33-44-55-66. + */ +void atomac(uchar *array, char *instr) +{ + int i,j,n; + char *pi; + j = 0; + pi = instr; + n = strlen_(instr); + for (i = 0; i <= n; i++) { + if (instr[i] == ':') { + array[j++] = htoi(pi); + pi = &instr[i+1]; + } else if (instr[i] == '-') { + array[j++] = htoi(pi); + pi = &instr[i+1]; + } else if (instr[i] == 0) { + array[j++] = htoi(pi); + } + if (j >= MAC_LEN) break; /*safety valve*/ + } + if (fdebug) + printf("atomac: %02x %02x %02x %02x %02x %02x\n", + array[0],array[1],array[2],array[3], array[4],array[5]); +} /*end atomac()*/ + +/* extern void atoip(uchar *array,char *instr); *from subs.c*/ +void MacSetInvalid(uchar *mac) +{ + int i; + if (mac == NULL) return; + for (i = 0; i < MAC_LEN; i++) { + if (i == 0) mac[i] = 0xFF; + else mac[i] = 0x00; + } +} + +int MacIsValid(uchar *mac) +{ + int fvalid = 0; + int i; + /* check for initial invalid value of FF:00:... */ + if (mac[0] == 0xff && mac[1] == 0x00) /* marked as invalid */ + return(fvalid); + /* check for all zeros */ + for (i = 0; i < MAC_LEN; i++) + if (mac[i] != 0) { /* not all zeros */ + fvalid = 1; + break; + } + return(fvalid); +} + +int IpIsValid(uchar *ipadr) +{ + int fvalid = 1; + if (ipadr[0] == 0) fvalid = 0; + return(fvalid); +} + +int SubnetIsValid(uchar *subnet) +{ + int fvalid = 0; + /* if masking off at least one bit, say valid */ + if (subnet[0] != 0) fvalid = 1; + return(fvalid); +} + +int SubnetIsSame(uchar *ip1, uchar *ip2, uchar *subnet) +{ + int i; + uchar c1, c2; + for (i = 0; i < 4; i ++) { + c1 = ip1[i] & subnet[i]; + c2 = ip2[i] & subnet[i]; + if (c1 != c2) return 0; + } + return 1; /*same, return true*/ +} + +#ifdef WIN32 +/* + * Obtain network adapter information (Windows). + */ +PIP_ADAPTER_ADDRESSES GetAdapters() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + ULONG OutBufferLength = 0; + ULONG RetVal = 0, i; + + // The size of the buffer can be different + // between consecutive API calls. + // In most cases, i < 2 is sufficient; + // One call to get the size and one call to get the actual parameters. + // But if one more interface is added or addresses are added, + // the call again fails with BUFFER_OVERFLOW. + // So the number is picked slightly greater than 2. + // We use i <5 in the example + for (i = 0; i < 5; i++) { + RetVal = GetAdaptersAddresses( + AF_INET, 0, NULL, + AdapterAddresses, + &OutBufferLength); + + if (RetVal != ERROR_BUFFER_OVERFLOW) { + break; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + + AdapterAddresses = (PIP_ADAPTER_ADDRESSES) malloc(OutBufferLength); + if (AdapterAddresses == NULL) { + RetVal = GetLastError(); + break; + } + } + if (RetVal == NO_ERROR) { + // If successful, return pointer to structure + return AdapterAddresses; + } + else { + LPVOID MsgBuf; + + printf("Call to GetAdaptersAddresses failed.\n"); + if (FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + RetVal, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &MsgBuf, + 0, + NULL )) { + printf("\tError: %s", MsgBuf); + } + LocalFree(MsgBuf); + } + return NULL; +} + +/* + * Set BMC MAC corresponding to current BMC IP address (Windows). + */ +int GetLocalMACByIP() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + addr = AdapterList->FirstUnicastAddress; + if (addr == NULL) si = NULL; + else si = (struct sockaddr_in*)addr->Address.lpSockaddr; + if (si != NULL) { + if(memcmp(&si->sin_addr.s_addr, rgmyip, 4) == 0) { + if (!MacIsValid(rgmymac)) + memcpy(rgmymac, AdapterList->PhysicalAddress, MAC_LEN); + memcpy(osmyip, &si->sin_addr.s_addr, 4); + memcpy(osmymac, AdapterList->PhysicalAddress, MAC_LEN); + wcstombs(ifname,AdapterList->FriendlyName, sizeof(ifname)); + result = 1; + break; + } + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +/* + * Get First IP Address in Windows OS + * ipaddr is 4 bytes, macaddr is 6 bytes, ipname can be 64 bytes. + * (called by idiscover.c) + */ +int GetFirstIP(uchar *ipaddr, uchar *macadr, char *ipname, char fdbg) +{ + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + struct sockaddr_in *si; + uchar *psaddr; + int result = -1; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + + addr = AdapterList->FirstUnicastAddress; + si = (struct sockaddr_in*)addr->Address.lpSockaddr; + psaddr = (uchar *)&si->sin_addr.s_addr; + if ((psaddr[0] != 0) && (psaddr[0] != 169)) { + if (fdbg) printf("found IP: s_addr=%d.%d.%d.%d\n", + psaddr[0], psaddr[1], psaddr[2], psaddr[3]); + if (ipaddr != NULL) + memcpy(ipaddr, &si->sin_addr.s_addr, 4); + if (macadr != NULL) { + memcpy(macadr, AdapterList->PhysicalAddress, MAC_LEN); + if (fdbg) printf("found MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + macadr[0], macadr[1], macadr[2], macadr[3], + macadr[4], macadr[5]); + } + if (ipname != NULL) { + wcstombs(ipname,AdapterList->FriendlyName, sizeof(ifname)); + if (fdbg) printf("found Adapter: %d\n",ipname); + } + result = 0; + break; + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +/* + * Set BMC MAC corresponding to current BMC IP address (Windows). + */ +int GetLocalIPByMAC(uchar *macadr) { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + if(memcmp(AdapterList->PhysicalAddress, macadr, MAC_LEN) == 0) { + addr = AdapterList->FirstUnicastAddress; + + si = (struct sockaddr_in*)addr->Address.lpSockaddr; + if (fdebug) { + uchar *psaddr; + psaddr = (uchar *)&si->sin_addr.s_addr; + printf("mac match: rgmyip=%d.%d.%d.%d s_addr=%d.%d.%d.%d\n", + rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3], + psaddr[0], psaddr[1], psaddr[2], psaddr[3]); + } + if (!IpIsValid(rgmyip) && (fsharedMAC==1)) /*not specified, shared*/ + memcpy(rgmyip, &si->sin_addr.s_addr, 4); + memcpy(osmyip, &si->sin_addr.s_addr, 4); + memcpy(osmymac, AdapterList->PhysicalAddress, MAC_LEN); + wcstombs(ifname,AdapterList->FriendlyName, sizeof(ifname)); + result = 1; + break; + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} +/* + * Set MAC and IP address from given interface name (Windows). + */ +int GetLocalDataByIface() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + size_t origsize, newsize, convertedChars; + wchar_t* wcstring; + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + origsize = strlen(ifname) + 1; + newsize = origsize; + convertedChars = 0; + wcstring = (wchar_t*) malloc(sizeof(wchar_t) * newsize) ; + if (wcstring == NULL) AdapterList = NULL; /*skip loop, do free*/ + else mbstowcs(wcstring, ifname, origsize ); + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + if(wcsstr(AdapterList->FriendlyName, wcstring)) { + printf("Using interface: %S\n", AdapterList->FriendlyName); + printf("\t%S\n", AdapterList->Description); + addr = AdapterList->FirstUnicastAddress; + + si = (struct sockaddr_in*)addr->Address.lpSockaddr; + if (fdebug) { + uchar *psaddr; + psaddr = (uchar *)&si->sin_addr.s_addr; + printf("mac match: rgmyip=%d.%d.%d.%d s_addr=%d.%d.%d.%d " + "fsharedMAC=%d\n", + rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3], + psaddr[0], psaddr[1], psaddr[2], psaddr[3], + fsharedMAC); + } + if (!IpIsValid(rgmyip)) { /*IP not specified*/ + memcpy(rgmyip, &si->sin_addr.s_addr, 4); + memcpy(rgmymac, AdapterList->PhysicalAddress, MAC_LEN); + } + memcpy(osmyip, &si->sin_addr.s_addr, 4); + memcpy(osmymac, AdapterList->PhysicalAddress, MAC_LEN); + /* FriendlyName == ifname already */ + result = 1; + break; + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +int FindEthNum(uchar *macadrin) +{ + int i; + uchar macadr[MAC_LEN]; + memcpy(macadr,macadrin,MAC_LEN); + if (fsharedMAC == 0 && vend_id == VENDOR_INTEL) { + /* Intel factory assigns them this way, so use that to compare */ + macadr[MAC_LEN-1] -= 2; /*OS MAC = BMC MAC - 2*/ + } + i = GetLocalIPByMAC(macadr); + if (i == 1) fethfound = 1; + if (fdebug) /* show the local OS eth if and MAC */ + printf("FindEth: OS %s IP=%d.%d.%d.%d MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + ifname, osmyip[0], osmyip[1], osmyip[2], osmyip[3], + osmymac[0], osmymac[1], osmymac[2], osmymac[3], + osmymac[4], osmymac[5]); + /* The actual Windows ethernet interface is determined + * in Get_IPMac_Addr using ipconfig, so + * init eth interface number as eth0 for Windows. */ + return(0); +} +#elif defined(HPUX) +#define INSAP 22 +#define OUTSAP 24 + +#include <sys/types.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <ctype.h> +#include <sys/stropts.h> +#include <sys/poll.h> +#include <sys/dlpi.h> + +#define bcopy(source, destination, length) memcpy(destination, source, length) +#define AREA_SZ 5000 /*=* buffer length in bytes *=*/ +#define GOT_CTRL 1 +#define GOT_DATA 2 +#define GOT_BOTH 3 +#define GOT_INTR 4 +#define GOT_ERR 128 +static u_long ctl_area[AREA_SZ]; +static u_long dat_area[AREA_SZ]; +static struct strbuf ctl = {AREA_SZ, 0, (char *)ctl_area}; +static struct strbuf dat = {AREA_SZ, 0, (char *)dat_area}; +static char *dlpi_dev[] = {"/dev/dlpi", ""}; + +/*=* get a message from a stream; return type of message *=*/ +static int get_msg(int fd) +{ + int flags = 0; + int res, ret; + ctl_area[0] = 0; + dat_area[0] = 0; + ret = 0; + res = getmsg(fd, &ctl, &dat, &flags); + if(res < 0) { + if(errno == EINTR) { + return(GOT_INTR); + } else { + return(GOT_ERR); + } + } + if(ctl.len > 0) { + ret |= GOT_CTRL; + } + if(dat.len > 0) { + ret |= GOT_DATA; + } + return(ret); +} + +/*=* verify that dl_primitive in ctl_area = prim *=*/ +static int check_ctrl(int prim) +{ + dl_error_ack_t *err_ack = (dl_error_ack_t *)ctl_area; + if(err_ack->dl_primitive != prim) { + return GOT_ERR; + } + return 0; +} + +/*=* put a control message on a stream *=*/ +static int put_ctrl(int fd, int len, int pri) +{ + ctl.len = len; + if(putmsg(fd, &ctl, 0, pri) < 0) { + return GOT_ERR; + } + return 0; +} + +/*=* put a control + data message on a stream *=*/ +static int put_both(int fd, int clen, int dlen, int pri) +{ + ctl.len = clen; + dat.len = dlen; + if(putmsg(fd, &ctl, &dat, pri) < 0) { + return GOT_ERR; + } + return 0; +} + +/*=* open file descriptor and attach *=*/ +static int dl_open(const char *dev, int ppa, int *fd) +{ + dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area; + if((*fd = open(dev, O_RDWR)) == -1) { + return GOT_ERR; + } + attach_req->dl_primitive = DL_ATTACH_REQ; + attach_req->dl_ppa = ppa; + put_ctrl(*fd, sizeof(dl_attach_req_t), 0); + get_msg(*fd); + return check_ctrl(DL_OK_ACK); +} + +/*=* send DL_BIND_REQ *=*/ +static int dl_bind(int fd, int sap, u_char *addr) +{ + dl_bind_req_t *bind_req = (dl_bind_req_t *)ctl_area; + dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)ctl_area; + bind_req->dl_primitive = DL_BIND_REQ; + bind_req->dl_sap = sap; + bind_req->dl_max_conind = 1; + bind_req->dl_service_mode = DL_CLDLS; + bind_req->dl_conn_mgmt = 0; + bind_req->dl_xidtest_flg = 0; + put_ctrl(fd, sizeof(dl_bind_req_t), 0); + get_msg(fd); + if (GOT_ERR == check_ctrl(DL_BIND_ACK)) { + return GOT_ERR; + } + bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr, + bind_ack->dl_addr_length); + return 0; +} + +int FindEthNum(uchar *addr) +{ /* Need to use DLPI for HPUX */ + /*See http://cplus.kompf.de/artikel/macaddr.html */ + int fd; + int ppa; + u_char mac_addr[25]; + char **dev; + int i = 0; + + for (dev = dlpi_dev; **dev != ''; ++dev) { + for (ppa=0; ppa<10; ++ppa) { + if (GOT_ERR != dl_open(*dev, ppa, &fd)) { + if (GOT_ERR != dl_bind(fd, INSAP, mac_addr)) { + // bcopy( mac_addr, addr, 6); + i = ppa; + if (memcmp(mac_addr,addr,MAC_LEN) == 0) { + memcpy(osmymac, addr, MAC_LEN); + return(ppa); + } + } + } + close(fd); + } + } + return(i); +} +#else + +static char *get_ifreq_mac(struct ifreq *ifrq) +{ + char *ptr; +#ifdef SOLARIS + ptr = (char *)&ifrq->ifr_ifru.ifru_enaddr[0]; +#elif BSD + ptr = (char *)&ifrq->ifr_ifru.ifru_addr.sa_data[0]; +#elif MACOS + static uchar mactmp[MAC_LEN]; + ptr = &mactmp[0]; + MacSetInvalid(ptr); +#else + ptr = (char *)&ifrq->ifr_hwaddr.sa_data[0]; +#endif + return (ptr); +} + +extern int find_ifname(char *ifname); /*see idiscover.c*/ + +int FindEthNum(uchar *macadrin) +{ /*only used for Linux*/ + struct ifreq ifr; + int skfd; + int nCurDevice; + int devnum = -1; + int devos = 0; + uchar macadr[MAC_LEN]; + uchar macsav[MAC_LEN]; + uchar mactmp[MAC_LEN]; + uchar ipsav[4]; + char szDeviceName[ 16 ]; /* MAX_DEVICE_NAME_LENGTH + 1 */ + uchar fipvalid = 0; + int n; + + memcpy(macadr,macadrin,MAC_LEN); + if (fsharedMAC == 0 && vend_id == VENDOR_INTEL) { + /* Intel factory assigns them this way, so use that to compare */ + macadr[MAC_LEN-1] -= 2; /*OS MAC = BMC MAC - 2*/ + } +#ifdef DBG + if (fdebug) { + uchar *pb; + pb = macadrin; + printf("input mac:%02x:%02x:%02x:%02x:%02x:%02x " + "tmp mac:%02x:%02x:%02x:%02x:%02x:%02x\n", + pb[0],pb[1],pb[2],pb[3],pb[4],pb[5], + macadr[0],macadr[1],macadr[2],macadr[3],macadr[4],macadr[5]); + } +#endif + + n = find_ifname(szDeviceName); + if (n >= 0) { + n = strlen_(szDeviceName); + if (n < sizeof(ifpattn)) { + strcpy(ifpattn,szDeviceName); + ifpattn[n - 1] = 0; /*truncate last digit*/ + } + if (fdebug) + printf("found ifname %s, pattern %s\n",szDeviceName,ifpattn); + } + + if ( ( skfd = socket(AF_INET, SOCK_DGRAM, 0 ) ) < 0) { + if ( fdebug ) { + perror("socket"); + return devnum; + } + } + + for( nCurDevice = 0 ; + (nCurDevice < NUM_DEVICES_TO_CHECK) && (devnum == -1); + nCurDevice++ ) + { + sprintf( szDeviceName, "%s%d", ifpattn, nCurDevice ); /*eth%d*/ + memset((char *)&ifr,0,sizeof(ifr)); + strcpy(ifr.ifr_name, szDeviceName ); +#ifdef SIOCGIFHWADDR + if (ioctl(skfd, SIOCGIFHWADDR, &ifr) > 0) { + if ( fdebug ) + printf("FindEthNum: Could not get MAC address for %s\n", + szDeviceName); + } else +#endif + { + uchar *pb; + pb = get_ifreq_mac(&ifr); +#ifdef DBG + if (fdebug) { + printf("%s mac: %02x:%02x:%02x:%02x:%02x:%02x\n", + szDeviceName, pb[0],pb[1],pb[2],pb[3],pb[4],pb[5]); + } +#endif + memcpy(macsav, pb, MAC_LEN); + /* check if this device is configured for IP addr */ + memset((char *)&ifr,0,sizeof(ifr)); + strcpy(ifr.ifr_name, szDeviceName); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(skfd, SIOCGIFADDR, &ifr) >= 0) { + fipvalid = 1; + memcpy(ipsav, &ifr.ifr_addr.sa_data[2], 4); + } else fipvalid = 0; + if (memcmp(macsav, macadr, MAC_LEN) == 0) { /*found match*/ + devnum = nCurDevice; + memcpy(osmymac, macsav, MAC_LEN); + if (fipvalid) memcpy(osmyip, ipsav, 4); + break; + } + if (nCurDevice == 0) { /*set a default of eth0*/ + devos = nCurDevice; + memcpy(osmymac,macsav, MAC_LEN); + if (fipvalid) memcpy(osmyip, ipsav, 4); + } else if (fipvalid) { /*check if NIC1 is eth1,2,3,...*/ + memcpy(mactmp,osmymac,MAC_LEN); + mactmp[MAC_LEN-1] -= 1; + if (memcmp(mactmp,macsav,MAC_LEN) == 0) { + devos = nCurDevice; + memcpy(osmymac, macsav, MAC_LEN); + memcpy(osmyip, ipsav, 4); + } + } + } /*end else*/ + } + if (!fsetifn) { + if (devnum == -1) { /*not found, use devos default*/ + devnum = devos; + sprintf( ifname, "%s%d", ifpattn, devnum ); /*eth%d*/ + } else { /* match was found, devnum set */ + fethfound = 1; + strcpy(ifname, szDeviceName ); + } + } + close(skfd); + if (fdebug) /* show the local OS eth if and MAC */ + printf("FindEth: OS %s IP=%d.%d.%d.%d MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + ifname, osmyip[0], osmyip[1], osmyip[2], osmyip[3], + osmymac[0], osmymac[1], osmymac[2], osmymac[3], + osmymac[4], osmymac[5]); + return(devnum); +} +#endif + +int show_channels(void) +{ + int ret, rlen; + uchar iData[2]; + uchar rData[10]; + uchar cc, mtype; + int j; + int rv = -1; + + for (j = 1; j < MAXCHAN; j++) { + rlen = sizeof(rData); + iData[0] = (uchar)j; /*channel #*/ + memset(rData,0,9); /*initialize recv data*/ + ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, fdebug); + if (rv != 0) rv = ret; + if (ret == 0xcc || cc == 0xcc) /* special case for ipmi_lan */ + continue; + if (ret != 0) { + if (fdebug) printf("get_chan_info rc = %x\n",ret); + break; + } + mtype = rData[1]; /* channel medium type */ + switch(mtype) { + case 4: printf("channel[%d] type = lan\n",j); break; /*802.3 LAN type*/ + case 5: printf("channel[%d] type = serial\n",j); break; + case 7: printf("channel[%d] type = pci_smbus\n",j); break; + case 12: printf("channel[%d] type = system_interface\n",j); break; + default: printf("channel[%d] type = other %d\n",j,mtype); break; + } + rv = 0; + } /*end for j*/ + return(rv); +} + +/* + * GetBmcEthDevice + * Attempt to auto-detect the BMC LAN channel and matching OS eth port. + * INPUT: lan_parm = lan channel from user -L option, 0xFF if not specified + * OUTPUT: lan_ch is set to BMC LAN channel number + * if success, returns index of OS eth port (0, 1, ...). + * if no lan channels found, returns -2. + * if other error, returns -1. + */ +int GetBmcEthDevice(uchar lan_parm) +{ + LAN_RECORD LanRecord; + int devnum = -1; + int ret; + uchar bmcMacAddress[ MAC_LEN ]; /*MAC_LEN = 6*/ + int rlen; + uchar iData[2]; + uchar rData[10]; + uchar cc; + int i = 0; + int j, jstart, jend, jlan; + uchar mtype; + uchar *pb; + int fchgmac; + // int found = 0; + + /* Find the LAN channel(s) via Channel Info */ + if (lan_parm < MAXCHAN) { /* try user-specified channel only */ + lan_ch = lan_parm; + jstart = lan_parm; + jend = lan_parm+1; + } else { + jstart = 1; + jend = MAXCHAN; + } + memset(bmcMacAddress,0xff,sizeof(bmcMacAddress)); /*initialize to invalid*/ + for (j = jstart; j < jend; j++) { + rlen = sizeof(rData); + iData[0] = (uchar)j; /*channel #*/ + memset(rData,0,9); /*initialize recv data*/ + ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, fdebug); + if (ret == 0xcc || cc == 0xcc) /* special case for ipmi_lan */ + continue; + if (ret != 0) { + if (fdebug) printf("get_chan_info rc = %x\n",ret); + break; + } + mtype = rData[1]; /* channel medium type */ + if (mtype == 4) { /* 802.3 LAN type*/ + if (fdebug) printf("chan[%d] = lan\n",j); + jlan = lan_ch; /*save prev lan chan */ + /* Get BMC MAC for this LAN channel. */ + /* Note: BMC MAC may not be valid yet. */ + lan_ch = (uchar)j; /*set lan channel for GetLanEntry*/ + ret = GetLanEntry( 5 /*MAC_ADDRESS_LAN_PARAM*/,0, &LanRecord); + if ( ret != 0 ) { + lan_ch = (uchar)jlan; /*restore lan_ch*/ + printf( "GetBmcEthDevice: GetLanEntry failed\n" ); + return devnum; + } else { + pb = &LanRecord.data[0]; + if (fdebug) printf("chan[%d] BMC MAC %x:%x:%x:%x:%x:%x\n",j, + pb[0], pb[1], pb[2], pb[3], pb[4], pb[5] ); + fchgmac = 0; + /* use the lowest valid lan channel MAC address */ + if (!MacIsValid(bmcMacAddress)) /* old MAC not valid*/ + fchgmac = 1; + else if (MacIsValid(pb) && /* new MAC is valid and*/ + (memcmp(bmcMacAddress,pb, sizeof(bmcMacAddress)) > 0)) + fchgmac = 1; /* new MAC lower */ + /* if no -L 3 and this is gcm, do not pick it. */ + if ((j == gcm_ch) && (lan_parm == PARM_INIT)) + fchgmac = 0; + if (fchgmac) { /* pick this channel & MAC */ + memcpy(bmcMacAddress,pb,sizeof(bmcMacAddress)); + lan_ch = (uchar)j; + } else lan_ch = (uchar)jlan; /*restore prev lan chan*/ + } + i++; /* i = num lan channels found */ + } else if (mtype == 5) { /* serial type*/ + if (fdebug) printf("chan[%d] = serial\n",j); + ser_ch = (uchar)j; /* set to last serial channel */ + } else if (mtype == 7) { /* PCI SMBus */ + if (fdebug) printf("chan[%d] = pci_smbus\n",j); + } else if (mtype == 12) { /* system interface */ + if (fdebug) printf("chan[%d] = system_interface\n",j); + } else /* other channel medium types, see IPMI 1.5 Table 6-3 */ + if (fdebug) printf("chan[%d] = %d\n",j,mtype); + } + if (i == 0) return(-2); /* no lan channels found */ + if (fdebug) printf("lan_ch detected = %d\n",lan_ch); + + /* This will work if the BMC MAC is shared with the OS */ + /* Otherwise, wait until we get the eth dev from the gateway below */ + devnum = FindEthNum(bmcMacAddress); + if ( fdebug ) + printf("GetBmcEthDevice: channel %d, %s%d\n",lan_ch,ifpattn,devnum); + return devnum; +} + +/* file_grep/findmatch - No longer used here, see ievents.c */ + +/* + * Get_Mac + * This routine finds a MAC address from a given IP address. + * Usually for the Alert destination. + * It uses ARP cache to do this. + */ +#if defined(WIN32) +int Get_Mac(uchar *ipadr,uchar *macadr, char *nodname) +{ + DWORD dwRetVal; + IPAddr DestIp = 0; + IPAddr SrcIp = 0; /* default for src ip */ + ULONG MacAddr[2]; /* for 6-byte hardware addresses */ + ULONG PhysAddrLen = MAC_LEN; /* default to length of six bytes */ + BYTE *bPhysAddr; + + if (!IpIsValid(ipadr)) { + if (fdebug) printf("Get_Mac: invalid IP addr\n"); + return 1; /*error*/ + } + memcpy(&DestIp, ipadr, 4); + + /* invoke system ARP query */ + dwRetVal = SendARP(DestIp, SrcIp, MacAddr, &PhysAddrLen); + + if (dwRetVal == NO_ERROR) + { /* no error - get the MAC */ + bPhysAddr = (BYTE *) & MacAddr; + if (PhysAddrLen) { + memcpy(macadr, bPhysAddr, MAC_LEN); + } else + printf("Warning: SendArp completed successfully, but returned length=0\n"); + } else if (dwRetVal == ERROR_GEN_FAILURE) + { /* MAC not available in this network - get gateway MAC */ + memcpy(macadr, rggwymac, MAC_LEN); + } else + { /* other errors */ + printf("Error: SendArp failed with error: %d", dwRetVal); + switch (dwRetVal) { + case ERROR_INVALID_PARAMETER: + printf(" (ERROR_INVALID_PARAMETER)\n"); + break; + case ERROR_INVALID_USER_BUFFER: + printf(" (ERROR_INVALID_USER_BUFFER)\n"); + break; + case ERROR_BAD_NET_NAME: + printf(" (ERROR_GEN_FAILURE)\n"); + break; + case ERROR_BUFFER_OVERFLOW: + printf(" (ERROR_BUFFER_OVERFLOW)\n"); + break; + case ERROR_NOT_FOUND: + printf(" (ERROR_NOT_FOUND)\n"); + break; + default: + printf("\n"); + break; + } + return 1; + } + return 0; +} /* end Get_Mac() for WIN32*/ +#elif defined(SOLARIS) +int Get_Mac(uchar *ipadr,uchar *macadr, char *nodename) +{ + FILE *fparp; + char buff[1024]; + /* char arpfile[] = "/proc/net/arp"; */ + char alertfile[] = "/tmp/dest.arping"; + char arping_cmd[128]; + char *pb, *pm; + int num, i; + int foundit = 0; + int ret = 0; + + if (IpIsValid(ipadr)) { /* if valid IP address */ + sprintf(arping_cmd, + "ping %d.%d.%d.%d >/dev/null; arp -a -n |grep %d.%d.%d.%d >%s\n", + ipadr[0],ipadr[1],ipadr[2],ipadr[3], + ipadr[0],ipadr[1],ipadr[2],ipadr[3], alertfile); + } else if (nodename != NULL) { /*if valid nodename */ + sprintf(arping_cmd, + "ping %s >/dev/null; arp -a |grep %s >%s\n", + nodename,nodename,alertfile); + } else ret = -1; + + if (ret == 0) { /* if valid IP address */ + /* make sure the destination is in the arp cache */ + if (fdebug) printf("%s", arping_cmd); + system(arping_cmd); + + fparp = fopen(alertfile,"r"); + if (fparp == NULL) { + fprintf(stdout,"Get_Mac: Cannot open %s, errno = %d\n", + alertfile,get_errno()); + ret = -1; + } else { + /* sample output: */ + /* e1000g0 cooper9 255.255.255.255 o 00:07:e9:06:55:c8 */ + while (fgets(buff, 1023, fparp)) { + /* should only run through loop once */ + num = strcspn(buff," \t"); /* skip 1st word ("e1000g0") */ + i = strspn(&buff[num]," \t"); /* skip whitespace */ + pb = &buff[num+i]; + num = strcspn(pb," \t"); /* skip 2nd word (nodename/IP) */ + i = strspn(&pb[num]," \t"); /* skip whitespace */ + pb += (num+i); + pm = &pb[25]; /* Now pb[25] has the MAC address */ + { /*validate new address?*/ + if (fdebug) printf("Get_Mac: mac=%s\n",pm); + foundit = 1; + if (!MacIsValid(macadr)) atomac(macadr,pm); + break; + } + } /*end while*/ + fclose(fparp); + } /*end else file opened*/ + } /*endif valid IP */ + + if (foundit == 0) { /* no errors, but no mac reply */ + if (MacIsValid(rggwymac) && !MacIsValid(macadr)) + /* this is useful if the ipadr is not in the local subnet */ + memcpy(macadr,rggwymac,6); /* get to it from the default gateway */ + } + return(ret); +} /*end Get_Mac for Solaris*/ +#elif defined(BSD) +int Get_Mac(uchar *ipadr,uchar *macadr, char *nodename) +{ + FILE *fparp; + char buff[1024]; + /* char arpfile[] = "/proc/net/arp"; */ + char alertfile[] = "/tmp/dest.arping"; + char arping_cmd[128]; + char *pb, *pm; + int num, i, j; + int foundit = 0; + int ret = 0; + + if (IpIsValid(ipadr)) { /* if valid IP address */ + sprintf(arping_cmd, + "ping -c2 %d.%d.%d.%d >/dev/null; arp -a -n |grep %d.%d.%d.%d >%s\n", + ipadr[0],ipadr[1],ipadr[2],ipadr[3], + ipadr[0],ipadr[1],ipadr[2],ipadr[3], alertfile); + } else if (nodename != NULL) { /*if valid nodename */ + sprintf(arping_cmd, + "ping -c2 %s >/dev/null; arp -a |grep %s >%s\n", + nodename,nodename,alertfile); + } else ret = -1; + + if (ret == 0) { /* if valid IP address */ + /* make sure the destination is in the arp cache */ + if (fdebug) printf("%s", arping_cmd); + system(arping_cmd); + + fparp = fopen(alertfile,"r"); + if (fparp == NULL) { + fprintf(stdout,"Get_Mac: Cannot open %s, errno = %d\n", + alertfile,get_errno()); + ret = -1; + } else { + /* sample output of arp -a -n: */ + /* ? (192.168.1.200) at 00:0e:0c:e5:df:65 on em0 [ethernet] */ + /* sample output of arp -a: */ + /* telcoserv (192.168.1.200) at 00:0e:0c:e5:df:65 on em0 [ethernet] */ + while (fgets(buff, 1023, fparp)) { + /* should only run through loop once */ + pb = &buff[0]; + for (j = 0; j < 3; j++) { /* skip 3 words */ + num = strcspn(pb," \t"); /* skip jth word */ + i = strspn(&pb[num]," \t"); /* skip whitespace */ + pb += (num+i); + } + pm = &pb[0]; /* Now pb[0] has the MAC address */ + { /* no need to validate new address*/ + if (fdebug) printf("Get_Mac: mac=%s\n",pm); + foundit = 1; + if (!MacIsValid(macadr)) atomac(macadr,pm); + break; + } + } /*end while*/ + fclose(fparp); + } /*end else file opened*/ + } /*endif valid IP */ + + if (foundit == 0) { /* no errors, but no mac reply */ + if (MacIsValid(rggwymac) && !MacIsValid(macadr)) + /* this is useful if the ipadr is not in the local subnet */ + memcpy(macadr,rggwymac,6); /* get to it from the default gateway */ + } + return(ret); +} /*end Get_Mac for BSD */ +#else +int Get_Mac(uchar *ipadr,uchar *macadr, char *nodename) +{ /* Get_Mac for Linux */ + FILE *fparp; + char buff[1024]; + /* char arpfile[] = "/proc/net/arp"; */ + char alertfile[] = "/tmp/dest.arping"; + char arping_cmd[128]; + char *pb, *pm, *px; + int num, i; + int foundit = 0; + int ret = 0; + char *_ifname; + + if (strcmp(ifname,"gcm") == 0) _ifname = ifname0; /*see gcm_ch instead*/ + else _ifname = ifname; + + /* Get a MAC address for a given IP address or nodename */ + if (IpIsValid(ipadr)) { /* if valid IP address */ + sprintf(arping_cmd, + "arping -I %s -c 2 %d.%d.%d.%d |grep reply |tail -n1 >%s\n", + _ifname,ipadr[0],ipadr[1],ipadr[2],ipadr[3],alertfile); + } else if (nodename != NULL) { /*if valid nodename */ + sprintf(arping_cmd, + "arping -I %s -c 2 %s |grep reply |tail -n1 >%s\n", + _ifname,nodename,alertfile); + } else ret = -1; + + if (ret == 0) { /* if valid IP address */ + /* make sure the destination is in the arp cache */ + if (fdebug) printf("%s", arping_cmd); + ret = system(arping_cmd); + + fparp = fopen(alertfile,"r"); + if (fparp == NULL) { + fprintf(stdout,"Get_Mac: Cannot open %s, errno = %d\n", + alertfile,get_errno()); + ret = -1; + } else { + ret = 0; + while (fgets(buff, 1023, fparp)) { + /* should only run through loop once */ + num = strcspn(buff," \t"); /* skip 1st word ("Unicast") */ + i = strspn(&buff[num]," \t"); + pb = &buff[num+i]; + if (strncmp(pb,"reply",5) == 0) { /* valid output */ + /* Find the ip address */ + pb += 6 + 5; /* skip "reply from " */ + num = strcspn(pb," \t"); + pb[num] = 0; + if (fdebug) printf("Get_Mac: ip=%s\n",pb); + /* IP address should already match input param */ + if (!IpIsValid(ipadr)) /* had nodname only*/ + atoip(ipadr,pb); /* fill in ipadr */ + /* Now find the mac address */ + pm = strchr(&pb[num+1],'['); + if (pm == NULL) pm = &pb[num+2]; /* just in case */ + pm++; + px = strchr(pm,']'); + if (px == NULL) px = pm + 17; /* just in case */ + px[0] = 0; + if (fdebug) printf("Get_Mac: mac=%s\n",pm); + foundit = 1; + if (!MacIsValid(macadr)) atomac(macadr,pm); + break; + } + } /*end while*/ + fclose(fparp); + } /*end else file opened*/ + } /*endif valid IP */ + + if (foundit == 0) { /* no errors, but no mac reply */ + if (MacIsValid(rggwymac) && !MacIsValid(macadr)) + /* this is useful if the ipadr is not in the local subnet */ + memcpy(macadr,rggwymac,6); /* get to it from the default gateway */ + } + return(ret); +} /* end Get_Mac() for Linux*/ +#endif + +#ifdef WIN32 +/* + * Set subnet mask based on current IP address (Windows). + */ +int SetSubnetMask() { + PMIB_IPADDRTABLE pIPAddrTable; + unsigned int i; + DWORD dwSize = 0, dwRetVal; + LPVOID lpMsgBuf; + + pIPAddrTable = (MIB_IPADDRTABLE*) malloc( sizeof( MIB_IPADDRTABLE) ); + + if ( pIPAddrTable ) { + // Make an initial call to GetIpAddrTable to get the + // necessary size into the dwSize variable + if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free( pIPAddrTable ); + pIPAddrTable = (MIB_IPADDRTABLE *) malloc ( dwSize ); + } + } else + printf("Memory allocation failed.\n"); + + if ( pIPAddrTable ) { + // Make a second call to GetIpAddrTable to get the + // actual data we want + if ( (dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 )) == NO_ERROR ) { + for(i = 0; i < pIPAddrTable->dwNumEntries; ++i) { + if(memcmp(&(pIPAddrTable->table[i].dwAddr), rgmyip, 4) == 0) { + memcpy(rgsubnet, &(pIPAddrTable->table[i].dwMask), 4); + free( pIPAddrTable ); + return 1; + } + } + } else { + if (FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dwRetVal, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL )) { + printf("\tError: %s", lpMsgBuf); + } + + printf("Call to GetIpAddrTable failed.\n"); + } + } + + if ( pIPAddrTable ) + free( pIPAddrTable ); + + return 0; +} + +/* + * Extract gateway address from routing table (Windows). + */ +int SetDefaultGateway() { + PMIB_IPFORWARDTABLE pIpForwardTable; + DWORD dwRetVal, dwSize; + + unsigned int nord_mask; + unsigned int nord_ip; + unsigned int nord_net; + + unsigned int i; + + nord_mask = *((unsigned int *)rgsubnet); + nord_ip = *((unsigned int *)rgmyip); + + nord_net = nord_ip & nord_mask; + + pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(sizeof(MIB_IPFORWARDTABLE)); + if (pIpForwardTable == NULL) { + printf("Error allocating memory\n"); + return 0; + } + + dwSize = 0; + if (GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free(pIpForwardTable); + pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(dwSize); + if (pIpForwardTable == NULL) { + printf("Error allocating memory\n"); + return 0; + } + } + + /* + * Note that the IPv4 addresses returned in + * GetIpForwardTable entries are in network byte order + */ + if ((dwRetVal = GetIpForwardTable(pIpForwardTable, &dwSize, 0)) == NO_ERROR) { + for (i = 0; i < (int) pIpForwardTable->dwNumEntries; i++) { + unsigned int gwaddr = pIpForwardTable->table[i].dwForwardNextHop; + if(nord_net == (gwaddr & nord_mask) && nord_ip != gwaddr) + { /* searching for gateways from our network with different address than ours */ + memcpy(rggwyip, &gwaddr, 4); + return 0; + } + } + free(pIpForwardTable); + return 1; + } + else { + printf("\tGetIpForwardTable failed.\n"); + free(pIpForwardTable); + return 0; + } + +} +/*endif WIN32*/ +#endif + +/* + * Get_IPMac_Addr + * This routine finds the IP and MAC for the local interface, + * the default gateway, and SNMP alert destination from the + * BMC and OS information. + * + * Linux snmpd.conf locations (see ipmiutil.spec): + * RedHat, MontaVista: /etc/snmp/snmpd.conf + * SuSE SLES 8: /etc/ucdsnmpd.conf + * SuSE SLES 9: /etc/snmpd.conf + */ +#ifdef WIN32 +int Get_IPMac_Addr() +{ /*for Windows*/ + char ipstr[] = "IP Address"; + char macstr[] = "Physical Address"; + char gwystr[] = "Default Gateway"; + char substr[] = "Subnet Mask"; + int found = 0; + char fgetmac; + + if (IpIsValid(rgmyip)) + { /* user-specified ip, get mac */ + if (fdebug) printf("User IP was specified\n"); + if (!MacIsValid(rgmymac)) + { /* no user-specified MAC, get it from IP */ + if (fdebug) printf("No user MAC specified\n"); + if(!GetLocalMACByIP()) + { /* couldn't get MAC from IP, get old one */ + if (fdebug) printf("No MAC from IP, use old\n"); + if(IpIsValid(bmcmyip) && MacIsValid(bmcmymac)) + { + printf("Using current BMC MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + bmcmymac[0], bmcmymac[1], + bmcmymac[2], bmcmymac[3], + bmcmymac[4], bmcmymac[5]); + memcpy(rgmymac,bmcmymac,MAC_LEN); + } else { + printf("Failed to obtain valid MAC\n"); + } + } else { + printf("Using adapter MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + rgmymac[0], rgmymac[1], + rgmymac[2], rgmymac[3], + rgmymac[4], rgmymac[5]); + } + } else { /* user MAC available */ + printf("Using user MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + rgmymac[0], rgmymac[1], + rgmymac[2], rgmymac[3], + rgmymac[4], rgmymac[5]); + } + } else { /* no user-specified IP */ + if (fdebug) printf("No user IP specified\n"); + if (!MacIsValid(rgmymac)) + { /* no user-specified MAC, get it from interface */ + if(!GetLocalDataByIface()) + { /* use existing MAC an IP */ + printf("Using current BMC IP %d.%d.%d.%d\n", + bmcmyip[0], bmcmyip[1], + bmcmyip[2], bmcmyip[3]); + memcpy(rgmyip,bmcmyip,4); + printf("Using current BMC MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + bmcmymac[0], bmcmymac[1], + bmcmymac[2], bmcmymac[3], + bmcmymac[4], bmcmymac[5]); + memcpy(rgmymac,bmcmymac,MAC_LEN); + + } + } else { /* user-specified MAC */ + if(!GetLocalIPByMAC(rgmymac)) + { /* use existing MAC and IP */ + printf("Using current BMC IP %d.%d.%d.%d\n", + bmcmyip[0], bmcmyip[1], + bmcmyip[2], bmcmyip[3]); + memcpy(rgmyip,bmcmyip,4); + printf("Using current BMC MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + bmcmymac[0], bmcmymac[1], + bmcmymac[2], bmcmymac[3], + bmcmymac[4], bmcmymac[5]); + memcpy(rgmymac,bmcmymac,MAC_LEN); + } + } + } + + if (rghostname[0] == 0) { /*hostname not specified*/ + if (!fipmilan) + gethostname(rghostname,sizeof(rghostname)); + } + if (fdebug) /* show the local OS eth if and MAC */ + printf("OS %s IP=%d.%d.%d.%d %s MAC=%02x:%02x:%02x:%02x:%02x:%02x used for arp\n", + ifname, osmyip[0],osmyip[1],osmyip[2],osmyip[3], rghostname, + osmymac[0], osmymac[1], osmymac[2], osmymac[3], + osmymac[4], osmymac[5]); + + if(!SubnetIsValid(rgsubnet)) { + SetSubnetMask(); + } + if (!IpIsValid(rggwyip)) { /* if gwy ip not user-specified */ + SetDefaultGateway(); + } + + if (lan_ch == gcm_ch) { + if (SubnetIsSame(rgmyip,rggwyip,rgsubnet)) fgetmac = 1; + else fgetmac = 0; + } else fgetmac = 1; + + if (fgetmac) { + if (IpIsValid(rggwyip) && !MacIsValid(rggwymac)) /*gwy mac not specified*/ + Get_Mac(rggwyip,rggwymac,NULL); + + if (IpIsValid(rggwy2ip) && !MacIsValid(rggwy2mac)) /*gwy2 mac not valid*/ + Get_Mac(rggwy2ip,rggwy2mac,NULL); + } + + return(0); +} /* end Get_IPMac_Addr for Windows */ + +#elif defined(HPUX) +int Get_IPMac_Addr() +{ /*for HP-UX*/ + return(-1); +} +#else +int Get_IPMac_Addr() +{ /*for Linux*/ +#if defined(SOLARIS) + char rtfile[] = "/tmp/route"; + char snmpfile[] = "/etc/snmp/conf/snmpd.conf"; +#elif defined(BSD) + char rtfile[] = "/tmp/route"; + char snmpfile[] = "/etc/snmpd.config"; +#else + char rtfile[] = "/proc/net/route"; + char snmpfile[] = "/etc/snmp/snmpd.conf"; +#endif + // char alertfile[] = "/tmp/alert.arping"; + // FILE *fparp; + FILE *fprt; + int fd = -1; + int skfd; + uchar *pc; + int rc = 0; + int i,j; + uchar bnetadr[4]; + uchar bgateadr[4]; + char gate_addr[128]; + char iface[16]; + char defcommunity[19] = "public"; + char buff[1024]; + char alertname[60]; + int num, nmatch; + struct ifreq ifr; + char *_ifname; + char fgetmac; + + /* Get the IP address and associated MAC address specified. */ + /* Local for ethN; Default Gateway; Alert Destination */ + + /* Get the default gateway IP */ +#if defined(SOLARIS) || defined(BSD) + char rtcmd[80]; + sprintf(rtcmd,"netstat -r -n |grep default |awk '{ print $2 }' >%s",rtfile); + system(rtcmd); + /* use rtfile output from netstat -r, see also /etc/defaultroute */ + fprt = fopen(rtfile,"r"); + if (fprt == NULL) { + fprintf(stdout,"netstat: Cannot open %s, errno = %d\n",rtfile,get_errno()); + } else { + while (fgets(buff, 1023, fprt)) { + if ((buff[0] > '0') && (buff[0] <= '9')) { /*valid*/ + atoip(bgateadr,buff); + if (fdebug) + printf("default gateway: %s, %d.%d.%d.%d %s\n",buff, + bgateadr[0], bgateadr[1], bgateadr[2], bgateadr[3],ifname); + if (!IpIsValid(rggwyip)) /* if not user-specified */ + memcpy(rggwyip,bgateadr,4); + break; + } + } + fclose(fprt); + } /*end-else good open */ +#else + /* cat /proc/net/route and save Gwy if Dest == 0 and Gateway != 0 */ + fprt = fopen(rtfile,"r"); + if (fprt == NULL) { + fprintf(stdout,"route: Cannot open %s, errno = %d\n",rtfile,get_errno()); + } else { + char rtfmt[] = "%16s %128s %128s %X %d %d %d %128s %d %d %d\n"; + int iflags, refcnt, use, metric, mss, window, irtt; + char mask_addr[128], net_addr[128]; + uint *pnet; + uint *pgate; + + pnet = (uint *)&bnetadr[0]; + pgate = (uint *)&bgateadr[0]; + while (fgets(buff, 1023, fprt)) { + num = sscanf(buff, rtfmt, + iface, net_addr, gate_addr, + &iflags, &refcnt, &use, &metric, mask_addr, + &mss, &window, &irtt); + if (num < 10 || !(iflags & RTF_UP)) + continue; + + j = 6; + for (i = 0; i < 4; i ++) { + bnetadr[i] = htoi(&net_addr[j]); + bgateadr[i] = htoi(&gate_addr[j]); + j -= 2; + } + if ((*pnet == 0) && (*pgate != 0)) { /* found default gateway */ + if (fdebug) + printf("default gateway: %s, %d.%d.%d.%d %s\n",gate_addr, + bgateadr[0], bgateadr[1], bgateadr[2], bgateadr[3],iface); + if (!IpIsValid(rggwyip)) /* if not user-specified */ + memcpy(rggwyip,bgateadr,4); + _ifname = iface; /*use this iface for gwy mac */ + if (!fsetifn) strncpy(ifname,iface,16); + break; + } + } /*end while*/ + fclose(fprt); + } /*end-else good open */ +#endif + + /* Create a channel to the NET kernel. */ + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket"); + return(-3); + } + + /* Find a valid local BMC MAC Address */ + if (lan_ch == gcm_ch) { + /* GCM has its own unique mac address */ + if (!MacIsValid(rgmymac)) { + if (MacIsValid(bmcmymac)) { + memcpy(rgmymac,bmcmymac,MAC_LEN); /*use existing*/ + } else { /*error*/ + printf("invalid MAC address for gcm\n"); + } + } /*else use rgmymac if specified*/ + _ifname = iface; /*use the iface from gwy (e.g. eth0) */ + fsharedMAC = 0; /*gcm has separate NIC, separate MAC*/ + + // fd = -1; + fd = skfd; // get_socket_for_af(AF_INET) below; + } else { /*else not gcm*/ + if (!fsetifn && !fethfound) { /*do not have ifname yet*/ + i = FindEthNum(bmcmymac); + if (i >= 0) sprintf(ifname,"%s%d",ifpattn,i); + } + ifr.ifr_addr.sa_family = AF_INET; + if (fdebug) printf("getipmac: ifname=%s\n",ifname); + _ifname = ifname; + strcpy(ifr.ifr_name, _ifname); + +#ifdef SIOCGIFHWADDR + /* Get the local if HWADDR (MAC Address) from OS */ + if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) { + if (fdebug) + printf("ioctl(SIOCGIFHWADDR,%s) error, errno = %d\n",_ifname,get_errno()); + } else memcpy(osmymac,get_ifreq_mac(&ifr),MAC_LEN); /*OS mac*/ +#endif + + if (memcmp(bmcmymac,osmymac,MAC_LEN) == 0) { + /* osmymac and ifname were set above by FindEthNum */ + printf("\tBMC shares IP/MAC with OS NIC %s\n",_ifname); + fsharedMAC = 1; + } /* else fsharedMAC = 0; */ + + if (fsharedMAC == 0) { /* then BMC has separate MAC */ + if (!MacIsValid(rgmymac) && MacIsValid(bmcmymac)) + memcpy(rgmymac,bmcmymac,MAC_LEN); /*use existing*/ + } else { /* else OS & BMC share a MAC */ + /* Use the local if HWADDR (MAC Address) from OS */ + if (!MacIsValid(rgmymac)) { /* if not user-specified */ + if (MacIsValid(bmcmymac)) + memcpy(rgmymac,bmcmymac,MAC_LEN); /*use existing*/ + else memcpy(rgmymac,osmymac,MAC_LEN); /*use OS mac*/ + } + } + fd = skfd; // get_socket_for_af(AF_INET) below; + } + + if (fd >= 0) { /* if valid fd, find OS IP */ + strcpy(ifr.ifr_name, _ifname); + ifr.ifr_addr.sa_family = AF_INET; + /* Get the IFADDR (IP Address) from OS */ + if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) { + int err; + err = get_errno(); + /* errno 99 here means that eth0 is not enabled/up/defined. */ + if (err == 99) + printf("ioctl(SIOCGIFADDR) error, %s not enabled\n",_ifname); + else if (fdebug) + printf("ioctl(SIOCGIFADDR,%s) error, errno=%d\n",_ifname,err); + } else { /* got the local OS IP successfully */ + pc = &ifr.ifr_addr.sa_data[2]; + if (fdebug) + printf("%s addr = %d.%d.%d.%d\n",_ifname,pc[0],pc[1],pc[2],pc[3]); + memcpy(osmyip, pc, 4); + if (!IpIsValid(rgmyip) && (fsharedMAC==1)) /*not specified, shared*/ + memcpy(rgmyip, osmyip, 4); + + /* get the local OS netmask */ + strcpy(ifr.ifr_name, _ifname); + if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) { + if (fdebug) + printf("ioctl(SIOCGIFNETMASK) error, errno=%d\n",get_errno()); + /* if leave invalid, will use default rgsubnet */ + } else { // sizeof(struct sockaddr) + pc = &ifr.ifr_netmask.sa_data[2]; + if (fdebug) + printf("subnet = %d.%d.%d.%d \n", pc[0],pc[1],pc[2],pc[3]); + memcpy(ossubnet, pc, 4); + if (!SubnetIsValid(rgsubnet) && fsharedMAC) /*not specified*/ + memcpy(rgsubnet, pc, 4); + } + +#ifdef SIOCGIFHWADDR + /* Get the localhost OS HWADDR (MAC Address) */ + if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { + if (fdebug) + printf("ioctl(SIOCGIFHWADDR,%s) error, errno = %d\n", + _ifname,get_errno()); + } else memcpy(osmymac,get_ifreq_mac(&ifr),MAC_LEN); /*OS mac*/ +#endif + } + } + close(skfd); /* done, close the socket */ + + if (rghostname[0] == 0) { /*hostname not specified*/ + if (!fipmilan) + gethostname(rghostname,sizeof(rghostname)); + } + if (fdebug) /* show the local OS eth if and MAC */ + printf("OS %s IP=%d.%d.%d.%d %s MAC=%02x:%02x:%02x:%02x:%02x:%02x used for arp\n", + _ifname, osmyip[0],osmyip[1],osmyip[2],osmyip[3], rghostname, + osmymac[0], osmymac[1], osmymac[2], osmymac[3], + osmymac[4], osmymac[5]); + + if (!IpIsValid(rgmyip) && IpIsValid(bmcmyip)) { + /* If no user-specified IP and there is a valid IP already in the + * BMC LAN configuration, use the existing BMC LAN IP. */ + memcpy(rgmyip,bmcmyip,4); + if (fdebug) printf("Using current IP %d.%d.%d.%d\n", + bmcmyip[0], bmcmyip[1], + bmcmyip[2], bmcmyip[3]); + } + + /* Get the default gateway MAC */ + if (lan_ch == gcm_ch) { + if (SubnetIsSame(osmyip,rggwyip,ossubnet)) fgetmac = 1; + else { /* gateway is not on the same subnet as RMM/GCM */ + fgetmac = 0; /*don't try to get mac if not the same subnet*/ + if ((fset_ip & GWYIP) == 0) memset(rggwyip,0,4); + } + } else fgetmac = 1; + if (fgetmac && IpIsValid(rggwyip) && !MacIsValid(rggwymac)) + Get_Mac(rggwyip,rggwymac,NULL); /*gwy mac not specified, so get mac*/ + + /* Get the Alert Destination IP */ + /* By default, attempt to obtain this from /etc/snmp/snmpd.conf. */ + /* cat /etc/snmp/snmpd.conf | grep trapsink |tail -n1 | cut -f2 -d' ' */ + alertname[0] = 0; /* default to null string */ + fprt = fopen(snmpfile,"r"); + if (fprt == NULL) { + printf("snmp: Cannot open %s, errno = %d\n",snmpfile,get_errno()); + } else { + // char snmpfmt[] = "%20s %60s\n"; + // char *keywd, *value; + while (fgets(buff, 1023, fprt)) { + /* parse each line */ + if (buff[0] == '#') continue; /*skip comment lines*/ + /* skip leading whitespace here */ + j = strspn(&buff[0]," \t"); + if (strncmp(&buff[j],"com2sec",7) == 0) { /* found community line */ + /* usu like this: "com2sec demouser default public" */ + i = j + 7; + for (j = 0; j < 3; j++) { + num = strspn(&buff[i]," \t"); + i += num; + num = strcspn(&buff[i]," \t\r\n"); + if (j < 2) i += num; + } + buff[i+num] = 0; + if (fsetcommunity == 0) { /* if not user-specified */ + strcpy(rgcommunity,&buff[i]); + strcpy(defcommunity,&buff[i]); + } + } +#ifdef BSD + if (strncmp(&buff[j],"traphost :=",11) == 0) nmatch = 11; + else nmatch = 0; +#else + if (strncmp(&buff[j],"trapsink",8) == 0) nmatch = 8; + else if (strncmp(&buff[j],"trap2sink",9) == 0) nmatch = 9; + else nmatch = 0; +#endif + if (nmatch > 0) { /* found trapsink line match */ + if (fdebug) printf("%s: %s",snmpfile,&buff[j]); + num = strspn(&buff[j+nmatch]," \t"); + i = j + nmatch + num; + if (buff[i] == '`') continue; + num = strcspn(&buff[i]," \t\r\n"); + strncpy(alertname,&buff[i],num); /* save alert destination */ + alertname[num] = 0; + i += num; + num = strspn(&buff[i]," \t"); /*skip whitespace*/ + i += num; + num = strcspn(&buff[i]," \t\r\n"); /*span next word*/ + if (num != 0) { /* there is another word, that is community */ + if (fsetcommunity == 0) { /* if not user-specified */ + strncpy(rgcommunity,&buff[i],num); /* save community */ + rgcommunity[num] = 0; + } + } else { /*have trapsink node with no community*/ + /* use previously discovered default community from above */ + strcpy(rgcommunity,defcommunity); + } + /* dont break, keep looking, use the last one */ + } + } /*end while*/ + fclose(fprt); + if (fdebug) + printf("snmp alertname=%s community=%s\n",alertname,rgcommunity); + } /*end else snmpfile*/ + + /* Get the Alert Destination MAC from the alertname. */ + if (alertname[0] != 0) { +#ifdef TEST + char arping_cmd[128]; + char *pb, *pm, *px; + int num, i; + if (fdebug) printf("alert %s ip=%d.%d.%d.%d osip=%d.%d.%d.%d " + "mac=%02x:%02x:%02x:%02x:%02x:%02x " + "osmac=%02x:%02x:%02x:%02x:%02x:%02x\n", + alertname, + rgdestip[0], rgdestip[1], rgdestip[2], rgdestip[3], + osmyip[0], osmyip[1], osmyip[2], osmyip[3], + rgdestmac[0], rgdestmac[1], rgdestmac[2], rgdestmac[3], + rgdestmac[4], rgdestmac[5], + osmymac[0], osmymac[1], osmymac[2], osmymac[3], + osmymac[4], osmymac[5]); +#endif + if (!IpIsValid(rgdestip)) { /* if not user-specified with -A */ + if (IpIsValid(bmcdestip)) { /* use existing if valid */ + memcpy(rgdestip,bmcdestip,4); + if (MacIsValid(bmcdestmac)) + memcpy(rgdestmac,bmcdestmac,MAC_LEN); + } + else if ((strncmp(alertname,"localhost",9) == 0) ) + { /* snmpd.conf = localhost (self) is the SNMP alert destination */ + if (IpIsValid(osmyip)) + memcpy(rgdestip,osmyip,4); + if (!MacIsValid(rgdestmac)) { /* if not user-specified */ + // Get_Mac(rgdestip,rgdestmac,alertname); (wont work for local) + memcpy(rgdestmac,osmymac,MAC_LEN); + } + } /*endif local */ + } + if (!MacIsValid(rgdestmac)) /* if MAC not vaild or user-specified */ + { + /* Use arping to get MAC from alertname or IP */ + Get_Mac(rgdestip,rgdestmac,alertname); + } + } /*endif have alertname*/ + + return(rc); +} /* end Get_IPMac_Addr */ +#endif + +int ShowChanAcc(uchar bchan) +{ + LAN_RECORD LanRecord; + int ret = 0; + uchar access; + char *pstr; + uchar pb0, pb1; + + if (bchan == lan_ch) pstr = "lan"; + else if (bchan == ser_ch) pstr = "ser"; + else pstr = "?"; + ret = GetChanAcc(bchan, 0x40, &LanRecord); + if (fdebug) + printf(" GetChanAcc(%d), ret = %d, data = %02x %02x\n", + bchan,ret, LanRecord.data[0], LanRecord.data[1]); + pb0 = LanRecord.data[0]; + pb1 = LanRecord.data[1]; + if (fcanonical) + printf("Channel %d Access Mode %s%c ",bchan,pspace3,bdelim); + else + printf("Channel(%d=%s) Access Mode: %02x %02x : ",bchan,pstr,pb0,pb1); + access = pb0; + switch (access & 0x03) { + case 0: printf("Disabled, "); break; + case 1: printf("Pre-Boot, "); break; + case 2: printf("Always Avail, "); break; + case 3: printf("Shared, "); break; + } + if (access & 0x20) printf("PEF Alerts Disabled\n"); /*0*/ + else printf("PEF Alerts Enabled\n"); /*1*/ + return(ret); +} + +static int GetSessionInfo(uchar *rData, int sz) +{ + int rv, rlen; + uchar ccode; + uchar iData[5]; + + iData[0] = 0x00; /*get data for this session*/ + rlen = sz; + rv = ipmi_cmdraw(CMD_GET_SESSION_INFO,NETFN_APP, BMC_SA,PUBLIC_BUS,BMC_LUN, + iData,1,rData, &rlen, &ccode, fdebug); + if ((rv == 0) && (ccode != 0)) rv = ccode; + return(rv); +} + +static int GetPefCapabilities(uchar *bmax) +{ + int rv, rlen; + uchar ccode; + uchar rData[MAX_BUFFER_SIZE]; + + rlen = sizeof(rData); + rv = ipmi_cmdraw(0x10, NETFN_SEVT, BMC_SA,PUBLIC_BUS,BMC_LUN, + NULL,0,rData, &rlen, &ccode, fdebug); + if ((rv == 0) && (ccode != 0)) rv = ccode; + if ((rv == 0) && (bmax != NULL)) + *bmax = rData[2]; /*max num PEF table entries*/ + return(rv); +} + +int GetSerialOverLan( uchar chan, uchar bset, uchar block ) +{ + uchar requestData[24]; + uchar rData[MAX_BUFFER_SIZE]; + int rlen; + int status, i; + uchar ccode; + uchar enable_parm, auth_parm, baud_parm; + ushort getsolcmd; + uchar user; + + if (fIPMI20 && fSOL20) { + getsolcmd = GET_SOL_CONFIG2; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + } else { + getsolcmd = GET_SOL_CONFIG; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + chan = 0; /*override chan for IPMI 1.5*/ + } + if (!fcanonical) + printf("%s, GetSOL for channel %d ...\n",progname,chan); + + requestData[0] = chan; /*channel*/ + requestData[1] = enable_parm; + requestData[2] = bset; /*set*/ + requestData[3] = block; /*block*/ + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd, requestData,4, rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + if (ccode == 0xC1) { /* unsupported command */ + printf("Serial-Over-Lan not available on this platform\n"); + return(status); + } else { + printf("SOL Enable ccode = %x\n",ccode); + status = ccode; + } + } else { /*success*/ + if (fcanonical) { + printf("Channel %d SOL Enable %s",chan,pspace3); + } else { + printf("SOL Enable: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + } + if (rData[1] == 0x01) printf("%c enabled\n",bdelim); + else printf("%c disabled\n",bdelim); + } + + if (!fcanonical) + { + requestData[0] = chan; + requestData[1] = auth_parm; + requestData[2] = bset; // selector + requestData[3] = block; // block + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("SOL Auth ccode = %x\n",ccode); + status = ccode; + } else { /*success*/ + printf("SOL Auth: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + printf(": "); + show_priv(rData[1]); /* priv level = User,Admin,... */ + printf("\n"); + } + + requestData[0] = chan; + requestData[1] = SOL_ACC_INTERVAL_PARAM; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("SOL Accum Interval ccode = %x\n",ccode); + status = ccode; + } else { /*success*/ + printf("SOL Accum Interval: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + printf(": %d msec\n",(rData[1] * 5)); + } + + requestData[0] = chan; + requestData[1] = SOL_RETRY_PARAM; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("SOL Retry ccode = %x\n",ccode); + status = ccode; + } else { /*success*/ + printf("SOL Retry Interval: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + printf(": %d msec\n",(rData[2] * 10)); + } + } + + if (!fRomley) + { + requestData[0] = chan; + requestData[1] = baud_parm; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("SOL nvol Baud ccode = %x\n",ccode); + status = ccode; + } else { /*success*/ + uchar b; + if (fcanonical) { + printf("Channel %d SOL Baud Rate%s",chan,pspace3); + } else { + printf("SOL nvol Baud Rate: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + } + /* if not user-specified and previously enabled, use existing */ + b = (rData[1] & 0x0f); + if ((fnewbaud == 0) && BaudValid(b)) { + sol_baud = b; + sol_bvalid = 1; + } + printf("%c %s\n",bdelim,Baud2Str(b)); + } + + if (!fcanonical) + { + requestData[0] = chan; + requestData[1] = SOL_VOL_BAUD_RATE_PARAM; /*0x06*/ + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("SOL vol Baud ccode = %x\n",ccode); + status = ccode; + } else { /*success*/ + printf("SOL vol Baud Rate: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + printf("%c %s\n",bdelim,Baud2Str(rData[1])); + } + } + } + if (fIPMI20) { + if (vend_id != VENDOR_IBM) { + /* IBM 0x00DC returns invalid cmd for SOL Payload commands. */ + if (!fcanonical) { + requestData[0] = chan; + rlen = sizeof(rData); + status = ipmi_cmdraw(GET_PAYLOAD_SUPPORT, NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + requestData,1,rData, &rlen, &ccode, fdebug); + if ((status != 0) || (ccode != 0)) { + printf("SOL Payload Support error %d, ccode = %x\n",status,ccode); + if (status == 0) status = ccode; + } else { /*success*/ + printf("SOL Payload Support(%d): ",chan); + for (i = 0; i < rlen; i++) printf("%02x ",rData[i]); + printf("\n"); + } + } /*endif not canonical*/ + /* get Payload Access for 4 users, not just lan_user */ + for (user = 1; user <= show_users; user++) + { + /* mBMC doesn't support more than 1 user */ + if (fmBMC && (user > 1)) break; + /* IPMI 2.0 has >= 4 users */ + requestData[0] = chan; + requestData[1] = user; + rlen = sizeof(rData); + status = ipmi_cmdraw(GET_PAYLOAD_ACCESS, NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + requestData,2,rData, &rlen, &ccode, fdebug); + if ((status != 0) || (ccode != 0)) { + printf("SOL Payload Access(%d,%d) error %d, ccode = %x\n", + chan,user,status,ccode); + if (status == 0) status = ccode; + } else { /*success*/ + if (fcanonical) { + printf("Channel %d SOL Payload Access(user%d)%s",chan,user, + pspace1); + } else { + printf("SOL Payload Access(%d,%d): ",chan,user); + for (i = 0; i < rlen; i++) printf("%02x ",rData[i]); + } + if ((rData[0] & 0x02) != 0) printf("%c enabled\n",bdelim); + else printf("%c disabled\n",bdelim); + } + } /*end user loop*/ + } /*endif not IBM*/ + } + + return(status); +} /*end GetSerialOverLan */ + +/* +ECHO SOL Config Enable +CMDTOOL 20 30 21 %1 01 01 + +ECHO SOL Authentication (Administrator) +CMDTOOL 20 30 21 %1 02 04 + +ECHO SOL Accumlate Interval and threshold +CMDTOOL 20 30 21 %1 03 06 14 + +ECHO SOL Retry Interval and threshold +CMDTOOL 20 30 21 %1 04 06 14 + +ECHO SOL non-volatile baud rate +CMDTOOL 20 30 21 %1 05 07 + +ECHO SOL volatile baud rate +CMDTOOL 20 30 21 %1 06 07 + +ECHO Set user Payload Access for user 1 +CMDTOOL 20 18 4c %1 01 02 00 00 00 + */ +int SetupSerialOverLan( int benable ) +{ + uchar requestData[24]; + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar completionCode; + uchar enable_parm, auth_parm, baud_parm; + ushort setsolcmd; + ushort getsolcmd; + uchar bchan, b; + + if (fIPMI20 && fSOL20) { + setsolcmd = SET_SOL_CONFIG2; + getsolcmd = GET_SOL_CONFIG2; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + bchan = lan_ch; + } else { + setsolcmd = SET_SOL_CONFIG; + getsolcmd = GET_SOL_CONFIG; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + bchan = 0x00; /*override chan for IPMI 1.5*/ + } + memset(requestData, 0, sizeof(requestData)); /* zero-fill */ + requestData[0] = bchan; + requestData[1] = enable_parm; + if (benable == 0) + requestData[2] = SOL_DISABLE_FLAG; + else + requestData[2] = SOL_ENABLE_FLAG; + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(setsolcmd, requestData,3,responseData, + &responseLength, &completionCode, fdebug); + if (status == ACCESS_OK) { + switch( completionCode ) { + case 0x00: /* success */ + break; + case 0xC1: /* unsupported command */ + SELprintf("SetupSerialOverLan: SOL not available on this platform\n"); + return 0; + default: /* other error */ + SELprintf("SetupSerialOverLan: SOL_ENABLE_PARAM ccode=%x\n", + completionCode); + return -1; + break; + } + } else { + SELprintf( "SET_SOL_CONFIG, enable SOL failed\n" ); + return -1; + } + if (benable == 0) return 0; + + requestData[0] = bchan; /* channel */ + requestData[1] = auth_parm; + requestData[2] = 0x00; /* set selector */ + requestData[3] = 0x00; /* block selector */ + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(getsolcmd, requestData,4,responseData, + &responseLength, &completionCode, fdebug); + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("SetupSerialOverLan: GET_SOL_AUTHENTICATION_PARAM code=%x\n", + completionCode); + + return -1; + } + } else { + SELprintf( "SOL_CONFIG, get SOL authentication failed\n" ); + return -1; + } + + if ((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) b = SOL_PRIVILEGE_LEVEL_OPERATOR; + else b = SOL_PRIVILEGE_LEVEL_USER; + requestData[0] = bchan; + requestData[1] = auth_parm; + requestData[2] = b | ( responseData[1] & 0x80 ); /* priv | enable */ + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(setsolcmd, requestData,3,responseData, + &responseLength, &completionCode, fdebug); + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("SET_SOL_AUTHENTICATION_PARAM code=%x\n", + completionCode); + + return -1; + } + } else { + SELprintf( "SET_SOL_CONFIG, set SOL authentication failed\n" ); + return -1; + } + + requestData[0] = bchan; + requestData[1] = SOL_ACC_INTERVAL_PARAM; + requestData[2] = sol_accum[0]; //0x04; + requestData[3] = sol_accum[1]; //0x32; + responseLength = MAX_BUFFER_SIZE; + if (fdebug) SELprintf("Setting SOL AccumInterval\n"); + status = ipmi_cmd(setsolcmd, requestData,4,responseData, + &responseLength, &completionCode, fdebug); + if (status != ACCESS_OK || completionCode) { + SELprintf("SET SOL AccumInterval ret=%d ccode=%x\n", + status,completionCode); + return -1; + } + + /* Some BMCs return sporadic errors for SOL params (e.g. Kontron)*/ + // if (vend_id == VENDOR_KONTRON) ; + // else + { + requestData[0] = bchan; + requestData[1] = SOL_RETRY_PARAM; + requestData[2] = sol_retry[0]; //0x06; + requestData[3] = sol_retry[1]; //0x14; + responseLength = MAX_BUFFER_SIZE; + if (fdebug) SELprintf("Setting SOL RetryInterval\n"); + status = ipmi_cmd(setsolcmd, requestData,4,responseData, + &responseLength, &completionCode, fdebug); + if (status != ACCESS_OK || completionCode) { + SELprintf("SET SOL RetryInterval ret=%d ccode=%x\n", + status,completionCode); + return -1; + } + } + + if (fRomley) ; /* skip SOL BAUD */ + else { /* else SOL BAUD is used, so set it. */ + if (fnewbaud == 0) { /* no user-specified SOL baud */ + /* if sol_bvalid, sol_baud was set to existing value above */ + if (!sol_bvalid) { + status = GetSerEntry(7, (LAN_RECORD *)&responseData); + if (status == 0) { /* use Serial baud for SOL */ + sol_baud = responseData[1]; + if (fdebug) SELprintf("Serial Baud is %s\n",Baud2Str(sol_baud)); + } + } + } + requestData[0] = bchan; + requestData[1] = baud_parm; + requestData[2] = sol_baud; + responseLength = MAX_BUFFER_SIZE; + if (fdebug) SELprintf("Setting SOL BAUD to %s\n",Baud2Str(sol_baud)); + status = ipmi_cmd(setsolcmd, requestData,3,responseData, + &responseLength, &completionCode, fdebug); + if (status != ACCESS_OK || completionCode) { + SELprintf("SET SOL BAUD ret=%d ccode=%x\n", status,completionCode); + return -1; + } + + requestData[0] = bchan; + requestData[1] = SOL_VOL_BAUD_RATE_PARAM; + requestData[2] = sol_baud; + responseLength = MAX_BUFFER_SIZE; + if (fdebug) + printf("Setting SOL vol BAUD to %s\n",Baud2Str(sol_baud)); + status = ipmi_cmd(setsolcmd, requestData,3,responseData, + &responseLength, &completionCode, fdebug); + if (status != ACCESS_OK || completionCode) { + printf("SET SOL vol BAUD ret=%d ccode=%x\n",status,completionCode); + return -1; + } + } + + if (fIPMI20 && fSOL20) { + if (vend_id == VENDOR_KONTRON && lan_user == 1) { + if (fdebug) SELprintf("Skipping SOL Payload Access for user %d\n", + lan_user); + } else if (vend_id == VENDOR_IBM) { /*non-conformance*/ + if (fdebug) SELprintf("Skipping SOL Payload Access for user %d\n", + lan_user); + } else { + if (fdebug) SELprintf("Setting SOL Payload Access for user %d\n", + lan_user); + requestData[0] = bchan; + requestData[1] = lan_user; /*enable this user*/ + requestData[2] = 0x02; /*enable std 2.0 SOL*/ + requestData[3] = 0; + requestData[4] = 0; + requestData[5] = 0; + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmdraw(SET_PAYLOAD_ACCESS, NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + requestData,6,responseData, &responseLength, + &completionCode, fdebug); + if (status != ACCESS_OK || completionCode) { + SELprintf("SET SOL Payload Access ret=%d ccode=%x\n", + status,completionCode); + return -1; + } + } + } + return 0; +} /*end SetupSerialOverLan */ + +static char *PefDesc(int idx, uchar stype) +{ + char *pdesc, *p; + static char mystr[60]; + int mylen = sizeof(mystr); + pdesc = &mystr[0]; + if (pefdesc != NULL) strcpy(pdesc,pefdesc[idx]); /* if Intel, pre-defined */ + else strcpy(pdesc,"reserved"); /* else set default to detect */ + if ((stype != 0) && (strcmp(pdesc,"reserved") == 0)) { + /* Dynamically set the pef desc string from the sensor type */ + switch(stype) { + case 0x01: strcpy(pdesc,"Temperature"); break; + case 0x02: strcpy(pdesc,"Voltage"); break; + case 0x04: strcpy(pdesc,"Fan"); break; + case 0x05: strcpy(pdesc,"Chassis"); break; + case 0x07: strcpy(pdesc,"BIOS"); break; + case 0x08: strcpy(pdesc,"Power Supply"); break; + case 0x09: strcpy(pdesc,"Power Unit"); break; + case 0x0c: strcpy(pdesc,"Memory"); break; + case 0x0f: strcpy(pdesc,"Boot"); break; + case 0x12: strcpy(pdesc,"System Restart"); break; + case 0x13: strcpy(pdesc,"NMI"); break; + case 0x23: strcpy(pdesc,"Watchdog"); break; + case 0x20: strcpy(pdesc,"OS Critical Stop"); break; + default: +#ifdef METACOMMAND + p = get_sensor_type_desc(stype); + if (p != NULL) { + strncpy(pdesc,p,mylen); + mystr[mylen-1] = 0; /*stringify*/ + } +#else + sprintf(pdesc,"Other[%02x]",stype); +#endif + break; + } + if (pef_array[idx-1][4] == PEF_SEV_OK) strcat(pdesc," OK"); + } + return(pdesc); +} + + +#ifdef METACOMMAND +int i_lan(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret; + PEF_RECORD PefRecord; + LAN_RECORD LanRecord; + int i, idx, j; + int c; + char *pstr; + uchar bset; + int ndest = 4; + int idest; + int nciphers = 16; + char mystr[80]; + char fpefok = 1; + uchar * pc; int sz; + + // progname = argv[0]; + printf("%s ver %s \n",progname,progver); + j = 0; freadonly = FLAG_INIT; + idx = argc; /*getopt loop counter*/ + /* available opt chars: y O Q + = ~ _ */ + while ((c = getopt(argc, argv,"a:b:cdef:gh:i:j:klm:n:op:q:rstu:v:w:xy:z#::A:B:C:DEF:G:H:I:J:K:L:M:N:P:Q:R:S:T:U:V:X:YZ:?")) != EOF) { + switch(c) { + case 'a': /* alert dest number (usu 1 thru 4) */ + alertnum = atob(optarg); + if (alertnum > alertmax) alertnum = 1; + j++; + break; + case 'b': bAuth = htoi(optarg); j++; break; /*undocumented*/ + case 'c': fcanonical = 1; bdelim = BDELIM; break; + case 'd': fenable = 0; fdisable = 1; freadonly = 0; break; + case 'e': fenable = 1; fdisable = 0; freadonly = 0; break; + case 'f': i = atoi(optarg); /*set arp_ctl*/ + if (i < 0 || i > 3) printf("Invalid ARP control %d\n",i); + else { + arp_ctl = i; + fsetarp = 1; + j++; + } + break; + case 'l': fpefenable = 0; fenable = 2; + fdisable = 0; freadonly = 0; break; + case 'h': /* VLAN ID */ + i = atoi(optarg); + if (i > 4095) vlan_enable = 0; + else { + vlan_enable = 1; + vlan_id = (ushort)i; + } + j++; + break; + case 'y': /* OEM LAN Failover enable/disable */ + i = atoi(optarg); + if (i < 0) printf("Failover(-y) parameter is negative\n"); + else failover_enable = i; + j++; + break; + case 'Q': /* VLAN Priority */ + i = atoi(optarg); + if (i > 7 || i < 0) vlan_enable = 0; + else { + vlan_enable = 1; + vlan_prio = (uchar)i; + } + j++; + break; + case 'i': /* eth interface (ifname) */ + fsetifn = 1; + i = sizeof(ifname); + if (strlen(optarg) > (uint)i) optarg[i] = 0; + strcpy(ifname,optarg); + if (fdebug) printf("ifname = %s\n",ifname); + j++; + break; + case 'j': fCustomPEF = 1; /*custom 10 PEF bytes */ + fpefenable = 1; /* PEF is implied here */ + freadonly = 0; + memset(custPEF,0,sizeof(custPEF)); + custPEF[0] = htoi(&optarg[0]); /*action */ + custPEF[1] = htoi(&optarg[2]); /*policy */ + custPEF[2] = htoi(&optarg[4]); /*severity*/ + custPEF[3] = htoi(&optarg[6]); /*genid1 */ + custPEF[4] = htoi(&optarg[8]); /*genid2 */ + custPEF[5] = htoi(&optarg[10]); /*sensor_type*/ + custPEF[6] = htoi(&optarg[12]); /*sensor_num */ + custPEF[7] = htoi(&optarg[14]); /*evt_trigger*/ + custPEF[8] = htoi(&optarg[16]); /*data1offset*/ + custPEF[9] = htoi(&optarg[18]); /*data1mask */ + if (optarg[20] != 0) { + /* optionally get 8 extra PEF entry bytes */ + custPEF[10] = htoi(&optarg[20]); /*data1cmp1 */ + custPEF[11] = htoi(&optarg[22]); /*data1cmp2 */ + custPEF[12] = htoi(&optarg[24]); /*data2mask */ + custPEF[13] = htoi(&optarg[26]); /*data2cmp1 */ + custPEF[14] = htoi(&optarg[28]); /*data2cmp2 */ + custPEF[15] = htoi(&optarg[30]); /*data3mask */ + custPEF[16] = htoi(&optarg[32]); /*data3cmp1 */ + custPEF[17] = htoi(&optarg[34]); /*data3cmp2 */ + } + j++; + break; + case 'k': fSetPEFOks = 1; j++; break; /*configure PEF OK rules */ + case 'm': set_max_kcs_loops(atoi(optarg)); break; + case 'n': /* number/index in PEF table to insert new entry */ + fpefenable = 1; + pefnum = atob(optarg); + if (pefnum >= MAXPEF) { + pefnum = MAXPEF - 1; + fAdjustPefNum = 1; + } else fUserPefNum = 1; + j++; + break; + case 'o': fdisableSOL = 1; /*disable SOL only*/ + fpefenable = 0; /*no change to PEF*/ + freadonly = 0; + break; + case 'r': freadonly = 1; fenable = 0; break; + case 's': fgetser = 1; break; + case 't': ftestonly = 1; freadonly = 1; break; + case 'v': /* user access privilege level */ + i = atoi(optarg); + if (valid_priv(i)) lan_access = i & 0x0f; + else printf("Invalid privilege -v %d, using Admin\n",i); + j++; + break; + case 'w': i = atoi(optarg); /*set grat arp interval, in #sec*/ + if (i >= 0 && i < 256) arp_interval = i * 2; + else printf("Invalid arp interval -w %d, skipping\n",i); + break; + case 'x': fdebug = 1; break; + case 'z': flanstats = 1; break; + case 'D': lan_dhcp = 1; j++; break; + case 'I': /* My BMC IP Address */ + fset_ip |= MYIP; + atoip(rgmyip,optarg); + j++; + break; + case 'M': /* My BMC MAC Address */ + atomac(rgmymac,optarg); + if (!MacIsValid(rgmymac)) printf("Invalid MAC for -M\n"); + j++; + break; + case 'S': /* Subnet IP Address */ + atoip(rgsubnet,optarg); + j++; + break; + case 'G': /* Gateway IP Address */ + fset_ip |= GWYIP; + atoip(rggwyip,optarg); + j++; + break; + case 'g': /* Secondary Gateway IP Address */ + fset_ip |= GWYIP; + atoip(rggwy2ip,optarg); + j++; + break; + case 'H': /* Gateway MAC Address */ + atomac(rggwymac,optarg); + if (!MacIsValid(rggwymac)) printf("Invalid MAC for -H\n"); + j++; + break; + case 'B': /* SOL Baud rate */ + fnewbaud = 1; + sol_baud = Str2Baud(optarg); + j++; + break; + case 'A': /* Alert Dest IP Address */ + fset_ip |= DESTIP; + /* allow name or ip here via Get_Mac() ? */ + atoip(rgdestip,optarg); + fpefenable = 1; /* PEF is implied here */ + j++; + break; + case 'X': /* Alert Dest MAC Address */ + atomac(rgdestmac,optarg); + if (!MacIsValid(rgdestmac)) printf("Invalid MAC for -X\n"); + fpefenable = 1; /* PEF is implied here */ + j++; + break; + case 'K': /* Kontron IPMI hostname */ + i = sizeof(rghostname); /*usu 18*/ + if (strlen(optarg) > (uint)i) optarg[i] = 0; + strcpy(rghostname,optarg); + j++; + break; + case 'C': /* Community String */ + fsetcommunity = 1; + i = sizeof(rgcommunity); /*usu 18*/ + if (strlen(optarg) > (uint)i) optarg[i] = 0; + strcpy(rgcommunity,optarg); + fpefenable = 1; /* PEF is implied here */ + j++; + break; + case 'u': /* username to set */ + myuser = strdup_(optarg); /*remote username */ + j++; + break; + case 'p': /* password to set */ + fpassword = 1; + if (strlen(optarg) > PSW_MAX) optarg[PSW_MAX] = 0; + strcpy(passwordData,optarg); + if (fdebug) printf("Password = %s\n",passwordData); + /* Hide password from 'ps' */ + memset(optarg, ' ', strlen(optarg)); + j++; + break; + case 'q': + case '#': + usernum = atob(optarg); + if (usernum > 15) usernum = 0; /*MAX_IPMI_USERS = 15*/ + j++; + break; + case 'L': + if (strcmp(optarg,"list") == 0) fshowchan = 1; + lan_ch_parm = atob(optarg); + if (lan_ch_parm > MAXCHAN) lan_ch_parm = PARM_INIT; /*invalid*/ + break; + case 'V': /* priv level */ + fprivset = 1; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-abcdefghijklmnopq#rstuvwxyzBDQK]\n",progname); + printf(" \t [-a alertnum -i eth1 -n pefnum ]\n"); + printf(" \t [-I ipadr -M macadr -S subnet ]\n"); + printf(" \t [-G gwyip -H gwymac -L lan_channel_num]\n"); + printf(" \t [-A alertip -X alertmac -C community ]\n"); + printf(" \t [-g 2nd_gwyip -v priv -B sol_baud ]\n"); + printf(" \t [-j 10_bytes_custom_pef -b authmask ]\n"); + printf("where -c shows Canonical, simpler output format\n"); + printf(" -d Disables BMC LAN & PEF\n"); + printf(" -e Enables BMC LAN & PEF\n"); + printf(" -f set ARP Control to 1=grat, 2=resp, 3=both\n"); + printf(" -g secondary Gateway IP (-G=primary_gwy_ip)\n"); + printf(" -h VLAN ID (>=4096 to disable)\n"); + printf(" -j specify custom PEF rule (10 or 18 hex bytes)\n"); + printf(" -k add PEF oK rules, if PEF enable\n"); + printf(" -l Enables BMC LAN only, not PEF\n"); + printf(" -o disable Only SOL\n"); + printf(" -p password to set \n"); + printf(" -q/-# User number of LAN username_to_set\n"); + printf(" -r Read-only BMC LAN & PEF settings\n"); + printf(" -s Show some Serial settings also \n"); + printf(" -t Test if BMC LAN is already configured\n"); + printf(" -u username to set \n"); + printf(" -v access priVilege: 4=Admin,3=Operator,2=User\n"); + printf(" -w set Grat ARP Interval to specified # seconds\n"); + printf(" -x Show eXtra debug messages\n"); + printf(" -y OEM LAN Failover (1=enable,0=disable if Intel)\n"); + printf(" -z Show IPMI LAN statistics\n"); + printf(" -B Baud for SerialOverLan (19.2K,115.2K,...)\n"); + printf(" -D Use DHCP instead of static IP (-I for server)\n"); + printf(" -K (Kontron) IPMI hostname to set\n"); + printf(" -Q VLAN Priority (default =0)\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } /*end switch*/ + nopts++; + } /*end while*/ + + if ((freadonly == FLAG_INIT) && (j > 0)) { + /* got some options implying set, but no -e -l -d option specified. */ + foptmsg = 1; /*show warning message later*/ + freadonly = 1; /*assume read only*/ + } + fipmilan = is_remote(); + if (fipmilan && !fprivset) + parse_lan_options('V',"4",0); /*even if freadonly request admin*/ + if ((fsetarp == 0) && ostype == OS_WINDOWS) + arp_ctl = 0x03; /*grat arp & arp resp enabled */ + + ret = GetDeviceID( &LanRecord); + if (ret != 0) { + goto do_exit; + } else { /* success */ + uchar ipmi_maj, ipmi_min; + ipmi_maj = LanRecord.data[4] & 0x0f; + ipmi_min = LanRecord.data[4] >> 4; + show_devid( LanRecord.data[2], LanRecord.data[3], ipmi_maj, ipmi_min); + if (ipmi_maj == 0) fIPMI10 = 1; + else if (ipmi_maj == 1 && ipmi_min < 5) fIPMI10 = 1; + else fIPMI10 = 0; /* >= IPMI 1.5 is ok */ + if (ipmi_maj >= 2) fIPMI20 = 1; + if (fIPMI20) show_users = 5; + else show_users = 3; + if (fIPMI10) { + printf("This IPMI v%d.%d system does not support PEF records.\n", + ipmi_maj,ipmi_min); + /* Wont handle PEF, but continue and look for BMC LAN anyway */ + // fIPMI10 = 1; + // ipmi_close_(); + // exit(1); + } + prod_id = LanRecord.data[9] + (LanRecord.data[10] << 8); + vend_id = LanRecord.data[6] + (LanRecord.data[7] << 8) + + (LanRecord.data[8] << 16); + /* check Device ID response for Manufacturer ID = 0x0322 (NSC) */ + if (vend_id == VENDOR_NSC) { /* NSC = 0x000322 */ + fmBMC = 1; /*NSC miniBMC*/ + if (pefnum == 12) pefnum = 10; /* change CritStop pefnum to 0x0a */ + pefdesc = &pefdesc2[0]; /*mini-BMC PEF*/ + pefmax = 30; + fsharedMAC = 1; /* shared MAC with OS */ + } else if (vend_id == VENDOR_LMC) { /* LMC (on SuperMicro) = 0x000878 */ + pefdesc = NULL; /* unknown, see PefDesc() */ + if (pefnum == 12) pefnum = 15; /* change CritStop pefnum */ + pefmax = 16; + fsharedMAC = 0; /* not-shared BMC LAN port */ + } else if (vend_id == VENDOR_INTEL) { /* Intel = 0x000157 */ + pefdesc = &pefdesc1[0]; /*default Intel PEF*/ + pefmax = 20; /*default Intel PEF*/ + switch(prod_id) { + case 0x4311: /* Intel NSI2U w SE7520JR23 */ + fmBMC = 1; /* Intel miniBMC*/ + if (pefnum == 12) pefnum = 14; /* change CritStop pefnum */ + pefdesc = &pefdesc2[0]; /*mini-BMC PEF*/ + pefmax = 30; + fsharedMAC = 1; /* shared-MAC BMC LAN port, same MAC */ + break; + case 0x0022: /* Intel TIGI2U w SE7520JR23 +IMM*/ + fsharedMAC = 1; /* shared-MAC BMC LAN port, same MAC */ + gcm_ch = 3; /* IMM GCM port, dedicated MAC */ + show_users = 4; + break; + case 0x000C: /*TSRLT2*/ + case 0x001B: /*TIGPR2U*/ + /* fmBMC=0; Intel Sahalee BMC*/ + fsharedMAC = 1; /* shared-MAC BMC LAN port, same MAC */ + break; + case 0x0026: /*S5000 Bridgeport*/ + case 0x0028: /*S5000PAL Alcolu*/ + case 0x0029: /*S5000PSL StarLake*/ + case 0x0811: /*S5000PHB TIGW1U */ + /* fmBMC=0; Intel Sahalee ESB2 BMC*/ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + gcm_ch = 3; + parm7 = &iparm7[0]; /*TTL=30*/ + break; + case 0x003E: /*NSN2U or CG2100 Urbanna*/ + fiBMC = 1; /* Intel iBMC */ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + // gcm_ch = 3; + parm7 = &iparm7[0]; /*TTL=30*/ + if (fsetarp == 0) + arp_ctl = 0x02; /*grat arp disabled, arp resp enabled */ + arp_interval = 0x00; /*0 sec, since grat arp disabled */ + sol_accum[0] = 0x0c; /*Intel defaults*/ + sol_accum[1] = 0x60; /*Intel defaults*/ + sol_retry[0] = 0x07; /*Intel defaults*/ + sol_retry[1] = 0x32; /*Intel defaults*/ + set_max_kcs_loops(URNLOOPS); /*longer for SetLan cmds (default 300)*/ + break; + case 0x0107: /* Intel Caneland*/ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + gcm_ch = 3; + break; + case 0x0100: /*Tiger2 ia64*/ + /* for ia64 set chan_pefon, chan_pefoff accordingly*/ + chan_pefon = CHAN_ACC_PEFON64; + chan_pefoff = CHAN_ACC_PEFOFF64; + /* fall through */ + default: /* else other Intel */ + /* fmBMC = 0; * Intel Sahalee BMC*/ + if (fIPMI20) fsharedMAC = 0; /* recent, not-shared BMC MAC */ + else fsharedMAC = 1; /* usu IPMI 1.x has shared BMC MAC */ + break; + } /*end switch*/ + if (is_romley(vend_id,prod_id)) { + fRomley = 1; + fiBMC = 1; /* Intel iBMC */ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + set_max_kcs_loops(URNLOOPS); /*longer for SetLan (default 300)*/ + fipv6 = 1; + if (fsetarp == 0) arp_ctl = 0x03; /*default to both for Romley*/ + } + } else { /* else other vendors */ + if (fIPMI20) fsharedMAC = 0; /* recent, not-shared BMC MAC */ + else fsharedMAC = 1; /* usu IPMI 1.x has shared BMC MAC */ + pefdesc = NULL; /* unknown, see PefDesc() */ + if (pefnum == 12) pefnum = 15; /* change CritStop pefnum to 15? */ + pefmax = 20; + if (!fUserPefNum) fAdjustPefNum = 1; + } + if (fmBMC) show_users = 1; /* mBMC doesn't support more than 1 user */ + } + + if (fshowchan) { + ret = show_channels(); + exit(ret); + } + + ret = GetPefCapabilities(&bset); + if ((ret == 0) && (bset <= MAXPEF)) pefmax = bset; + + /* Get the BMC LAN channel & match it to an OS eth if. */ + i = GetBmcEthDevice(lan_ch_parm); + if (i == -2) { /* no lan channels found (see lan_ch) */ + if (lan_ch_parm == PARM_INIT) + printf("This system does not support IPMI LAN channels.\n"); + else /*specified a LAN channel*/ + printf("BMC channel %d does not support IPMI LAN.\n",lan_ch_parm); + ret = LAN_ERR_NOTSUPPORT; + goto do_exit; + } else if (i < 0) { /* mac not found, use platform defaults */ + i = 0; /* default to eth0, lan_ch set already. */ + if (vend_id == VENDOR_INTEL) { + if ((prod_id == 0x001B) || (prod_id == 0x000c)) { + /* Intel TIGPR2U or TSRLT2 defaults are special */ + if (lan_ch_parm == 6) + { i = 0; lan_ch = 6; } + else { i = 1; lan_ch = 7; } + ser_ch = 1; + } + } + } + if ((i == gcm_ch) && (gcm_ch != PARM_INIT) && (lan_ch_parm == PARM_INIT)) { + /* Has a GCM, defaulted to it, and user didn't specify -L */ + /* Need this to avoid picking channel 3, the IMM/RMM GCM channel. */ + lan_ch = 1; /*default BMC LAN channel*/ + // i = 0; /*default eth0 (was eth1) */ + } + if (fsetifn == 0) { /*not user specified, use the detected one*/ + // if (lan_ch == gcm_ch) strcpy(ifname,"gcm"); + sprintf(ifname,"%s%d",ifpattn,i); /*eth%d*/ + } + if (fdebug) printf("lan_ch = %d, ifname = %s\n",lan_ch,ifname); + + /* set the lan_user appropriately */ + if (myuser == NULL) { /* if no -u param */ + if (ipmi_reserved_user(vend_id, 1)) lan_user = 2; + else lan_user = 1; /*use default null user */ + } else if (usernum != 0) lan_user = usernum; /*use -q specified usernum*/ + /* else use default lan_user (=2) if -u and not -q */ + + if (ftestonly) { /*test only if BMC LAN is configured or not */ + /* TODO: test gcm also, if present */ + ret = GetLanEntry(4, 0, &LanRecord); /*ip addr src*/ + if (ret == 0) { + if ((LanRecord.data[0] == SRC_BIOS) || + (LanRecord.data[0] == SRC_DHCP)) ret = 0; /* DHCP, so ok */ + else { /*static IP*/ + ret = GetLanEntry(3, 0, &LanRecord); /* ip address */ + if (ret == 0) { + if (!IpIsValid(LanRecord.data)) { + printf("invalid BMC IP address\n"); + ret = 1; /* invalid ip */ + } else ret = GetLanEntry(12, 0, &LanRecord); /*gateway ip*/ + if (ret == 0) { + if (!IpIsValid(LanRecord.data)) { + printf("invalid gateway ip\n"); + ret = 2; /*invalid gwy ip*/ + } else ret = GetLanEntry(13, 0, &LanRecord); + if (ret == 0) { + if (!MacIsValid(&LanRecord.data[0])) { + printf("invalid gateway mac\n"); + ret = 3; /*invalid gwy mac */ + } + } + } + } + } + } /*endif GetLanEntry ok*/ + if (ret == 0) printf("BMC LAN already configured\n"); + else printf("BMC LAN not configured\n"); + goto do_exit; + } /*endif ftestonly*/ + + memset(SessInfo,0,sizeof(SessInfo)); + ret = GetSessionInfo(SessInfo,sizeof(SessInfo)); + // rlen = sizeof(SessInfo)); ret = get_session_info(0,0,SessInfo,&rlen); + if (fdebug) printf("GetSessionInfo ret=%d, data: %02x %02x %02x %02x \n", + ret,SessInfo[0],SessInfo[1],SessInfo[2],SessInfo[3]); + if (!freadonly && fipmilan) { /* setting LAN params, and using IPMI LAN */ + if (SessInfo[2] > 1) { /* another session is active also */ + printf("Another session is also active, cannot change IPMI LAN settings now.\n"); + ret = ERR_NOT_ALLOWED; + goto do_exit; + } + } + + if (!fIPMI10) { + if (fcanonical) + { /* canonical/simple output */ + ret = GetPefEntry(0x01, 0,(PEF_RECORD *)&LanRecord); + if (ret != 0) ndest = 0; + else { /*success*/ + j = LanRecord.data[0]; + mystr[0] = 0; + if (j == 0) strcat(mystr,"none "); + else { + if (j & 0x01) strcat(mystr,"PEFenable "); + if (j & 0x02) strcat(mystr,"DoEventMsgs "); + if (j & 0x04) strcat(mystr,"Delay "); + if (j & 0x08) strcat(mystr,"AlertDelay "); + } + printf("PEF Control %s%c %s\n",pspace4,bdelim,mystr); + } + } else { /* normal/full output */ + ret = GetPefEntry(0x01, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0 && (LanRecord.data[0] != 0)) { + fpefok = 1; + bmcpefctl = LanRecord.data[0]; + } else { /* skip PEF rules/params if disabled */ + printf("PEF Control %s%c %s\n",pspace4,bdelim,"none "); + ndest = 0; + fpefok = 0; + } + + if (fpefok) { + printf("%s, GetPefEntry ...\n",progname); + for (idx = 1; idx <= pefmax; idx++) + { + ret = GetPefEntry( 0x06, (ushort)idx, &PefRecord); + if (ret == 0) { // Show the PEF record + char *pa; + pc = (uchar *)&PefRecord; + sz = 21; // sizeof(PEF_RECORD) = 21 + if (PefRecord.sensor_type == 0) { + if (idx <= pefnum) + printf("PEFilter(%02d): empty\n",idx); + memcpy(pef_array[idx-1], &PefRecord, sz); + if (fAdjustPefNum) pefnum = (char)idx; + } else { + memcpy(pef_array[idx-1], &PefRecord, sz); + if (PefRecord.fconfig & 0x80) pc = "enabled"; + else pc = "disabled"; + i = PefRecord.rec_id; + switch(PefRecord.action) { + case 0x01: pa = "alert"; break; + case 0x02: pa = "poweroff"; break; + case 0x04: pa = "reset"; break; + case 0x08: pa = "powercycle"; break; + case 0x10: pa = "OEMaction"; break; + case 0x20: pa = "NMI"; break; + default: pa = "no action"; + } + printf("PEFilter(%02d): %02x %s event - %s for %s\n", + idx, PefRecord.sensor_type, + PefDesc(i,PefRecord.sensor_type), pc,pa); + } + if (fdebug) { /* show raw PEFilter record */ + pc = &PefRecord.rec_id; + printf("raw PEF(%.2d): ",pc[0]); + for (i = 0; i < sz; i++) printf("%02x ",pc[i]); + printf("\n"); + } + } else { + printf("GetPefEntry(%d), ret = %d\n",idx,ret); + if (ret == 0xC1) { /*PEF is not supported, so skip the rest. */ + fpefok = 0; + ndest = 0; /* if no PEF, no alerts & no alert dest */ + break; + } + } + } + } /*endif fpefok*/ + if (fpefok) { + if (fdebug) ShowPef(); + ret = GetPefEntry(0x01, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + j = LanRecord.data[0]; + mystr[0] = 0; + if (j & 0x01) strcat(mystr,"PEFenable "); + if (j & 0x02) strcat(mystr,"DoEventMsgs "); + if (j & 0x04) strcat(mystr,"Delay "); + if (j & 0x08) strcat(mystr,"AlertDelay "); + printf("PEF Control: %02x : %s\n",j, mystr); + } + ret = GetPefEntry(0x02, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + j = LanRecord.data[0]; + mystr[0] = 0; + if (j & 0x01) strcat(mystr,"Alert "); + if (j & 0x02) strcat(mystr,"PwrDn "); + if (j & 0x04) strcat(mystr,"Reset "); + if (j & 0x08) strcat(mystr,"PwrCyc "); + if (j & 0x10) strcat(mystr,"OEM "); + if (j & 0x20) strcat(mystr,"DiagInt "); + printf("PEF Actions: %02x : %s\n",j, mystr); + } + ret = GetPefEntry(0x03, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) printf("PEF Startup Delay: %02x : %d sec\n", + LanRecord.data[0],LanRecord.data[0]); + if (!fmBMC) { + ret = GetPefEntry(0x04, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) printf("PEF Alert Startup Delay: %02x: %d sec\n", + LanRecord.data[0],LanRecord.data[0]); + /* fmBMC gets cc=0x80 here */ + } + /* note that ndest should be read from lan param 17 below. */ + for (i = 1; i <= ndest; i++) + { + ret = GetPefEntry(0x09, (ushort)i,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + mystr[0] = 0; + j = LanRecord.data[2]; + if (LanRecord.data[1] & 0x08) { + sprintf(mystr,"Chan[%d] Dest[%d] ",((j & 0xf0) >> 4),(j & 0x0f)); + strcat(mystr,"Enabled "); + } else strcpy(mystr,"Disabled "); + printf("PEF Alert Policy[%d]: %02x %02x %02x %02x : %s\n",i, + LanRecord.data[0], LanRecord.data[1], + LanRecord.data[2], LanRecord.data[3],mystr); + } + } /*endfor ndest*/ + } /*endif fpefok*/ + } /*endif not canonical*/ + + if (fpefenable && !freadonly) { /* fenable or fdisable */ + if (fSetPEFOks) pefadd = 5; + else pefadd = 2; + sz = (pefnum - 1) + pefadd + fCustomPEF; + printf("\n%s, SetPefEntry(1-%d) ...\n",progname,sz); + if (fdebug) printf("pefnum = %d, pefmax = %d\n",pefnum,pefmax); + for (idx = 1; idx <= pefmax; idx++) + { + // Set & Enable all PEF records + memset(&PefRecord.rec_id,0,sizeof(PEF_RECORD)); + PefRecord.rec_id = (uchar)idx; /* next record, or user-specified */ + if (idx < pefnum) { /* pefnum defaults to 12.(0x0c) */ + if (pef_array[idx-1][7] == 0) /*empty pef record, set to default*/ + memcpy(&PefRecord.rec_id,pef_defaults[idx-1],sizeof(PEF_RECORD)); + else { /* set config however it was previously */ + memcpy(&PefRecord.rec_id,pef_array[idx-1],sizeof(PEF_RECORD)); + if (PefRecord.severity == 0) + PefRecord.severity = pef_defaults[idx-1][4]; + } + } else if ((idx == pefnum) && /* new OS Crit Stop entry */ + (PefRecord.sensor_type == 0)) { + // Set PEF values for 0x20, OS Critical Stop event + PefRecord.severity = PEF_SEV_CRIT; + PefRecord.genid1 = 0xff; + PefRecord.genid2 = 0xff; + PefRecord.sensor_type = 0x20; /* OS Critical Stop */ + PefRecord.sensor_no = 0xff; + PefRecord.event_trigger = 0x6f; + PefRecord.data1 = 0xff; + PefRecord.mask1 = 0x00; + } else if ((idx == pefnum+1) && /* new Power Redundancy entry */ + (PefRecord.sensor_type == 0)) { + // Set PEF values for 0x09/0x02/0x0b/0x41, Power Redundancy Lost + PefRecord.severity = PEF_SEV_WARN; + PefRecord.genid1 = 0xff; + PefRecord.genid2 = 0xff; + PefRecord.sensor_type = 0x09; /* Power Unit */ + PefRecord.sensor_no = 0xff; /* usu 01 or 02 */ + PefRecord.event_trigger = 0x0b; /* event trigger */ + PefRecord.data1 = 0x02; /* 02 -> 41=Redundancy Lost */ + PefRecord.mask1 = 0x00; + } else if (fSetPEFOks && idx == (pefnum+2)) { + PefRecord.severity = PEF_SEV_OK; + PefRecord.genid1 = 0xff; + PefRecord.genid2 = 0xff; + PefRecord.sensor_type = 0x09; /* Power Unit, Redund OK */ + PefRecord.sensor_no = 0xff; /* usu 01 or 02 */ + PefRecord.event_trigger = 0x0b; /* event trigger */ + PefRecord.data1 = 0x01; /* 01 -> 40=Redundancy OK */ + PefRecord.mask1 = 0x00; + } else if (fSetPEFOks && idx == (pefnum+3)) { + PefRecord.severity = PEF_SEV_OK; + PefRecord.genid1 = 0xff; + PefRecord.genid2 = 0xff; + PefRecord.sensor_type = 0x01; /* Temp OK */ + PefRecord.sensor_no = 0xff; /* usu 01 or 02 */ + PefRecord.event_trigger = 0x81; /* event trigger */ + PefRecord.data1 = 0x95; /* 95 -> 50(NC),52(Crit) match */ + PefRecord.mask1 = 0x0a; + } else if (fSetPEFOks && idx == (pefnum+4)) { + PefRecord.severity = PEF_SEV_OK; + PefRecord.genid1 = 0xff; + PefRecord.genid2 = 0xff; + PefRecord.sensor_type = 0x02; /* Voltage OK */ + PefRecord.sensor_no = 0xff; /* usu 01 or 02 */ + PefRecord.event_trigger = 0x81; /* event trigger */ + PefRecord.data1 = 0x95; /* 95 -> 50(NC),52(Crit) match */ + PefRecord.mask1 = 0x0a; + } else if (fCustomPEF && idx == (pefnum+pefadd)) { + /* user entered 10 or 18 PEF entry bytes */ + PefRecord.action = custPEF[0]; + PefRecord.policy = custPEF[1]; + PefRecord.severity = custPEF[2]; + PefRecord.genid1 = custPEF[3]; + PefRecord.genid2 = custPEF[4]; + PefRecord.sensor_type = custPEF[5]; + PefRecord.sensor_no = custPEF[6]; + PefRecord.event_trigger = custPEF[7]; + PefRecord.data1 = custPEF[8]; + PefRecord.mask1 = custPEF[9]; + memcpy(&PefRecord.action,custPEF,18); + } else { + memcpy(&PefRecord.rec_id,pef_array[idx-1],sizeof(PEF_RECORD)); + if (PefRecord.sensor_type == 0) continue; /* if reserved, skip it */ + } + if (fdebug && (PefRecord.rec_id != idx)) { + /* memcpy from pef_defaults or pef_array clobbered rec_id */ + printf("Warning: SetPef idx=%d, rec_id=%d\n",idx,PefRecord.rec_id); + PefRecord.rec_id = (uchar)idx; /*fix it*/ + } + if (fdisable) { + /* Disable all PEF rules */ + if (idx >= pefnum) PefRecord.fconfig = 0x00; /*disabled, software*/ + else PefRecord.fconfig = 0x40; /*disabled, preset */ + PefRecord.action = 0x00; + PefRecord.policy = 0x00; + } else { /*fenable*/ + if (PefRecord.sensor_type != 0) { /* not an empty PEF entry */ + /* Enable all non-empty PEF rules */ + if (fCustomPEF && (idx == (pefnum+pefadd))) { + PefRecord.action = custPEF[0]; + PefRecord.policy = custPEF[1]; + } else { + PefRecord.action = 0x01; /*Alert*/ + PefRecord.policy = 0x01; /*see Alert Policy #1*/ + } + if (idx < pefnum) { /* special handling for presets, 1 thru 11 */ + PefRecord.fconfig = 0x80; /* enabled, software */ + ret = SetPefEntry(&PefRecord); + if (fdebug) + printf("SetPefEntry(%d/80) ret=%d\n",PefRecord.rec_id,ret); + // if (ret != 0) { nerrs++; lasterr = ret; } + // else ngood++; + PefRecord.fconfig = 0xC0; /* enabled, preset */ + } else { + PefRecord.fconfig = 0x80; /* enabled, software */ + } + } /*endif not empty*/ + } + { // Show the new PEF record before setting it. + pc = (uchar *)&PefRecord; + sz = 21; + printf("PEFilter(%d): ",PefRecord.rec_id); + for (i = 0; i < sz; i++) printf("%02x ",pc[i]); + printf("\n"); + } + ret = SetPefEntry(&PefRecord); + if (fdebug) + printf("SetPefEntry(%d) ret = %d\n", PefRecord.rec_id,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } /*end for*/ + } + } /*end if not fIPMI10*/ + + if (!fcanonical) + printf("\n%s, GetLanEntry for channel %d ...\n",progname,lan_ch); + idest = 1; + for (idx = 0; idx < NLAN; idx++) + { + int ival; + if (fcanonical && (canon_param[idx] == 0)) continue; + if (idx == 8 || idx == 9) continue; /* not implemented */ + ival = lanparams[idx].cmd; + if (ival >= 96 && ival <= 98) continue; /* not implemented */ + if (ival >= 102 && ival <= 108) { /*custom IPv6 parameters*/ + if (fipv6 == 0) continue; /*skip these*/ + } + if (ival == 194 && vend_id == VENDOR_KONTRON) { /*oem hostname parm*/ + lanparams[idx].sz = 36; + strcpy(lanparams[idx].desc,"IPMI Hostname"); + } else if (ival >= 192 && ival <= 194) { /*custom DHCP parameters*/ + if (vend_id != VENDOR_INTEL) continue; + if (fmBMC || fiBMC || fcanonical) continue; /*skip these*/ + } + if (ival >= 20 && ival <= 25) { + if (!fIPMI20) continue; /*VLAN params 20-25, fIPMI20 only/opt*/ + } + if ((ndest == 0) && (ival >= 18 && ival <= 19)) continue; /*skip dest*/ + if (ival == 11) { /*grat arp interval*/ + if (vend_id == VENDOR_SUPERMICROX) continue; + if (vend_id == VENDOR_SUPERMICRO) continue; + } + if (ival == 14 || ival == 15) { /*secondary gateway is optional*/ + if (vend_id == VENDOR_KONTRON) continue; + } + if (ival == 201) { /*Get Channel Access*/ + ret = ShowChanAcc(lan_ch); + } else { + if (ival == 18 || ival == 19) { /*dest params*/ + if (ndest == 0) continue; /*skip if ndest==0 */ + bset = (uchar)idest; /* dest id = 1 thru n */ + } else bset = 0; + ret = GetLanEntry((uchar)ival, bset, &LanRecord); + } + if (ret == 0) { // Show the LAN record + pc = (uchar *)&LanRecord; + sz = lanparams[idx].sz; + if (ival == 18) { /*skip if invalid dest type param*/ + if ((idest > 1) && (pc[2] == 0)) { idest = 1; continue; } + } else if (ival == 19) { /*skip if invalid dest addr param*/ + if ((idest > 1) && !IpIsValid(&pc[3])) { idest = 1; continue; } + } + if (ival == 201) ; /* did it above */ + else { + if (fcanonical) { + if ((ival == 19) && (idest > 1)) ; /*skip it*/ + else { + j = strlen_(lanparams[idx].desc); + // (ival < 7) || (ival == 19) || ival == 102) + if (j <= 12) pstr = pspace3; + else pstr = pspace2; + printf("Channel %d %s %s%c ",lan_ch, + lanparams[idx].desc,pstr,bdelim); + } + } else + printf("Lan Param(%d) %s: ",ival,lanparams[idx].desc); + } + if (ival == 1) { + authmask = pc[0]; /* auth type support mask */ + /* if (fmBMC) authmask is usually 0x15, else 0x14 */ + } else if (ival == 3) { + if (IpIsValid(pc)) memcpy(bmcmyip,pc,4); + } else if (ival == 5) { + if (MacIsValid(pc)) memcpy(bmcmymac,pc,MAC_LEN); + } else if (ival == 6) { + if (SubnetIsValid(pc)) memcpy(bmcsubnet,pc,4); + /* else if invalid, leave default as 255.255.255.0 */ + //} else if (ival == 7) { + // if (pc[0] >= 30) memcpy(bparm7,pc,3); + } else if (ival == 17) { /* num dest */ + ndest = pc[0]; /* save the number of destinations */ + } else if (ival == 19) { /* dest addr */ + if (IpIsValid(&pc[3])) memcpy(bmcdestip,&pc[3],4); + if (MacIsValid(&pc[7])) memcpy(bmcdestmac,&pc[7],MAC_LEN); + } else if (ival == 22) { /*Cipher Suite Support*/ + nciphers = pc[0]; + } + /* now start to display data */ + if (ival == 16) { printf("%s \n",pc); /* string */ + } else if (ival == 194 && vend_id == VENDOR_KONTRON) { + printf("%s \n",pc); /* string */ + } else if (ival == 201) { ; /* did it above */ + } else { /* print results for all other ival's */ + pstr = ""; /*interpreted meaning*/ + if (fcanonical) { + switch(ival) { + case 4: /*param 4, ip src*/ + if (pc[0] == SRC_STATIC) pstr = "Static"; /*0x01*/ + else if (pc[0] == SRC_DHCP) pstr = "DHCP"; /*0x02*/ + else if (pc[0] == SRC_BIOS) pstr = "BIOS"; /*0x03*/ + else pstr = "Other"; + printf("%s\n",pstr); + break; + case 5: /*param 5, mac addr*/ + case 13: /*param 6, def gwy mac*/ + printf("%02x:%02x:%02x:%02x:%02x:%02x\n", + pc[0], pc[1], pc[2], pc[3], pc[4], pc[5]); + break; + case 3: /*param 4, ip address*/ + case 6: /*param 6, subnet mask*/ + case 12: /*param 12, def gwy ip*/ + case 14: /*param 14, sec gwy ip*/ + case 192: /*param 192, DHCP svr ip*/ + printf("%d.%d.%d.%d\n",pc[0], pc[1], pc[2], pc[3]); + break; + case 19: /*param 19, dest address*/ + if (idest == 1) { + printf("IP=%d.%d.%d.%d " + "MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + pc[3], pc[4], pc[5], pc[6], + pc[7], pc[8], pc[9], pc[10], pc[11], pc[12]); + } + break; + case 102: /*param 102, IPv6 enable*/ + if (pc[0] == 0x01) printf("enabled\n"); + else printf("disabled\n"); + break; + default: + printf("%02x \n",pc[0]); + break; + } + } else { /*not canonical */ + if (ival == 3 || ival == 6 || ival == 12 || ival == 14 + || ival == 192) { + printf("%d.%d.%d.%d",pc[0], pc[1], pc[2], pc[3]); + } else if (ival == 23) { /*Cipher Suites*/ + for (i = 1; i <= nciphers; i++) printf("%2d ",pc[i]); + } else if (ival == 24) { /*Cipher Suite Privi Levels*/ + for (i = 1; i < 9; i++) { + char c1, c2; + char *p; + p = parse_priv((pc[i] & 0x0f)); + c1 = p[0]; + p = parse_priv((pc[i] & 0xf0) >> 4); + c2 = p[0]; + if ((i*2) >= nciphers) c2 = ' '; + printf(" %c %c ",c1,c2); + if ((i*2) > nciphers) break; + } + } else + for (i = 0; i < sz; i++) + { + /* print in hex, decimal, or string, based on ival */ + if (ival == 1) { /* Auth type support */ + pstr = &mystr[0]; + getauthstr(authmask,pstr); + printf("%02x ",authmask); + } else if (ival == 4) { /* IP addr source */ + if (pc[i] == SRC_STATIC) pstr = "Static"; /*0x01*/ + else if (pc[i] == SRC_DHCP) pstr = "DHCP"; /*0x02*/ + else if (pc[i] == SRC_BIOS) pstr = "BIOS"; /*0x03*/ + else pstr = "Other"; + printf("%02x ",pc[i]); + } else if (ival == 10) { /* grat ARP */ + mystr[0] = 0; + if (pc[i] == 0) strcat(mystr,"ARP disabled "); + else if (pc[i] & 0x01) strcat(mystr,"Grat-ARP enabled"); + else strcat(mystr,"Grat-ARP disabled"); + if (pc[i] & 0x02) strcat(mystr,", ARP-resp enabled"); + pstr = &mystr[0]; + printf("%02x ",pc[i]); + } else if (ival == 11) { /* grat ARP interval */ + float f; + f = (float)pc[i] / (float)2; /*500msec increments*/ + sprintf(mystr,"%.1f sec",f); + pstr = &mystr[0]; + printf("%02x ",pc[i]); + } else if (ival == 19) { /* dest addr */ + if (i > 2 && i < 7) { + char *sepstr; + if (i == 3) printf("["); + if (i == 6) sepstr = "] "; + else if (i >=3 && i < 6) sepstr = "."; + else sepstr = " "; + printf("%d%s",pc[i],sepstr); /* IP address in dec */ + } + else printf("%02x ",pc[i]); /* show mac/etc. in hex */ + } + else printf("%02x ",pc[i]); /* show in hex */ + } /*end for*/ + if (ival == 2) { /*Auth type enables*/ + pstr = &mystr[0]; + i = 0; + if (lan_ch > 0) i = lan_ch - 1; + getauthstr(pc[i],pstr); + } + if (pstr[0] != 0) printf(": %s\n",pstr); + else printf("\n"); + } /*end-else not canonical*/ + } /*end-else others*/ + if (ival == 18 || ival == 19) { + if (idest < ndest) { + idest++; + idx--; /* repeat this param*/ + } else idest = 1; + } + } else { /* ret != 0 */ + if (ival >= 20 && ival <= 25) { /*if errors, optional*/ + if (fdebug) printf("GetLanEntry(%d), ret = %d\n",ival,ret); + } else + printf("GetLanEntry(%d), ret = %d\n",ival,ret); + if (ival == 17) ndest = 0; /*error getting num dest*/ + } + } /*end for*/ + if (fRomley) { /*get LAN Failover param*/ + uchar b; + ret = lan_failover_intel(0xFF,(uchar *)&b); + if (ret != 0) + printf("Intel Lan Failover, ret = %d\n",ret); + else { + if (b == 1) pstr = "enabled"; + else pstr = "disabled"; + if (fcanonical) + printf("Intel Lan Failover %s%c %s\n", + pspace3, bdelim,pstr); + else printf("Intel Lan Failover %s%c %02x %c %s\n", + pspace2, bdelim,b,bdelim,pstr); + } + } + if (vend_id == VENDOR_SUPERMICROX || vend_id == VENDOR_SUPERMICRO) { + ret = oem_supermicro_get_lan_port(&bset); + if (ret == 0) { + pstr = oem_supermicro_lan_port_string(bset); + if (fcanonical) + printf("SuperMicro Lan Interface %s%c %s\n", + pspace2, bdelim,pstr); + else printf("SuperMicro Lan Interface %c %02x %c %s\n", + bdelim,bset,bdelim,pstr); + } else { + if (fdebug) printf("oem_supermicro_get_lan_port error %d\n",ret); + ret = 0; /*may not be supported on all smc plaforms*/ + } + } + // if (fmBMC) lan_access = 0x04; /*Admin*/ + // else lan_access = 0x04; /*Admin*/ + if (!fIPMI10) { /* Get SOL params */ + ret = GetSerialOverLan(lan_ch,0,0); + if (ret != 0) printf("GetSOL error %d\n",ret); + } + for (i = 1; i <= show_users; i++) + GetUser((uchar)i); + + if (fgetser && !fcanonical) { + printf("\n%s, GetSerEntry ...\n",progname); + if (fmBMC) /* mBMC doesn't support serial */ + printf("No serial channel support on this platform\n"); + else + for (idx = 0; idx < NSER; idx++) { + int ival; + // if (idx == 9) continue; /* not implemented */ + ival = serparams[idx].cmd; + if (ival == 201) { + ret = GetChanAcc(ser_ch, 0x40, &LanRecord); + } else { + ret = GetSerEntry((uchar)ival, &LanRecord); + } + if (ret == 0) { // Show the SER record + pc = (uchar *)&LanRecord; + sz = serparams[idx].sz; + printf("Serial Param(%d) %s: ",ival,serparams[idx].desc); + if (idx == 10) { /* modem init string */ + pc[sz] = 0; + printf("%02x %s\n",pc[0],&pc[1]); + } + else if ((idx >= 11 && idx <= 13) || idx == 15) { /* strings */ + printf("%s\n",pc); + } + else { + for (i = 0; i < sz; i++) { + printf("%02x ",pc[i]); /* show in hex */ + } + printf("\n"); + } /*end else*/ + } + } /*end for*/ + } /*endif fgetser*/ + + if (!freadonly) /* Set IPMI LAN enable/disable params. */ + { + if (fipmilan) /* Sets not valid via ipmi_lan if same channel. */ + printf("\nWarning: Setting LAN %d params while using a LAN channel.\n", lan_ch); + + { + if (fenable && (fsharedMAC==0) && !lan_dhcp) { + /* must have an IP from -I option */ + if (!IpIsValid(rgmyip)) { /* if not user-specified */ + if (IpIsValid(bmcmyip)) { + memcpy(rgmyip,bmcmyip,4); + if (fdebug) printf("Using current IP %d.%d.%d.%d\n", + bmcmyip[0], bmcmyip[1], + bmcmyip[2], bmcmyip[3]); + } else { + printf("\nNot shared BMC LAN, must specify a unique " + "IP address via -I\n"); + ret = ERR_BAD_PARAM; + goto do_exit; + } + } + } + /* Set LAN parameters. fenable or fdisable */ + printf("\n%s, SetLanEntry for channel %d ...\n",progname,lan_ch); + /* use ifname to resolve MAC addresses below */ + if (fdisable) { + if (!fIPMI10) { + ret = DisablePef(alertnum); + printf("DisablePef, ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + if (lan_user != 0) { + j = DisableUser(lan_user); /*disable this lan user*/ + printf("DisableUser(%d), ret = %d\n",lan_user,j); + if (j != 0) { nerrs++; lasterr = j; } + else ngood++; + } + LanRecord.data[0] = 0x01; /* static IP address source */ + ret = SetLanEntry(4, &LanRecord, 1); + printf("SetLanEntry(4), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + /* clear the BMC IP address */ + memset(&LanRecord,0,4); + ret = SetLanEntry(3, &LanRecord, 4); + printf("SetLanEntry(3), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + /* clear the gateway IP address */ + memset(&LanRecord,0,4); + ret = SetLanEntry(12, &LanRecord, 4); + printf("SetLanEntry(12), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + /* clear the gateway MAC address */ + memset(&LanRecord,0,6); + ret = SetLanEntry(13, &LanRecord, 6); + printf("SetLanEntry(13), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } else if (fdisableSOL) { + ret = SetupSerialOverLan(0); /*disable*/ + SELprintf("SetupSerialOverLan: ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } else { /*fenable*/ + uchar chanctl; + if (bmcpefctl != 0) chanctl = chan_pefon; /*previously on*/ + else chanctl = chan_pefoff; + ret = SetChanAcc(lan_ch, 0x80, chanctl); + if (fdebug) printf("SetChanAcc(lan/active), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + ret = SetChanAcc(lan_ch, 0x40, chanctl); + if (fdebug) printf("SetChanAcc(lan/nonvol), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + ret = SetUser(lan_user,myuser,passwordData); + printf("SetUser(%d), ret = %d\n",lan_user,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + if (fdisable && (vend_id == VENDOR_SUPERMICROX + || vend_id == VENDOR_SUPERMICRO) ) { + failover_enable = 0; /*dedicated*/ + ret = oem_supermicro_set_lan_port(failover_enable); + printf("Set SuperMicro Lan port to %s, ret = %d\n", + oem_supermicro_lan_port_string(failover_enable),ret); + if (ret != 0) { nerrs++; lasterr = ret; } + } + + if (fdisable || fdisableSOL) { + // if (nerrs > 0) printf("Warning: %d errors occurred\n",nerrs); + goto do_exit; + } + + if (authmask == 0) authmask = 0x17; /*if none from GetLanEntry(1)*/ + LanRecord.data[0] = (bAuth & authmask); /*Callback level*/ + LanRecord.data[1] = (bAuth & authmask); /*User level */ + LanRecord.data[2] = (bAuth & authmask); /*Operator level*/ + LanRecord.data[3] = (bAuth & authmask); /*Admin level */ + LanRecord.data[4] = 0; /*OEM level*/ + if (fdebug) printf("SetLanEntry(2): %02x %02x %02x %02x %02x\n", + LanRecord.data[0],LanRecord.data[1],LanRecord.data[2], + LanRecord.data[3],LanRecord.data[4]); + ret = SetLanEntry(2, &LanRecord, 5); + printf("SetLanEntry(2), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + + /* Get the values to use from Linux eth0, etc. */ + ret = Get_IPMac_Addr(); + if (lan_dhcp) { /* use DHCP */ + LanRecord.data[0] = SRC_DHCP; /* BMC running DHCP */ + /* = SRC_BIOS; * address source = BIOS using DHCP */ + ret = SetLanEntry(4, &LanRecord, 1); + printf("SetLanEntry(4), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + if (MacIsValid(rgmymac)) { + memcpy(&LanRecord,rgmymac,6); + ret = SetLanEntry(5, &LanRecord, 6); + if (ret == 0x82) { /*BMC may not allow the MAC to be set*/ + if (fdebug) + printf("SetLanEntry(5), ret = %x cannot modify MAC\n",ret); + } else { + printf("SetLanEntry(5), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + + /* DHCP also relates to OEM LAN params 192, 193, 194 */ + if ((vend_id == VENDOR_INTEL) && !fmBMC && !fiBMC) + { /*DHCP params 192-194 are Intel only*/ + if (IpIsValid(rgmyip)) + { + /* Set DHCP Server IP in param 192 from -I param. */ + memcpy(&LanRecord,rgmyip,4); + ret = SetLanEntry(192, &LanRecord, 4); + printf("SetLanEntry(192), ret = %d\n",ret); + if (!MacIsValid(rgdhcpmac)) /* if MAC not set yet */ + ret = Get_Mac(rgmyip,rgdhcpmac,NULL); + if (ret == 0) { + memcpy(&LanRecord,rgdhcpmac,MAC_LEN); + ret = SetLanEntry(193, &LanRecord, MAC_LEN); + printf("SetLanEntry(193), ret = %d\n",ret); + } + } + LanRecord.data[0] = 0x01; /*enable DHCP*/ + ret = SetLanEntry(194, &LanRecord, 1); + printf("SetLanEntry(194), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else { /* use static IP */ + printf("LAN%d (%s)\tip=%d.%d.%d.%d mac=%02x:%02x:%02x:%02x:%02x:%02x\n", + lan_ch,ifname, rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3], + rgmymac[0], rgmymac[1], rgmymac[2], rgmymac[3], + rgmymac[4], rgmymac[5]); + if (IpIsValid(rgmyip)) { + if (lan_ch != gcm_ch) { /*skip if gcm*/ + LanRecord.data[0] = 0x00; /*disable grat arp while setting IP*/ + ret = SetLanEntry(10, &LanRecord, 1); + if (fdebug) printf("SetLanEntry(10,0), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + } + LanRecord.data[0] = 0x01; /* static IP address source */ + ret = SetLanEntry(4, &LanRecord, 1); + printf("SetLanEntry(4), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + memcpy(&LanRecord,rgmyip,4); + ret = SetLanEntry(3, &LanRecord, 4); + printf("SetLanEntry(3), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + if (MacIsValid(rgmymac)) { + memcpy(&LanRecord,rgmymac,6); + ret = SetLanEntry(5, &LanRecord, 6); + if (ret == 0x82) { + /* Do not show anything, not an error if BMC does not + allow the BMC MAC to be changed. */ + if (fdebug) + printf("SetLanEntry(5), ret = %x cannot modify MAC\n",ret); + } else { + printf("SetLanEntry(5), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + if (!SubnetIsValid(rgsubnet)) /* not specified, use previous */ + memcpy(rgsubnet,bmcsubnet,4); + memcpy(&LanRecord,rgsubnet,4); + ret = SetLanEntry(6, &LanRecord, 4); + printf("SetLanEntry(6), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + if (vend_id != VENDOR_PEPPERCON) { + /* may want to check bparm7 here */ + LanRecord.data[0] = parm7[0]; /*IPv4 header, TTL */ + LanRecord.data[1] = parm7[1]; /*IPv4 header, Flags */ + LanRecord.data[2] = parm7[2]; /*IPv4 hdr, Precedence/Service */ + ret = SetLanEntry(7, &LanRecord, 3); + printf("SetLanEntry(7), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + /* if lan_ch == 3, gcm gets error setting grat arp (ccode=0xCD) */ + if (lan_ch != gcm_ch) { /*skip if gcm*/ + /* 01=enable grat arp, 02=enable arp resp, 03=both */ + LanRecord.data[0] = arp_ctl; /*grat arp*/ + ret = SetLanEntry(10, &LanRecord, 1); + printf("SetLanEntry(10,%x), ret = %d\n",arp_ctl,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + LanRecord.data[0] = arp_interval; /*grat arp interval*/ + ret = SetLanEntry(11, &LanRecord, 1); + printf("SetLanEntry(11), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + if ((vend_id == VENDOR_INTEL) && !fmBMC && !fiBMC) { + LanRecord.data[0] = 0x00; /*disable DHCP*/ + ret = SetLanEntry(194, &LanRecord, 1); + printf("SetLanEntry(194), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else { /* error, don't continue */ + printf("Missing IP Address, can't continue. Use -I to specify\n"); + ret = ERR_BAD_PARAM; + goto do_exit; + } + if (vend_id == VENDOR_KONTRON && rghostname[0] != 0) { + /* set the IPMI Hostname if specified */ + sz = strlen_(rghostname); + /* LanRecord is larger than rghostname, bounds ok */ + strncpy((char *)&LanRecord.data,rghostname,sz); + ret = SetLanEntry(194, &LanRecord, sz); + printf("SetLanEntry(194), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else { + LanRecord.data[0] = 0x31; + ret = SetLanEntry(195, &LanRecord, 1); /*re-read hostname*/ + // printf("SetLanEntry(195), ret = %d\n",ret); + // if (ret != 0) { nerrs++; lasterr = ret; } + } + } + if (IpIsValid(rggwyip)) { + if (!MacIsValid(rggwymac)) /* if gwy MAC not set by user */ + ret = Get_Mac(rggwyip,rggwymac,NULL); + printf("gateway \tip=%d.%d.%d.%d mac=%02x:%02x:%02x:%02x:%02x:%02x\n", + rggwyip[0], rggwyip[1], rggwyip[2], rggwyip[3], + rggwymac[0], rggwymac[1], rggwymac[2], rggwymac[3], + rggwymac[4], rggwymac[5]); + if (!SubnetIsSame(rgmyip,rggwyip,rgsubnet)) + printf("WARNING: IP Address and Gateway are not on the same subnet.\n"); + + /* Set the Default Gateway IP & MAC */ + memcpy(&LanRecord,rggwyip,4); + ret = SetLanEntry(12, &LanRecord, 4); + printf("SetLanEntry(12), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + if (!MacIsValid(rggwymac)) { /* if gwy MAC not resolved */ + printf(" Warning: Gateway MAC address was not resolved! " + "Check %s interface, use -i ethN, or use -H gwymac.\n", + ifname); + } else { + memcpy(&LanRecord,rggwymac,6); + ret = SetLanEntry(13, &LanRecord, 6); + printf("SetLanEntry(13), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + if (IpIsValid(rggwy2ip)) { + if (!MacIsValid(rggwy2mac)) /* if gwy2 MAC not set by user */ + ret = Get_Mac(rggwy2ip,rggwy2mac,NULL); + /* Set the Secondary Gateway IP & MAC */ + memcpy(&LanRecord,rggwy2ip,4); + ret = SetLanEntry(14, &LanRecord, 4); + printf("SetLanEntry(14), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + memcpy(&LanRecord,rggwy2mac,6); + ret = SetLanEntry(15, &LanRecord, 6); + printf("SetLanEntry(15), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } /* end-else static IP */ + ret = SetupSerialOverLan(1); /*enable*/ + SELprintf("SetupSerialOverLan: ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + if (!IpIsValid(rgdestip) && IpIsValid(bmcdestip)) { + memcpy(rgdestip,bmcdestip,4); + if (fdebug) printf("Using current dest IP %d.%d.%d.%d\n", + bmcdestip[0], bmcdestip[1], + bmcdestip[2], bmcdestip[3]); + } + if (ndest == 0) { + if (fdebug) printf("ndest==0, anum=%d rgdestip=%d.%d.%d.%d\n", + alertnum, rgdestip[0], rgdestip[1], rgdestip[2], rgdestip[3]); + printf("alert dest \tnot supported\n"); + } else if (!IpIsValid(rgdestip)) { + printf("alert dest \taddress not specified\n"); + } else { /* valid alert dest ip */ + if (!MacIsValid(rgdestmac)) /* if dest MAC not set by user */ + ret = Get_Mac(rgdestip,rgdestmac,NULL); /*try to resolve MAC */ + if (!MacIsValid(rgdestmac)) { /* if dest MAC not resolved */ + printf(" Warning: Alert mac address was not resolved!" + " Check %s interface or use -i.\n",ifname); + /* use existing BMC alert dest mac (as best guess) */ + memcpy(rgdestmac,bmcdestmac,6); + } + /* show destination data */ + printf("alert dest %d\tip=%d.%d.%d.%d mac=%02x:%02x:%02x:%02x:%02x:%02x\n", + alertnum, rgdestip[0], rgdestip[1], rgdestip[2], rgdestip[3], + rgdestmac[0], rgdestmac[1], rgdestmac[2], rgdestmac[3], + rgdestmac[4], rgdestmac[5]); + printf("snmp community \t%s\n",rgcommunity); + /* Only need the SNMP community if there is an Alert Destination */ + memset(&LanRecord.data[0], 0, 18); /* make sure zero-filled */ + strcpy(&LanRecord.data[0],rgcommunity); + ret = SetLanEntry(16, &LanRecord, 18); + printf("SetLanEntry(16), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + /* Set Alert Destination Type */ + LanRecord.data[0] = alertnum; /* dest id = 1 */ + LanRecord.data[1] = 0x00; /* dest type = PET, no ack */ + LanRecord.data[2] = 0x01; /* ack timeout / retry interval */ + LanRecord.data[3] = 0x00; /* no retries */ + // LanRecord.data[4] = 0x69; + ret = SetLanEntry(18, &LanRecord, 4); + printf("SetLanEntry(18), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + { + /* Set the Alert Destination IP & MAC (param 19) */ + LanRecord.data[0] = alertnum; /* dest id = 1 */ + LanRecord.data[1] = 0x00; + LanRecord.data[2] = 0x00; + memcpy(&LanRecord.data[3],rgdestip,4); + memcpy(&LanRecord.data[7],rgdestmac,6); + ret = SetLanEntry(19, &LanRecord, 13); + printf("SetLanEntry(19), ret = %d\n", ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } /*endif valid alert*/ + + /* Now enable PEF since we have an Alert destination. */ + if (!fdisable && !fIPMI10 && fpefenable) { /*fpefenable*/ + ret = EnablePef(alertnum); + printf("EnablePef, ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + /* ChanAcc changed, so show it again */ + j = ShowChanAcc(lan_ch); + } + + if ((vlan_enable != PARM_INIT) && (fIPMI20)) { + if (vlan_enable == 0) { /*disable vlan*/ + LanRecord.data[0] = 0x00; + LanRecord.data[1] = 0x00; + ret = SetLanEntry(20, &LanRecord, 2); + printf("SetLanEntry(20,disable) ret = %d\n", ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } else { /*vlan_enable == 1, enable vlan with id */ + LanRecord.data[0] = (vlan_id & 0x00ff); + LanRecord.data[1] = ((vlan_id & 0x0f00) >> 8) | 0x80; + ret = SetLanEntry(20, &LanRecord, 2); + printf("SetLanEntry(20,%d), ret = %d\n", vlan_id,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + LanRecord.data[0] = vlan_prio; + ret = SetLanEntry(21, &LanRecord, 1); + printf("SetLanEntry(21), ret = %d\n", ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + if (failover_enable != PARM_INIT) { + if (fRomley) { + if (failover_enable > 1) failover_enable = 0; /*default*/ + ret = lan_failover_intel(failover_enable,(uchar *)&i); + printf("Set Intel Lan Failover (%d), ret = %d\n", + failover_enable,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + } else if (vend_id == VENDOR_SUPERMICROX + || vend_id == VENDOR_SUPERMICRO) { + if (failover_enable > 2) failover_enable = 2; /*default*/ + ret = oem_supermicro_set_lan_port(failover_enable); + printf("Set SuperMicro Lan port to %s, ret = %d\n", + oem_supermicro_lan_port_string(failover_enable),ret); + if (ret != 0) { nerrs++; lasterr = ret; } + } + } /*endif failover specified*/ + } /*end-else not via ipmi_lan*/ + } /*endif not readonly*/ + + if (flanstats) + { /* get BMC LAN Statistics */ +#ifdef METACOMMAND + j = get_lan_stats(lan_ch); +#else + uchar idata[2]; + uchar rdata[20]; + int rlen; + uchar cc; + idata[0] = lan_ch; + idata[1] = 0x00; /*do not clear stats*/ + rlen = sizeof(rdata); + j = ipmi_cmd(GET_LAN_STATS, idata,2, rdata,&rlen, &cc, fdebug); + if (j == 0) { /*show BMC LAN stats*/ + ushort *rw; + rw = (ushort *)&rdata[0]; + printf("IPMI LAN channel %d statistics: \n",lan_ch); + printf(" \tReceived IP Packets = %d\n",rw[0]); + printf(" \tRecvd IP Header errors = %d\n",rw[1]); + printf(" \tRecvd IP Address errors = %d\n",rw[2]); + printf(" \tRecvd IP Fragments = %d\n",rw[3]); + printf(" \tTransmitted IP Packets = %d\n",rw[4]); + printf(" \tReceived UDP Packets = %d\n",rw[5]); + printf(" \tReceived Valid RMCP Pkts = %d\n",rw[6]); + printf(" \tReceived UDP Proxy Pkts = %d\n",rw[7]); + printf(" \tDropped UDP Proxy Pkts = %d\n",rw[8]); + } +#endif + } + +do_exit: + ipmi_close_(); + if (foptmsg) { + if (fset_ip != 0) + printf("WARNING: IP address options were specified, but no -e,-l,-d option.\n"); + else + printf("WARNING: %d options were specified, but no -e,-l,-d option.\n", + nopts); + printf("Read-only usage assumed.\n"); + } + if (nerrs > 0) { + printf("Warning: %d ok, %d errors occurred, last error = %d\n",ngood,nerrs,lasterr); + ret = lasterr; + } + // show_outcome(progname,ret); + return(ret); +} /* end main()*/ + +/* end ilan.c */ diff --git a/util/imb_api.h b/util/imb_api.h new file mode 100644 index 0000000..56a940c --- /dev/null +++ b/util/imb_api.h @@ -0,0 +1,708 @@ +/*M* +// PVCS: +// $Workfile: imb_api.h $ +// $Revision: 1.0 $ +// $Modtime: Jul 22 2002 16:40:32 $ +// $Author: arcress at users.sf.net $ +// +// Combined include files needed for imbapi.c +// + *M*/ +/*----------------------------------------------------------------------* +The BSD License +Copyright (c) 2002, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ +#ifndef _WINDEFS_H +#define _WINDEFS_H + +#ifndef NULL +#define NULL 0 +#endif +#define TRUE 1 +#define FALSE 0 + +#if defined(WIN32) | defined(BSD) | defined(DOS) +/* WIN32 defines wchar_t in stdio.h */ +/* BSD defines wchar_t in stdlib.h */ +/* DOS defines wchar_t in stdlib.h */ +#else + // defined(LINUX) | defined(SOLARIS) +#ifndef _WCHAR_T +#define _WCHAR_T +typedef long wchar_t; +#endif +#endif + +#define far +#define near +#define FAR far +#define NEAR near +#ifndef CONST +#define CONST const +#endif +typedef unsigned int UINT32; +typedef unsigned long DWORD; +typedef int BOOL; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef float FLOAT; +typedef FLOAT *PFLOAT; +typedef BOOL near *PBOOL; +typedef BOOL far *LPBOOL; +typedef BYTE near *PBYTE; +typedef BYTE far *LPBYTE; +typedef int near *PINT; +typedef int far *LPINT; +typedef WORD near *PWORD; +typedef WORD far *LPWORD; +typedef long far *LPLONG; +typedef DWORD near *PDWORD; +typedef DWORD far *LPDWORD; +typedef void far *LPVOID; +typedef CONST void far *LPCVOID; +typedef int INT; +typedef unsigned int UINT; +typedef unsigned int *PUINT; +#ifndef NTSTATUS +typedef DWORD NTSTATUS; +#endif +/* + File structures +*/ +#ifndef WIN32 +typedef struct _OVERLAPPED { + DWORD Internal; + DWORD InternalHigh; + DWORD Offset; + DWORD OffsetHigh; +/* HANDLE hEvent; */ +} OVERLAPPED, *LPOVERLAPPED; +#endif +/* + * Data structure redefines + */ +typedef char CHAR; +typedef short SHORT; +typedef long LONG; +typedef char * PCHAR; +typedef short * PSHORT; +typedef long * PLONG; +typedef unsigned char UCHAR; +typedef unsigned short USHORT; +typedef unsigned long ULONG; +typedef char CCHAR; +typedef short CSHORT; +typedef ULONG CLONG; +typedef CCHAR * PCCHAR; +typedef CSHORT * PCSHORT; +typedef CLONG * PCLONG; +typedef void * PVOID; +#ifndef WIN32 +typedef void VOID; +typedef struct _LARGE_INTEGER { + ULONG LowPart; + LONG HighPart; +} LARGE_INTEGER; +typedef struct _ULARGE_INTEGER { + ULONG LowPart; + ULONG HighPart; +} ULARGE_INTEGER; +#endif +typedef LARGE_INTEGER * PLARGE_INTEGER; +typedef LARGE_INTEGER PHYSICAL_ADDRESS; +typedef LARGE_INTEGER * PPHYSICAL_ADDRESS; +typedef ULARGE_INTEGER * PULARGE_INTEGER; +typedef UCHAR BOOLEAN; +typedef BOOLEAN *PBOOLEAN; +typedef wchar_t WCHAR; +typedef WCHAR *PWCHAR, *PWSTR; +typedef CONST WCHAR *LPCWSTR, *PCWSTR; + +/* + Unicode strings are counted 16-bit character strings. If they are + NULL terminated, Length does not include trailing NULL. +*/ +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING; +typedef UNICODE_STRING *PUNICODE_STRING; +#define UNICODE_NULL ((WCHAR)0) /* winnt*/ +#define IN /* */ +#define OUT /* */ +#define OPTIONAL /* */ + +#ifdef WIN32 +#define HandleType HANDLE +#else +#define HandleType long +#define FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field)) +#define UNREFERENCED_PARAMETER(x) +#define INVALID_HANDLE_VALUE ((HandleType)-1) +#endif +typedef HandleType *PHANDLE; +/* + Define the method codes for how buffers are passed for I/O and FS controls +*/ +#define METHOD_BUFFERED 0 +/* + Define the access check value for any access + The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in + ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these + constants *MUST* always be in sync. +*/ +#define FILE_ANY_ACCESS 0 +/* + These are the generic rights. +*/ +#define MAX_PATH 260 +// #define GetLastError() (NTstatus.Status) +/* + Macro definition for defining IOCTL and FSCTL function control codes. Note + that function codes 0-2047 are reserved for Microsoft Corporation, and + 2048-4095 are reserved for customers. +*/ +/* + * Linux drivers expect ioctls defined using macros defined in ioctl.h. + * So, instead of using the CTL_CODE defined for NT and UW, I define CTL_CODE + * using these macros. That way imb_if.h, where the ioctls are defined get + * to use the correct ioctl command we expect. + * Notes: I am using the generic _IO macro instead of the more specific + * ones. The macros expect 8bit entities, so I am cleaning what is sent to + * us from imb_if.h - Mahendra + */ +#ifdef LINUX +#define CTL_CODE(DeviceType, Function, Method, Access)\ + _IO(DeviceType & 0x00FF, Function & 0x00FF) +#else +/* WIN32 may have this defined in winsdk\include\winioctl.h */ +#ifndef CTL_CODE +#define CTL_CODE( DeviceType, Function, Method, Access ) ((ULONG)( \ + ((ULONG)(DeviceType) << 16) | ((ULONG)(Access) << 14) | ((ULONG)(Function) << 2) | ((ULONG)Method) \ +)) +#endif +#endif +#endif /*_WINDEFS_H */ +/*----------------------------------------------------------------------*/ +#ifndef _SMI_H +#define _SMI_H +#define SMI_Version1_00 0x00001000 +#define SMI_Version2_00 0x00002000 +/* LPVOID = (void far *) */ +/* DWORD = (unsigned long ) */ +/* typedef DWORD far *LPDWORD; */ +/* LPOVERLAPPED = struct w 4 DWORDs */ +struct smi { + DWORD smi_VersionNo; + DWORD smi_Reserved1; + DWORD smi_Reserved2; + LPVOID ntstatus; /* address of NT status block*/ + LPVOID lpvInBuffer; /* address of buffer for input data*/ + DWORD cbInBuffer; /* size of input buffer*/ + LPVOID lpvOutBuffer; /* address of output buffer*/ + DWORD cbOutBuffer; /* size of output buffer*/ + LPDWORD lpcbBytesReturned; /* address of actual bytes of output*/ + LPOVERLAPPED lpoOverlapped; /* address of overlapped structure*/ +}; +struct smi32 { + UINT32 smi_VersionNo; + UINT32 smi_Reserved1; + UINT32 smi_Reserved2; + UINT32 ntstatus; /* address of NT status block*/ + UINT32 lpvInBuffer; /* address of buffer for input data*/ + UINT32 cbInBuffer; /* size of input buffer*/ + UINT32 lpvOutBuffer; /* address of output buffer*/ + UINT32 cbOutBuffer; /* size of output buffer*/ + UINT32 lpcbBytesReturned; /* address of actual bytes of output*/ + struct { UINT32 h[4]; } lpoOverlapped; /* address of overlapped structure*/ +}; +#ifndef STATUS_SUCCESS +typedef struct _IO_STATUS_BLOCK { + ULONG Status; + ULONG Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; +/* + * I2C ioctl's return NTStatus codes + */ +#define STATUS_SUCCESS (0x00000000U) +#define STATUS_UNSUCCESSFUL (0xC0000001U) +#define STATUS_DEVICE_BUSY (0x80000011U) +#ifndef WIN32 +// see <win2000ddk>\inc\winnt.h(1171) +#define STATUS_PENDING (0x00000103U) +#define STATUS_INVALID_PARAMETER (0xC000000DU) +#endif +#define STATUS_INVALID_DEVICE_REQUEST (0xC0000010U) +#define STATUS_BUFFER_TOO_SMALL (0xC0000023U) +#define STATUS_FILE_CLOSED (0xC0000128U) +#define STATUS_INSUFFICIENT_RESOURCES (0xC000009AU) +#define STATUS_NO_DATA_DETECTED (0x80000022U) +#define STATUS_NO_SUCH_DEVICE (0xC000000EU) +#define STATUS_ALLOTTED_EXCEEDED (0xC000000FU) +#define STATUS_IO_DEVICE_ERROR (0xC0000185U) +#define STATUS_TOO_MANY_OPEN_FILES (0xC000011FU) +#define STATUS_ACCESS_DENIED (0xC0000022U) +#define STATUS_BUFFER_OVERFLOW (0x80000005U) +#define STATUS_CANCELLED (0xC0000120U) +#endif /* STATUS_SUCCESS*/ +#endif /* _SMI_H*/ +/*----------------------------------------------------------------------*/ +#ifndef IMB_IF__ +#define IMB_IF__ +/* + * This is the structure passed in to the IOCTL_IMB_SHUTDOWN_CODE request + */ +typedef struct { + int code; + int delayTime; +} ShutdownCmdBuffer; +#define SD_NO_ACTION 0 +#define SD_RESET 1 +#define SD_POWER_OFF 2 + +#pragma pack(1) +/* + * This is the generic IMB packet format, the final checksum cant be + * represented in this structure and will show up as the last data byte + */ +typedef struct { + BYTE rsSa; + BYTE nfLn; + BYTE cSum1; + BYTE rqSa; + BYTE seqLn; + BYTE cmd; + BYTE data[1]; +} ImbPacket; +#define MIN_IMB_PACKET_SIZE 7 +#define MAX_IMB_PACKET_SIZE 57 /*was 33, now 64-7=57*/ +// #define MAX_IMB_PACKET_SIZE 135 (if using flashupdt large packets) +#define MAX_RBUFFER_SIZE 64 /*no longer used*/ +/* + * This is the standard IMB response format where the first byte of + * IMB packet data is interpreted as a command completion code. +*/ +typedef struct { + BYTE rsSa; + BYTE nfLn; + BYTE cSum1; + BYTE rqSa; + BYTE seqLn; + BYTE cmd; + BYTE cCode; + BYTE data[1]; +} ImbRespPacket; +#define MIN_IMB_RESPONSE_SIZE 7 /* min packet + completion code */ +#define MAX_IMB_RESPONSE_SIZE MAX_IMB_PACKET_SIZE +/************************ + * ImbRequestBuffer + ************************/ +/*D* +// Name: ImbRequestBuffer +// Purpose: Structure definition for holding IMB message data +// Context: Used by SendTimedImbpMessage and SendTimedI2cMessge +// functions in the library interface. In use, it is overlayed on a +// char buffer of size MIN_IMB_REQ_BUF_SIZE + +// Fields: +// respBufSize size of the response buffer +// +// timeout timeout value in milli seconds +// +// req body of request to send +// +*D*/ +typedef struct { + BYTE rsSa; + BYTE cmd; + BYTE netFn; + BYTE rsLun; + BYTE dataLength; + BYTE data[16]; +} ImbRequest; +typedef struct { + UINT32 flags; /* request flags*/ +#define NO_RESPONSE_EXPECTED 0x01 /*dont wait around for an IMB response*/ + UINT32 timeOut; /* in uSec units*/ + ImbRequest req; /* message buffer*/ +} ImbRequestBuffer; +#define MIN_IMB_REQ_BUF_SIZE 13 /* a buffer without any request data*/ +#define MAX_IMB_REQ_SIZE (MIN_IMB_RESP_BUF_SIZE + MAX_IMB_PACKET_SIZE) +/************************ + * ImbResponseBuffer + ************************/ +/*D* +// Name: ImbResponseBuffer +// Purpose: Structure definition for response of a previous send +// Context: Used by DeviceIoControl to pass the message to be sent to +// MISSMIC port +// Fields: +// cCode completion code returned by firmware +// data buffer for response data from firmware +*D*/ +typedef struct { + BYTE cCode; + BYTE data[1]; +} ImbResponseBuffer; +#define MIN_IMB_RESP_BUF_SIZE 1 +#define MAX_IMB_RESP_SIZE (MIN_IMB_RESP_BUF_SIZE + MAX_IMB_RESPONSE_SIZE) +#pragma pack() + +/* + * Async message access structures and types + */ +typedef UINT32 ImbAsyncSeq; +/* + * This is the structure passed in to IOCTL_IMB_GET_ASYNC_MSG +*/ +typedef struct { + UINT32 timeOut; + ImbAsyncSeq lastSeq; +} ImbAsyncRequest; +#define ASYNC_SEQ_START 0 +typedef struct { + ImbAsyncSeq thisSeq; + BYTE data[1]; +} ImbAsyncResponse; +#define MIN_ASYNC_RESP_SIZE sizeof( ImbAsyncSeq ) +#define MAX_ASYNC_RESP_SIZE (MIN_ASYNC_RESP_SIZE + MAX_IMB_PACKET_SIZE) +/* +** Driver Ioctls +** In Linux, these calculate to: +** IOCTL_IMB_SEND_MESSAGE =1082 +** IOCTL_IMB_GET_ASYNC_MSG =1088 +** IOCTL_IMB_MAP_MEMORY =108e +** IOCTL_IMB_UNMAP_MEMORY =1090 +** IOCTL_IMB_SHUTDOWN_CODE =1092 +** IOCTL_IMB_REGISTER_ASYNC_OBJ =1098 +** IOCTL_IMB_DEREGISTER_ASYNC_OBJ=109a +** IOCTL_IMB_CHECK_EVENT =109c +** IOCTL_IMB_POLL_ASYNC =1094 +*/ +#define FILE_DEVICE_IMB 0x00008010 +#define IOCTL_IMB_BASE 0x00000880 +#define IOCTL_IMB_SEND_MESSAGE CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 2), METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_GET_ASYNC_MSG CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 8), METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_MAP_MEMORY CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 14),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_UNMAP_MEMORY CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 16),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_SHUTDOWN_CODE CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 18),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_REGISTER_ASYNC_OBJ CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 24),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_DEREGISTER_ASYNC_OBJ CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 26),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_CHECK_EVENT CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 28),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_POLL_ASYNC CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 20),METHOD_BUFFERED, FILE_ANY_ACCESS) +#endif /* IMB_IF__ */ +/*----------------------------------------------------------------------*/ +/* No asynchronous messages available */ +#define IMB_MSG_NOT_AVAILABLE ((NTSTATUS)0xE0070012L) +#ifdef IMBLOG_H__ +/* Define the facility codes */ +#define FACILITY_RPC_STUBS 0x3 +#define FACILITY_RPC_RUNTIME 0x2 +#define FACILITY_IO_ERROR_CODE 0x4 +#define IMB_IO_ERROR_CODE 0x7 + +#define STATUS_SEVERITY_WARNING 0x2 +#define STATUS_SEVERITY_SUCCESS 0x0 +#define STATUS_SEVERITY_INFORMATIONAL 0x1 +#define STATUS_SEVERITY_ERROR 0x3 +/* Not enough memory for internal storage of device %1. */ +#define INSUFFICIENT_RESOURCES ((NTSTATUS)0xE0070001L) + +#define INVALID_INPUT_BUFFER ((NTSTATUS)0xE0070002L) + +#define INVALID_OUTPUT_BUFFER ((NTSTATUS)0xE0070003L) + +#define IMB_SEND_TIMEOUT ((NTSTATUS)0xE0070004L) + +#define IMB_RECEIVE_TIMEOUT ((NTSTATUS)0xE0070005L) + +#define IMB_IF_SEND_TIMEOUT ((NTSTATUS)0xE0070006L) + +#define IMB_IF_RECEIVE_TIMEOUT ((NTSTATUS)0xE0040007L) + +#define HARDWARE_FAILURE ((NTSTATUS)0xE0040008L) + +#define DRIVER_FAILURE ((NTSTATUS)0xE0040009L) + +#define IMB_INVALID_IF_RESPONSE ((NTSTATUS)0xE004000AL) + +#define IMB_INVALID_PACKET ((NTSTATUS)0xE004000BL) + +#define IMB_RESPONSE_DATA_OVERFLOW ((NTSTATUS)0xE004000CL) + +#define IMB_INVALID_REQUEST ((NTSTATUS)0xE007000DL) + +#define INVALID_DRIVER_IOCTL ((NTSTATUS)0xE007000EL) + +#define INVALID_DRIVER_REQUEST ((NTSTATUS)0xE007000FL) + +#define IMB_CANT_GET_SMS_BUFFER ((NTSTATUS)0xE0070010L) + +#define INPUT_BUFFER_TOO_SMALL ((NTSTATUS)0xE0070011L) + +#define IMB_SEND_ERROR ((NTSTATUS)0xE0070013L) +#endif /* IMBLOG_H__ */ +/*----------------------------------------------------------------------*/ +#ifndef IMBAPI_H__ +#define IMBAPI_H__ +#include <sys/types.h> +#if defined(MACOS) +/* has caddr_t */ +#else +#ifndef _SYS_TYPES_H +#ifndef _CADDR_T +#define _CADDR_T + typedef char * caddr_t; +#endif +#endif +#endif + +#define WRITE_READ_I2C 0x52 +#define WRITE_EMP_BUFFER 0x7a +#define GET_DEVICE_ID 0x1 +#define CMD_GET_DEVICE_ID 0x01 +#define SEND_MESSAGE 0x34 +#define GET_MESSAGE 0x33 +#define BMC_SA 0x20 +#define BMC_LUN 0 +#define APP_NETFN 0x06 +#define IPMI_09_VERSION 0x90 +#define IPMI_10_VERSION 0x01 + +#define IPMI_15_VERSION 0x51 + +#ifndef IPMI10_GET_DEVICE_ID_RESP_LENGTH +#define IPMI10_GET_DEVICE_ID_RESP_LENGTH 12 +#endif + +#define IPMB_CHANNEL 0x0 +#define EMP_CHANNEL 0x1 +#define LAN_CHANNEL 0x2 +#define ANY_CHANNEL 0xFF +#define RESERVED_LUN 0x3 +#define IPMB_LUN 0x2 +#define EMP_LUN 0x0 + +#define PUBLIC_BUS 0 + +#define BMC_CONTROLLER 0x20 +#define FPC_CONTROLLER 0x22 +typedef enum { + ACCESN_OK, + ACCESN_ERROR, + ACCESN_OUT_OF_RANGE, + ACCESN_END_OF_DATA, + ACCESN_UNSUPPORTED, + ACCESN_INVALID_TRANSACTION, + ACCESN_TIMED_OUT +} ACCESN_STATUS; +#pragma pack(1) +/* + * Request structure provided to SendTimedImbpRequest() +*/ +typedef struct { + unsigned char cmdType; + unsigned char rsSa; + unsigned char busType; + unsigned char netFn; + unsigned char rsLun; + unsigned char * data; + int dataLength; +} IMBPREQUESTDATA; +/* + * Request structure provided to SendTimedI2cRequest() +*/ +typedef struct { + unsigned char rsSa; + unsigned char busType; + unsigned char numberOfBytesToRead; + unsigned char * data; + int dataLength; +} I2CREQUESTDATA; +#pragma pack() +/*#ifdef IMB_API + * + * This section is provided to be able to compile using imb_if.h + * + * + * function return type. This is also defined in the local instrumentation + * so we ifdef here to avoid conflict. +*/ +#define METHOD_BUFFERED 0 +#define FILE_ANY_ACCESS 0 +/* + * This is necessary to compile using memIf.h + */ +typedef enum _INTERFACE_TYPE +{ + Internal, + Isa, + Eisa, + MicroChannel, + TurboChannel, + MaximumInterfaceType +} INTERFACE_TYPE, * PINTERFACE_TYPE; +#ifdef WIN32 +/* From memIf.h */ +#pragma pack(1) +typedef struct +{ + INTERFACE_TYPE InterfaceType; // Isa, Eisa, etc.... + ULONG BusNumber; // Bus number + PHYSICAL_ADDRESS BusAddress; // Bus-relative address + ULONG AddressSpace; // 0 is memory, 1 is I/O + ULONG Length; // Length of section to map +} PHYSICAL_MEMORY_INFO, * PPHYSICAL_MEMORY_INFO; +#pragma pack() +#endif +/*#else // not IMB_API */ +/* + * These are defined in imb_if.h but are needed by users of the imbapi library +*/ +#define ASYNC_SEQ_START 0 +/* + * This is the generic IMB packet format, the final checksum cant be + * represented in this structure and will show up as the last data byte + */ +/*#endif // IMB_API */ + +/****************************** + * FUNCTION PROTOTYPES + ******************************/ +#ifdef LINK_LANDESK +#define SendTimedImbpRequest ia_SendTimedImbpRequest +#define StartAsyncMesgPoll ia_StartAsyncMesgPoll +#define SendTimedI2cRequest ia_SendTimedI2cRequest +#define SendTimedEmpMessageResponse ia_SendTimedEmpMessageResponse +#define SendTimedEmpMessageResponse_Ex ia_SendTimedEmpMessageResponse_Ex +#define SendTimedLanMessageResponse ia_SendTimedLanMessageResponse +#define SendTimedLanMessageResponse_Ex ia_SendTimedLanMessageResponse_Ex +#define SendAsyncImbpRequest ia_SendAsyncImbpRequest +#define GetAsyncImbpMessage ia_GetAsyncImbpMessage +#define GetAsyncImbpMessage_Ex ia_GetAsyncImbpMessage_Ex +#define IsAsyncMessageAvailable ia_IsAsyncMessageAvailable +#define RegisterForImbAsyncMessageNotification ia_RegisterForImbAsyncMessageNotification +#define UnRegisterForImbAsyncMessageNotification ia_UnRegisterForImbAsyncMessageNotification +#define SetShutDownCode ia_SetShutDownCode +#define GetIpmiVersion ia_GetIpmiVersion +#else +int initIPMI(void); +int termIPMI(void); +#endif + +ACCESN_STATUS +SendTimedImbpRequest ( + IMBPREQUESTDATA *reqPtr, + int timeOut, + BYTE * respDataPtr, + int * respDataLen, + BYTE * completionCode + ); +ACCESN_STATUS +SendTimedI2cRequest ( + I2CREQUESTDATA *reqPtr, + int timeOut, + BYTE * respDataPtr, + int * respDataLen, + BYTE * completionCode + ); +ACCESN_STATUS +SendAsyncImbpRequest ( + IMBPREQUESTDATA *reqPtr, + BYTE * seqNo + ); +ACCESN_STATUS +GetAsyncImbpMessage ( + ImbPacket * msgPtr, + DWORD * msgLen, + DWORD timeOut, + ImbAsyncSeq * seqNo, + DWORD channelNumber + ); +ACCESN_STATUS +GetAsyncImbpMessage_Ex ( + ImbPacket * msgPtr, + DWORD * msgLen, + DWORD timeOut, + ImbAsyncSeq * seqNo, + DWORD channelNumber, + BYTE * sessionHandle, + BYTE * privilege + ); +ACCESN_STATUS +UnmapPhysicalMemory( int virtualAddress, int Length ); +ACCESN_STATUS +StartAsyncMesgPoll(void); +ACCESN_STATUS +MapPhysicalMemory ( + int startAddress, + int addressLength, + int *virtualAddress + ); +ACCESN_STATUS +SetShutDownCode ( + int delayTime, + int code + ); +ACCESN_STATUS +SendTimedEmpMessageResponse ( + ImbPacket * ptr, + char *responseDataBuf, + int responseDataLen, + int timeOut + ); +ACCESN_STATUS +SendTimedEmpMessageResponse_Ex ( + ImbPacket * ptr, + char *responseDataBuf, + int responseDataLen, + int timeOut, + BYTE sessionHandle, + BYTE channelNumber + ); +ACCESN_STATUS +SendTimedLanMessageResponse ( + ImbPacket * ptr, + char *responseDataBuf, + int responseDataLen, + int timeOut + ); +ACCESN_STATUS +SendTimedLanMessageResponse_Ex ( + ImbPacket * ptr, + char *responseDataBuf, + int responseDataLen, + int timeOut , + BYTE sessionHandle, + BYTE channelNumber + ); +ACCESN_STATUS +IsAsyncMessageAvailable (HandleType eventId); +ACCESN_STATUS +RegisterForImbAsyncMessageNotification (HandleType *handleId); +ACCESN_STATUS +UnRegisterForImbAsyncMessageNotification (HandleType handleId,int iFlag); +BYTE GetIpmiVersion(void); +#endif /* IMBAPI_H__ */ diff --git a/util/imbapi.c b/util/imbapi.c new file mode 100644 index 0000000..cbc8fa1 --- /dev/null +++ b/util/imbapi.c @@ -0,0 +1,2594 @@ +/*M* +// PVCS: +// $Workfile: imbapi.c $ +// $Revision: 1.12 $ +// $Modtime: 06 Aug 2001 13:16:56 $ +// +// Purpose: This file contains the entry point that opens the IMB device +// in order to issue the IMB driver API related IOCTLs. +// This file implements the IMB driver API for the Server +// Management Agents. +// +// $Log: //epg-scc/sst/projectdatabases/isc/isc3x/LNWORK/SRC/imbapi/imbapi.c.v $ +// +// 04/04/02 ARCress - Mods for open-source & various compile cleanup mods +// 05/28/02 ARCress - fixed buffer size error +// 04/08/03 ARCress - misc cleanup +// 01/20/04 ARCress - added WIN32 flags +// 05/24/05 ARCress - added LINK_LANDESK flags +// 08/24/06 ARCress - mods for addtl DEBUG (dbgmsg) +// 03/19/08 ARCress - fix for SendTimedLan(IpmiVersion) if IPMI 2.0 +*M*/ +/*----------------------------------------------------------------------* +The BSD License +Copyright (c) 2002-2006, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#if defined(SOLARIS) || defined(BSD) +#undef IMB_API +#else +/* Ok for WIN32, LINUX, SCO_UW, etc., but not Solaris */ +#define IMB_API 1 +#endif + +#ifdef IMB_API + +#ifdef WIN32 +#define NO_MACRO_ARGS 1 +#include <windows.h> +#include <stdio.h> +#define uint unsigned int + +#else /* LINUX, SCO_UW, UNIX */ +#include <unistd.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#endif +#include "imb_api.h" + +#ifdef SCO_UW +#define NO_MACRO_ARGS 1 +#define __FUNCTION__ "func" +#define IMB_DEVICE "/dev/instru/mismic" +#else +#define IMB_DEVICE "/dev/imb" +#define PAGESIZE EXEC_PAGESIZE +#endif + +/*Just to make the DEBUG code cleaner.*/ +#if defined(DBG_IPMI) || defined(LINUX_DEBUG) +#include <stdarg.h> +static void dbgmsg( char *pattn, ... ) +{ + va_list arglist; + FILE *fdlog; + + fdlog = fopen( "imbdbg.log", "a+" ); + if (fdlog == NULL) fdlog = stdout; + va_start( arglist, pattn ); + vfprintf( fdlog, pattn, arglist ); + va_end( arglist ); + fclose(fdlog); +} +#endif +#ifdef NO_MACRO_ARGS +#define DEBUG(format, args) /*not_debug*/ +#else +#ifdef LINUX_DEBUG +#define DEBUG(format, args...) dbgmsg(format, ##args) +// #define DEBUG(format, args...) printf(format, ##args) +#else +#define DEBUG(format, args...) /*not_debug*/ +#endif +#endif + +#define IMB_OPEN_TIMEOUT 400 +#define IMB_MAX_RETRIES 2 +#define IMB_DEFAULT_TIMEOUT (1000) /*timeout for SendTimedImb in msec*/ +#define ERR_NO_DRV -16 /*cannot open IPMI driver*/ + +#define LOCAL_IPMB 1 /*instead of METACOMMAND_IPMB*/ + +int ipmi_timeout_ia = IMB_DEFAULT_TIMEOUT; /* in msec */ +#ifdef METACOMMAND_IPMB /*++++ not used*/ +extern int ipmi_cmd_ipmb(BYTE cmd, BYTE netfn, BYTE sa, BYTE bus, BYTE lun, + BYTE *pdata, int sdata, BYTE *presp, + int *sresp, BYTE *pcc, char fdebugcmd); /*ipmilan.c*/ +#endif +#ifdef METACOMMAND +extern FILE *fpdbg; +extern FILE *fperr; +#else +static FILE *fpdbg = NULL; +static FILE *fperr = NULL; +#endif + +/* uncomment out the #define below or use -DLINUX_DEBUG_MAX in the makefile +// if you want a dump of the memory to debug mmap system call in +// MapPhysicalMemory() below. +// +//#define LINUX_DEBUG_MAX 1 */ +//#define IMB_MEMORY 1 */ + +/*keep it simple. use global varibles for event objects and handles +//pai 10/8 */ + +/* UnixWare should eventually have its own source code file. Right now +// new code has been added based on the existing policy of using +// pre-processor directives to separate os-specific code (pai 11/21) */ + +static int IpmiVersion; +static HandleType AsyncEventHandle = 0; +// static void * AsyncEventObject = 0; + +/*//////////////////////////////////////////////////////////////////////////// +// GLOBAL VARIABLES +///////////////////////////////////////////////////////////////////////////// */ + +#if defined(__i386__) || defined(__i586__) || defined(__i686__) +// static DWORD ioctl_sendmsg = 0x1082; /* force 0x1082 if 32-bit */ +static DWORD ioctl_sendmsg = IOCTL_IMB_SEND_MESSAGE; +#else +static DWORD ioctl_sendmsg = IOCTL_IMB_SEND_MESSAGE; +#endif + +static IO_STATUS_BLOCK NTstatus; /*dummy place holder. See deviceiocontrol. */ +static HandleType hDevice1; /*used in open_imb() */ +static HandleType hDevice; /*used to call DeviceIoControl()*/ +/*mutex_t deviceMutex; */ +#ifdef LINUX_DEBUG +static char fdebug = 1; +#else +static char fdebug = 0; +#endif + +#ifdef LINK_LANDESK +#define SendTimedImbpRequest ia_SendTimedImbpRequest +#define StartAsyncMesgPoll ia_StartAsyncMesgPoll +#define SendTimedI2cRequest ia_SendTimedI2cRequest +#define SendTimedEmpMessageResponse ia_SendTimedEmpMessageResponse +#define SendTimedEmpMessageResponse_Ex ia_SendTimedEmpMessageResponse_Ex +#define SendTimedLanMessageResponse ia_SendTimedLanMessageResponse +#define SendTimedLanMessageResponse_Ex ia_SendTimedLanMessageResponse_Ex +#define SendAsyncImbpRequest ia_SendAsyncImbpRequest +#define GetAsyncImbpMessage ia_GetAsyncImbpMessage +#define GetAsyncImbpMessage_Ex ia_GetAsyncImbpMessage_Ex +#define IsAsyncMessageAvailable ia_IsAsyncMessageAvailable +#define RegisterForImbAsyncMessageNotification ia_RegisterForImbAsyncMessageNotification +#define UnRegisterForImbAsyncMessageNotification ia_UnRegisterForImbAsyncMessageNotification +#define SetShutDownCode ia_SetShutDownCode +#define GetIpmiVersion ia_GetIpmiVersion +#endif + +int open_imb(int fskipcmd); + +void set_fps(void) +{ + if (fpdbg == NULL) fpdbg = stdout; + if (fperr == NULL) fperr = stdout; +} + +#ifndef WIN32 +DWORD GetLastError(void) { return(NTstatus.Status); } + +/*/////////////////////////////////////////////////////////////////////////// +// DeviceIoControl +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: DeviceIoControl +// Purpose: Simulate NT DeviceIoControl using unix calls and structures. +// Context: called for every NT DeviceIoControl +// Returns: FALSE for fail and TRUE for success. Same as standarad NTOS call +// as it also sets Ntstatus.status. +// Parameters: Standard NT call parameters, see below. +// Notes: none +*F*/ +static BOOL +DeviceIoControl( + HandleType dummy_hDevice, /* handle of device */ + DWORD dwIoControlCode, /* control code of operation to perform*/ + LPVOID lpvInBuffer, /* address of buffer for input data */ + DWORD cbInBuffer, /* size of input buffer */ + LPVOID lpvOutBuffer, /* address of output buffer */ + DWORD cbOutBuffer, /* size of output buffer */ + LPDWORD lpcbBytesReturned, /* address of actual bytes of output */ + LPOVERLAPPED lpoOverlapped /* address of overlapped struct */ + ) +{ + struct smi s; + int rc, max_i; + int ioctl_status; + + DEBUG("DeviceIoControl: hDevice1=%x hDevice=%x ioctl=%x\n", + hDevice1,hDevice,dwIoControlCode); + rc = open_imb(1); /*open if needed, set fskipcmd to avoid recursion*/ + if (rc == 0) { +#ifdef DBG_IPMI + dbgmsg("DeviceIoControl: open_imb failed %d\n", rc); +#endif + return FALSE; + } + + /*-------------dont use locking-------------- + //lock the mutex, before making the request.... + if(mutex_lock(&deviceMutex) != 0) { + return(FALSE); + } + *-------------------------------------------*/ +#ifndef NO_MACRO_ARGS + DEBUG("%s: ioctl cmd = 0x%lx ", __FUNCTION__,dwIoControlCode); + DEBUG("cbInBuffer %d cbOutBuffer %d\n", cbInBuffer, cbOutBuffer); +#endif + /* Test for Intel imb driver max buf size */ + /* Max was 41, too small. Calculate real max - ARCress 6/01/05 */ + max_i = MAX_IMB_PACKET_SIZE + MIN_IMB_REQ_BUF_SIZE; /*33 + 13*/ + if (cbInBuffer > max_i) cbInBuffer = max_i; + + s.lpvInBuffer = lpvInBuffer; + s.cbInBuffer = cbInBuffer; + s.lpvOutBuffer = lpvOutBuffer; + s.cbOutBuffer = cbOutBuffer; + s.lpcbBytesReturned = lpcbBytesReturned; + s.lpoOverlapped = lpoOverlapped; + s.ntstatus = (LPVOID)&NTstatus; /*dummy place holder. Linux IMB driver + //doesnt return status or info via it.*/ +#ifdef IMB_DEBUG + if (fdebug) { + int j, n; + char *tag; + unsigned int *bi; + unsigned char *b; + + printf("ioctl %x smi buffer:\n",dwIoControlCode); + /* show arg/smi structure */ + bi = (unsigned int *)&s; + n = ( sizeof(struct smi) / sizeof(int) ); + printf("smi(%p), (sz=%d/szint=%d)->%d:\n", bi, sizeof(struct smi), + sizeof(int),n); + for (j = 0; j < n; j++) { + switch(j) { + case 0: tag = "version "; break; + case 2: tag = "reserved1"; break; + case 4: tag = "reserved2"; break; + case 6: tag = "ntstatus "; break; + case 8: tag = "pinbuf "; break; + case 10: tag = "sinbuf "; break; + case 12: tag = "poutbuf"; break; + case 14: tag = "soutbuf"; break; + case 16: tag = "cbRet "; break; + case 18: tag = "pOverlap"; break; + default: tag = "other "; + } + printf("bi[%d]%s: %08x \n",j,tag,bi[j]); + } /*end for*/ + } +#endif + + if ( (ioctl_status = ioctl(hDevice1, dwIoControlCode,&s) ) <0) { +#ifndef NO_MACRO_ARGS + DEBUG("%s %s: ioctl cmd = 0x%x failed %d \n", + __FILE__,__FUNCTION__,dwIoControlCode,ioctl_status); +#endif +#ifdef DBG_IPMI + dbgmsg("DeviceIoControl: ioctl cmd = 0x%x failed %d \n", + dwIoControlCode,ioctl_status); +#endif + /* mutex_unlock(&deviceMutex); */ + return FALSE; + } + /*-------------dont use locking-------------- + mutex_unlock(&deviceMutex); + *-------------------------------------------*/ + +#ifndef NO_MACRO_ARGS + DEBUG("%s: ioctl_status %d bytes returned = %d \n", + __FUNCTION__, ioctl_status, *lpcbBytesReturned); +#endif + +/*MR commented this just as in Sol1.10. lpcbBytesReturned has the right data +// *lpcbBytesReturned = NTstatus.Information; */ + + if (ioctl_status == STATUS_SUCCESS) { +#ifndef NO_MACRO_ARGS + DEBUG("%s returning true\n", __FUNCTION__); +#endif + return (TRUE); + } + else { +#ifndef NO_MACRO_ARGS + DEBUG("%s returning false\n", __FUNCTION__); +#endif + return (FALSE); + } +} +#endif + +static void _dump_buf(char *tag, BYTE *pbuf, int sz, char fshowascii) +{ + BYTE line[17]; + BYTE a; + int i, j; + char *stag; + FILE *fpdbg1; + +#ifdef DBG_IPMI + fpdbg1 = fopen( "imbdbg.log", "a+" ); + if (fpdbg1 == NULL) fpdbg1 = stdout; +#else + fpdbg1 = stdout; +#endif + if (tag == NULL) stag = "dump_buf"; /*safety valve*/ + else stag = tag; + fprintf(fpdbg1,"%s (len=%d): ", stag,sz); + line[0] = 0; line[16] = 0; + j = 0; + if (sz < 0) { fprintf(fpdbg1,"\n"); return; } /*safety valve*/ + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { + line[j] = 0; + j = 0; + fprintf(fpdbg1,"%s\n %04x: ",line,i); + } + if (fshowascii) { + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + } + fprintf(fpdbg1,"%02x ",pbuf[i]); + } + if (fshowascii) { + if ((j > 0) && (j < 16)) { + /* space over the remaining number of hex bytes */ + for (i = 0; i < (16-j); i++) fprintf(fpdbg1," "); + } + else j = 16; + line[j] = 0; + } + fprintf(fpdbg1,"%s\n",line); +#ifdef DBG_IPMI + if (fpdbg1 != stdout) fclose(fpdbg1); +#endif + return; +} + +#ifdef LOCAL_IPMB +#define SMS_MSG_LUN 0x02 +extern void os_usleep(int s, int u); /*subs.c*/ +static int sendSeq = 1; +static BYTE cksum(const BYTE *buf, register int len) +{ /* 8-bit 2s compliment checksum */ + register BYTE csum; + register int i; + csum = 0; + for (i = 0; i < len; i++) csum = (csum + buf[i]) % 256; + csum = -csum; + return(csum); +} + +// SendTimedIpmbpRequest +ACCESN_STATUS +SendTimedIpmbpRequest ( + IMBPREQUESTDATA *reqPtr, /* request info and data */ + int timeOut, /* how long to wait, in mSec units */ + BYTE *respDataPtr, /* where to put response data */ + int *respDataLen, /* how much response data there is */ + BYTE *completionCode /* request status from bmc controller*/ + ) +{ + BYTE responseData[MAX_IMB_REQ_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + DWORD reqLength; + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + BOOL status; + int i; + + req->req.rsSa = BMC_SA; + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = BMC_LUN; /*=0*/ + req->req.data[0] = reqPtr->busType; + req->req.data[1] = reqPtr->rsSa; + req->req.data[2] = ((reqPtr->netFn << 2) | (reqPtr->rsLun & 0x03)); + req->req.data[3] = cksum(&req->req.data[1],2); + req->req.data[4] = BMC_SA; + req->req.data[5] = ((sendSeq << 2) | (SMS_MSG_LUN & 0x03)); + req->req.data[6] = reqPtr->cmdType; + for (i = 0; i < reqPtr->dataLength; i++) + req->req.data[7+i] = reqPtr->data[i]; + req->req.data[7+i] = cksum(&req->req.data[4], reqPtr->dataLength + 3); + req->req.dataLength = reqPtr->dataLength + 8; + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + reqLength = req->req.dataLength + MIN_IMB_REQ_BUF_SIZE; + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + reqLength, + & responseData, + sizeof( responseData ), + & respLength, + NULL); + if (fdebug) printf("sendIpmb: send_message status=%d rlen=%d cc=%x\n", + status,respLength,resp->cCode); + if ( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if ( respLength == 0 ) { + return ACCESN_ERROR; + } + sendSeq++; + if ( resp->cCode != 0) { + *completionCode = resp->cCode; + *respDataLen = 0; + return ACCESN_OK; + } + + /* + * Sent ok, wait for GetMessage response + */ + for (i=0; i < 10; i++) /* RETRIES=10 for GetMessage */ + { + //req->req.busType = PUBLIC_BUS; /*=0*/ + req->req.rsSa = BMC_SA; + req->req.cmd = GET_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = BMC_LUN; /*=0*/ + req->req.dataLength = 0; + reqLength = req->req.dataLength + MIN_IMB_REQ_BUF_SIZE; + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + reqLength, + & responseData, + sizeof( responseData ), + & respLength, + NULL); + if (fdebug) printf("sendIpmb: get_message status=%d rlen=%d cc=%x\n", + status,respLength,resp->cCode); + if ( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if ( respLength == 0 ) { + return ACCESN_ERROR; + } + if ( (resp->cCode != 0x80) && (resp->cCode != 0x83) ) + break; /*success, exit loop*/ + os_usleep(0,1000); /* 1 msec*/ + } /*end-for*/ + + /* + * give the caller his response + */ + *completionCode = resp->cCode; + *respDataLen = 0; + if (( respLength > 1 ) && ( respDataPtr)) { + /* check that resp cmd & netfn match */ + *respDataLen = respLength - 7; + memcpy( respDataPtr, &resp->data[7], *respDataLen); + } + return ACCESN_OK; +} +#endif + +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedImbpRequest +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SendTimedImbpRequest +// Purpose: This function sends a request for BMC implemented function +// Context: Used by Upper level agents (sis modules) to access BMC implemented functionality. +// Returns: OK else error status code +// Parameters: +// reqPtr +// timeOut +// respDataPtr +// respLen +// Notes: none +*F*/ +ACCESN_STATUS +SendTimedImbpRequest ( + IMBPREQUESTDATA *reqPtr, /* request info and data */ + int timeOut, /* how long to wait, in mSec units */ + BYTE *respDataPtr, /* where to put response data */ + int *respDataLen, /* how much response data there is */ + BYTE *completionCode /* request status from bmc controller*/ + ) +{ + BYTE responseData[MAX_IMB_REQ_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + DWORD reqLength; + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + BOOL status; + + + req->req.rsSa = reqPtr->rsSa; + req->req.cmd = reqPtr->cmdType; + req->req.netFn = reqPtr->netFn; + req->req.rsLun = reqPtr->rsLun; + req->req.dataLength = (BYTE)reqPtr->dataLength; + +#ifndef NO_MACRO_ARGS + DEBUG("cmd=%02x, pdata=%p, datalen=%d, size=%d\n", req->req.cmd, + reqPtr->data, reqPtr->dataLength, sizeof(requestData)); +#endif + memcpy( req->req.data, reqPtr->data, reqPtr->dataLength ); + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + +#ifndef NO_MACRO_ARGS + DEBUG("%s: rsSa 0x%x cmd 0x%x netFn 0x%x rsLun 0x%x\n", __FUNCTION__, + req->req.rsSa, req->req.cmd, req->req.netFn, req->req.rsLun); +#endif + reqLength = req->req.dataLength + MIN_IMB_REQ_BUF_SIZE; + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + reqLength, + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl returned status = %d\n",__FUNCTION__, status); +#endif +#ifdef DBG_IPMI + printf("%s: rsSa %x cmd %x netFn %x lun %x, status=%d, cc=%x, rlen=%d\n", + __FUNCTION__, req->req.rsSa, req->req.cmd, req->req.netFn, + req->req.rsLun, status, resp->cCode, respLength ); + dbgmsg("SendTimedImb: rsSa %x cmd %x netFn %x lun %x, status=%d, cc=%x, rlen=%d\n", + req->req.rsSa, req->req.cmd, req->req.netFn, + req->req.rsLun, status, resp->cCode, respLength ); + if (req->req.cmd == 0x34) { + _dump_buf("requestData",requestData,reqLength,0); //if DBG_IPMI + _dump_buf("responseData",responseData,respLength,0); //if DBG_IPMI + } +#endif + + if( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if( respLength == 0 ) { + return ACCESN_ERROR; + } + + /* + * give the caller his response + */ + *completionCode = resp->cCode; + *respDataLen = 0; + + if(( respLength > 1 ) && ( respDataPtr)) + { + *respDataLen = respLength - 1; + memcpy( respDataPtr, resp->data, *respDataLen); + } + + + return ACCESN_OK; +} + + +/*//////////////////////////////////////////////////////////////////// +// open_imb +////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: open_imb +// Purpose: To open imb device +// Context: Called from each routine to make sure that open is done. +// Returns: returns 0 for Fail and 1 for Success, sets hDevice to open +// handle. +// Parameters: none +// Notes: none +*F*/ +#ifdef WIN32 +#define IMB_DEVICE_WIN "\\\\.\\Imb" +int open_imb(int fskipcmd) +{ +/* This routine will be called from all other routines before doing any + interfacing with imb driver. It will open only once. */ + IMBPREQUESTDATA requestData; + BYTE respBuffer[MAX_IMB_RESP_SIZE]; + DWORD respLength; + BYTE completionCode; + int ret; + + set_fps(); + if (hDevice1 == 0) /*INVALID_HANDLE_VALUE*/ + { + // + // Open IMB driver device + // + hDevice = CreateFile( IMB_DEVICE_WIN, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (hDevice == NULL || hDevice == INVALID_HANDLE_VALUE) { + if (fdebug) printf("ipmi_open_ia: error opening %s to imbdrv.sys\n", + IMB_DEVICE_WIN); + return (0); /*FALSE*/ + } + + if (fskipcmd) { + IpmiVersion = IPMI_15_VERSION; + return (1); /*TRUE*/ + } + // Detect the IPMI version for processing requests later. + // This is a crude but most reliable method to differentiate + // between old IPMI versions and the 1.0 version. If we had used the + // version field instead then we would have had to revalidate all the + // older platforms (pai 4/27/99) + requestData.cmdType = GET_DEVICE_ID; + requestData.rsSa = BMC_SA; + requestData.rsLun = BMC_LUN; + requestData.netFn = APP_NETFN ; + requestData.busType = PUBLIC_BUS; + requestData.data = NULL; + requestData.dataLength = 0; + respLength = sizeof(respBuffer); + ret = SendTimedImbpRequest ( &requestData, IMB_OPEN_TIMEOUT, + respBuffer, &respLength, &completionCode); + if ( (ret != ACCESN_OK ) || ( completionCode != 0) ) + { + if (fdebug) /*GetDeviceId failed*/ + printf("ipmi_open_ia: imbdrv request error, ret=%d ccode=%x\n", + ret,completionCode); + CloseHandle(hDevice); + return (0); /*FALSE*/ + } + hDevice1 = hDevice; + + if (respLength < (IPMI10_GET_DEVICE_ID_RESP_LENGTH-1)) + IpmiVersion = IPMI_09_VERSION; + else { + if ( respBuffer[4] == 0x01 ) + IpmiVersion = IPMI_10_VERSION; + else /* IPMI 1.5 or 2.0 */ + IpmiVersion = IPMI_15_VERSION; + } + } + return (1); /*TRUE*/ + +} /*end open_imb for Win32 */ + +#else /* LINUX, SCO_UW, etc. */ + +int open_imb(int fskipcmd) +{ +/* This routine will be called from all other routines before doing any + interfacing with imb driver. It will open only once. */ + IMBPREQUESTDATA requestData; + BYTE respBuffer[MAX_IMB_RESP_SIZE]; + int respLength; + BYTE completionCode; + + int ret_code; + + set_fps(); + + if (hDevice1 == 0) + { +#ifndef NO_MACRO_ARGS + DEBUG("%s: opening the driver, ioctl_sendmsg = %x\n", + __FUNCTION__, ioctl_sendmsg); +#endif + /* %%%%* IOCTL_IMB_SEND_MESSAGE = 0x1082 + printf("ipmi_open_ia: " + "IOCTL_IMB_SEND_MESSAGE =%x \n" "IOCTL_IMB_GET_ASYNC_MSG=%x \n" + "IOCTL_IMB_MAP_MEMORY = %x \n" "IOCTL_IMB_UNMAP_MEMORY= %x \n" + "IOCTL_IMB_SHUTDOWN_CODE=%x \n" "IOCTL_IMB_REGISTER_ASYNC_OBJ =%x \n" + "IOCTL_IMB_DEREGISTER_ASYNC_OBJ=%x \n" + "IOCTL_IMB_CHECK_EVENT =%x \n" "IOCTL_IMB_POLL_ASYNC =%x \n", + IOCTL_IMB_SEND_MESSAGE, IOCTL_IMB_GET_ASYNC_MSG, + IOCTL_IMB_MAP_MEMORY, IOCTL_IMB_UNMAP_MEMORY, IOCTL_IMB_SHUTDOWN_CODE, + IOCTL_IMB_REGISTER_ASYNC_OBJ, IOCTL_IMB_DEREGISTER_ASYNC_OBJ, + IOCTL_IMB_CHECK_EVENT , IOCTL_IMB_POLL_ASYNC); *%%%%*/ + + /*O_NDELAY flag will cause problems later when driver makes + //you wait. Hence removing it. */ + /*if ((hDevice1 = open(IMB_DEVICE,O_RDWR|O_NDELAY)) <0) */ + if ((hDevice1 = open(IMB_DEVICE,O_RDWR)) <0) + { + hDevice1 = 0; +#ifndef WIN32 + /* dont always display open errors if Linux */ + if (fdebug) +#endif + { + /*debug or not 1st time */ + printf("imbapi ipmi_open_ia: open(%s) failed, %s\n", + IMB_DEVICE,strerror(errno)); + } + return (0); + } + + if (fskipcmd) { + IpmiVersion = IPMI_15_VERSION; + return (1); /*TRUE*/ + } + /* Detect the IPMI version for processing requests later. + // This is a crude but most reliable method to differentiate + // between old IPMI versions and the 1.0 version. If we had used the + // version field instead then we would have had to revalidate all + // the older platforms (pai 4/27/99) */ + requestData.cmdType = GET_DEVICE_ID; + requestData.rsSa = BMC_SA; + requestData.rsLun = BMC_LUN; + requestData.netFn = APP_NETFN ; + requestData.busType = PUBLIC_BUS; + requestData.data = NULL; + requestData.dataLength = 0; + respLength = sizeof(respBuffer); +#ifndef NO_MACRO_ARGS + DEBUG("%s: opened driver, getting IPMI version\n", __FUNCTION__); +#endif + ret_code = SendTimedImbpRequest(&requestData, + IMB_OPEN_TIMEOUT, respBuffer, &respLength, + &completionCode); + if ( (ret_code != ACCESN_OK) || (completionCode != 0) ) + { + printf("ipmi_open_ia: SendTimedImbpRequest error. Ret = %d CC = 0x%02X\n", + ret_code, completionCode); + close(hDevice1); + hDevice1 = 0; + return (0); + } + + if (respLength < (IPMI10_GET_DEVICE_ID_RESP_LENGTH-1)) + IpmiVersion = IPMI_09_VERSION; + else { + if ( respBuffer[4] == 0x01 ) + IpmiVersion = IPMI_10_VERSION; + else /* IPMI 1.5 or 2.0 */ + IpmiVersion = IPMI_15_VERSION; + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: IPMI version 0x%x\n", __FUNCTION__, IpmiVersion); +#endif + +/* +//initialise a mutex + if(mutex_init(&deviceMutex , USYNC_THREAD, NULL) != 0) + { + return(0); + } +*/ + + } + + return (1); +} /*end open_imb()*/ + +#endif + +int close_imb(void) +{ + int rc = 0; + if (hDevice1 != 0) { +#ifdef WIN32 + CloseHandle(hDevice1); +#else + rc = close(hDevice1); +#endif + } + return(rc); +} + +#ifndef LINK_LANDESK +/* If there is not a LANDESK lib, provide these 2 functions for apps + * that may be already be coded to that interface. + */ +int initIPMI(void) +{ /* for compatibility with LanDesk programs*/ + int rc; + rc = open_imb(0); /*sets hDevice1*/ + if (rc == 1) rc = 0; + else rc = -1; + return(rc); +} +int termIPMI(void) +{ /* for compatibility with LanDesk programs*/ + return(close_imb()); +} +#endif + +/*---------------------------------------------------------------------* + * ipmi_open_ia & ipmi_close_ia + *---------------------------------------------------------------------*/ +int ipmi_open_ia(char fdebugcmd) +{ + int rc = 0; + fdebug = fdebugcmd; + rc = open_imb(0); /*sets hDevice1*/ + if (rc == 1) rc = 0; + else rc = -1; + return(rc); +} + +int ipmi_close_ia(void) +{ + int rc = 0; + rc = close_imb(); + return(rc); +} + + +int ipmi_cmdraw_ia(BYTE cmd, BYTE netfn, BYTE lun, BYTE sa, BYTE bus, + BYTE *pdata, BYTE sdata, BYTE *presp, int *sresp, + BYTE *pcc, char fdebugcmd) +{ + IMBPREQUESTDATA requestData; + int status = 0; + char *imbDev; + BYTE * pc; + int sz, i; +#ifndef WIN32 + struct stat stbuf; +#endif + + if (fdebug) printf("ipmi_cmdraw_ia(%02x,%02x,%02x,%02x,bus=%02x)\n", + cmd,netfn,lun,sa,bus); +#ifdef METACOMMAND_IPMB /*++++ not used*/ + if (bus != PUBLIC_BUS) { + if (fdebug) printf("ipmi_cmdraw_ia: bus=%x, using ipmb\n",bus); + status = ipmi_cmd_ipmb(cmd,netfn,lun,sa,bus,pdata,sdata,presp,sresp, + pcc,fdebugcmd); + return(status); + } +#endif + set_fps(); + + requestData.cmdType = cmd; + requestData.rsSa = sa; + requestData.busType = bus; + requestData.netFn = netfn; + requestData.rsLun = lun; + requestData.dataLength = sdata; + requestData.data = pdata; + + if (fdebugcmd) { + sz = sizeof(IMBPREQUESTDATA); + pc = (BYTE *)&requestData.cmdType; + fprintf(fpdbg,"ipmi_cmdraw_ia: request (len=%d): ",sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + pc = requestData.data; + sz = requestData.dataLength; + fprintf(fpdbg," req.data=%p, dlen=%d: ", pc, sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + } + +#ifdef WIN32 + imbDev = "[imbdrv]"; + if (1) +#else + imbDev = "/dev/imb"; + if (stat(imbDev, &stbuf) == -1) { + fprintf(fperr,"ipmi_cmdraw_ia: No IMB driver found (%s)\n",imbDev); + return(ERR_NO_DRV); + } else /* imb device node is there */ +#endif + { + sz = *sresp; /* note that sresp must be pre-set */ + memset(presp, 0, sz); + for ( i =0 ; i < IMB_MAX_RETRIES; i++) + { + *sresp = sz; /* retries may need to re-init *sresp */ +#ifdef LOCAL_IPMB + if (bus != PUBLIC_BUS) + status = SendTimedIpmbpRequest(&requestData, ipmi_timeout_ia, presp, sresp, pcc); + else +#endif + status = SendTimedImbpRequest(&requestData, ipmi_timeout_ia, presp, sresp, pcc); + if((status) == 0 ) { break; } + if (fdebugcmd) // only gets here if error + fprintf(fpdbg,"ipmi_cmdraw_ia: sendImbRequest error status=%x, ccode=%x\n", + (uint)status, *pcc); + } + } + + if (fdebugcmd) { /* if debug, show both good and bad statuses */ + fprintf(fpdbg,"ipmi_cmdraw_ia: sendImbRequest status=%x, ccode=%x\n", + (uint)status, *pcc); + if (status == 0) { + BYTE * pc; int sz; + sz = *sresp; + pc = (BYTE *)presp; + fprintf(fpdbg,"ipmi_cmdraw_ia: response (len=%d): ",sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + } + } + if (status == 1) status = -3; /*LAN_ERR_RECV_FAIL, a meaningful error*/ + return(status); +} /* end ipmi_cmdraw_ia() */ + +/*---------------------------------------------------------------------*/ +/*Used only by UW. Left here for now. IMB driver will not accept this +//ioctl. */ +ACCESN_STATUS +StartAsyncMesgPoll() +{ + + DWORD retLength; + BOOL status; + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl cmd = %x\n",__FUNCTION__,IOCTL_IMB_POLL_ASYNC); +#endif + status = DeviceIoControl ( hDevice, + IOCTL_IMB_POLL_ASYNC, + NULL, + 0, + NULL, + 0, + & retLength, + 0 + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status == TRUE ) { + return ACCESN_OK; + } else { + return ACCESN_ERROR; + } + +} + +/*///////////////////////////////////////////////////////////////////////////// +// SendTimedI2cRequest +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SendTimedI2cRequest +// Purpose: This function sends a request to a I2C device +// Context: Used by Upper level agents (sis modules) to access dumb I2c devices +// Returns: ACCESN_OK else error status code +// Parameters: +// reqPtr +// timeOut +// respDataPtr +// respLen +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedI2cRequest ( + I2CREQUESTDATA *reqPtr, /* I2C request */ + int timeOut, /* how long to wait, mSec units */ + BYTE *respDataPtr, /* where to put response data */ + int *respDataLen, /* size of response buffer and */ + /* size of returned data */ + BYTE *completionCode /* request status from BMC */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + + struct WriteReadI2C { /* format of a write/read I2C request */ + BYTE busType; + BYTE rsSa; + BYTE count; + BYTE data[1]; + } * wrReq = (struct WriteReadI2C *) req->req.data; + +#define MIN_WRI2C_SIZE 3 /* size of write/read request minus any data */ + + + /* + // If the Imb driver is not present return AccessFailed + */ + + req->req.rsSa = BMC_SA; + req->req.cmd = WRITE_READ_I2C; + req->req.netFn = APP_NETFN; + req->req.rsLun = BMC_LUN; + req->req.dataLength = reqPtr->dataLength + MIN_WRI2C_SIZE; + + wrReq->busType = reqPtr->busType; + wrReq->rsSa = reqPtr->rsSa; + wrReq->count = reqPtr->numberOfBytesToRead; + + memcpy( wrReq->data, reqPtr->data, reqPtr->dataLength ); + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof( requestData ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if( respLength == 0 ) { + return ACCESN_ERROR; + } + + /* + // give the caller his response + */ + *completionCode = resp->cCode; + *respDataLen = respLength - 1; + + if(( *respDataLen ) && (respDataPtr)) + memcpy( respDataPtr, resp->data, *respDataLen); + + return ACCESN_OK; + +} + +/*This is not a API exported by the driver in stricter sense. It is +//added to support EMP functionality. Upper level software could have +//implemented this function.(pai 5/4/99) */ +/*///////////////////////////////////////////////////////////////////////////// +// SendTimedEmpMessageResponse +///////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedEmpMessageResponse +// Purpose: This function sends a response message to the EMP port +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedEmpMessageResponse ( + ImbPacket *ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut /* how long to wait, in mSec units */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /*ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = 0; + + i = 0; + if (IpmiVersion != IPMI_09_VERSION) + req->req.data[i++] = EMP_CHANNEL; + + req->req.data[i++] = ptr->rqSa; + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMCs slave address as responder + //address. */ + + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + req->req.data[i++] = ptr->cmd; + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + j = 1; + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; +} + + +/*This is not a API exported by the driver in stricter sense. It is added to support +// EMP functionality. Upper level software could have implemented this function.(pai 5/4/99) */ +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedEmpMessageResponse_Ex +//////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedEmpMessageResponse_Ex +// Purpose: This function sends a response message to the EMP port +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedEmpMessageResponse_Ex ( + + ImbPacket * ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut, /* how long to wait, in mSec units*/ + BYTE sessionHandle, /*This is introduced in IPMI1.5,this is required to be sent in + //send message command as a parameter,which is then used by BMC + //to identify the correct DPC session to send the mesage to. */ + BYTE channelNumber /*There are 3 different channels on which DPC communication goes on + //Emp - 1,Lan channel one - 6,Lan channel two(primary channel) - 7. */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /* ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = 0; + + i = 0; + + /*checking for the IPMI version & then assigning the channel number for EMP + //Actually the channel number is same in both the versions.This is just to + //maintain the consistancy with the same method for LAN. + //This is the 1st byte of the SEND MESSAGE command. */ + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = EMP_CHANNEL; + else if (IpmiVersion == IPMI_15_VERSION) + req->req.data[i++] = channelNumber; + + /*The second byte of data for SEND MESSAGE starts with session handle */ + req->req.data[i++] = sessionHandle; + + /*Then it is the response slave address for SEND MESSAGE. */ + req->req.data[i++] = ptr->rqSa; + + /*Then the net function + lun for SEND MESSAGE command. */ + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + + /*Here the checksum is calculated.The checksum calculation starts after the channel number. + //so for the IPMI 1.5 version its a checksum of 3 bytes that is session handle,response slave + //address & netfun+lun. */ + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + { + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + else + req->req.data[i++] = ((~(req->req.data[2]+ req->req.data[3])) +1); + } + + /*This is the next byte of the message data for SEND MESSAGE command.It is the request + //slave address. */ + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMCs slave address as responder + //address. */ + + /*This is just the sequence number,which is the next byte of data for SEND MESSAGE */ + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + /*The next byte is the command like get software ID(00).*/ + req->req.data[i++] = ptr->cmd; + + /*after the cmd the data ,which is sent by DPC & is retrived using the get message earlier + // is sent back to DPC. */ + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + + /*The last byte of data for SEND MESSAGE command is the check sum ,which is calculated + //from the next byte of the previous checksum that is the request slave address. */ + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + { + if (IpmiVersion == IPMI_10_VERSION) + j = 1; + else + j = 2; + } + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + /*The flags & timeouts are used by the driver internally. */ + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); + + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if (fdebug) { + printf("SendTimedEmp(%x,%x): status=%d cc=%x rlen=%d i=%d\n", + sessionHandle, channelNumber, + status,responseData[0],respLength,i); + _dump_buf("requestData",requestData,sizeof(requestData),0); + } + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; + + +} + +/*This is not a API exported by the driver in stricter sense. It is +//added to support EMP functionality. Upper level software could have +//implemented this function.(pai 5/4/99) */ +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedLanMessageResponse +///////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedLanMessageResponse +// Purpose: This function sends a response message to the DPC Over Lan +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedLanMessageResponse( + ImbPacket *ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut /* how long to wait, in mSec units */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /* ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + + /* After discussion with firmware team (Shailendra), the lun number needs to stay at 0 + // even though the DPC over Lan firmware EPS states that the lun should be 1 for DPC + // Over Lan. - Simont (5/17/00) */ + req->req.rsLun = 0; + + i = 0; + if (IpmiVersion != IPMI_09_VERSION) + req->req.data[i++] = LAN_CHANNEL; + + req->req.data[i++] = ptr->rqSa; + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMCs slave address as responder + //address. */ + + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + req->req.data[i++] = ptr->cmd; + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + j = 1; + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); + + if (fdebug) { + printf("SendTimedLan(): status=%d cc=%x rlen=%d i=%d\n", + status, responseData[0],respLength,i); + _dump_buf("requestData",requestData,sizeof(requestData),0); + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; +} + + +/*This is not a API exported by the driver in stricter sense. It is +//added to support EMP functionality. Upper level software could have +//implemented this function.(pai 5/4/99) */ +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedLanMessageResponse_Ex +///////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedLanMessageResponse_Ex +// Purpose: This function sends a response message to the DPC Over Lan +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedLanMessageResponse_Ex( + ImbPacket *ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut , /* how long to wait, in mSec units */ + BYTE sessionHandle, /*This is introduced in IPMI1.5,this is required to be sent in + //send message command as a parameter,which is then used by BMC + //to identify the correct DPC session to send the mesage to. */ + BYTE channelNumber /*There are 3 different channels on which DPC communication goes on + //Emp - 1,Lan channel one - 6,Lan channel two(primary channel) - 7. */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /* ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + + /* After discussion with firmware team (Shailendra), the lun number needs to stay at 0 + // even though the DPC over Lan firmware EPS states that the lun should be 1 for DPC + // Over Lan. - Simont (5/17/00) */ + req->req.rsLun = 0; + + i = 0; + + /*checking for the IPMI version & then assigning the channel number for Lan accordingly. + //This is the 1st byte of the SEND MESSAGE command. */ + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = LAN_CHANNEL; + else if (IpmiVersion == IPMI_15_VERSION) + req->req.data[i++] = channelNumber; + + /*The second byte of data for SEND MESSAGE starts with session handle */ + req->req.data[i++] = sessionHandle; + + /*Then it is the response slave address for SEND MESSAGE. */ + req->req.data[i++] = ptr->rqSa; + + /*Then the net function + lun for SEND MESSAGE command. */ + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + + /*Here the checksum is calculated.The checksum calculation starts after the channel number. + //so for the IPMI 1.5 version its a checksum of 3 bytes that is session handle,response slave + //address & netfun+lun. */ + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + { + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + else + req->req.data[i++] = ((~(req->req.data[2]+ req->req.data[3])) +1); + } + + /*This is the next byte of the message data for SEND MESSAGE command.It is the request + //slave address. */ + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMC's slave address as responder + //address. */ + + /*This is just the sequence number,which is the next byte of data for SEND MESSAGE */ + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + /*The next byte is the command like get software ID(00). */ + req->req.data[i++] = ptr->cmd; + + /*after the cmd the data ,which is sent by DPC & is retrived using the get message earlier + // is sent back to DPC. */ + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + + /*The last byte of data for SEND MESSAGE command is the check sum ,which is calculated + //from the next byte of the previous checksum that is the request slave address. */ + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + { + if (IpmiVersion == IPMI_10_VERSION) + j = 1; + else + j = 2; + } + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + /*The flags & timeouts are used by the driver internally */ + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + if (fdebug) { + printf("SendTimedLan(%x,%x): status=%d cc=%x rlen=%d i=%d\n", + sessionHandle, channelNumber, + status,responseData[0],respLength,i); + if (responseData[0] != 0) /*0xcc == invalid request data*/ + { + BYTE *pb; + pb = (BYTE *)req->req.data; + printf("SendMessage data: %02x %02x %02x %02x %02x %02x %02x %02x\n", + pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7]); + _dump_buf("requestData",requestData,sizeof(requestData),0); + } + } + + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; +} + + + +/*///////////////////////////////////////////////////////////////////////// +//SendAsyncImbpRequest +/////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SendAsyncImbpRequest +// Purpose: This function sends a request for Asynchronous IMB implemented function +// Context: Used by Upper level agents (sis modules) to access Asynchronous IMB implemented functionality. +// Returns: OK else error status code +// Parameters: +// reqPtr Pointer to Async IMB request +// seqNo Sequence Munber +// Notes: none +*F*/ +ACCESN_STATUS +SendAsyncImbpRequest ( + IMBPREQUESTDATA *reqPtr, /* request info and data */ + BYTE * seqNo /* sequence number used in creating IMB msg */ + ) +{ + + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + + req->req.rsSa = reqPtr->rsSa; + req->req.cmd = reqPtr->cmdType; + req->req.netFn = reqPtr->netFn; + req->req.rsLun = reqPtr->rsLun; + req->req.dataLength = (BYTE)reqPtr->dataLength; + + memcpy( req->req.data, reqPtr->data, reqPtr->dataLength ); + + req->flags = NO_RESPONSE_EXPECTED; + req->timeOut = 0; /* no timeouts for async sends */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof( requestData ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if( respLength != 2 ) { + return ACCESN_ERROR; + } + /* + // give the caller his sequence number + */ + *seqNo = resp->data[0]; + + return ACCESN_OK; + +} + +/*/////////////////////////////////////////////////////////////////////////// +//GetAsyncImbpMessage +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: GetAsyncImbpMessage +// Purpose: This function gets the next available async message with a message id +// greater than SeqNo. The message looks like an IMB packet +// and the length and Sequence number is returned +// Context: Used by Upper level agents (sis modules) to access Asynchronous IMB implemented functionality. +// Returns: OK else error status code +// Parameters: +// msgPtr Pointer to Async IMB request +// msgLen Length +// timeOut Time to wait +// seqNo Sequence Munber +// Notes: none +*F*/ + +ACCESN_STATUS +GetAsyncImbpMessage ( + ImbPacket * msgPtr, /* request info and data */ + DWORD *msgLen, /* IN - length of buffer, OUT - msg len */ + DWORD timeOut, /* how long to wait for the message */ + ImbAsyncSeq *seqNo, /* previously returned seq number */ + /* (or ASYNC_SEQ_START) */ + DWORD channelNumber + ) +{ + + BOOL status; + BYTE responseData[MAX_ASYNC_RESP_SIZE], lun, b; + ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData; + DWORD respLength = sizeof( responseData ); + ImbAsyncRequest req; + BYTE *msgb; + + while(1) + { + + + if( (msgPtr == NULL) || (msgLen == NULL) || ( seqNo == NULL) ) + return ACCESN_ERROR; + + msgb = (BYTE *)msgPtr; + req.timeOut = timeOut * 1000; /* convert to uSec units */ + req.lastSeq = *seqNo; + + + status = DeviceIoControl( hDevice, + IOCTL_IMB_GET_ASYNC_MSG, + & req, + sizeof( req ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error = GetLastError(); + /* + // handle "msg not available" specially. it is + // different from a random old error. + */ + switch( error ) { + case IMB_MSG_NOT_AVAILABLE: + return ACCESN_END_OF_DATA; + default: + return ACCESN_ERROR; + } + return ACCESN_ERROR; + } + if( respLength < MIN_ASYNC_RESP_SIZE ) { + return ACCESN_ERROR; + } + respLength -= MIN_ASYNC_RESP_SIZE; + + if( *msgLen < respLength ) { + return ACCESN_ERROR; + } + + + /*same code as in NT section */ + if ( IpmiVersion == IPMI_09_VERSION) + { + + switch( channelNumber) { + case IPMB_CHANNEL: + lun = IPMB_LUN; + break; + + case EMP_CHANNEL: + lun = EMP_LUN; + break; + + default: + lun = RESERVED_LUN; + break; + } + + b = (((ImbPacket *)(resp->data))->nfLn) & 0x3; + if (channelNumber != ANY_CHANNEL) { + if ( (lun == RESERVED_LUN) || + (lun != b) ) + { + *seqNo = resp->thisSeq; + continue; + } + } + + memcpy( msgPtr, resp->data, respLength ); + *msgLen = respLength; + /* Hack to return actual lun */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength] = b; + } + else + { + /* it is a 1.0 or above version */ + + b = resp->data[0]; + if ((channelNumber != ANY_CHANNEL) && + (channelNumber != b)) + { + *seqNo = resp->thisSeq; + continue; + } + + memcpy(msgPtr, &(resp->data[1]), respLength-1); + *msgLen = respLength-1; + /* Hack to return actual channel */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength-1] = b; + + } + + /* + // give the caller his sequence number + */ + *seqNo = resp->thisSeq; + + return ACCESN_OK; + + } /*while (1) */ +} + + +/*/////////////////////////////////////////////////////////////////////////// +//GetAsyncImbpMessage_Ex +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: GetAsyncImbpMessage_Ex +// Purpose: This function gets the next available async message with a message id +// greater than SeqNo. The message looks like an IMB packet +// and the length and Sequence number is returned +// Context: Used by Upper level agents (sis modules) to access Asynchronous IMB implemented functionality. +// Returns: OK else error status code +// Parameters: +// msgPtr Pointer to Async IMB request +// msgLen Length +// timeOut Time to wait +// seqNo Sequence Munber +// Notes: none +*F*/ + +ACCESN_STATUS +GetAsyncImbpMessage_Ex ( + ImbPacket * msgPtr, /* request info and data */ + DWORD *msgLen, /* IN - length of buffer, OUT - msg len */ + DWORD timeOut, /* how long to wait for the message */ + ImbAsyncSeq *seqNo, /* previously returned seq number */ + /* (or ASYNC_SEQ_START) */ + DWORD channelNumber, + BYTE * sessionHandle, + BYTE * privilege + ) +{ + + BOOL status; + BYTE responseData[MAX_ASYNC_RESP_SIZE], lun, b; + ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData; + DWORD respLength = sizeof( responseData ); + ImbAsyncRequest req; + BYTE *msgb; + + while(1) + { + + + if( (msgPtr == NULL) || (msgLen == NULL) || ( seqNo == NULL) ) + return ACCESN_ERROR; + + msgb = (BYTE *)msgPtr; + req.timeOut = timeOut * 1000; /* convert to uSec units */ + req.lastSeq = *seqNo; + + + status = DeviceIoControl( hDevice, + IOCTL_IMB_GET_ASYNC_MSG, + & req, + sizeof( req ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error = GetLastError(); + /* + // handle "msg not available" specially. it is + // different from a random old error. + */ + switch( error ) { + case IMB_MSG_NOT_AVAILABLE: + return ACCESN_END_OF_DATA; + default: + return ACCESN_ERROR; + } + return ACCESN_ERROR; + } + if( respLength < MIN_ASYNC_RESP_SIZE ) { + return ACCESN_ERROR; + } + respLength -= MIN_ASYNC_RESP_SIZE; + + if( *msgLen < respLength ) { + return ACCESN_ERROR; + } + + + /*same code as in NT section */ + if ( IpmiVersion == IPMI_09_VERSION) + { + + switch( channelNumber) { + case IPMB_CHANNEL: + lun = IPMB_LUN; + break; + + case EMP_CHANNEL: + lun = EMP_LUN; + break; + + default: + lun = RESERVED_LUN; + break; + } + + b = ((((ImbPacket *)(resp->data))->nfLn) & 0x3); + if (channelNumber != ANY_CHANNEL) { + if ( (lun == RESERVED_LUN) || + (lun != b) ) + { + *seqNo = resp->thisSeq; + continue; + } + } + + memcpy( msgPtr, resp->data, respLength ); + *msgLen = respLength; + /* Hack to return actual lun */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength] = b; + + } + else + { + if((sessionHandle ==NULL) || (privilege ==NULL)) + return ACCESN_ERROR; + + /*With the new IPMI version the get message command returns the + //channel number along with the privileges.The 1st 4 bits of the + //second byte of the response data for get message command represent + //the channel number & the last 4 bits are the privileges. */ + *privilege = (resp->data[0] & 0xf0)>> 4; + +#ifndef NO_MACRO_ARGS + DEBUG("GetAsy: chan=%x chan_parm=%x\n",resp->data[0],channelNumber); +#endif + b = (resp->data[0] & 0x0f); + if ((channelNumber != ANY_CHANNEL) && + (channelNumber != b) ) + { + *seqNo = resp->thisSeq; + continue; + } + + + /*The get message command according to IPMI 1.5 spec now even + //returns the session handle.This is required to be captured + //as it is required as request data for send message command. */ + *sessionHandle = resp->data[1]; + memcpy( msgPtr, &(resp->data[2]), respLength-1 ); + *msgLen = respLength-1; + + /* Hack to return actual channel */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength-1] = b; + + } + + /* + // give the caller his sequence number + */ + *seqNo = resp->thisSeq; + + return ACCESN_OK; + + } /*while (1) */ +} + + + +/*////////////////////////////////////////////////////////////////////////////// +//IsAsyncMessageAvailable +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: IsMessageAvailable +// Purpose: This function waits for an Async Message +// +// Context: Used by Upper level agents access Asynchronous IMB based +// messages +// Returns: OK else error status code +// Parameters: +// eventId +// +// Notes: This call will block the calling thread if no Async events are +// are available in the queue. +// +*F*/ +ACCESN_STATUS +IsAsyncMessageAvailable (HandleType eventId ) +{ + int dummy; + int respLength = 0; + BOOL status; + + /* confirm that app is not using a bad Id */ + + + if ( AsyncEventHandle != eventId) { +#ifdef LINUX + printf("Invalid AsyncHandle %x!=%x\n",AsyncEventHandle,eventId); +#endif + return ACCESN_ERROR; + } + + dummy = 0; + status = DeviceIoControl(hDevice, + IOCTL_IMB_CHECK_EVENT, + &AsyncEventHandle, + sizeof(HandleType), + &dummy, + sizeof(int), + (LPDWORD) & respLength, + NULL + ); + // if (fdebug) + // printf("IsAsyncMessageAvail: status=%d rlen=%d dummy=%x\n", + // status, respLength, dummy); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) + return ACCESN_ERROR; + + + return ACCESN_OK; +} + + +/*I have retained this commented code because later we may want to use +//DPC message specific Processing (pai 11/21) */ + +#ifdef NOT_COMPILED_BUT_LEFT_HERE_FOR_NOW + +/*////////////////////////////////////////////////////////////////////////////// +//GetAsyncDpcMessage +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: GetAsyncDpcMessage +// Purpose: This function gets the next available async message from +// the DPC client. +// +// Context: Used by Upper level agents access Asynchronous IMB based +// messages sent by the DPC client. +// Returns: OK else error status code +// Parameters: +// msgPtr Pointer to Async IMB request +// msgLen Length +// timeOut Time to wait +// seqNo Sequence Munber +// Notes: This call will block the calling thread if no Async events are +// are available in the queue. +// +*F*/ + +ACCESN_STATUS +GetAsyncDpcMessage ( + ImbPacket * msgPtr, /* request info and data */ + DWORD * msgLen, /* IN - length of buffer, OUT - msg len */ + DWORD timeOut, /* how long to wait for the message */ + ImbAsyncSeq * seqNo, /* previously returned seq number (or ASYNC_SEQ_START) */ + ) +{ + BOOL status; + BYTE responseData[MAX_ASYNC_RESP_SIZE]; + ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData; + DWORD respLength = sizeof( responseData ); + ImbAsyncRequest req; + + if( msgPtr == NULL || msgLen == NULL || seqNo == NULL ) + return ACCESN_ERROR; + + req.lastSeq = *seqNo; + + + hEvt = CreateEvent (NULL, TRUE, FALSE, NULL) ; + if (!hEvt) { + return ACCESN_ERROR; + } + + status = DeviceIoControl( hDevice, + IOCTL_IMB_GET_DPC_MSG, + & req, + sizeof( req ), + & responseData, + sizeof( responseData ), + & respLength, + &ovl + ); + + if( status != TRUE ) { + DWORD error = GetLastError(); + /* + // handle "msg not available" specially. it is different from + // a random old error. + // + */ + if (!status) + { + switch (error ) + { + case ERROR_IO_PENDING: + + WaitForSingleObject (hEvt, INFINITE) ; + ResetEvent (hEvt) ; + break; + + case IMB_MSG_NOT_AVAILABLE: + + CloseHandle(hEvt); + return ACCESN_END_OF_DATA; + + default: + CloseHandle(hEvt); + return ACCESN_ERROR; + + } + } + + + + if ( + ( GetOverlappedResult(hDevice, + &ovl, + (LPDWORD)&respLength, + TRUE + ) == 0 ) || (respLength <= 0) + ) + + { + + CloseHandle(hEvt); + return ACCESN_ERROR; + + } + + + } + + if( respLength < MIN_ASYNC_RESP_SIZE ) { + CloseHandle(hEvt); + return ACCESN_ERROR; + } + + respLength -= MIN_ASYNC_RESP_SIZE; + + if( *msgLen < respLength ) { + + /* The following code should have been just return ACCESN_out_of_range */ + CloseHandle(hEvt); + return ACCESN_ERROR; + } + + memcpy( msgPtr, resp->data, respLength ); + + *msgLen = respLength; + /* + // give the caller his sequence number + */ + *seqNo = resp->thisSeq; + + CloseHandle(hEvt); + + + return ACCESN_OK; + +} +#endif /*NOT_COMPILED_BUT_LEFT_HERE_FOR_NOW*/ + + + +/*///////////////////////////////////////////////////////////////////////////// +//RegisterForImbAsyncMessageNotification +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: RegisterForImbAsyncMessageNotification +// Purpose: This function Registers the calling application +// for Asynchronous notification when a sms message +// is available with the IMB driver. +// +// Context: Used by Upper level agents to know that an async +// SMS message is available with the driver. +// Returns: OK else error status code +// Parameters: +// handleId pointer to the registration handle +// +// Notes: The calling application should use the returned handle to +// get the Async messages.. +*F*/ +ACCESN_STATUS +RegisterForImbAsyncMessageNotification (HandleType *handleId) + +{ + BOOL status; + DWORD respLength ; + int dummy; + + /*allow only one app to register */ + + if( (handleId == NULL ) || (AsyncEventHandle) ) + return ACCESN_ERROR; + + + status = DeviceIoControl(hDevice, + IOCTL_IMB_REGISTER_ASYNC_OBJ, + &dummy, + sizeof( int ), + &AsyncEventHandle, + sizeof(HandleType), + (LPDWORD) & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( (respLength != sizeof(int)) || (status != TRUE )) { + if (fdebug) { + printf("RegisterForImbAsync error status=%d, len=%d sizeint=%d\n", status, respLength, sizeof(int)); + if( respLength != sizeof(int)) printf("Async len err\n"); + if( status != TRUE) printf("Async status err\n"); + } + return ACCESN_ERROR; + } + + *handleId = AsyncEventHandle; + +#ifndef NO_MACRO_ARGS + DEBUG("handleId = %x AsyncEventHandle %x\n", *handleId, AsyncEventHandle); +#endif + return ACCESN_OK; +} + + + + + +/*///////////////////////////////////////////////////////////////////////////// +//UnRegisterForImbAsyncMessageNotification +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: UnRegisterForImbAsyncMessageNotification +// Purpose: This function un-registers the calling application +// for Asynchronous notification when a sms message +// is available with the IMB driver. +// +// Context: Used by Upper level agents to un-register +// for async. notification of sms messages +// Returns: OK else error status code +// Parameters: +// handleId pointer to the registration handle +// iFlag value used to determine where this function was called from +// _it is used currently on in NetWare environment_ +// +// Notes: +*F*/ +ACCESN_STATUS +UnRegisterForImbAsyncMessageNotification (HandleType handleId, int iFlag) + +{ + BOOL status; + DWORD respLength ; + int dummy; + + iFlag = iFlag; /* to keep compiler happy We are not using this flag*/ + + if ( AsyncEventHandle != handleId) + return ACCESN_ERROR; + + status = DeviceIoControl(hDevice, + IOCTL_IMB_DEREGISTER_ASYNC_OBJ, + &AsyncEventHandle, + sizeof(HandleType), + &dummy, + (DWORD)sizeof(int ), + (LPDWORD) & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) + return ACCESN_ERROR; + + return ACCESN_OK; +} + + +/*/////////////////////////////////////////////////////////////////////////// +// SetShutDownCode +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SetShutDownCode +// Purpose: To set the shutdown action code +// Context: Called by the System Control Subsystem +// Returns: none +// Parameters: +// code shutdown action code which can be either +// SD_NO_ACTION, SD_RESET, SD_POWER_OFF as defined in imb_if.h +*F*/ + +ACCESN_STATUS +SetShutDownCode ( + int delayTime, /* time to delay in 100ms units */ + int code /* what to do when time expires */ + ) +{ + DWORD retLength; + BOOL status; + ShutdownCmdBuffer cmd; + + /* + // If Imb driver is not present return AccessFailed + */ + if(hDevice == INVALID_HANDLE_VALUE) + return ACCESN_ERROR; + + cmd.code = code; + cmd.delayTime = delayTime; + + status = DeviceIoControl( hDevice, + IOCTL_IMB_SHUTDOWN_CODE, + & cmd, + sizeof( cmd ), + NULL, + 0, + & retLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if(status == TRUE) + return ACCESN_OK; + else + return ACCESN_ERROR; +} + +#ifdef IMB_MEMORY +/*///////////////////////////////////////////////////////////////////////// +// MapPhysicalMemory +/////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: MapPhysicalMemory +// Purpose: This function maps specified range of physical memory in calling +// pocesse's address space +// Context: Used by Upper level agents (sis modules) to access +// system physical memory +// Returns: ACCESN_OK else error status code +// Parameters: +// +// startAddress starting physical address of the memory to be mapped +// addressLength length of the physical memory to be mapped +// virtualAddress pointer to the mapped virtual address +// Notes: none +*F*/ +/*/////////////////////////////////////////////////////////////////////////// +// UnmapPhysicalMemory +//////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: UnMapPhysicalMemory +// Purpose: This function unmaps the previously mapped physical memory +// Context: Used by Upper level agents (sis modules) +// Returns: ACCESN_OK else error status code +// Parameters: +// +// addressLength length of the physical memory to be mapped +// virtualAddress pointer to the mapped virtual address +// Notes: none +*F*/ +#ifdef WIN32 +ACCESN_STATUS +MapPhysicalMemory ( + int startAddress, // physical address to map in + int addressLength, // how much to map + int *virtualAddress // where it got mapped to + ) +{ + DWORD retLength; + BOOL status; + PHYSICAL_MEMORY_INFO pmi; + + if ( startAddress == (int) NULL || addressLength <= 0 ) + return ACCESN_OUT_OF_RANGE; + + pmi.InterfaceType = Internal; + pmi.BusNumber = 0; + pmi.BusAddress.HighPart = (LONG)0x0; + pmi.BusAddress.LowPart = (LONG)startAddress; + pmi.AddressSpace = (LONG) 0; + pmi.Length = addressLength; + + status = DeviceIoControl ( hDevice, + IOCTL_IMB_MAP_MEMORY, + & pmi, + sizeof(PHYSICAL_MEMORY_INFO), + virtualAddress, + sizeof(PVOID), + & retLength, + 0 + ); + if( status == TRUE ) { + return ACCESN_OK; + } else { + return ACCESN_ERROR; + } +} + +ACCESN_STATUS +UnmapPhysicalMemory ( + int virtualAddress, // what memory to unmap + int Length ) +{ + DWORD retLength; + BOOL status; + + status = DeviceIoControl ( hDevice, + IOCTL_IMB_UNMAP_MEMORY, + & virtualAddress, + sizeof(PVOID), + NULL, + 0, + & retLength, + 0 + ); + + if( status == TRUE ) { + return ACCESN_OK; + } else { + return ACCESN_ERROR; + } +} + +#else /*Linux, SCO, UNIX, etc.*/ + +ACCESN_STATUS +MapPhysicalMemory(int startAddress,int addressLength, int *virtualAddress ) +{ + int fd, i; + unsigned int length = addressLength; + off_t startpAddress = (off_t)startAddress; + unsigned int diff; + caddr_t startvAddress; + + if ((startAddress == (int) NULL) || (addressLength <= 0)) + return ACCESN_ERROR; + + if ( (fd = open("/dev/mem", O_RDONLY)) < 0) { + char buf[128]; + + sprintf(buf,"%s %s: open(%s) failed", + __FILE__,__FUNCTION__,"/dev/mem"); + perror(buf); + return ACCESN_ERROR ; + } + + /* aliging the offset to a page boundary and adjusting the length */ + diff = (int)startpAddress % PAGESIZE; + startpAddress -= diff; + length += diff; + + if ( (startvAddress = mmap( (caddr_t)0, + length, + PROT_READ, + MAP_SHARED, + fd, + startpAddress + ) ) == (caddr_t)-1) + { + char buf[128]; + + sprintf(buf,"%s %s: mmap failed", __FILE__,__FUNCTION__); + perror(buf); + close(fd); + return ACCESN_ERROR; + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: mmap of 0x%x success\n",__FUNCTION__,startpAddress); +#endif +#ifdef LINUX_DEBUG_MAX +/* dont want this memory dump for normal level of debugging. +// So, I have put it under a stronger debug symbol. mahendra */ + + for(i=0; i < length; i++) + { + printf("0x%x ", (startvAddress[i])); + if(isascii(startvAddress[i])) { + printf("%c ", (startvAddress[i])); + } + } +#endif /*LINUX_DEBUG_MAX */ + + *virtualAddress = (int)(startvAddress + diff); + return ACCESN_OK; +} + +ACCESN_STATUS +UnmapPhysicalMemory( int virtualAddress, int Length ) +{ + unsigned int diff = 0; + + /* page align the virtual address and adjust length accordingly */ + diff = ((unsigned int) virtualAddress) % PAGESIZE; + virtualAddress -= diff; + Length += diff; +#ifndef NO_MACRO_ARGS + DEBUG("%s: calling munmap(0x%x,%d)\n",__FUNCTION__,virtualAddress,Length); +#endif + + if(munmap((caddr_t)virtualAddress, Length) != 0) + { + char buf[128]; + + sprintf(buf,"%s %s: munmap failed", __FILE__,__FUNCTION__); + perror(buf); + return ACCESN_ERROR; + + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: munmap(0x%x,%d) success\n",__FUNCTION__,virtualAddress,Length); +#endif + + return ACCESN_OK; +} +#endif /*unix*/ + +#endif /*IMB_MEMORY*/ + + +/*///////////////////////////////////////////////////////////////////////////// +// GetIpmiVersion +//////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: GetIpmiVersion +// Purpose: This function returns current IPMI version +// Context: +// Returns: IPMI version +// Parameters: +// reqPtr +// timeOut +// respDataPtr +// respLen +// Notes: svuppula +*F*/ +BYTE GetIpmiVersion() +{ + return ((BYTE)IpmiVersion); +} + +#ifdef IMBDLL +/* Inlude this routine if building WIN32 imbapi.dll */ +BOOL WINAPI DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) +{ + switch(ulReason) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + break; + case DLL_PROCESS_DETACH: + case DLL_THREAD_DETACH: + break; + default: + return FALSE; + } + return TRUE; +} +#endif + +#endif +/*end of imbapi.c*/ diff --git a/util/ipicmg.c b/util/ipicmg.c new file mode 100644 index 0000000..c549151 --- /dev/null +++ b/util/ipicmg.c @@ -0,0 +1,1911 @@ +/* + * ipicmg.c + * + * This module handles PICMG extended IPMI commands. + * + * Change History: + * 06/03/2010 ARCress - new, included in source tree + * 08/15/2011 ARCress - updated with PICMG 2.3 + * + *---------------------------------------------------------------------- + * Copyright (c) 2010 Kontron. All right reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Kontron, or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * THE COPYRIGHT HOLDER AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL THE + * COPYRIGHT HOLDER OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR + * DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + *---------------------------------------------------------------------- + */ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include "ipmicmd.h" +#include "ipicmg.h" + +/* Misc PICMG defines */ +#define PICMG_EXTENSION_ATCA_MAJOR_VERSION 2 +#define PICMG_EXTENSION_AMC0_MAJOR_VERSION 4 +#define PICMG_EXTENSION_UTCA_MAJOR_VERSION 5 + + +#define PICMG_EKEY_MODE_QUERY 0 +#define PICMG_EKEY_MODE_PRINT_ALL 1 +#define PICMG_EKEY_MODE_PRINT_ENABLED 2 +#define PICMG_EKEY_MODE_PRINT_DISABLED 3 + +#define PICMG_EKEY_MAX_CHANNEL 16 +#define PICMG_EKEY_MAX_FABRIC_CHANNEL 15 +#define PICMG_EKEY_MAX_INTERFACE 3 + +#define PICMG_EKEY_AMC_MAX_CHANNEL 16 +#define PICMG_EKEY_AMC_MAX_DEVICE 15 /* 4 bits */ + +/* Global data */ +static char * progname = "ipicmg"; +static char * progver = "2.93"; +static char fdebug = 0; +static char fset_mc = 0; +static uint8_t g_bus = PUBLIC_BUS; +static uint8_t g_sa = BMC_SA; +static uint8_t g_lun = BMC_LUN; +static uint8_t g_addrtype = ADDR_SMI; +static uint8_t g_fruid = 0; +static unsigned char PicmgExtMajorVersion; + +typedef enum picmg_bused_resource_mode { + PICMG_BUSED_RESOURCE_SUMMARY, +} t_picmg_bused_resource_mode ; + + +typedef enum picmg_card_type { + PICMG_CARD_TYPE_CPCI, + PICMG_CARD_TYPE_ATCA, + PICMG_CARD_TYPE_AMC, + PICMG_CARD_TYPE_RESERVED +} t_picmg_card_type ; + +/* This is the version of the PICMG Extenstion */ +static t_picmg_card_type PicmgCardType = PICMG_CARD_TYPE_RESERVED; + +const struct valstr picmg_frucontrol_vals[] = { + { 0, "Cold Reset" }, + { 1, "Warm Reset" }, + { 2, "Graceful Reboot" }, + { 3, "Issue Diagnostic Interrupt" }, + { 4, "Quiesce" }, + { 5, NULL }, +}; + +const struct valstr picmg_clk_family_vals[] = { + { 0x00, "Unspecified" }, + { 0x01, "SONET/SDH/PDH" }, + { 0x02, "Reserved for PCI Express" }, + { 0x03, "Reserved" }, /* from 03h to C8h */ + { 0xC9, "Vendor defined clock family" }, /* from C9h to FFh */ + { 0x00, NULL }, +}; + +const struct oemvalstr picmg_clk_accuracy_vals[] = { + { 0x01, 10, "PRS" }, + { 0x01, 20, "STU" }, + { 0x01, 30, "ST2" }, + { 0x01, 40, "TNC" }, + { 0x01, 50, "ST3E" }, + { 0x01, 60, "ST3" }, + { 0x01, 70, "SMC" }, + { 0x01, 80, "ST4" }, + { 0x01, 90, "DUS" }, + { 0x02, 0xE0, "PCI Express Generation 2" }, + { 0x02, 0xF0, "PCI Express Generation 1" }, + { 0xffffff, 0x00, NULL } +}; + +const struct oemvalstr picmg_clk_resource_vals[] = { + { 0x0, 0, "On-Carrier Device 0" }, + { 0x0, 1, "On-Carrier Device 1" }, + { 0x1, 1, "AMC Site 1 - A1" }, + { 0x1, 2, "AMC Site 1 - A2" }, + { 0x1, 3, "AMC Site 1 - A3" }, + { 0x1, 4, "AMC Site 1 - A4" }, + { 0x1, 5, "AMC Site 1 - B1" }, + { 0x1, 6, "AMC Site 1 - B2" }, + { 0x1, 7, "AMC Site 1 - B3" }, + { 0x1, 8, "AMC Site 1 - B4" }, + { 0x2, 0, "ATCA Backplane" }, + { 0xffffff, 0x00, NULL } +}; + +const struct oemvalstr picmg_clk_id_vals[] = { + { 0x0, 0, "Clock 0" }, + { 0x0, 1, "Clock 1" }, + { 0x0, 2, "Clock 2" }, + { 0x0, 3, "Clock 3" }, + { 0x0, 4, "Clock 4" }, + { 0x0, 5, "Clock 5" }, + { 0x0, 6, "Clock 6" }, + { 0x0, 7, "Clock 7" }, + { 0x0, 8, "Clock 8" }, + { 0x0, 9, "Clock 9" }, + { 0x0, 10, "Clock 10" }, + { 0x0, 11, "Clock 11" }, + { 0x0, 12, "Clock 12" }, + { 0x0, 13, "Clock 13" }, + { 0x0, 14, "Clock 14" }, + { 0x0, 15, "Clock 15" }, + { 0x1, 1, "TCLKA" }, + { 0x1, 2, "TCLKB" }, + { 0x1, 3, "TCLKC" }, + { 0x1, 4, "TCLKD" }, + { 0x1, 5, "FLCKA" }, + { 0x2, 1, "CLK1A" }, + { 0x2, 2, "CLK1A" }, + { 0x2, 3, "CLK1A" }, + { 0x2, 4, "CLK1A" }, + { 0x2, 5, "CLK1A" }, + { 0x2, 6, "CLK1A" }, + { 0x2, 7, "CLK1A" }, + { 0x2, 8, "CLK1A" }, + { 0x2, 9, "CLK1A" }, + { 0xffffff, 0x00, NULL } +}; + +const struct valstr picmg_busres_id_vals[] = { + { 0x0, "Metallic Test Bus pair #1" }, + { 0x1, "Metallic Test Bus pair #2" }, + { 0x2, "Synch clock group 1 (CLK1)" }, + { 0x3, "Synch clock group 2 (CLK2)" }, + { 0x4, "Synch clock group 3 (CLK3)" }, + { 0x5, NULL } +}; +const struct valstr picmg_busres_board_cmd_vals[] = { + { 0x0, "Query" }, + { 0x1, "Release" }, + { 0x2, "Force" }, + { 0x3, "Bus Free" }, + { 0x4, NULL } +}; + +const struct valstr picmg_busres_shmc_cmd_vals[] = { + { 0x0, "Request" }, + { 0x1, "Relinquish" }, + { 0x2, "Notify" }, + { 0x3, NULL } +}; + +const struct oemvalstr picmg_busres_board_status_vals[] = { + { 0x0, 0x0, "In control" }, + { 0x0, 0x1, "No control" }, + { 0x1, 0x0, "Ack" }, + { 0x1, 0x1, "Refused" }, + { 0x1, 0x2, "No control" }, + { 0x2, 0x0, "Ack" }, + { 0x2, 0x1, "No control" }, + { 0x3, 0x0, "Accept" }, + { 0x3, 0x1, "Not Needed" }, + { 0xffffff, 0x00, NULL } +}; + +const struct oemvalstr picmg_busres_shmc_status_vals[] = { + { 0x0, 0x0, "Grant" }, + { 0x0, 0x1, "Busy" }, + { 0x0, 0x2, "Defer" }, + { 0x0, 0x3, "Deny" }, + + { 0x1, 0x0, "Ack" }, + { 0x1, 0x1, "Error" }, + + { 0x2, 0x0, "Ack" }, + { 0x2, 0x1, "Error" }, + { 0x2, 0x2, "Deny" }, + + { 0xffffff, 0x00, NULL } +}; + +void +ipmi_picmg_help (void) +{ + printf(" properties - get PICMG properties\n"); + printf(" frucontrol - FRU control\n"); + printf(" addrinfo - get address information\n"); + printf(" activate - activate a FRU\n"); + printf(" deactivate - deactivate a FRU\n"); + printf(" policy get - get the FRU activation policy\n"); + printf(" policy set - set the FRU activation policy\n"); + printf(" portstate get - get port state \n"); + printf(" portstate getdenied - get all denied[disabled] port description\n"); + printf(" portstate getgranted - get all granted[enabled] port description\n"); + printf(" portstate getall - get all port state description\n"); + printf(" portstate set - set port state \n"); + printf(" amcportstate get - get port state \n"); + printf(" amcportstate set - set port state \n"); + printf(" led prop - get led properties\n"); + printf(" led cap - get led color capabilities\n"); + printf(" led get - get led state\n"); + printf(" led set - set led state\n"); + printf(" power get - get power level info\n"); + printf(" power set - set power level\n"); + printf(" clk get - get clk state\n"); + printf(" clk getdenied - get all(up to 16) denied[disabled] clock descriptions\n"); + printf(" clk getgranted - get all(up to 16) granted[enabled] clock descriptions\n"); + printf(" clk getall - get all(up to 16) clock descriptions\n"); + printf(" clk set - set clk state\n"); + printf(" busres summary - display brief bused resource status info \n"); +} + +struct sAmcAddrMap { + unsigned char ipmbLAddr; + char* amcBayId; + unsigned char siteNum; +} amcAddrMap[] = { + {0xFF, "reserved", 0}, + {0x72, "A1" , 1}, + {0x74, "A2" , 2}, + {0x76, "A3" , 3}, + {0x78, "A4" , 4}, + {0x7A, "B1" , 5}, + {0x7C, "B2" , 6}, + {0x7E, "B3" , 7}, + {0x80, "B4" , 8}, + {0x82, "reserved", 0}, + {0x84, "reserved", 0}, + {0x86, "reserved", 0}, + {0x88, "reserved", 0}, +}; + +int +ipmi_picmg_getaddr(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char msg_data[5]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_ADDRESS_INFO_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + msg_data[0] = 0; /* picmg identifier */ + msg_data[1] = 0; /* default fru id */ + + if(argc > 0) { + msg_data[1] = (uint8_t)strtoul(argv[0], NULL,0); /* FRU ID */ + } + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error getting address information CC: 0x%02x\n", rv); + return rv; + } + + printf("Hardware Address : 0x%02x\n", rsp[1]); + printf("IPMB-0 Address : 0x%02x\n", rsp[2]); + printf("FRU ID : 0x%02x\n", rsp[4]); + printf("Site ID : 0x%02x\n", rsp[5]); + + printf("Site Type : "); + switch (rsp[6]) { + case PICMG_ATCA_BOARD: + printf("ATCA board\n"); + break; + case PICMG_POWER_ENTRY: + printf("Power Entry Module\n"); + break; + case PICMG_SHELF_FRU: + printf("Shelf FRU\n"); + break; + case PICMG_DEDICATED_SHMC: + printf("Dedicated Shelf Manager\n"); + break; + case PICMG_FAN_TRAY: + printf("Fan Tray\n"); + break; + case PICMG_FAN_FILTER_TRAY: + printf("Fan Filter Tray\n"); + break; + case PICMG_ALARM: + printf("Alarm module\n"); + break; + case PICMG_AMC: + printf("AMC"); + printf(" -> IPMB-L Address: 0x%02x\n", amcAddrMap[rsp[5]].ipmbLAddr); + break; + case PICMG_PMC: + printf("PMC\n"); + break; + case PICMG_RTM: + printf("RTM\n"); + break; + default: + if (rsp[6] >= 0xc0 && rsp[6] <= 0xcf) { + printf("OEM\n"); + } else { + printf("unknown\n"); + } + } + + return 0; +} + +int +ipmi_picmg_properties(void * intf, int show ) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + unsigned char PicmgExtMajorVersion; + struct ipmi_rq req; + unsigned char msg_data; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_PICMG_PROPERTIES_CMD; + req.msg.data = &msg_data; + req.msg.data_len = 1; + msg_data = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error %d getting picmg properties\n", rv); + return rv; + } + + if( show ) + { + printf("PICMG identifier : 0x%02x\n", rsp[0]); + printf("PICMG Ext. Version : %i.%i\n", rsp[1]&0x0f, + (rsp[1]&0xf0) >> 4); + printf("Max FRU Device ID : 0x%02x\n", rsp[2]); + printf("FRU Device ID : 0x%02x\n", rsp[3]); + } + + /* We cache the major extension version ... + to know how to format some commands */ + PicmgExtMajorVersion = rsp[1]&0x0f; + + if( PicmgExtMajorVersion == PICMG_CPCI_MAJOR_VERSION ) { + PicmgCardType = PICMG_CARD_TYPE_CPCI; + } + else if( PicmgExtMajorVersion == PICMG_ATCA_MAJOR_VERSION) { + PicmgCardType = PICMG_CARD_TYPE_ATCA; + } + else if( PicmgExtMajorVersion == PICMG_AMC_MAJOR_VERSION) { + PicmgCardType = PICMG_CARD_TYPE_AMC; + } + + return 0; +} + + + +#define PICMG_FRU_DEACTIVATE (unsigned char) 0x00 +#define PICMG_FRU_ACTIVATE (unsigned char) 0x01 + +int +ipmi_picmg_fru_activation(void * intf, int argc, char ** argv, unsigned char state) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + struct picmg_set_fru_activation_cmd cmd; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_FRU_ACTIVATION_CMD; + req.msg.data = (unsigned char*) &cmd; + req.msg.data_len = 3; + + cmd.picmg_id = 0; /* PICMG identifier */ + cmd.fru_id = atob(argv[0]); /* FRU ID */ + cmd.fru_state = state; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error %d on activation/deactivation of FRU\n",rv); + return rv; + } + if (rsp[0] != 0x00) { + printf("Error, invalid response\n"); + } + + return 0; +} + + +int +ipmi_picmg_fru_activation_policy_get(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[4]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_FRU_POLICY_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + + msg_data[0] = 0; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU ID */ + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + printf(" %s\n", ((rsp[1] & 0x01) == 0x01) ? + "activation locked" : "activation not locked"); + printf(" %s\n", ((rsp[1] & 0x02) == 0x02) ? + "deactivation locked" : "deactivation not locked"); + + return 0; +} + +int +ipmi_picmg_fru_activation_policy_set(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[4]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_SET_FRU_POLICY_CMD; + req.msg.data = msg_data; + req.msg.data_len = 4; + + msg_data[0] = 0; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU ID */ + msg_data[2] = atob(argv[1])& 0x03; /* FRU act policy mask */ + msg_data[3] = atob(argv[2])& 0x03; /* FRU act policy set bits */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + +#define PICMG_MAX_LINK_PER_CHANNEL 4 + +int +ipmi_picmg_portstate_get(void * intf, int interfc, uchar channel, int mode) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char msg_data[4]; + struct fru_picmgext_link_desc* d; /* descriptor pointer for rec. data */ + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_PORT_STATE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = (interfc & 0x3)<<6; /* interface */ + msg_data[1] |= (channel & 0x3F); /* channel number */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else if( mode == PICMG_EKEY_MODE_QUERY ) + printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + if (rsp_len >= 6) { + int index; + /* add support for more than one link per channel */ + for(index=0;index<PICMG_MAX_LINK_PER_CHANNEL;index++){ + if( rsp_len > (1+ (index*5))){ + d = (struct fru_picmgext_link_desc *) &(rsp[1 + (index*5)]); + + if + ( + mode == PICMG_EKEY_MODE_PRINT_ALL + || + mode == PICMG_EKEY_MODE_QUERY + || + ( + mode == PICMG_EKEY_MODE_PRINT_ENABLED + && + rsp[5 + (index*5) ] == 0x01 + ) + || + ( + mode == PICMG_EKEY_MODE_PRINT_DISABLED + && + rsp[5 + (index*5) ] == 0x00 + ) + ) + { + printf(" Link Grouping ID: 0x%02x\n", d->grouping); + printf(" Link Type Extension: 0x%02x\n", d->ext); + printf(" Link Type: 0x%02x ", d->type); + if (d->type == 0 || d->type == 0xff) + { + printf("Reserved %d\n",d->type); + } + else if (d->type >= 0x06 && d->type <= 0xef) + { + printf("Reserved %d\n",d->type); + } + else if (d->type >= 0xf0 && d->type <= 0xfe) + { + printf("OEM GUID Definition %d\n",d->type); + } + else + { + switch (d->type) + { + case FRU_PICMGEXT_LINK_TYPE_BASE: + printf("PICMG 3.0 Base Interface 10/100/1000\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET: + printf("PICMG 3.1 Ethernet Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND: + printf("PICMG 3.2 Infiniband Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR: + printf("PICMG 3.3 Star Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_PCIE: + printf("PCI Express Fabric Interface\n"); + break; + default: + printf("Invalid\n"); + break; + } + } + printf(" Link Designator: \n"); + printf(" Port Flag: 0x%02x\n", d->desig_port); + printf(" Interface: 0x%02x - ", d->desig_if); + switch (d->desig_if) + { + case FRU_PICMGEXT_DESIGN_IF_BASE: + printf("Base Interface\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_FABRIC: + printf("Fabric Interface\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL: + printf("Update Channel\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_RESERVED: + printf("Reserved\n"); + break; + default: + printf("Invalid"); + break; + } + printf(" Channel Number: 0x%02x\n", d->desig_channel); + printf(" STATE: %s\n", + ( rsp[5 +(index*5)] == 0x01) ?"enabled":"disabled"); + printf("\n"); + } + } + } + } + else + { + printf("Unexpected answer len %d, can't print result\n",rsp_len); + } + + return 0; +} + + +int +ipmi_picmg_portstate_set(void * intf, int interfc, uchar channel, + uchar port, int type, int typeext, int group, int enable) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char msg_data[6]; + // struct fru_picmgext_link_desc* d; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_SET_PORT_STATE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 6; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = (channel & 0x3f) | ((interfc & 3) << 6); + msg_data[2] = (port & 0xf) | ((type & 0xf) << 4); + msg_data[3] = ((type >> 4) & 0xf) | ((typeext & 0xf) << 4); + msg_data[4] = group & 0xff; + msg_data[5] = (unsigned char) (enable & 0x01); /* en/dis */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + + + +/* AMC.0 commands */ + +#define PICMG_AMC_MAX_LINK_PER_CHANNEL 4 + +int +ipmi_picmg_amc_portstate_get(void * intf,int device,uchar channel, + int mode) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[4]; + + struct fru_picmgext_amc_link_info* d; /* descriptor pointer for rec. data */ + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_AMC_GET_PORT_STATE_CMD; + req.msg.data = msg_data; + + /* FIXME : add check for AMC or carrier device */ + if(device == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){ + req.msg.data_len = 2; /* for amc only channel */ + }else{ + req.msg.data_len = 3; /* for carrier channel and device */ + } + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = channel ; + msg_data[2] = (uchar)device ; + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else if ( mode == PICMG_EKEY_MODE_QUERY ) + printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + if (rsp_len >= 5) { + int index; + + /* add support for more than one link per channel */ + for(index=0;index<PICMG_AMC_MAX_LINK_PER_CHANNEL;index++){ + + if( rsp_len > (1+ (index*4))){ + unsigned char type; + unsigned char ext; + unsigned char grouping; + unsigned char port; + unsigned char enabled; + d = (struct fru_picmgext_amc_link_info *)&(rsp[1 + (index*4)]); + + + /* Removed endianness check here, probably not required + as we dont use bitfields */ + port = d->linkInfo[0] & 0x0F; + type = ((d->linkInfo[0] & 0xF0) >> 4 )|(d->linkInfo[1] & 0x0F ); + ext = ((d->linkInfo[1] & 0xF0) >> 4 ); + grouping = d->linkInfo[2]; + + + enabled = rsp[4 + (index*4) ]; + + if + ( + mode == PICMG_EKEY_MODE_PRINT_ALL + || + mode == PICMG_EKEY_MODE_QUERY + || + ( + mode == PICMG_EKEY_MODE_PRINT_ENABLED + && + enabled == 0x01 + ) + || + ( + mode == PICMG_EKEY_MODE_PRINT_DISABLED + && + enabled == 0x00 + ) + ) + { + if(device == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){ + printf(" Link device : AMC\n"); + }else{ + printf(" Link device : 0x%02x\n", device ); + } + + printf(" Link Grouping ID: 0x%02x\n", grouping); + + if (type == 0 || type == 1 ||type == 0xff) + { + printf(" Link Type Extension: 0x%02x\n", ext); + printf(" Link Type: Reserved\n"); + } + else if (type >= 0xf0 && type <= 0xfe) + { + printf(" Link Type Extension: 0x%02x\n", ext); + printf(" Link Type: OEM GUID Definition\n"); + } + else + { + if (type <= FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE ) + { + printf(" Link Type Extension: %s\n", + amc_link_type_ext_str[type][ext]); + printf(" Link Type: %s\n", + amc_link_type_str[type]); + } + else{ + printf(" Link Type Extension: 0x%02x\n", ext); + printf(" Link Type: undefined\n"); + } + } + printf(" Link Designator: \n"); + printf(" Channel Number: 0x%02x\n", channel); + printf(" Port Flag: 0x%02x\n", port ); + printf(" STATE: %s\n", + ( enabled == 0x01 )?"enabled":"disabled"); + printf("\n"); + } + } + } + } + else + { + printf("ipmi_picmg_amc_portstate_get: " + "Unexpected answer, can't print result\n"); + } + + return 0; +} + + +int +ipmi_picmg_amc_portstate_set(void * intf, uchar channel, uchar port, + int type, int typeext, int group, int enable, int device) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char msg_data[7]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_AMC_SET_PORT_STATE_CMD; + req.msg.data = msg_data; + + msg_data[0] = 0x00; /* PICMG identifier*/ + msg_data[1] = channel; /* channel id */ + msg_data[2] = port & 0xF; /* port flags */ + msg_data[2] |= (type & 0x0F)<<4; /* type */ + msg_data[3] = (type & 0xF0)>>4; /* type */ + msg_data[3] |= (typeext & 0x0F)<<4; /* extension */ + msg_data[4] = (group & 0xFF); /* group */ + msg_data[5] = (enable & 0x01); /* state */ + req.msg.data_len = 6; + + /* device id - only for carrier needed */ + if (device >= 0) { + msg_data[6] = (uchar)device; + req.msg.data_len = 7; + } + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + + +int +ipmi_picmg_get_led_properties(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_FRU_LED_PROPERTIES_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + printf("General Status LED Properties: 0x%2x\n\r", rsp[1] ); + printf("App. Specific LED Count: 0x%2x\n\r", rsp[2] ); + + return 0; +} + +int +ipmi_picmg_get_led_capabilities(void * intf, int argc, char ** argv) +{ + int i; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_LED_COLOR_CAPABILITIES_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* LED-ID */ + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + printf("LED Color Capabilities: %02x", rsp[1] ); + for ( i=0 ; i<8 ; i++ ) { + if ( rsp[1] & (0x01 << i) ) { + printf("%s, ", led_color_str[ i ]); + } + } + printf("\n\r"); + + printf("Default LED Color in\n\r"); + printf(" LOCAL control: %s\n\r", led_color_str[ rsp[2] ] ); + printf(" OVERRIDE state: %s\n\r", led_color_str[ rsp[3] ] ); + + return 0; +} + +int +ipmi_picmg_get_led_state(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_FRU_LED_STATE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* LED-ID */ + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + printf("LED states: %x ", rsp[1] ); + if (rsp[1] == 0x1) + printf("[LOCAL CONTROL]\n\r"); + else if (rsp[1] == 0x2) + printf("[OVERRIDE]\n\r"); + else if (rsp[1] == 0x4) + printf("[LAMPTEST]\n\r"); + else + printf("\n\r"); + + printf(" Local Control function: %x ", rsp[2] ); + if (rsp[2] == 0x0) + printf("[OFF]\n\r"); + else if (rsp[2] == 0xff) + printf("[ON]\n\r"); + else + printf("[BLINKING]\n\r"); + + printf(" Local Control On-Duration: %x\n\r", rsp[3] ); + printf(" Local Control Color: %x [%s]\n\r", rsp[4], led_color_str[ rsp[4] ]); + + /* override state or lamp test */ + if (rsp[1] == 0x02) { + printf(" Override function: %x ", rsp[5] ); + if (rsp[2] == 0x0) + printf("[OFF]\n\r"); + else if (rsp[2] == 0xff) + printf("[ON]\n\r"); + else + printf("[BLINKING]\n\r"); + + printf(" Override On-Duration: %x\n\r", rsp[6] ); + printf(" Override Color: %x [%s]\n\r", rsp[7], led_color_str[ rsp[7] ]); + + }else if (rsp[1] == 0x06) { + printf(" Override function: %x ", rsp[5] ); + if (rsp[2] == 0x0) + printf("[OFF]\n\r"); + else if (rsp[2] == 0xff) + printf("[ON]\n\r"); + else + printf("[BLINKING]\n\r"); + printf(" Override On-Duration: %x\n\r", rsp[6] ); + printf(" Override Color: %x [%s]\n\r", rsp[7], led_color_str[ rsp[7] ]); + printf(" Lamp test duration: %x\n\r", rsp[8] ); + } + + return 0; +} + +int +ipmi_picmg_set_led_state(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_SET_FRU_LED_STATE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 6; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* LED-ID */ + msg_data[3] = atob(argv[2]); /* LED function */ + msg_data[4] = atob(argv[3]); /* LED on duration */ + msg_data[5] = atob(argv[4]); /* LED color */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + + return 0; +} + +int +ipmi_picmg_get_power_level(void * intf, int argc, char ** argv) +{ + int i; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_POWER_LEVEL_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* Power type */ + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + printf("Dynamic Power Configuration: %s\n", (rsp[1]&0x80)==0x80?"enabled":"disabled" ); + printf("Actual Power Level: %i\n", (rsp[1] & 0xf)); + printf("Delay to stable Power: %i\n", rsp[2]); + printf("Power Multiplier: %i\n", rsp[3]); + + + for ( i = 1; i+3 < rsp_len ; i++ ) { + printf(" Power Draw %i: %i\n", i, (rsp[i+3]) * rsp[3] / 10); + } + return 0; +} + +int +ipmi_picmg_set_power_level(void * intf, int argc, char ** argv) +{ + // int i; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_SET_POWER_LEVEL_CMD; + req.msg.data = msg_data; + req.msg.data_len = 4; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* power level */ + msg_data[3] = atob(argv[2]); /* present to desired */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + +int +ipmi_picmg_bused_resource(void * intf, t_picmg_bused_resource_mode mode) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + memset(&req, 0, sizeof(req)); + + switch ( mode ) { + case PICMG_BUSED_RESOURCE_SUMMARY: + { + t_picmg_busres_resource_id resource; + t_picmg_busres_board_cmd_types cmd =PICMG_BUSRES_BOARD_CMD_QUERY; + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_BUSED_RESOURCE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + /* IF BOARD + query for all resources + */ + for( resource=PICMG_BUSRES_METAL_TEST_BUS_1;resource<=PICMG_BUSRES_SYNC_CLOCK_GROUP_3;resource+=(t_picmg_busres_resource_id)1 ) { + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = (unsigned char) cmd; + msg_data[2] = (unsigned char) resource; + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("bused resource control: no response\n"); + else printf("bused resource control: returned Completion Code 0x%02x\n",rv); + return rv; + } else { + printf("Resource 0x%02x '%-26s' : 0x%02x [%s] \n" , + resource, val2str(resource,picmg_busres_id_vals), + rsp[1], oemval2str(cmd,rsp[1], + picmg_busres_board_status_vals)); + } + } + } + break; + default: rv = -1; + break; + } + + return rv; +} + +int +ipmi_picmg_fru_control(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_FRU_CONTROL_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* control option */ + + printf("FRU Device Id: %d FRU Control Option: %s\n\r", msg_data[1], \ + val2str( msg_data[2], picmg_frucontrol_vals)); + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("frucontrol: no response\n"); + else printf("frucontrol: returned Completion Code 0x%02x\n",rv); + return rv; + } else { + printf("frucontrol: ok\n"); + } + + return 0; +} + + +int +ipmi_picmg_clk_get(void * intf, int clk_id,int clk_res,int mode) +{ + // int i; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char enabled; + unsigned char direction; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_AMC_GET_CLK_STATE_CMD; + req.msg.data = msg_data; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = clk_id; + + if(clk_res == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){ + req.msg.data_len = 2; /* for amc only channel */ + }else{ + req.msg.data_len = 3; /* for carrier channel and device */ + msg_data[2] = clk_res; + } + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + { + enabled = (rsp[1]&0x8)!=0; + direction = (rsp[1]&0x4)!=0; + + if + ( + mode == PICMG_EKEY_MODE_QUERY + || + mode == PICMG_EKEY_MODE_PRINT_ALL + || + ( + mode == PICMG_EKEY_MODE_PRINT_DISABLED + && + enabled == 0 + ) + || + ( + mode == PICMG_EKEY_MODE_PRINT_ENABLED + && + enabled == 1 + ) + ) { + if( PicmgCardType != PICMG_CARD_TYPE_AMC ) { + printf("CLK resource id : %3d [ %s ]\n", clk_res , + oemval2str( ((clk_res>>6)&0x03), (clk_res&0x0F), + picmg_clk_resource_vals)); + } else { + printf("CLK resource id : N/A [ AMC Module ]\n"); + clk_res = 0x40; /* Set */ + } + printf("CLK id : %3d [ %s ]\n", clk_id, + oemval2str( ((clk_res>>6)&0x03), clk_id , + picmg_clk_id_vals)); + + + printf("CLK setting : 0x%02x\n", rsp[1]); + printf(" - state: %s\n", (enabled)?"enabled":"disabled"); + printf(" - direction: %s\n", (direction)?"Source":"Receiver"); + printf(" - PLL ctrl: 0x%x\n", rsp[1]&0x3); + + if(enabled){ + unsigned long freq = 0; + freq = ( rsp[5] << 0 + | rsp[6] << 8 + | rsp[7] << 16 + | rsp[8] << 24 ); + printf(" - Index: %3d\n", rsp[2]); + printf(" - Family: %3d [ %s ]\n", rsp[3], + val2str( rsp[3], picmg_clk_family_vals)); + printf(" - AccLVL: %3d [ %s ]\n", rsp[4], + oemval2str(rsp[3],rsp[4],picmg_clk_accuracy_vals)); + printf(" - Freq: %d\n", freq); + } + } + } + return 0; +} + + +int +ipmi_picmg_clk_set(void * intf, int argc, char ** argv) +{ + // int i; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[11]; + unsigned long freq=0; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_AMC_SET_CLK_STATE_CMD; + req.msg.data = msg_data; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = (uchar)strtoul(argv[0], NULL,0); /* clk id */ + msg_data[2] = (uchar)strtoul(argv[1], NULL,0); /* clk index */ + msg_data[3] = (uchar)strtoul(argv[2], NULL,0); /* setting */ + msg_data[4] = (uchar)strtoul(argv[3], NULL,0); /* family */ + msg_data[5] = (uchar)strtoul(argv[4], NULL,0); /* acc */ + + freq = strtoul(argv[5], NULL,0); + msg_data[6] = (uchar)((freq >> 0)& 0xFF); /* freq */ + msg_data[7] = (uchar)((freq >> 8)& 0xFF); /* freq */ + msg_data[8] = (uchar)((freq >>16)& 0xFF); /* freq */ + msg_data[9] = (uchar)((freq >>24)& 0xFF); /* freq */ + + req.msg.data_len = 10; + if( PicmgCardType == PICMG_CARD_TYPE_ATCA ) + { + if( argc > 7) + { + req.msg.data_len = 11; + msg_data[10] = (uchar)strtoul(argv[6], NULL,0); /* resource id */ + } + else + { + printf("missing resource id for atca board\n"); + return -1; + } + } + +#if 1 +printf("## ID: %d\n", msg_data[1]); +printf("## index: %d\n", msg_data[2]); +printf("## setting: 0x%02x\n", msg_data[3]); +printf("## family: %d\n", msg_data[4]); +printf("## acc: %d\n", msg_data[5]); +printf("## freq: %d\n", freq ); +printf("## res: %d\n", msg_data[10]); +#endif + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + + +#ifdef METACOMMAND +int i_picmg(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int rc = 0; + int showProperties = 0; + void *intf = NULL; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"m:i:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'i': /*specify a fru id*/ + if (strncmp(optarg,"0x",2) == 0) g_fruid = htoi(&optarg[2]); + else g_fruid = htoi(optarg); + printf("Using FRU ID 0x%02x\n",g_fruid); + break; + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + ipmi_picmg_help(); + return ERR_USAGE; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + /* Get PICMG properties is called to obtain version information */ + if (argc !=0 && !strncmp(argv[0], "properties", 10)) { + showProperties =1; + } + + if (argc == 0 || (!strncmp(argv[0], "help", 4))) { + ipmi_picmg_help(); + return ERR_USAGE; + } + + rc = ipmi_picmg_properties(intf,showProperties); + if (rc < 0) { /*cannot contact MC, so exit*/ + goto do_exit; + } + + /* address info command */ + else if (!strncmp(argv[0], "addrinfo", 8)) { + rc = ipmi_picmg_getaddr(intf, argc-1, &argv[1]); + } + else if (!strncmp(argv[0], "busres", 6)) { + if (argc > 1) { + if (!strncmp(argv[1], "summary", 7)) { + ipmi_picmg_bused_resource(intf, PICMG_BUSED_RESOURCE_SUMMARY ); + } + } else { + printf("usage: busres summary\n"); + } + } + /* fru control command */ + else if (!strncmp(argv[0], "frucontrol", 10)) { + if (argc > 2) { + rc = ipmi_picmg_fru_control(intf, argc-1, &(argv[1])); + } + else { + printf("usage: frucontrol <FRU-ID> <OPTION>\n"); + printf(" OPTION:\n"); + printf(" 0 - Cold Reset\n"); + printf(" 1 - Warm Reset\n"); + printf(" 2 - Graceful Reboot\n"); + printf(" 3 - Issue Diagnostic Interrupt\n"); + printf(" 4 - Quiesce [AMC only]\n"); + printf(" 5-255 - Reserved\n"); + + rc = -1; + } + + } + + /* fru activation command */ + else if (!strncmp(argv[0], "activate", 8)) { + if (argc > 1) { + rc = ipmi_picmg_fru_activation(intf, argc-1, &(argv[1]), PICMG_FRU_ACTIVATE); + } + else { + printf("specify the FRU to activate\n"); + rc = -1; + } + } + + /* fru deactivation command */ + else if (!strncmp(argv[0], "deactivate", 10)) { + if (argc > 1) { + rc = ipmi_picmg_fru_activation(intf, argc-1, &(argv[1]), PICMG_FRU_DEACTIVATE); + }else { + printf("specify the FRU to deactivate\n"); + rc = -1; + } + } + + /* activation policy command */ + else if (!strncmp(argv[0], "policy", 6)) { + if (argc > 1) { + if (!strncmp(argv[1], "get", 3)) { + if (argc > 2) { + rc = ipmi_picmg_fru_activation_policy_get(intf, argc-1, &(argv[2])); + } else { + printf("usage: get <fruid>\n"); + } + } else if (!strncmp(argv[1], "set", 3)) { + if (argc > 4) { + rc = ipmi_picmg_fru_activation_policy_set(intf, argc-1, &(argv[2])); + } else { + printf("usage: set <fruid> <lockmask> <lock>\n"); + printf(" lockmask: [1] affect the deactivation locked bit\n"); + printf(" [0] affect the activation locked bit\n"); + printf(" lock: [1] set/clear deactivation locked\n"); + printf(" [0] set/clear locked \n"); + } + } + else { + printf("specify fru\n"); + rc = -1; + } + } else { + printf("wrong parameters\n"); + rc = -1; + } + } + + /* portstate command */ + else if (!strncmp(argv[0], "portstate", 9)) { + + if (fdebug) printf("PICMG: portstate API"); + + if (argc > 1) { + if (!strncmp(argv[1], "get", 3)) { + + int iface; + int channel; + + if (fdebug) printf("PICMG: get"); + + if(!strncmp(argv[1], "getall", 6)) { + for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) { + for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) { + if(!(( iface == FRU_PICMGEXT_DESIGN_IF_FABRIC ) && + ( channel > PICMG_EKEY_MAX_FABRIC_CHANNEL ) )) + { + rc = ipmi_picmg_portstate_get(intf,iface,(uchar)channel, + PICMG_EKEY_MODE_PRINT_ALL); + } + } + } + } + else if(!strncmp(argv[1], "getgranted", 10)) { + for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) { + for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) { + rc = ipmi_picmg_portstate_get(intf,iface,(uchar)channel, + PICMG_EKEY_MODE_PRINT_ENABLED); + } + } + } + else if(!strncmp(argv[1], "getdenied", 9)){ + for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) { + for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) { + rc = ipmi_picmg_portstate_get(intf,iface,(uchar)channel, + PICMG_EKEY_MODE_PRINT_DISABLED); + } + } + } + else if (argc > 3){ + iface = atob(argv[2]); + channel = atob(argv[3]); + if (fdebug) printf("PICMG: requesting interface %d",iface); + if (fdebug) printf("PICMG: requesting channel %d",channel); + + rc = ipmi_picmg_portstate_get(intf,iface,(uchar)channel, + PICMG_EKEY_MODE_QUERY ); + } + else { + printf("<intf> <chn>|getall|getgranted|getdenied\n"); + } + } + else if (!strncmp(argv[1], "set", 3)) { + if (argc == 9) { + int interfc = strtoul(argv[2], NULL, 0); + int channel = strtoul(argv[3], NULL, 0); + int port = strtoul(argv[4], NULL, 0); + int type = strtoul(argv[5], NULL, 0); + int typeext = strtoul(argv[6], NULL, 0); + int group = strtoul(argv[7], NULL, 0); + int enable = strtoul(argv[8], NULL, 0); + + if (fdebug) printf("PICMG: interface %d",interfc); + if (fdebug) printf("PICMG: channel %d",channel); + if (fdebug) printf("PICMG: port %d",port); + if (fdebug) printf("PICMG: type %d",type); + if (fdebug) printf("PICMG: typeext %d",typeext); + if (fdebug) printf("PICMG: group %d",group); + if (fdebug) printf("PICMG: enable %d",enable); + + rc = ipmi_picmg_portstate_set(intf, interfc, + (uchar)channel, (uchar)port, type, typeext ,group ,enable); + } + else { + printf("<intf> <chn> <port> <type> <ext> <group> <1|0>\n"); + rc = -1; + } + } + } + else { + printf("<set>|<getall>|<getgranted>|<getdenied>\n"); + rc = -1; + } + } + /* amc portstate command */ + else if (!strncmp(argv[0], "amcportstate", 12)) { + + if (fdebug) printf("PICMG: amcportstate API"); + + if (argc > 1) { + if (!strncmp(argv[1], "get", 3)){ + int channel; + int device; + + if (fdebug) printf("PICMG: get"); + + if(!strncmp(argv[1], "getall", 6)){ + int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE; + if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){ + maxDevice = 0; + } + for(device=0;device<=maxDevice;device++){ + for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){ + rc = ipmi_picmg_amc_portstate_get(intf,device,(uchar)channel, + PICMG_EKEY_MODE_PRINT_ALL); + } + } + } + else if(!strncmp(argv[1], "getgranted", 10)){ + int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE; + if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){ + maxDevice = 0; + } + for(device=0;device<=maxDevice;device++){ + for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){ + rc = ipmi_picmg_amc_portstate_get(intf,(uchar)device,(uchar)channel, + PICMG_EKEY_MODE_PRINT_ENABLED); + } + } + } + else if(!strncmp(argv[1], "getdenied", 9)){ + int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE; + if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){ + maxDevice = 0; + } + for(device=0;device<=maxDevice;device++){ + for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){ + rc = ipmi_picmg_amc_portstate_get(intf,(uchar)device,(uchar)channel, + PICMG_EKEY_MODE_PRINT_DISABLED); + } + } + } + else if (argc > 2){ + channel = atoi(argv[2]); + if (argc > 3){ + device = atoi(argv[3]); + }else{ + device = -1; + } + if (fdebug) printf("PICMG: requesting device %d",device); + if (fdebug) printf("PICMG: requesting channel %d",channel); + + rc = ipmi_picmg_amc_portstate_get(intf,(uchar)device,(uchar)channel, + PICMG_EKEY_MODE_QUERY ); + } + else { + printf("<chn> <device>|getall|getgranted|getdenied\n"); + } + } + else if (!strncmp(argv[1], "set", 3)) { + if (argc > 7) { + int channel = atoi(argv[2]); + int port = atoi(argv[3]); + int type = atoi(argv[4]); + int typeext = atoi(argv[5]); + int group = atoi(argv[6]); + int enable = atoi(argv[7]); + int device = -1; + if(argc > 8){ + device = atoi(argv[8]); + } + + if (fdebug) printf("PICMG: channel %d",channel); + if (fdebug) printf("PICMG: portflags %d",port); + if (fdebug) printf("PICMG: type %d",type); + if (fdebug) printf("PICMG: typeext %d",typeext); + if (fdebug) printf("PICMG: group %d",group); + if (fdebug) printf("PICMG: enable %d",enable); + if (fdebug) printf("PICMG: device %d",device); + + rc = ipmi_picmg_amc_portstate_set(intf, (uchar)channel, (uchar)port, type, + typeext, group, enable, device); + } + else { + printf("<chn> <portflags> <type> <ext> <group> <1|0> [<device>]\n"); + rc = -1; + } + } + } + else { + printf("<set>|<get>|<getall>|<getgranted>|<getdenied>\n"); + rc = -1; + } + } + /* ATCA led commands */ + else if (!strncmp(argv[0], "led", 3)) { + if (argc > 1) { + if (!strncmp(argv[1], "prop", 4)) { + if (argc > 2) { + rc = ipmi_picmg_get_led_properties(intf, argc-1, &(argv[2])); + } + else { + printf("led prop <FRU-ID>\n"); + } + } + else if (!strncmp(argv[1], "cap", 3)) { + if (argc > 3) { + rc = ipmi_picmg_get_led_capabilities(intf, argc-1, &(argv[2])); + } + else { + printf("led cap <FRU-ID> <LED-ID>\n"); + } + } + else if (!strncmp(argv[1], "get", 3)) { + if (argc > 3) { + rc = ipmi_picmg_get_led_state(intf, argc-1, &(argv[2])); + } + else { + printf("led get <FRU-ID> <LED-ID>\n"); + } + } + else if (!strncmp(argv[1], "set", 3)) { + if (argc > 6) { + rc = ipmi_picmg_set_led_state(intf, argc-1, &(argv[2])); + } + else { + printf("led set <FRU-ID> <LED-ID> <function> <duration> <color>\n"); + printf(" <FRU-ID>\n"); + printf(" <LED-ID> 0: Blue LED\n"); + printf(" 1: LED 1\n"); + printf(" 2: LED 2\n"); + printf(" 3: LED 3\n"); + printf(" 0x04-0xFE: OEM defined\n"); + printf(" 0xFF: All LEDs under management control\n"); + printf(" <function> 0: LED OFF override\n"); + printf(" 1 - 250: LED blinking override (off duration)\n"); + printf(" 251: LED Lamp Test\n"); + printf(" 252: LED restore to local control\n"); + printf(" 255: LED ON override\n"); + printf(" <duration> 1 - 127: LED Lamp Test / on duration\n"); + printf(" <color> 0: reserved\n"); + printf(" 1: BLUE\n"); + printf(" 2: RED\n"); + printf(" 3: GREEN\n"); + printf(" 4: AMBER\n"); + printf(" 5: ORANGE\n"); + printf(" 6: WHITE\n"); + printf(" 7: reserved\n"); + printf(" 0xE: do not change\n"); + printf(" 0xF: use default color\n"); + } + } + else { + printf("prop | cap | get | set\n"); + } + } + } + /* power commands */ + else if (!strncmp(argv[0], "power", 5)) { + if (argc > 1) { + if (!strncmp(argv[1], "get", 3)) { + if (argc > 3) { + rc = ipmi_picmg_get_power_level(intf, argc-1, &(argv[2])); + } + else { + printf("power get <FRU-ID> <type>\n"); + printf(" <type> 0 : steady state powert draw levels\n"); + printf(" 1 : desired steady state draw levels\n"); + printf(" 2 : early power draw levels\n"); + printf(" 3 : desired early levels\n"); + + rc = -1; + } + } + else if (!strncmp(argv[1], "set", 3)) { + if (argc > 4) { + rc = ipmi_picmg_set_power_level(intf, argc-1, &(argv[2])); + } + else { + printf("power set <FRU-ID> <level> <present-desired>\n"); + printf(" <level> 0 : Power Off\n"); + printf(" 0x1-0x14 : Power level\n"); + printf(" 0xFF : do not change\n"); + printf("\n"); + printf(" <present-desired> 0: do not change present levels\n"); + printf(" 1: copy desired to present level\n"); + + rc = -1; + } + } + else { + printf("<set>|<get>\n"); + rc = -1; + } + } + else { + printf("<set>|<get>\n"); + rc = -1; + } + }/* clk commands*/ + else if (!strncmp(argv[0], "clk", 3)) { + if (argc > 1) { + if (!strncmp(argv[1], "get", 3)) { + int clk_id; + int clk_res = -1; + int max_res = 15; + + if( PicmgCardType == PICMG_CARD_TYPE_AMC ) { + max_res = 0; + } + + if(!strncmp(argv[1], "getall", 6)) { + if(fdebug) printf("Getting all clock state\n"); + for(clk_res=0;clk_res<=max_res;clk_res++) { + for(clk_id=0;clk_id<=15;clk_id++) { + rc = ipmi_picmg_clk_get(intf,clk_id,clk_res, + PICMG_EKEY_MODE_PRINT_ALL); + } + } + } + else if(!strncmp(argv[1], "getdenied", 6)) { + if( fdebug ) { printf("Getting disabled clocks\n") ;} + for(clk_res=0;clk_res<=max_res;clk_res++) { + for(clk_id=0;clk_id<=15;clk_id++) { + rc = ipmi_picmg_clk_get(intf,clk_id,clk_res, + PICMG_EKEY_MODE_PRINT_DISABLED); + } + } + } + else if(!strncmp(argv[1], "getgranted", 6)) { + if( fdebug ) { printf("Getting enabled clocks\n") ;} + for(clk_res=0;clk_res<=max_res;clk_res++) { + for(clk_id=0;clk_id<=15;clk_id++) { + rc = ipmi_picmg_clk_get(intf,clk_id,clk_res, + PICMG_EKEY_MODE_PRINT_ENABLED); + } + } + } + else if (argc > 2) { + clk_id = atoi(argv[2]); + if (argc > 3) { + clk_res = atoi(argv[3]); + } + + rc = ipmi_picmg_clk_get(intf, clk_id, clk_res, + PICMG_EKEY_MODE_QUERY ); + } + else { + printf("clk get "); + printf("<CLK-ID> [<DEV-ID>] |getall|getgranted|getdenied\n"); + rc = -1; + } + } + else if (!strncmp(argv[1], "set", 3)) { + if (argc > 7) { + rc = ipmi_picmg_clk_set(intf, argc-1, &(argv[2])); + } + else { + printf("clk set <CLK-ID> <index> <setting> <family> <acc-lvl> <freq> [<DEV-ID>] \n"); + + rc = -1; + } + } + else { + printf("<set>|<get>|<getall>|<getgranted>|<getdenied>\n"); + rc = -1; + } + } + else { + printf("<set>|<get>|<getall>|<getgranted>|<getdenied>\n"); + rc = -1; + } + } + + else if(showProperties == 0 ){ + + ipmi_picmg_help(); + rc = ERR_USAGE; + } + +do_exit: + ipmi_close_(); + return rc; +} /*end i_picmg*/ + +/* end ipicmg.c */ + diff --git a/util/ipicmg.h b/util/ipicmg.h new file mode 100644 index 0000000..59fce39 --- /dev/null +++ b/util/ipicmg.h @@ -0,0 +1,313 @@ +/* + (C) Kontron + */ + +#ifndef _IPMI_PICMG_H_ +#define _IPMI_PICMG_H_ + +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int + +#define BMC_SA 0x20 +#define PUBLIC_BUS 0 +#define BMC_LUN 0 + +/* PICMG version */ +#define PICMG_CPCI_MAJOR_VERSION 1 +#define PICMG_ATCA_MAJOR_VERSION 2 +#define PICMG_AMC_MAJOR_VERSION 4 + +#define FRU_PICMGEXT_LINK_TYPE_BASE 0x01 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET 0x02 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND 0x03 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR 0x04 +#define FRU_PICMGEXT_LINK_TYPE_PCIE 0x05 + +#ifndef HAVE_FRU_PICMG_EXT +#define HAVE_FRU_PICMG_EXT +#pragma pack(1) +struct fru_picmgext_link_desc { +#ifndef WORDS_BIGENDIAN + unsigned int desig_channel:6; + unsigned int desig_if:2; + unsigned int desig_port:4; + unsigned int type:8; + unsigned int ext:4; + unsigned int grouping:8; +#else + unsigned int grouping:8; + unsigned int ext:4; + unsigned int type:8; + unsigned int desig_port:4; + unsigned int desig_if:2; + unsigned int desig_channel:6; +#endif +}; /* __attribute__ ((packed)); */ +struct fru_picmgext_amc_link_info { + unsigned char linkInfo[3]; +}; /* __attribute__ ((packed)); */ +#pragma pack() +#endif + +#define OEM_PICMG 12634 +// IPMI_OEM_PICMG = 12634, + +#define FRU_PICMG_BACKPLANE_P2P 0x04 +#define FRU_PICMG_ADDRESS_TABLE 0x10 +#define FRU_PICMG_SHELF_POWER_DIST 0x11 +#define FRU_PICMG_SHELF_ACTIVATION 0x12 +#define FRU_PICMG_SHMC_IP_CONN 0x13 +#define FRU_PICMG_BOARD_P2P 0x14 +#define FRU_AMC_CURRENT 0x16 +#define FRU_AMC_ACTIVATION 0x17 +#define FRU_AMC_CARRIER_P2P 0x18 +#define FRU_AMC_P2P 0x19 +#define FRU_AMC_CARRIER_INFO 0x1a +#define FRU_UTCA_FRU_INFO_TABLE 0x20 +#define FRU_UTCA_CARRIER_MNG_IP 0x21 +#define FRU_UTCA_CARRIER_INFO 0x22 +#define FRU_UTCA_CARRIER_LOCATION 0x23 +#define FRU_UTCA_SHMC_IP_LINK 0x24 +#define FRU_UTCA_POWER_POLICY 0x25 +#define FRU_UTCA_ACTIVATION 0x26 +#define FRU_UTCA_PM_CAPABILTY 0x27 +#define FRU_UTCA_FAN_GEOGRAPHY 0x28 +#define FRU_UTCA_CLOCK_MAPPING 0x29 +#define FRU_UTCA_MSG_BRIDGE_POLICY 0x2A +#define FRU_UTCA_OEM_MODULE_DESC 0x2B +#define FRU_PICMG_CLK_CARRIER_P2P 0x2C +#define FRU_PICMG_CLK_CONFIG 0x2D + +#define FRU_PICMGEXT_LINK_TYPE_BASE 0x01 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET 0x02 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND 0x03 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR 0x04 +#define FRU_PICMGEXT_LINK_TYPE_PCIE 0x05 +#define FRU_PICMGEXT_LINK_TYPE_BASE 0x01 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET 0x02 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND 0x03 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR 0x04 +#define FRU_PICMGEXT_LINK_TYPE_PCIE 0x05 +#define FRU_PICMGEXT_AMC_LINK_TYPE_RESERVED 0x00 +#define FRU_PICMGEXT_AMC_LINK_TYPE_RESERVED1 0x01 +#define FRU_PICMGEXT_AMC_LINK_TYPE_PCI_EXPRESS 0x02 +#define FRU_PICMGEXT_AMC_LINK_TYPE_ADVANCED_SWITCHING1 0x03 +#define FRU_PICMGEXT_AMC_LINK_TYPE_ADVANCED_SWITCHING2 0x04 +#define FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET 0x05 +#define FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO 0x06 +#define FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE 0x07 +#define FRU_PICMGEXT_OEM_SWFW 0x03 +#define FRU_PICMGEXT_DESIGN_IF_BASE 0x00 +#define FRU_PICMGEXT_DESIGN_IF_FABRIC 0x01 +#define FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL 0x02 +#define FRU_PICMGEXT_DESIGN_IF_RESERVED 0x03 + + + #define FRU_PICMGEXT_AMC_LINK_TYPE_PCIE 0x02 + #define FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1 0x03 + #define FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2 0x04 + #define FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET 0x05 + #define FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO 0x06 + #define FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE 0x07 + + #define AMC_LINK_TYPE_EXT_PCIE_G1_NSSC 0x00 + #define AMC_LINK_TYPE_EXT_PCIE_G1_SSC 0x01 + #define AMC_LINK_TYPE_EXT_PCIE_G2_NSSC 0x02 + #define AMC_LINK_TYPE_EXT_PCIE_G2_SSC 0x03 + #define AMC_LINK_TYPE_EXT_ETH_1000_BX 0x00 + #define AMC_LINK_TYPE_EXT_ETH_10G_XAUI 0x01 + #define AMC_LINK_TYPE_EXT_STORAGE_FC 0x00 + #define AMC_LINK_TYPE_EXT_STORAGE_SATA 0x01 + #define AMC_LINK_TYPE_EXT_STORAGE_SAS 0x02 + +#define IPMI_NETFN_PICMG 0x2C + +/* PICMG commands */ +#define PICMG_GET_PICMG_PROPERTIES_CMD 0x00 +#define PICMG_GET_ADDRESS_INFO_CMD 0x01 +#define PICMG_GET_SHELF_ADDRESS_INFO_CMD 0x02 +#define PICMG_SET_SHELF_ADDRESS_INFO_CMD 0x03 +#define PICMG_FRU_CONTROL_CMD 0x04 +#define PICMG_GET_FRU_LED_PROPERTIES_CMD 0x05 +#define PICMG_GET_LED_COLOR_CAPABILITIES_CMD 0x06 +#define PICMG_SET_FRU_LED_STATE_CMD 0x07 +#define PICMG_GET_FRU_LED_STATE_CMD 0x08 +#define PICMG_SET_IPMB_CMD 0x09 +#define PICMG_SET_FRU_POLICY_CMD 0x0A +#define PICMG_GET_FRU_POLICY_CMD 0x0B +#define PICMG_FRU_ACTIVATION_CMD 0x0C +#define PICMG_GET_DEVICE_LOCATOR_RECORD_CMD 0x0D +#define PICMG_SET_PORT_STATE_CMD 0x0E +#define PICMG_GET_PORT_STATE_CMD 0x0F +#define PICMG_COMPUTE_POWER_PROPERTIES_CMD 0x10 +#define PICMG_SET_POWER_LEVEL_CMD 0x11 +#define PICMG_GET_POWER_LEVEL_CMD 0x12 +#define PICMG_RENEGOTIATE_POWER_CMD 0x13 +#define PICMG_GET_FAN_SPEED_PROPERTIES_CMD 0x14 +#define PICMG_SET_FAN_LEVEL_CMD 0x15 +#define PICMG_GET_FAN_LEVEL_CMD 0x16 +#define PICMG_BUSED_RESOURCE_CMD 0x17 + +/* AMC.0 commands */ +#define PICMG_AMC_SET_PORT_STATE_CMD 0x19 +#define PICMG_AMC_GET_PORT_STATE_CMD 0x1A +/* AMC.0 R2.0 commands */ +#define PICMG_AMC_SET_CLK_STATE_CMD 0x2C +#define PICMG_AMC_GET_CLK_STATE_CMD 0x2D + +/* Site Types */ +#define PICMG_ATCA_BOARD 0x00 +#define PICMG_POWER_ENTRY 0x01 +#define PICMG_SHELF_FRU 0x02 +#define PICMG_DEDICATED_SHMC 0x03 +#define PICMG_FAN_TRAY 0x04 +#define PICMG_FAN_FILTER_TRAY 0x05 +#define PICMG_ALARM 0x06 +#define PICMG_AMC 0x07 +#define PICMG_PMC 0x08 +#define PICMG_RTM 0x09 + +#pragma pack(1) +struct picmg_set_fru_activation_cmd { + unsigned char picmg_id; /* always 0*/ + unsigned char fru_id; /* threshold setting mask */ + unsigned char fru_state; /* fru activation/deactivation */ +}; // __attribute__ ((packed)); +#pragma pack() + +typedef enum picmg_busres_board_cmd_types { + PICMG_BUSRES_BOARD_CMD_QUERY =0, + PICMG_BUSRES_BOARD_CMD_RELEASE, + PICMG_BUSRES_BOARD_CMD_FORCE, + PICMG_BUSRES_BOARD_CMD_BUS_FREE +} t_picmg_busres_board_cmd_types ; + +typedef enum picmg_busres_shmc_cmd_types { + PICMG_BUSRES_SHMC_CMD_REQUEST =0, + PICMG_BUSRES_SHMC_CMD_RELINQUISH, + PICMG_BUSRES_SHMC_CMD_NOTIFY +} t_picmg_busres_shmc_cmd_types ; + +typedef enum picmg_busres_resource_id { + PICMG_BUSRES_METAL_TEST_BUS_1=0, + PICMG_BUSRES_METAL_TEST_BUS_2, + PICMG_BUSRES_SYNC_CLOCK_GROUP_1, + PICMG_BUSRES_SYNC_CLOCK_GROUP_2, + PICMG_BUSRES_SYNC_CLOCK_GROUP_3 +} t_picmg_busres_resource_id; + +/* the LED color capabilities */ +static const char* led_color_str[] = { //__attribute__((unused)) = { + "reserved", + "BLUE", + "RED", + "GREEN", + "AMBER", + "ORANGE", + "WHITE", + "reserved" +}; + + +static const char* amc_link_type_str[] = { // __attribute__((unused)) = { + "RESERVED", + "RESERVED1", + "PCI EXPRESS", + "ADVANCED SWITCHING1", + "ADVANCED SWITCHING2", + "ETHERNET", + "RAPIDIO", + "STORAGE", +}; + +static const char* amc_link_type_ext_str[][16]= { // __attribute__((unused)) + /* FRU_PICMGEXT_AMC_LINK_TYPE_RESERVED */ + { + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" + }, + /* FRU_PICMGEXT_AMC_LINK_TYPE_RESERVED1 */ + { + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" + }, + /* FRU_PICMGEXT_AMC_LINK_TYPE_PCI_EXPRESS */ + { + "Gen 1 - NSSC", + "Gen 1 - SSC", + "Gen 2 - NSSC", + "Gen 2 - SSC", + "", "", "", "", + "", "", "", "", + "", "", "", "" + }, + /* FRU_PICMGEXT_AMC_LINK_TYPE_ADVANCED_SWITCHING1 */ + { + "Gen 1 - NSSC", + "Gen 1 - SSC", + "Gen 2 - NSSC", + "Gen 2 - SSC", + "", "", "", "", + "", "", "", "", + "", "", "", "" + }, + /* FRU_PICMGEXT_AMC_LINK_TYPE_ADVANCED_SWITCHING2 */ + { + "Gen 1 - NSSC", + "Gen 1 - SSC", + "Gen 2 - NSSC", + "Gen 2 - SSC", + "", "", "", "", + "", "", "", "", + "", "", "", "" + }, + /* FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET */ + { + "1000BASE-BX (SerDES Gigabit)", + "10GBASE-BX410 Gigabit XAUI", + "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "" + }, + /* FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO */ + { + "1.25 Gbaud transmission rate", + "2.5 Gbaud transmission rate", + "3.125 Gbaud transmission rate", + "", "", "", "", "", + "", "", "", "", "", "", "", "" + }, + /* FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE */ + { + "Fibre Channel", + "Serial ATA", + "Serial Attached SCSI", + "", "", "", "", "", + "", "", "", "", "", "", "", "" + } +}; + +struct sAmcPortState { +#ifndef WORDS_BIGENDIAN + unsigned short lane0 : 1; + unsigned short lane1 : 1; + unsigned short lane2 : 1; + unsigned short lane3 : 1; + unsigned short type : 8; + unsigned short type_ext : 4; + unsigned char group_id : 8; +#else + unsigned char group_id : 8; + unsigned short type_ext : 4; + unsigned short type : 8; + unsigned short lane3 : 1; + unsigned short lane2 : 1; + unsigned short lane1 : 1; + unsigned short lane0 : 1; +#endif + + unsigned char state; +}; + + +#endif diff --git a/util/ipmi_port.c b/util/ipmi_port.c new file mode 100644 index 0000000..3dccf6a --- /dev/null +++ b/util/ipmi_port.c @@ -0,0 +1,146 @@ +/* + * ipmi_port.c + * Allocate the RMCP port (623.) with a bind so that port manager + * does not try to reuse it. Only needed for Linux. + * + * Note that the Intel dpcproxy service also uses port 623 to listen + * for incoming telnet/SOL clients, so we should not start ipmi_port + * if dpcproxy is running. + * + * Changes: + * 05/18/07 Andy Cress - created + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <signal.h> +#ifdef TEST +#include "ipmicmd.h" +#endif + +#define RMCP_PORT 623 +static char * progver = "1.4"; /* program version */ +static char *progname = "ipmi_port"; /* program name */ +static int sockfd = 0; +static struct sockaddr_in _srcaddr; +static int interval = 20; /* num sec to wait, was 60 */ +static char fdebug = 0; + +static int mkdaemon(int fchdir, int fclose); +static int mkdaemon(int fchdir, int fclose) +{ + int fdlimit = sysconf(_SC_OPEN_MAX); /*fdlimit usu = 1024.*/ + int fd = 0; + int i; + + fdlimit = fileno(stderr); + switch (fork()) { + case 0: break; + case -1: return -1; + default: _exit(0); /* exit the original process */ + } + if (setsid() < 0) return -1; /* shouldn't fail */ + switch (fork()) { + case 0: break; + case -1: return -1; + default: _exit(0); + } + if (fchdir) i = chdir("/"); + if (fclose) { + /* Close stdin,stdout,stderr and replace them with /dev/null */ + for (fd = 0; fd < fdlimit; fd++) close(fd); + fd = open("/dev/null",O_RDWR); + i = dup(0); + i = dup(0); + } + return 0; +} + +static int open_rmcp_port(int port); +static int open_rmcp_port(int port) +{ + int rv; + + /* Open a socket binding to the RMCP port */ + rv = socket(AF_INET, SOCK_DGRAM, 0); + if (rv < 0) return (rv); + else sockfd = rv; + + memset(&_srcaddr, 0, sizeof(_srcaddr)); + _srcaddr.sin_family = AF_INET; + _srcaddr.sin_port = htons(port); + _srcaddr.sin_addr.s_addr = htonl(INADDR_ANY); + rv = bind(sockfd, (struct sockaddr *)&_srcaddr, sizeof(_srcaddr)); + if (rv < 0) { + printf("bind(%d,%d) error, rv = %d\n",port,INADDR_ANY,rv); + close(sockfd); + return (rv); + } + + return(rv); +} + +static void iport_cleanup(int sig) +{ + if (sockfd != 0) close(sockfd); + exit(EXIT_SUCCESS); +} + +/*int ipmi_port(int argc, char **argv) */ +int main(int argc, char **argv) +{ + int rv; + int c; + int background = 0; + struct sigaction sact; + + while ((c = getopt(argc, argv, "bx?")) != EOF) { + switch (c) { + case 'x': fdebug = 1; break; + case 'b': background = 1; break; + default: + printf("Usage: %s [-xb] (-b means background)\n",progname); + exit(1); + } + } + if (!background) + printf("%s ver %s\n", progname,progver); + + rv = open_rmcp_port(RMCP_PORT); + if (rv != 0) { + printf("open_rmcp_port(%d) failed, rv = %d\n",RMCP_PORT,rv); + exit(1); + } else if (!background) + printf("open_rmcp_port(%d) succeeded, sleeping\n",RMCP_PORT); + + /* convert to a daemon if background */ + if (background) { + rv = mkdaemon(1,1); + if (rv != 0) { + printf("%s: Cannot become daemon, rv = %d\n", progname,rv); + exit(1); + } + } + + /* handle signals for cleanup */ + sact.sa_handler = iport_cleanup; + sact.sa_flags = 0; + sigemptyset(&sact.sa_mask); + sigaction(SIGINT, &sact, NULL); + sigaction(SIGQUIT, &sact, NULL); + sigaction(SIGTERM, &sact, NULL); + + if (rv == 0) while(1) + { + sleep(interval); /*wait 60 seconds*/ + } + if (sockfd != 0) close(sockfd); + return(rv); +} + +/*end ipmi_port.c */ diff --git a/util/ipmi_sample.c b/util/ipmi_sample.c new file mode 100644 index 0000000..ddda7f3 --- /dev/null +++ b/util/ipmi_sample.c @@ -0,0 +1,312 @@ +/* + * ipmi_sample.c + * + * A sample IPMI utility, to which more commands can be added. + * + * 02/27/06 Andy Cress - created + * 02/25/11 Andy Cress - added get_chassis_status + */ +/*M* +Copyright (c) 2007, Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron America, Inc. nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include <string.h> +#include "ipmicmd.h" +#ifdef GET_SENSORS +/* need to also include isensor.o, ievents.o when linking. */ +#include "isensor.h" +#endif +#ifdef GET_FRU +#include "ifru.h" +#endif + +/* + * Global variables + */ +static char * progname = "ipmi_sample"; +static char * progver = "1.2"; +static char fdebug = 0; +static char fset_mc = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static char *mytag = NULL; +static char *sdrfile = NULL; + +static int get_chassis_status(uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + + ret = ipmi_cmdraw( CHASSIS_STATUS, NETFN_CHAS, g_sa,g_bus,g_lun, + idata,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_chassis_status()*/ + +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +{ + int ret = 0; + char c; + uchar devrec[16]; + uchar chstatus[4]; + char *s1; + int loops = 1; + int nsec = 10; + char *nodefile = NULL; + int done = 0; + FILE *fp = NULL; + char nod[40]; char usr[24]; char psw[24]; + char drvtyp[10]; + char biosstr[40]; + int n; +#ifdef GET_SENSORS + uchar *sdrlist; +#endif + + printf("%s ver %s\n", progname,progver); + + while ((c = getopt( argc, argv,"i:l:m:f:s:t:xEF:N:P:R:T:U:V:YZ:?")) != EOF ) + switch(c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'f': nodefile = optarg; break; /* specific sensor tag */ + case 'l': loops = atoi(optarg); break; + case 'i': nsec = atoi(optarg); break; /*interval in sec*/ + case 's': sdrfile = optarg; break; + case 't': mytag = optarg; break; /* specific sensor tag */ + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + if (c == 'F') strncpy(drvtyp,optarg,sizeof(drvtyp)); + break; + default: + printf("Usage: %s [-filmstx -NUPREFTVY]\n", progname); + printf(" where -x show eXtra debug messages\n"); + printf(" -f File use list of remote nodes from File\n"); + printf(" -i 10 interval for each loop in seconds\n"); + printf(" -l 10 loops sensor readings 10 times\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -s File loads SDRs from File\n"); + printf(" -t tag search for 'tag' in SDRs\n"); + print_lan_opt_usage(); + exit(1); + } + /* Rather than parse_lan_options above, the set_lan_options function + * could be used if the program already knows the nodename, etc. */ + ret = get_BiosVersion(biosstr); + if (ret == 0) printf("BIOS Version: %s\n",biosstr); + + while(!done) + { + if (nodefile != NULL) { + /* This will loop for each node in the file if -f was used. + * The file should contain one line per node: + * node1 user1 password1 + * node2 user2 password2 + */ + if (fp == NULL) { + fp = fopen(nodefile,"r"); + if (fp == NULL) { + printf("Cannot open file %s\n",nodefile); + ret = ERR_FILE_OPEN; + goto do_exit; + } + if (fdebug) printf("opened file %s ok\n",nodefile); + } + n = fscanf(fp,"%s %s %s", nod, usr, psw); + if (fdebug) printf("fscanf returned %d \n",n); + if (n == EOF || n <= 0) { + fclose(fp); + done = 1; + goto do_exit; + } + printf("Using -N %s -U %s -P %s ...\n",nod,usr,psw); + if (n > 0) parse_lan_options('N',nod,0); + if (n > 1) parse_lan_options('U',usr,0); + if (n > 2) parse_lan_options('P',psw,0); + if (drvtyp != NULL) parse_lan_options('F',drvtyp,0); + } + + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + printf("Cannot do ipmi_getdeviceid, ret = %d\n",ret); + goto do_exit; + } else { /*success*/ + uchar ipmi_maj, ipmi_min; + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + } + + ret = get_chassis_status(chstatus,4); + if (ret == 0) { + if (chstatus[0] & 0x01) s1 = "on"; + else s1 = "off"; + printf("Chassis Status = %02x (%s)\n",chstatus[0],s1); + } + +#ifdef GET_FRU + { + uchar *fru_data = NULL; + printf("Getting FRU ...\n"); + ret = load_fru(0x20,0,0x07, &fru_data); + if (ret == 0) + ret = show_fru(0x20,0,0x07,fru_data); + if (fru_data != NULL) + free_fru(fru_data); + } +#endif +#ifdef GET_SENSORS + printf("Getting SDRs ...\n"); + if (sdrfile != NULL) { + ret = get_sdr_file(sdrfile,&sdrlist); + } else { + ret = get_sdr_cache(&sdrlist); + } + printf("get_sdr_cache ret = %d\n",ret); + if (ret == 0) { + uchar sdrbuf[SDR_SZ]; + uchar reading[4]; + uchar snum = 0; + ushort id; + double val; + char *typestr; + char tag[17]; + int j; + + for (j = 0; j < loops; j++) + { + if (j > 0) { + printf("loop %d: wait %d seconds ...\n",j,nsec); + os_usleep(nsec,0); /*sleep 5 sec between loops*/ + } + id = 0; + /* Get sensor readings for all full SDRs */ + while(find_sdr_next(sdrbuf,sdrlist,id) == 0) { + id = sdrbuf[0] + (sdrbuf[1] << 8); /*this SDR id*/ + if (sdrbuf[3] != 0x01) continue; /*only type 1 full SDRs*/ + strncpy(tag,&sdrbuf[48],16); + tag[16] = 0; + snum = sdrbuf[7]; + ret = GetSensorReading(snum, sdrbuf, reading); + if (ret == 0) { + val = RawToFloat(reading[0], sdrbuf); + typestr = get_unit_type( sdrbuf[20], sdrbuf[21], sdrbuf[22],0); + } else { + val = 0; + typestr = "na"; + printf("%04x: get sensor %x reading ret = %d\n",id,snum,ret); + } + printf("%04x: sensor %x %s \treading = %.2f %s\n", + id,snum,tag,val,typestr); + memset(sdrbuf,0,SDR_SZ); + } /*end while*/ + } /*end for(loops) */ + + /* Find a specific sensor by its tag and get a reading */ + if (mytag != NULL) { + /* see option -t, mytag = "System"; or "System Temp" */ + memset(sdrbuf,0,SDR_SZ); + ret = find_sdr_by_tag(sdrbuf, sdrlist, mytag, fdebug); + printf("find_sdr_by_tag(%s) ret = %d\n",mytag,ret); + strncpy(tag,&sdrbuf[48],16); /*assume full sdr tag offset*/ + tag[16] = 0; + snum = sdrbuf[7]; + ret = GetSensorReading(snum, sdrbuf, reading); + printf("get sensor %x reading ret = %d\n",snum,ret); + if (sdrbuf[3] == 0x01) { /*full SDR*/ + if (ret == 0) { + val = RawToFloat(reading[0], sdrbuf); + typestr = get_unit_type(sdrbuf[20],sdrbuf[21],sdrbuf[22],0); + } else { + val = 0; + typestr = "na"; + } + printf("sensor %x %s reading = %.2f %s\n",snum,tag,val,typestr); + } else printf("sensor %x type %x reading = %02x\n", + snum,sdrbuf[3],reading[2]); + } + + free_sdr_cache(sdrlist); + } /*endif sdr_cache is valid*/ +#endif + ipmi_close_(); + if (nodefile == NULL) done = 1; + } /*end while not done */ + +do_exit: + show_outcome(progname,ret); + exit (ret); +} /* end main()*/ + +/* end ipmi_sample.c */ diff --git a/util/ipmi_sample.mak b/util/ipmi_sample.mak new file mode 100644 index 0000000..41860c1 --- /dev/null +++ b/util/ipmi_sample.mak @@ -0,0 +1,57 @@ +# ipmi_sample.mak
+# This makefile will build the ipmiutil ipmi_sample application
+#
+LIBC_RT=libcmt.lib /NODEFAULTLIB:"msvcirt.lib"
+# LIBC_RT=msvcrt.lib /NODEFAULTLIB:"msvcirt.lib"
+
+MARCH=IX86
+# MARCH=X64
+# The ipmiutil directory
+SRC_D=%CD%
+LIB_D=%CD%
+INC=/I$(SRC_D)
+
+# Set your compiler options
+# CFLAGS_O=/W3 /O2 /Zi /MT /nologo
+CFLAGS_O=/W3 /Zi /MT /nologo
+CF_SAM=/DWIN32 $(INC) /D_CONSOLE /D_CRT_SECURE_NO_DEPRECATE /DHAVE_STRING_H
+CFLAGS_SAM=$(CFLAGS_O) $(CF_SAM)
+LFLAGS=/nologo /subsystem:console /machine:$(MARCH) /opt:ref
+LIBS_W=comsuppw.lib wbemuuid.lib
+LIBS_EX=advapi32.lib kernel32.lib wsock32.lib ws2_32.lib $(LIBS_W) $(LIBC_RT)
+LIBS_PEF=/LIBPATH:$(LIB_D) iphlpapi.lib
+CC=cl
+LINK=link
+RM=del
+
+HEADER = ipmicmd.h
+SAMP_LIB = ipmiutil.lib
+TARG1_EXE = ipmi_sample.exe
+TARG2_EXE = ipmi_sample_evt.exe
+
+###################################################################
+all: $(TARG1_EXE)
+
+clean:
+ $(RM) *.obj 2>NUL
+ $(RM) $(TARG1_EXE) 2>NUL
+
+ipmi_sample.obj: ipmi_sample.c $(HEADER)
+ $(CC) /c $(CFLAGS_SAM) ipmi_sample.c
+
+$(TARG1_EXE): $(SAMP_LIB) ipmi_sample.obj
+ $(LINK) $(LFLAGS) /OUT:$(TARG1_EXE) ipmi_sample.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
+
+ipmi_sample_evt.obj: ipmi_sample_evt.c $(HEADER)
+ $(CC) /c $(CFLAGS_SAM) ipmi_sample_evt.c
+
+isensor2.obj: isensor.c isensor.h $(HEADER)
+ $(CC) /c /Foisensor2.obj $(CFLAGS_SAM) isensor.c
+
+ievents2.obj: ievents.c ievents.h $(HEADER)
+ $(CC) /c /Foievents2.obj $(CFLAGS_SAM) /DSENSORS_OK ievents.c
+
+$(TARG2_EXE): $(SAMP_LIB) ipmi_sample_evt.obj ievents2.obj isensor2.obj
+ $(LINK) $(LFLAGS) /OUT:$(TARG2_EXE) ipmi_sample_evt.obj ievents2.obj isensor2.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
+
+
diff --git a/util/ipmi_sample_evt.c b/util/ipmi_sample_evt.c new file mode 100644 index 0000000..b51ba24 --- /dev/null +++ b/util/ipmi_sample_evt.c @@ -0,0 +1,445 @@ +/* + * ipmi_sample_evt.c + * + * A sample IPMI utility to get IPMI SEL events. + * + * 09/10/12 Andy Cress - created + */ +/*M* +Copyright (c) 2012, Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron America, Inc. nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdarg.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include <string.h> +#include "ipmicmd.h" + +extern int decode_sel_entry(uchar *evt, char *obuf, int sz); /*see ievents.c*/ +extern void set_sel_opts(int sensdesc, int canon, void *sdrs, char dbg, char u); +extern char *get_sensor_type_desc(uchar stype); /*see ievents.c*/ +extern int get_sdr_cache(uchar **pret); /*see isensor.c*/ +extern void free_sdr_cache(uchar *pret); /*see isensor.c*/ +extern int write_syslog(char *msg); /*see isel.c*/ + +/* + * Global variables + */ +static char * progname = "ipmi_sample_evt"; +static char * progver = "1.0"; +static char fdebug = 0; +static char fset_mc = 0; +static char fipmilan = 0; +static char finit_ok = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static char *mytag = NULL; +static char *sdrfile = NULL; +static ushort sel_recid = 0; +static uint sel_time = 0; +static int wait_interval = 3; /* 3 seconds between calls */ +static uchar *sdrs = NULL; +static int drvtype = 0; /* driver_type from ipmicmd.h: 3=MV_OpenIPMI */ +FILE *fdout = NULL; +#define LAST_REC 0xFFFF +#ifdef WIN32 +static char idxfile[80] = "c:\\ipmievt.idx"; +static char outfile[80] = "c:\\ipmievt.log"; +#else +static char idxfile[80] = "/var/lib/ipmiutil/ipmievt.idx"; +static char outfile[80] = "/var/log/ipmievt.log"; +#endif + +/* These routines were copied from igetevent.c + * msgout, getevent_sel, syncevent_sel, show_event, ievt_cleanup + */ +static void ievt_cleanup(void); +static void msgout(char *pattn, ...) +{ + va_list arglist; + + if (fdout == NULL) return; + va_start( arglist, pattn ); + vfprintf( fdout, pattn, arglist ); + va_end( arglist ); + fflush( fdout ); +} + +#if defined(WIN32) | defined(DOS) +/* no daemon code */ +static void ievt_siginit(void) { return; } +#else +/* Linux daemon code */ +#include <signal.h> +static void ievt_sighnd(int sig) +{ + ievt_cleanup(); + exit(EXIT_SUCCESS); +} + +static void ievt_siginit(void); +static void ievt_siginit(void) +{ + struct sigaction sact; + + /* handle signals for cleanup */ + sact.sa_handler = ievt_sighnd; + sact.sa_flags = 0; + sigemptyset(&sact.sa_mask); + sigaction(SIGINT, &sact, NULL); + sigaction(SIGQUIT, &sact, NULL); + sigaction(SIGTERM, &sact, NULL); +} +#endif + +static int get_sel_entry(ushort recid, ushort *nextid, uchar *rec) +{ + uchar ibuf[6]; + uchar rbuf[32]; + int rlen; + ushort xid, id = 0; + uchar cc; + int rv; + + ibuf[0] = 0; + ibuf[1] = 0; + ibuf[2] = (recid & 0x00ff); + ibuf[3] = (recid & 0xff00) >> 8; + ibuf[4] = 0; + ibuf[5] = 0xFF; /*get entire record*/ + rlen = sizeof(rbuf); + rv = ipmi_cmd(GET_SEL_ENTRY, ibuf, 6, rbuf, &rlen, &cc, fdebug); + if (rv == 0) { + if (cc != 0) rv = cc; + else { /*success*/ + xid = rbuf[0] + (rbuf[1] << 8); /*next rec id*/ + memcpy(rec,&rbuf[2],16); + *nextid = xid; + id = rbuf[2] + (rbuf[3] << 8); /*curr rec id*/ + /* recid (requested) should match newid (received) */ + if (fdebug) { + if ((recid != id) && (recid != LAST_REC) && (recid != 0)) { + /* the OpenIPMI driver does this sometimes */ + msgout("get_sel MISMATCH: recid=%x newid=%x next=%x\n", + recid,id,xid); + dump_buf("get_sel cmd",ibuf,6,0); + dump_buf("get_sel rsp",rbuf,rlen,0); + } + } + } + } + if (fdebug) msgout("get_sel(%x) rv=%d cc=%x id=%x next=%x\n", + recid,rv,cc,id,*nextid); + return(rv); +} + +static int getevent_sel(uchar *rdata, int *rlen, uchar *ccode) +{ + uchar rec[24]; + int rv = 0; + ushort newid; + ushort nextid; + ushort recid; + + /* get current last record */ + recid = sel_recid; + rv = get_sel_entry(recid,&nextid,rec); + if (rv == 0xCB && recid == 0) { /* SEL is empty */ + *ccode = (uchar)rv; /* save the real ccode */ + rv = 0x80; /* this is ok, just keep waiting */ + } + if (rv == 0) { + if (fdebug) msgout("sel ok, id=%x next=%x\n",recid,nextid); + if ((nextid == LAST_REC) || (recid == nextid)) { + *ccode = 0x80; /*nothing new*/ + } else { + recid = nextid; /* else get new one */ + rv = get_sel_entry(recid,&nextid,rec); + if (rv == 0) { /* new event */ + newid = rec[0] + (rec[1] << 8); + if (drvtype == DRV_MV && recid != newid) { + /* handle MV driver bug, try to get next one. */ + if (fdebug) msgout("%s bug, record mismatch\n", + show_driver_type(DRV_MV)); + } + if (fdebug) msgout("recid=%x newid=%x next=%x\n", + recid,newid,nextid); + memcpy(rdata,rec,16); + *rlen = 16; + *ccode = 0; + sel_recid = recid; /*or newid*/ + memcpy(&sel_time,&rec[2],4); + } + } + } + else { /* Error reading last recid saved */ + if (fdebug) msgout("sel recid %x error, rv = %d\n",recid,rv); + /* We want to set sel_recid = 0 here for some errors. */ + if (rv == 0xCB || rv == 0xCD) { /* empty, or wrong SDR id */ + sel_recid = 0; + *ccode = (uchar)rv; + rv = 0x80; /* wait again */ + } + } + return(rv); +} + +static int startevent_sel(ushort *precid, uint *ptime) +{ + FILE *fd; + uchar rec[24]; + uint t = 0; + ushort r = 0; + ushort r2 = 0; + int rv = -1; + + fd = fopen(idxfile,"r"); + if (fdebug) msgout("start: idxfile=%s fd=%p\n",idxfile,fd); + if (fd != NULL) { + // Read the file, get savtime & savid + rv = fscanf(fd,"%x %x",&t,&r); + fclose(fd); + if (r == LAST_REC) r = 0; + rv = 0; /*read it, success*/ + } else { /* treat as first time */ + r = LAST_REC; + rv = get_sel_entry(r,&r2,rec); + if (rv == 0) { + memcpy(&t,&rec[2],4); + r = rec[0] + (rec[1] << 8); /*use current rec id*/ + } else r = 0; + rv = 1; /*first time*/ + } + if (fdebug) msgout("start: recid=%x time=%x\n",r,t); + *ptime = t; + *precid = r; + return(rv); +} + +static int syncevent_sel(ushort recid, uint itime) +{ + FILE *fd; + int rv; + // Rewrite the saved time & record id + if (fdebug) msgout("sync: recid=%x time=%x\n",recid,itime); + fd = fopen(idxfile,"w"); + if (fd == NULL) { + msgout("syncevent: cannot open %s for writing\n",idxfile); + rv = -1; + } else { + fprintf(fd,"%x %x\n",itime,recid); + fclose(fd); + rv = 0; + } + return(rv); +} + +static void ievt_cleanup(void) +{ + char obuf[48]; + snprintf(obuf,sizeof(obuf),"%s exiting.\n",progname); + msgout(obuf); + write_syslog(obuf); + if (finit_ok) { + syncevent_sel(sel_recid,sel_time); + free_sdr_cache(sdrs); + } + ipmi_close_(); /*inert if not opened*/ + exit(EXIT_SUCCESS); +} + +void show_event(uchar *evt,char *obuf, int sz) +{ + int i; + char sysbuf[250]; + /* obuf should be 132 chars or more */ + + msgout("event data: "); + for (i=0; i<16; i++) msgout("%02x ",evt[i]); + msgout("\n"); + + decode_sel_entry(evt,obuf,sz); + msgout(obuf); /*writes to outfile*/ + /* write the message to syslog also. */ + snprintf(sysbuf,sizeof(sysbuf),"%s: %s",progname,obuf); + write_syslog(sysbuf); +} + +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +{ + int ret = 0; + char c; + uchar devrec[16]; + uchar event[32]; /*usu 16 bytes */ + char outbuf[160]; + char *s1; + int rlen; + uchar ccode; + uchar sensor_type; + + fdout = stderr; + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"m:s:t:xEF:N:P:R:T:U:V:YZ:?")) != EOF ) + switch(c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 's': sdrfile = optarg; break; + case 't': mytag = optarg; break; /* specific sensor tag */ + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-msx -NUPREFTVY]\n", progname); + printf(" where -x show eXtra debug messages\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -s File loads SDRs from File\n"); + printf(" -t tag search for 'tag' in SDRs\n"); + print_lan_opt_usage(); + exit(1); + } + /* Rather than parse_lan_options above, the set_lan_options function + * could be used if the program already knows the nodename, etc. */ + + fipmilan = is_remote(); + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + printf("Cannot do ipmi_getdeviceid, ret = %d\n",ret); + goto do_exit; + } else { /*success*/ + uchar ipmi_maj, ipmi_min; + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + } + drvtype = get_driver_type(); + + /* could make it a daemon here, if desired */ + fdout = fopen(outfile,"a"); + if (fdout == NULL) { + printf("%s: Cannot open %s\n", progname,outfile); + fdout = stderr; + } else { + sprintf(outbuf,"%s ver %s started\n", progname,progver); + msgout(outbuf); + } + sprintf(outbuf,"%s reading sensors ...\n",progname); + write_syslog(outbuf); + ret = get_sdr_cache(&sdrs); + if (fdebug) msgout("get_sdr_cache ret = %d\n",ret); + if (ret == 0) set_sel_opts(1,0, sdrs,fdebug,0); + + if (fipmilan) { + char *node; + node = get_nodename(); + strcat(idxfile,"-"); + strcat(idxfile,node); + strcat(outfile,"-"); + strcat(outfile,node); + } + ret = startevent_sel(&sel_recid,&sel_time); + + ievt_siginit(); + finit_ok = 1; + ret = 0; /*ignore any earlier errors, keep going*/ + + while (ret == 0) + { /*wait for bmc message events*/ + if (fdebug) + msgout("%s: Polling every %d sec for a new event after id %x...\n", + progname, wait_interval, sel_recid); + rlen = sizeof(event); + ret = getevent_sel(event,&rlen,&ccode); + if (ret == 0) ret = ccode; + if (fdebug) msgout("getevent_sel ret = %d\n",ret); + if (ret == 0) { /* got an event successfully */ + sensor_type = event[10]; + msgout("got event id %04x, sensor_type = %02x\n", + sel_recid,sensor_type); + show_event(event,outbuf,sizeof(outbuf)); + syncevent_sel(sel_recid,sel_time); + } else if (ret == 0x80) { + ret = 0; /*keep waiting*/ + } else { + msgout("get_event error: ret = 0x%x\n",ret); + break; + } + os_usleep(wait_interval,0); + } /*end while loop*/ + +do_exit: + ievt_cleanup(); + show_outcome(progname,ret); + exit (ret); +} /* end main()*/ + +/* end ipmi_sample_evt.c */ diff --git a/util/ipmibmc.c b/util/ipmibmc.c new file mode 100644 index 0000000..e895338 --- /dev/null +++ b/util/ipmibmc.c @@ -0,0 +1,231 @@ +/*M* +// $Workfile: ipmibmc.c $ +// $Revision: 1.0 $ +// $Modtime: 12 Nov 2008 15:20:14 $ +// $Author: arcress at users.sourceforge.net $ +// +// This implements support for the /dev/bmc interface from +// the Solaris 10 IPMI driver. +// +// 11/12/08 ARC - created + *M*/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2008, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#ifdef SOLARIS +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stropts.h> +#include <stddef.h> +#include <stropts.h> +#include <iso/stdlib_iso.h> + +#include "ipmicmd.h" /* for uchar, NCMDS */ + +#define MAX_SEND_SIZE 34 +#define MAX_RECV_SIZE 33 +#define MIN_RQ_SIZE 2 +#define MIN_RS_SIZE 3 +#define MAX_BUF_SIZE 256 +#define MSG_BUF_SIZE 1024 + +// #define IOCTL_IPMI_KCS_ACTION 0x01 +// #define IOCTL_IPMI_INTERFACE_METHOD 0x02 +#define BMC_MSG_REQ 1 +#define BMC_MSG_RSP 2 +#define BMC_MSG_ERR 3 + +extern ipmi_cmd_t ipmi_cmds[NCMDS]; +static int ipmi_fd = -1; + +typedef struct bmc_rq { + uchar netfn; + uchar lun; + uchar cmd; + uchar dlen; + uchar data[MAX_SEND_SIZE]; +} bmc_rq_t; + +typedef struct bmc_rs { + uchar netfn; + uchar lun; + uchar cmd; + uchar ccode; + uchar dlen; + uchar data[MAX_RECV_SIZE]; +} bmc_rs_t; + +typedef struct bmc_ioctl_t { + bmc_rq_t req; + bmc_rs_t rsp; +} bmc_ioctl_t; + +typedef struct bmc_msg { + uchar m_type; /* Message type (1=req, 2=resp, 3=error)*/ + uint32 m_id; /* Message ID */ + uchar reserved[32]; + uchar msg[1]; /* Variable length message data */ +} bmc_msg_t; + + +int ipmi_open_bmc(char fdebugcmd) +{ + int rc = -1; + char *pdev; + + if (ipmi_fd != -1) return(0); + pdev = "/dev/bmc"; + ipmi_fd = open(pdev, O_RDWR); + if (ipmi_fd == -1) { + if (fdebugcmd) printf("ipmi_open_bmc: cannot open %s, errno=%d\n",pdev,errno); + return(rc); + } + + /* dont bother to check for ioctl method, just use putmsg method */ + + rc = 0; + if (fdebugcmd) printf("ipmi_open_bmc: successfully opened bmc\n"); + return(rc); +} + +int ipmi_close_bmc(void) +{ + int rc = 0; + if (ipmi_fd != -1) { + close(ipmi_fd); + ipmi_fd = -1; + } + return(rc); +} + +int ipmi_cmdraw_bmc( uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd) +{ + int rv = -1; + static uint32 msg_seq = 0; + int flags = 0; + struct strbuf sendbuf; + struct strbuf recvbuf; + bmc_msg_t *msg; + bmc_rq_t *rq; + bmc_rs_t *rs; + int sz, i; + + if (sdata > MAX_SEND_SIZE) i = sdata - MAX_SEND_SIZE; + else i = 0; + sz = (sizeof(bmc_msg_t) - 1) + sizeof(bmc_rq_t) + i; + msg = malloc(sz); + if (msg == NULL) return(rv); + rq = (bmc_rq_t *)&msg->msg[0]; + + msg->m_type = BMC_MSG_REQ; + msg->m_id = msg_seq++; + rq->netfn = netfn; + rq->lun = lun; + rq->cmd = cmd; + rq->dlen = sdata; + memcpy(rq->data, pdata, sdata); + sendbuf.len = sz; + sendbuf.buf = (uchar *)msg; + if (fdebugcmd) { + dump_buf("ipmi_cmdraw_bmc sendbuf",sendbuf.buf,sendbuf.len,0); + } + + rv = putmsg(ipmi_fd, NULL, &sendbuf, 0); + if (rv < 0) { + perror("BMC putmsg: "); + free(msg); + return(rv); + } + free(msg); + + recvbuf.buf = malloc(MSG_BUF_SIZE); + recvbuf.maxlen = MSG_BUF_SIZE; + rv = getmsg(ipmi_fd, NULL, &recvbuf, &flags); + if (rv < 0) { + perror("BMC getmsg: "); + free(recvbuf.buf); + return(rv); + } + + msg = (bmc_msg_t *)recvbuf.buf; + if (fdebugcmd) { + dump_buf("ipmi_cmdraw_bmc recvbuf",recvbuf.buf,recvbuf.len,0); + } + switch (msg->m_type) { + case BMC_MSG_RSP: + rs = (bmc_rs_t *)&msg->msg[0]; + *pcc = rs->ccode; + i = rs->dlen; + if (i < 0) i = 0; + *sresp = i; + if (*pcc == 0 && i > 0) + memcpy(presp,rs->data,i); + rv = 0; + break; + case BMC_MSG_ERR: + default: + rv = msg->msg[0]; + printf("ipmi_cmdraw_bmc: %s\n", strerror(rv)); + break; + } + free(recvbuf.buf); + + return(rv); +} + +int ipmi_cmd_bmc(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + int rc, i; + + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == cmd) break; + } + if (i >= NCMDS) { + printf("ipmi_cmd_bmc: Unknown command %x\n",cmd); + return(-1); + } + if (cmd >= CMDMASK) cmd = cmd & CMDMASK; /* unmask it */ + rc = ipmi_cmdraw_bmc(cmd, ipmi_cmds[i].netfn, ipmi_cmds[i].lun, + ipmi_cmds[i].sa, ipmi_cmds[i].bus, + pdata,sdata,presp,sresp,pcc,fdebugcmd); + return(rc); +} +#endif +/* end of ipmibmc.c */ diff --git a/util/ipmicmd.c b/util/ipmicmd.c new file mode 100644 index 0000000..dd2268b --- /dev/null +++ b/util/ipmicmd.c @@ -0,0 +1,1429 @@ +/*M* +// PVCS: +// $Workfile: ipmicmd.c $ +// $Revision: 1.12 $ +// $Modtime: 23 Feb 2005 11:24:14 $ +// $Author: arcress at users.sourceforge.net $ +// +// Define the ipmi_cmd routine and supporting logic to execute IPMI +// commands via one of the supported IPMI drivers: +// /dev/ipmi0 /dev/ipmi/0 = MontaVista OpenIPMI driver +// /dev/imb = Intel IMB ipmidrvr (comes with ISM) +// /dev/ipmikcs /dev/ipmi/kcs = valinux driver by San Mehat +// libfreeipmi.so = GNU FreeIPMI user-space library +// ldipmidaemon = LanDesk IPMI daemon (user-space process) +// +// 08/05/02 ARC - created +// 08/15/02 ARC - added decode_cc +// 10/24/02 ARC - made cmd param ushort to be more unique +// 01/29/03 ARC - added MontaVista OpenIPMI driver support +// 07/25/03 ARC - added serial-over-lan commands +// 07/30/03 ARC - added GetThresholds, fix for ipmi_cmd_raw, +// changed some error messages +// 09/04/03 ARC - added debug messages for fDriverTyp first time +// 05/05/04 ARC - leave _mv device open, rely on each app calling ipmi_close, +// helps performance. +// 08/10/04 ARC - fix typo in ipmi_cmd_raw/mv: cmd->icmd (thanks Kevin Gao) +// 08/26/04 ARC - fix out-of-bounds error in decode_cc +// 10/27/04 ARC - added gnu FreeIPMI library support +// 11/11/04 ARC - added fdebug to ipmi_getdeviceid & ipmi_open_gnu +// 02/23/05 ARC - added routines for LanDesk, fDriverTyp=5 +// 07/15/05 ARC - test for ldipmi first, since it hangs KCS if another +// driver tries to coexist. +// 07/06/06 ARC - better separate driver implementations, cleaner now + *M*/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2002-2006, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <io.h> +#include <fcntl.h> +#elif defined(EFI) +// defined (EFI32) || defined (EFI64) || defined(EFIX64) +#include <bmc.h> +#include <libdbg.h> +#else +/* Linux, Solaris, BSD */ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#ifndef DOS +#include <sys/ioctl.h> +#include <termios.h> +#endif +#include <stdarg.h> +#include <errno.h> +#endif + +#include "ipmicmd.h" /* has NCMDS, ipmi_cmd_t */ + +ipmi_cmd_t ipmi_cmds[NCMDS] = { /*if add here, also change NCMDS in ipmicmd.h*/ + {/*empty,temp*/ 0, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 20}, + {GET_SEL_INFO, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 0, 14}, + {GET_SEL_ALLOCATION_INFO,BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 0, 9}, + {GET_SEL_ENTRY, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 6, 18}, + {RESERVE_SEL, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 0, 2}, + {CLEAR_SEL, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 6, 1}, + {GET_SEL_TIME, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 6, 4}, + {GET_LAN_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 4, 19}, + {SET_LAN_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 21, 0}, + {GET_LAN_STATS, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 2, 18}, + {GET_SER_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 4, 19}, + {SET_SER_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 21, 0}, + {SET_SER_MUX, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 2, 0}, + {GET_PEF_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 3, 22}, + {SET_PEF_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 22, 0}, +// {SET_PEF_ENABLE, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 4, 0}, /*old*/ + {GET_DEVSDR_INFO, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 0, 6}, + {GET_DEVICE_SDR, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 6, 18}, + {RESERVE_DEVSDR_REP,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 0, 2}, + {GET_SENSOR_READING,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 1, 4}, + {GET_SENSOR_READING_FACTORS,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 2, 7}, + {GET_SENSOR_TYPE, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 1, 2}, + {GET_SENSOR_THRESHOLD,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 1, 7}, + {SET_SENSOR_THRESHOLD,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 8, 0}, + {GET_SENSOR_HYSTERESIS,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 2, 2}, + {SET_SENSOR_HYSTERESIS,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 4, 0}, + {GET_SDR, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 6, 18},/*full=63*/ + {GET_SDR_REPINFO, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 0, 14}, + {RESERVE_SDR_REP, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 0, 2}, + {GET_FRU_INV_AREA, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 1, 3}, + {READ_FRU_DATA, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 4, 18}, + {WRITE_FRU_DATA, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN,20 /*3+N(17)*/, 1}, + {GET_DEVICE_ID, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 15}, + {SET_USER_ACCESS, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 4, 0}, + {GET_USER_ACCESS, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 2, 4}, + {GET_USER_NAME, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 1, 16}, + {SET_USER_NAME, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 17, 0}, + {SET_USER_PASSWORD,BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 18, 0}, + {MASTER_WRITE_READ,BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 4 /*or 3*/, 1}, + {GET_SYSTEM_GUID, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 16}, + {WATCHDOG_GET, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 8}, + {WATCHDOG_SET, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 6, 0}, + {WATCHDOG_RESET, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 0}, + {CHASSIS_STATUS, BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 0, 2}, + {CHASSIS_CTL, BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 1, 0}, + {CHASSIS_IDENTIFY, BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 1, 0}, + {GET_POWERON_HOURS,BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 0, 0}, + {SET_BOOT_OPTIONS, BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 19, 0}, + {GET_BOOT_OPTIONS, BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 3, 18}, + {ACTIVATE_SOL1, BMC_SA, PUBLIC_BUS, NETFN_SOL, BMC_LUN, 0, 0}, + {SET_SOL_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_SOL, BMC_LUN, 3, 0}, + {GET_SOL_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_SOL, BMC_LUN, 4, 2}, + {ACTIVATE_SOL2, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 0, 0}, + {SET_SOL_CONFIG2, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 3, 0}, + {GET_SOL_CONFIG2, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 4, 2}, + {GET_SEVT_ENABLE, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 1, 5}, + {SET_SEVT_ENABLE, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 6, 0}, + {REARM_SENSOR, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 6, 0}, + {READ_EVENT_MSGBUF,BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 16}, + {GET_EVENT_RECEIVER,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 0, 2}, + {GET_CHANNEL_INFO, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 1, 9}, + {SET_CHANNEL_ACC, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 3, 0}, + {GET_CHANNEL_ACC, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 2, 1} }; + +/* Subroutine definitions for each driver */ +#ifdef EFI +int ipmi_open_efi(char fdebug); +int ipmi_cmdraw_efi( uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +#else + +#include "ipmilan2.h" /*includes ipmilan.h also*/ +#ifdef WIN32 +extern int ipmi_cmdraw_ia( uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_ia(char fdebug); +extern int ipmi_close_ia(void); +extern int ipmi_cmdraw_ms(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_ms(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_ms(char fdebug); +extern int ipmi_close_ms(void); +#elif defined(SOLARIS) +extern int ipmi_cmdraw_bmc(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_bmc(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_bmc(char fdebug); +extern int ipmi_close_bmc(void); +extern int ipmi_cmdraw_lipmi(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_lipmi(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_lipmi(char fdebug); +extern int ipmi_close_lipmi(void); +#elif defined(LINUX) +extern int ipmi_cmdraw_ia( uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_ia(char fdebug); +extern int ipmi_close_ia(void); +extern int ipmi_cmdraw_mv(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_mv(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_mv(char fdebug); +extern int ipmi_close_mv(void); +extern int ipmi_open_ld(char fdebug); +extern int ipmi_close_ld(void); +extern int ipmi_cmdraw_ld(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_ld(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_direct(char fdebug); +extern int ipmi_close_direct(void); +extern int ipmi_cmdraw_direct( uchar cmd, uchar netfn, uchar lun, + uchar sa, uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_direct(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_set_max_kcs_loops(int ms); +#elif defined(DOS) +extern int ipmi_open_direct(char fdebug); +extern int ipmi_close_direct(void); +extern int ipmi_cmdraw_direct( uchar cmd, uchar netfn, uchar lun, + uchar sa, uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_direct(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_set_max_kcs_loops(int ms); +#else +/* BSD */ +extern int ipmi_open_direct(char fdebug); +extern int ipmi_close_direct(void); +extern int ipmi_cmdraw_direct( uchar cmd, uchar netfn, uchar lun, + uchar sa, uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_direct(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_set_max_kcs_loops(int ms); +extern int ipmi_cmdraw_mv(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_mv(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_mv(char fdebug); +extern int ipmi_close_mv(void); +#endif +extern int fd_wait(int fd, int nsec, int usec); +#endif + +/* Global Data */ +int fDriverTyp = DRV_UNKNOWN; /* 1=IMB driver, 2=VA driver, 3=MV open driver */ + /* 4= GNU FreeIPMI, 5= LanDesk, 6= builtin IPMI LAN */ + /* 7= direct KCS, 8= direct SMB, 9= IPMI LAN v2.0 */ +int fipmi_lan = 0; +int fjustpass = 0; +FILE *fperr = NULL; +FILE *fpdbg = NULL; +FILE *fplog = NULL; +char log_name[60] = {'\0'}; /*log_name global*/ +char *gnode = "localhost"; /* used for IPMI LAN, specified with option -N */ +char *guser = NULL; +char *gpswd = NULL; +char gnodename[SZGNODE] = {0}; /*the node name returned after a connection */ +int gcipher_suite = 3; /*used in ipmilanplus.c*/ +int gshutdown = 0; +int fauth_type_set = 0; +int gauth_type = IPMI_SESSION_AUTHTYPE_MD5; /*if 0, use any: MD5, MD2, etc.*/ +int gpriv_level = IPMI_PRIV_LEVEL_USER; /*or IPMI_PRIV_LEVEL_ADMIN */ +int gaddr_len = 0; +uchar gaddr[128]; /* sizeof(struct sockaddr_storage) = 128 */ + /* struct sockaddr_in/_in6 gaddr; _in6=28, _in=16 bytes */ +uchar my_devid[20] = {0,0,0,0,0,0,0,0}; /*saved devid, only needs 16 bytes*/ +char fdebug = 0; + +typedef struct { + uchar adrtype; + uchar sa; + uchar bus; + uchar lun; + uchar capab; +} mc_info; +mc_info bmc = { ADDR_SMI, BMC_SA, PUBLIC_BUS, BMC_LUN, 0x8F }; /*BMC via SMI*/ +mc_info mc2 = { ADDR_IPMB, BMC_SA, PUBLIC_BUS, BMC_LUN, 0x4F }; /*IPMB target*/ +mc_info mymc = { ADDR_IPMB, BMC_SA, PUBLIC_BUS, BMC_LUN, 0x4F }; /*IPMB */ +static char bcomma = ','; +static mc_info *mc = &bmc; +#ifdef WIN32 +static char msg_no_drv[] = { /*no Windows driver*/ + "Cannot open an IPMI driver: imbdrv.sys or ipmidrv.sys\n"}; +#elif defined(SOLARIS) +static char msg_no_drv[] = { /*no Solaris driver*/ + "Cannot open an IPMI driver: /dev/bmc or /dev/lipmi\n"}; +#elif defined(LINUX) +static char msg_no_drv[] = { /*no Linux driver*/ + "Cannot open an IPMI driver: /dev/imb, /dev/ipmi0, " + "/dev/ipmi/0, \n\t " +/* "/dev/ipmikcs, /dev/ipmi/kcs, " *no longer support valinux */ +#ifdef LINK_LANDESK + "ldipmi, " +#endif + "or direct driverless.\n" }; + +#elif defined(DOS) +static char msg_no_drv[] = { /*no DOS IPMI driver*/ + "Cannot open an IPMI direct KCS interface.\n"}; +#else +static char msg_no_drv[] = { /*no BSD IPMI driver*/ + "Cannot open an IPMI driver: /dev/ipmi0 or direct.\n"}; +#endif + +/* From IPMI v1.5/v2.0 spec, Table 5-2 Completion Codes */ +#define NUMCC 32 +struct { + uchar code; + char *mesg; + } cc_mesg[NUMCC] = { +/* Note: completion codes 0x80-0x9f may vary depending on the command. + * 0x80 = Invalid Session Handle or Empty Buffer or Unsupported Feature + */ +{0x00, "Command completed successfully"}, +{0x80, "Invalid Session Handle or Empty Buffer"}, +{0x81, "Lost Arbitration"}, +{0x82, "Bus Error"}, +{0x83, "NAK on Write - busy"}, +{0x84, "Truncated Read"}, +{0x85, "Invalid session ID in request"}, /*for ActivateSession*/ +{0x86, "Requested privilege level exceeds limit"}, /*for ActivateSession*/ +{0xC0, "Node Busy"}, +{0xC1, "Invalid Command"}, +{0xC2, "Command invalid for given LUN"}, +{0xC3, "Timeout while processing command"}, +{0xC4, "Out of space"}, +{0xC5, "Reservation ID cancelled or invalid"}, +{0xC6, "Request data truncated"}, +{0xC7, "Request data length invalid"}, +{0xC8, "Request data field length limit exceeded"}, +{0xC9, "Parameter out of range"}, +{0xCA, "Cannot return requested number of data bytes"}, +{0xCB, "Requested sensor, data, or record not present"}, +{0xCC, "Invalid data field in request"}, +{0xCD, "Command illegal for this sensor/record type"}, +{0xCE, "Command response could not be provided"}, +{0xCF, "Cannot execute duplicated request"}, +{0xD0, "SDR Repository in update mode, no response"}, +{0xD1, "Device in firmware update mode, no response"}, +{0xD2, "BMC initialization in progress, no response"}, +{0xD3, "Destination unavailable"}, +{0xD4, "Cannot execute command. Insufficient privilege level"}, +{0xD5, "Cannot execute command. Request parameters not supported"}, +{0xD6, "Cannot execute command. Subfunction unavailable"}, +{0xFF, "Unspecified error"} +}; + +char * decode_cc(ushort icmd, int cc) +{ + static char other_msg[25]; + char *pmsg; + int i; + for (i = 0; i < NUMCC; i++) { + if (cc == cc_mesg[i].code) break; + } + if (i == NUMCC) { /* if not found, show other_msg */ + sprintf(other_msg,"Other error 0x%02x",cc); + pmsg = other_msg; + } else { + if ((icmd == READ_EVENT_MSGBUF) && (cc == 0x80)) + pmsg = "no data available (queue/buffer empty)"; + else pmsg = cc_mesg[i].mesg; + } + return(pmsg); +} + +char *decode_rv(int rv) +{ + char *msg; + static char msgbuf[80]; + if (rv == 0x6F) msg = "License not supported"; /*for Dell*/ + else if (rv > 0) msg = decode_cc((ushort)0,rv); + else switch(rv) { + case 0: msg = "completed successfully"; break; + case -1: msg = "error -1"; break; + case LAN_ERR_SEND_FAIL: msg = "send to BMC failed"; break; + case LAN_ERR_RECV_FAIL: msg = "receive from BMC failed"; break; + case LAN_ERR_CONNECT: msg = "cannot connect to BMC"; break; + case LAN_ERR_ABORT: msg = "abort signal caught"; break; + case LAN_ERR_TIMEOUT: msg = "timeout occurred"; break; + case LAN_ERR_BADLENGTH: msg = "length greater than max"; break; + case LAN_ERR_INVPARAM: msg = "invalid lan parameter"; break; + case LAN_ERR_NOTSUPPORT: msg = "request not supported"; break; + case LAN_ERR_TOO_SHORT: msg = "receive too short"; break; + case LAN_ERR_HOSTNAME: msg = "error resolving hostname"; break; + case LAN_ERR_PING: msg = "error during ping"; break; + case LAN_ERR_V1: msg = "BMC only supports lan v1"; break; + case LAN_ERR_V2: msg = "BMC only supports lan v2"; break; + case LAN_ERR_OTHER: msg = "other error"; break; + case ERR_NO_DRV: msg = "cannot open IPMI driver"; break; + case ERR_BAD_PARAM: msg = "invalid parameter"; break; + case ERR_NOT_ALLOWED: msg = "access not allowed"; break; + case ERR_USAGE: msg = "usage or help requested"; break; + case LAN_ERR_DROPPED: msg = "session dropped by BMC"; break; + case ERR_FILE_OPEN: msg = "cannot open file"; break; + case ERR_NOT_FOUND: msg = "item not found"; break; + case ERR_BMC_MSG: msg = "error getting msg from BMC"; break; + /* ipmidir.h: ERGETTINGIPMIMESSAGE -504 */ + case ERR_BAD_FORMAT: msg = "bad format"; break; + case ERR_BAD_LENGTH: msg = "length less than min"; break; + default: + sprintf(msgbuf,"error %d",rv); + msg = msgbuf; + break; + } + return(msg); +} + +int get_cmd_rslen(uchar cmd, uchar netfn) +{ /* used by ipmicmd_gnu */ + int rslen = 0; + int i; + ushort cmdkey; + cmdkey = cmd | (netfn << 8); + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == cmdkey) { + rslen = ipmi_cmds[i].rslen; + break; + } + } + return(rslen); +} /*end get_cmd_rslen()*/ + +static int ndrivers = NDRIVERS; +static struct { + int idx; + char *tag; + } drv_types[NDRIVERS] = { + { DRV_IMB, "imb" }, + { DRV_MV, "open" }, + { DRV_LD, "landesk" }, + { DRV_LAN2, "lan2" }, + { DRV_LAN2I,"lan2i" }, + { DRV_LAN, "lan" }, + { DRV_KCS, "kcs" }, + { DRV_SMB, "smb" }, + { DRV_MS, "ms" }, + { DRV_BMC, "sun_bmc" }, + { DRV_LIPMI,"sun_lipmi" }, + { DRV_SMC, "supermicro" }, + { DRV_IBM, "ibm" }, + { DRV_HP, "hp" }, /*++++*/ +#ifdef EFI + { DRV_EFI, "efi" } +#else + { 0, "" } /*DRV_UNKNOWN*/ +#endif +}; + // { DRV_VA, "va" }, + // { DRV_GNU, "free" }, + +char *show_driver_type(int idx) +{ + int i; + char *tag; + for (i = 0; i < ndrivers; i++) + { + if (drv_types[i].idx == idx) { + tag = drv_types[i].tag; + break; + } + } + if (i >= ndrivers) { /*not found*/ + tag = "unknown"; + } + return(tag); +} + +int get_driver_type(void) +{ + return(fDriverTyp); +} + +void set_iana(int iana) +{ + my_devid[6] = (iana & 0x0000ff); + my_devid[7] = ((iana & 0x00ff00) >> 8); + my_devid[8] = ((iana & 0xff0000) >> 16); +} + +void set_mfgid(uchar *devid, int len) +{ + if (devid == NULL) return; + if (len > sizeof(my_devid)) len = sizeof(my_devid); + memcpy(my_devid,devid,len); +} + +void get_mfgid(int *pvend, int *pprod) +{ + if (pvend != NULL) + *pvend = my_devid[6] + (my_devid[7] << 8) + (my_devid[8] << 16); + if (pprod != NULL) + *pprod = my_devid[9] + (my_devid[10] << 8); +} + +int set_driver_type(char *tag) +{ + int rv = 0; + int i; + /* else if (str_icmp(tag,"lan2") == 0) * leave vendor id as is. */ + for (i = 0; i < ndrivers; i++) + { + if (str_icmp(drv_types[i].tag, tag) == 0) { + fDriverTyp = drv_types[i].idx; + if (fDriverTyp == DRV_LAN2I) { /*LAN2 Intel*/ + set_iana(VENDOR_INTEL); /*VENDOR_INTEL = 0x000157*/ + } else if (fDriverTyp == DRV_SMC) { /*supermicro*/ + set_iana(VENDOR_SUPERMICRO); /*VENDOR_SUPERMICRO = 0x002A7C*/ + fDriverTyp = DRV_LAN; + } + if (fDriverTyp == DRV_IBM) { /*LAN IBM*/ + set_iana(VENDOR_IBM); + fDriverTyp = DRV_LAN; + } + if (fDriverTyp == DRV_HP) { /*LAN2 HP ++++*/ + set_iana(VENDOR_HP); + fDriverTyp = DRV_LAN2; + gauth_type = IPMI_SESSION_AUTHTYPE_NONE; /*HP default*/ + } + break; + } + } + if (i >= ndrivers) { /*not found*/ + fDriverTyp = DRV_UNKNOWN; /*not set yet, so detect*/ + rv = 1; + // if (fdebugcmd) + { + printf("Invalid -F argument (%s), valid driver types are:\n",tag); + for (i = 0; i < ndrivers; i++) + printf("\t%s\n",drv_types[i].tag); + } + } + return(rv); +} + +/* + * use_devsdrs + * detect whether to use SDR repository or Device SDRs from + * the saved GetDeviceID response. + * ipmi_getdeviceid saves it into my_devid. + */ +int use_devsdrs(int picmg) +{ + int fdev, vend, prod; + /* set Device SDRs flag as specified in the GetDeviceID */ + if ((my_devid[1] & 0x80) == 0x80) fdev = 1; + else fdev = 0; + if (picmg) return(fdev); + /* check for vendor/products that can report the flag wrong */ + vend = my_devid[6] + (my_devid[7] << 8) + (my_devid[8] << 16); + prod = my_devid[9] + (my_devid[10] << 8); + switch(vend) { + case VENDOR_INTEL: + if ((prod != 0x800) && (prod != 0x808) && (prod != 0x841)) + fdev = 0; + break; + case VENDOR_NSC: fdev = 0; break; + case VENDOR_NEC: fdev = 0; break; + case VENDOR_DELL: fdev = 0; break; + case VENDOR_HP: fdev = 0; break; + case VENDOR_SUN: fdev = 0; break; + default: break; + } + return(fdev); +} + +/* get_lan_channel returns the next lan channel starting with chfirst. */ +int get_lan_channel(uchar chfirst, uchar *chan) +{ + int ret, j; + uchar iData[4]; + uchar rData[9]; + int rlen; + uchar cc; + int found = 0; + + for (j = chfirst; j < 12; j++) + { + rlen = sizeof(rData); + iData[0] = (uchar)j; /*channel #*/ + memset(rData,0,9); /*initialize recv data*/ + ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, fdebug); + if (ret == 0xcc || cc == 0xcc) /* special case for ipmi_lan */ + continue; + if (ret != 0) { + if (fdebug) printf("get_chan_info rc = %x\n",ret); + break; + } + /* rData[1] == channel medium type */ + if (rData[1] == 4) { /* medium type 4 = 802.3 LAN type*/ + if (fdebug) printf("chan[%d] = lan\n",j); + found = 1; + *chan = (uchar)j; + break; + } + } + if (found == 0) ret = -1; + return(ret); +} + +int nodeislocal(char *nodename) +{ + if (nodename == NULL) return 1; + if (nodename[0] == 0) return 1; + if (strcmp(nodename,"localhost") == 0) return 1; + return 0; +} + +int set_max_kcs_loops(int ms) +{ + int rv = 0; +#if defined(LINUX) + rv = ipmi_set_max_kcs_loops(ms); +#elif defined(BSD) + rv = ipmi_set_max_kcs_loops(ms); +#elif defined(DOS) + rv = ipmi_set_max_kcs_loops(ms); +#endif + return(rv); +} + +/* + * ipmi_open + * This is called by ipmi_cmd and ipmicmd_raw if a session has not + * yet been opened (fDriverTyp == DRV_UNKNOWN). + * The order to try these drivers could be customized for specific + * environments by modifying this routine. + * + * ipmi_cmd[raw] would call a specific open routine if set_driver_type(). + */ +int ipmi_open(char fdebugcmd) +{ + int rc = 0; + fperr = stderr; + fpdbg = stdout; + + fdebug = fdebugcmd; +#ifdef EFI + rc = ipmi_open_efi(fdebugcmd); +#else + if (!nodeislocal(gnode)) { fipmi_lan = 1; } + if (fdebugcmd) printf("ipmi_open: driver type = %s\n", + show_driver_type(fDriverTyp)); + /* first time, so try each */ + if (fipmi_lan) { + /* Try IPMI LAN 1.5 first */ + rc = ipmi_open_lan(gnode,guser,gpswd,fdebugcmd); + fDriverTyp = DRV_LAN; + if (rc == LAN_ERR_V2) { + /* Use IPMI LAN 2.0 if BMC said it only supports LAN2 */ + /* This is a violation of IPMI 2.0 Spec section 13.4, + * but some HP firmware behaves this way, so handle it. */ + rc = ipmi_open_lan2(gnode,guser,gpswd,fdebugcmd); + fDriverTyp = DRV_LAN2; + } + } else { /* local, not lan */ +#ifdef WIN32 + rc = ipmi_open_ia(fdebugcmd); + if (rc == ACCESS_OK) + fDriverTyp = DRV_IMB; + else if ((rc = ipmi_open_ms(fdebugcmd)) == ACCESS_OK) + fDriverTyp = DRV_MS; + else rc = ERR_NO_DRV; +#elif defined(SOLARIS) + rc = ipmi_open_bmc(fdebugcmd); + if (rc == ACCESS_OK) + fDriverTyp = DRV_BMC; + else if ((rc = ipmi_open_lipmi(fdebugcmd)) == ACCESS_OK) + fDriverTyp = DRV_LIPMI; + else rc = ERR_NO_DRV; +#elif defined(LINUX) + if ((rc = ipmi_open_ld(fdebugcmd)) == ACCESS_OK) { + fDriverTyp = DRV_LD; + ipmi_close_ld(); + } else if ((rc = ipmi_open_mv(fdebugcmd)) == ACCESS_OK) { + fDriverTyp = DRV_MV; + /* ipmi_close_mv(); * leave it open until explicit close */ + } else if ((rc = ipmi_open_ia(fdebugcmd)) == ACCESS_OK) { + fDriverTyp = DRV_IMB; + } else if ((rc = ipmi_open_direct(fdebugcmd)) == ACCESS_OK) { + /* set to either DRV_KCS or DRV_SMB */ + } else rc = ERR_NO_DRV; +#elif defined(DOS) + rc = ipmi_open_direct(fdebugcmd); + /* sets fDriverTyp to either DRV_KCS or DRV_SMB */ + if (rc != ACCESS_OK) rc = ERR_NO_DRV; +#else + /* BSD or MACOS */ + if ((rc = ipmi_open_mv(fdebugcmd)) == ACCESS_OK) { + /* FreeBSD "kldload ipmi" has /dev/ipmi0 */ + fDriverTyp = DRV_MV; + /* ipmi_close_mv(); * leave it open until explicit close */ + } else if ((rc = ipmi_open_direct(fdebugcmd)) == ACCESS_OK) { + /* sets fDriverTyp to either DRV_KCS or DRV_SMB */ + } else rc = ERR_NO_DRV; +#endif + + } /*endelse local, not lan*/ +#endif + if (fdebugcmd) printf("ipmi_open rc = %d type = %s\n",rc, + show_driver_type(fDriverTyp)); + return (rc); +} + +int ipmi_close_(void) +{ + int rc = 0; +#ifndef EFI + switch (fDriverTyp) + { +#ifdef WIN32 + case DRV_IMB: rc = ipmi_close_ia(); break; + case DRV_MS: rc = ipmi_close_ms(); break; +#elif defined(SOLARIS) + case DRV_BMC: rc = ipmi_close_bmc(); break; + case DRV_LIPMI: rc = ipmi_close_lipmi(); break; +#elif defined(LINUX) + case DRV_IMB: rc = ipmi_close_ia(); break; + case DRV_MV: rc = ipmi_close_mv(); break; + case DRV_LD: rc = ipmi_close_ld(); break; + case DRV_SMB: + case DRV_KCS: rc = ipmi_close_direct(); break; +#elif defined(DOS) + case DRV_SMB: + case DRV_KCS: rc = ipmi_close_direct(); break; +#else + /* BSD or MACOS */ + case DRV_MV: rc = ipmi_close_mv(); break; + case DRV_SMB: + case DRV_KCS: rc = ipmi_close_direct(); break; +#endif + case DRV_LAN: rc = ipmi_close_lan(gnode); break; + case DRV_LAN2I: + case DRV_LAN2: rc = ipmi_close_lan2(gnode); break; + default: break; + } /*end switch*/ +#endif + fDriverTyp = DRV_UNKNOWN; + return (rc); +} + +/* don't worry about conflict with other ipmi libs any longer */ +int ipmi_close(void) { return(ipmi_close_()); } + +#if defined(EFI) +int ipmi_open_efi(int fdebugcmd) +{ + int rc = 0; + static bool BmcLibInitialized = false; + + if (BmcLibInitialized == false ) { + rc = BmcLibInitialize(); + if (rc == 0) { + BmcLibInitialized = true; + fDriverTyp = DRV_EFI; + } + } + return rc; +} + +#define TIMEOUT_EFI (1000*1000) /*see ipmi_timeout_ia*/ +int ipmi_cmdraw_efi(uchar cmd, uchar netfn, uchar sa, uchar bus, uchar lun, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + BMC_MESSAGE ReqMsg; + BMC_MESSAGE RespMsg; + int status = 0; + uchar * pc; + int sz, i; + + ReqMsg.DevAdd = sa; + ReqMsg.NetFn = netfn; + ReqMsg.LUN = lun; + ReqMsg.Cmd = cmd; + ReqMsg.Len = sdata; + for( sz=0; (sz<sdata && sz< IPMI_REQBUF_SIZE); sz++ ) + ReqMsg.Data[sz] = pdata[sz]; + sz = *sresp; /* note that sresp must be pre-set */ + memset(presp, 0, sz); + for ( i =0 ; i < BMC_MAX_RETRIES; i++) + { + *sresp = sz; /* retries may need to re-init *sresp */ + if((status =ProcessTimedMessage(&ReqMsg, &RespMsg,TIMEOUT_EFI)) == 0) { + *sresp = RespMsg.Len; + for( sz=0 ; sz<RespMsg.Len && sz<IPMI_RSPBUF_SIZE ; sz++ ) + presp[sz] = RespMsg.Data[sz]; + *pcc = RespMsg.CompCode; + break; + } + if (fdebugcmd) // only gets here if error + fprintf(fpdbg,"ipmi_cmd_efi: ProcessTimedMessage error status=%x\n", + (uint)status); + } + return(status); +} +#endif + +/* + * ipmi_cmdraw() + * + * This routine can be used to invoke IPMI commands that are not + * already pre-defined in the ipmi_cmds array. + * It invokes whichever driver-specific routine is needed (ia, mv, etc.). + * Parameters: + * uchar cmd (input): IPMI Command + * uchar netfn (input): IPMI NetFunction + * uchar sa (input): IPMI Slave Address of the MC + * uchar bus (input): BUS of the MC + * uchar lun (input): IPMI LUN + * uchar *pdata (input): pointer to ipmi data + * int sdata (input): size of ipmi data + * uchar *presp (output): pointer to response data buffer + * int *sresp (input/output): on input, size of response buffer, + * on output, length of response data + * uchar *cc (output): completion code + * char fdebugcmd(input): flag =1 if debug output desired + */ +int ipmi_cmdraw(uchar cmd, uchar netfn, uchar sa, uchar bus, uchar lun, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + int rc = 0; + ushort icmd; + + fperr = stderr; + fpdbg = stdout; + + if (sdata > 255) return(LAN_ERR_BADLENGTH); + if (fDriverTyp == DRV_UNKNOWN) { /*first time, so find which one */ + rc = ipmi_open(fdebugcmd); + if (fdebugcmd) + fprintf(fpdbg,"Driver type %s, open rc = %d\n", + show_driver_type(fDriverTyp),rc); + if (rc == ERR_NO_DRV && !fipmi_lan) fprintf(fperr, "%s", msg_no_drv); + else if (rc != 0) fprintf(fperr,"ipmi_open error = %d\n", rc); + if (rc != 0) return(rc); + } /*endif first time*/ + + icmd = (cmd & 0x00ff) | (netfn << 8); + *pcc = 0; + /* Check for the size of the response buffer being zero. */ + /* This may be valid for some commands, but print a debug warning. */ + if (fdebugcmd && (*sresp == 0)) printf("ipmi_cmdraw: warning, sresp==0\n"); + +#ifdef EFI + rc = ipmi_cmdraw_efi(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); +#else + switch (fDriverTyp) + { +#ifdef WIN32 + case DRV_IMB: + rc = ipmi_cmdraw_ia(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; + case DRV_MS: + rc = ipmi_cmdraw_ms(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; +#elif defined(SOLARIS) + case DRV_BMC: + rc = ipmi_cmdraw_bmc(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; + case DRV_LIPMI: + rc = ipmi_cmdraw_lipmi(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; +#elif defined(LINUX) + case DRV_IMB: + rc = ipmi_cmdraw_ia(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; + case DRV_MV: + rc = ipmi_cmdraw_mv(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; + case DRV_LD: + rc = ipmi_cmdraw_ld( cmd, netfn, lun, sa, bus, + pdata,sdata, presp,sresp, pcc, fdebugcmd); + break; + case DRV_SMB: + case DRV_KCS: + rc = ipmi_cmdraw_direct(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; +#elif defined(DOS) + case DRV_SMB: + case DRV_KCS: + rc = ipmi_cmdraw_direct(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; +#else + /* BSD or MACOS */ + case DRV_MV: + rc = ipmi_cmdraw_mv(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; + case DRV_SMB: + case DRV_KCS: + rc = ipmi_cmdraw_direct(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; +#endif + case DRV_LAN: + rc = ipmi_cmdraw_lan(gnode, cmd, netfn, lun, sa, bus, + pdata,sdata, presp,sresp, pcc, fdebugcmd); + break; + case DRV_LAN2I: + case DRV_LAN2: + rc = ipmi_cmdraw_lan2(gnode, cmd, netfn, lun, sa, bus, + pdata,sdata, presp,sresp, pcc, fdebugcmd); + break; + default: /* no ipmi driver */ + rc = ERR_NO_DRV; + break; + } /*end switch*/ +#endif + + if ((rc >= 0) && (*pcc != 0) && fdebugcmd) { + fprintf(fpdbg,"ccode %x: %s\n",*pcc,decode_cc(icmd,(int)*pcc)); + } + /* clear the temp cmd (OLD) */ + // ipmi_cmds[0].cmdtyp = 0; + // ipmi_cmds[0].sa = BMC_SA; + + return(rc); +} + +/* + * ipmi_cmd_mc() + * This uses the mc pointer to route commands via either the SMI or + * IPMB method to the designated mc. + * See also ipmi_set_mc and ipmi_restore_mc. + */ +int ipmi_cmd_mc(ushort icmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + uchar cmd, netfn; + int rv; + + cmd = icmd & CMDMASK; + netfn = (icmd & 0xFF00) >> 8; + if (sdata > 255) return(LAN_ERR_BADLENGTH); + if ((fDriverTyp != DRV_MV) && (mc->adrtype == ADDR_IPMB) && !fipmi_lan) { + rv = ipmi_cmd_ipmb(cmd, netfn, mc->sa, mc->bus, mc->lun, + pdata, sdata, presp, sresp, pcc, fdebugcmd); + } else { /* use ADDR_SMI */ + rv = ipmi_cmdraw(cmd, netfn, mc->sa, mc->bus, mc->lun, + pdata, sdata, presp, sresp, pcc, fdebugcmd); + } + return(rv); +} + +int ipmi_cmdraw_mc(uchar cmd, uchar netfn, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + int rv; + if (sdata > 255) return(LAN_ERR_BADLENGTH); + if ((fDriverTyp != DRV_MV) && (mc->adrtype == ADDR_IPMB) && !fipmi_lan) { + rv = ipmi_cmd_ipmb(cmd, netfn, mc->sa, mc->bus, mc->lun, + pdata, sdata, presp, sresp, pcc, fdebugcmd); + } else { /* use ADDR_SMI */ + rv = ipmi_cmdraw(cmd, netfn, mc->sa, mc->bus, mc->lun, + pdata, sdata, presp, sresp, pcc, fdebugcmd); + } + return(rv); +} + +/* + * ipmi_cmd() + * + * This is the externally exposed subroutine for commands that + * are defined in the ipmi_cmds array above. + * It calls the ipmi_cmdraw routine for further processing. + */ +int ipmi_cmd(ushort icmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + int rc, i; + uchar bcmd; + uchar netfn, sa, bus, lun; + + fperr = stderr; + fpdbg = stdout; + if (sdata > 255) return(LAN_ERR_BADLENGTH); + if (fDriverTyp == DRV_UNKNOWN) { /*first time, so find which one */ + rc = ipmi_open(fdebugcmd); + if (fdebugcmd) + fprintf(fpdbg,"Driver type %s, open rc = %d\n", + show_driver_type(fDriverTyp),rc); + if (rc != 0) { + if (rc == ERR_NO_DRV && !fipmi_lan) fprintf(fperr, "%s", msg_no_drv); + else fprintf(fperr,"ipmi_open error = %d\n", rc); + return(rc); + } + } /*endif first time*/ + + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == icmd) break; + } + if (i >= NCMDS) { + fprintf(fperr, "ipmi_cmd: Unknown command %x\n",icmd); + return(-1); + } + bcmd = icmd & CMDMASK; /* unmask it */ + netfn = ipmi_cmds[i].netfn; + lun = ipmi_cmds[i].lun; + sa = ipmi_cmds[i].sa; + bus = ipmi_cmds[i].bus; + + rc = ipmi_cmdraw(bcmd, netfn, sa, bus, lun, + pdata,sdata, presp,sresp, pcc, fdebugcmd); + return(rc); +} + +/* MOVED ipmi_cmd_ipmb() to ipmilan.c */ + +int ipmi_getpicmg(uchar *presp, int sresp, char fdebug) +{ + uchar idata[2]; + int rc; uchar cc; + + /* check that sresp is big enough */ + if (sresp < 4) return(-3); + idata[0] = PICMG_ID; + rc = ipmi_cmdraw(PICMG_GET_PROPERTIES, NETFN_PICMG, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, 1, presp,&sresp, &cc, fdebug); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + return(ACCESS_OK); /* success */ +} + +int ipmi_getdeviceid(uchar *presp, int sresp, char fdebug) +{ + int rc, i; uchar cc; + /* check that sresp is big enough (default is 15 bytes for Langley)*/ + if (sresp < 15) return(ERR_BAD_LENGTH); + rc = ipmi_cmd_mc(GET_DEVICE_ID, NULL, 0, presp,&sresp, &cc, fdebug); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + i = sresp; + if (i > sizeof(my_devid)) i = sizeof(my_devid); + memcpy(my_devid,presp,i); /* save device id for later use */ + return(ACCESS_OK); /* success */ +} + +void get_devid_ver(uchar *bmaj, uchar *bmin, uchar *iver) +{ + if (bmaj != NULL) *bmaj = my_devid[2]; + if (bmin != NULL) *bmin = my_devid[3]; + if (iver != NULL) *iver = my_devid[4]; +} + +void show_devid(uchar b1, uchar b2, uchar i1, uchar i2) +{ + /* b1 = devid[2]; b2 = devid[3]; i2|i1 = devid[4]; */ + printf("-- BMC version %x.%02x%c IPMI version %d.%d \n",b1,b2,bcomma,i1,i2); +} + +void ipmi_set_mc(uchar bus, uchar sa, uchar lun, uchar atype) +{ + mc = &mc2; + mc->bus = bus; + mc->sa = sa; + mc->lun = lun; + mc->adrtype = atype; /* ADDR_SMI or ADDR_IPMB */ + if (fdebug) printf("ipmi_set_mc(%02x,%02x,%02x,%02x)\n",bus,sa,lun,atype); + return; +} + +void ipmi_restore_mc(void) +{ + mc = &bmc; + return; +} + +void ipmi_get_mc(uchar *bus, uchar *sa, uchar *lun, uchar *type) +{ + /* mc = &bmc or &mc2; */ + if (bus != NULL) *bus = mc->bus; + if (sa != NULL) *sa = mc->sa; + if (lun != NULL) *lun = mc->lun; + if (type != NULL) *type = mc->adrtype; /* ADDR_SMI or ADDR_IPMB */ + return; +} + +void ipmi_set_mymc(uchar bus, uchar sa, uchar lun, uchar type) +{ + mymc.bus = bus; + mymc.sa = sa; + mymc.lun = lun; + mymc.adrtype = type; /* ADDR_SMI or ADDR_IPMB */ + return; +} + +void ipmi_get_mymc(uchar *bus, uchar *sa, uchar *lun, uchar *type) +{ + if (bus != NULL) *bus = mymc.bus; + if (sa != NULL) *sa = mymc.sa; + if (lun != NULL) *lun = mymc.lun; + if (type != NULL) *type = mymc.adrtype; /* ADDR_SMI or ADDR_IPMB */ + return; +} + +int ipmi_sendrecv(struct ipmi_rq * req, uchar *rsp, int *rsp_len) +{ /* compatible with intf->sendrecv() */ + int rv; + uchar ccode; + int rlen; + + rlen = IPMI_RSPBUF_SIZE; + *rsp_len = 0; + rv = ipmi_cmdraw_mc(req->msg.cmd, req->msg.netfn, + req->msg.data, (uchar)req->msg.data_len, + rsp, &rlen, &ccode, fdebug); + if (rv == 0 && ccode != 0) rv = ccode; + if (rv == 0) { /*success*/ + *rsp_len = rlen; + } + return (rv); +} + +#ifdef WIN32 +static HANDLE con_in = INVALID_HANDLE_VALUE; +static DWORD cmodein; +static DWORD cmodeold; + +void tty_setraw(int mode) +{ + // system("@echo off"); + con_in = GetStdHandle(STD_INPUT_HANDLE); + GetConsoleMode(con_in, &cmodein); + cmodeold = cmodein; + if (mode == 2) { + cmodein &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | + ENABLE_ECHO_INPUT); + } else { /* (mode==1) just suppress ECHO */ + cmodein &= ~ENABLE_ECHO_INPUT; + } + SetConsoleMode(con_in, cmodein); +} +void tty_setnormal(int mode) +{ + // system("echo on"); + if (mode == 1) + cmodein |= ENABLE_ECHO_INPUT; + else + cmodein = cmodeold; + SetConsoleMode(con_in, cmodein); +} +int tty_getattr(int *lflag, int *oflag, int *iflag) +{ + *lflag = (int)cmodein; + *oflag = 0; + *iflag = 0; + return(0); +} +#elif defined(DOS) +void tty_setraw(int mode) +{ return; } +void tty_setnormal(int mode) +{ return; } +int tty_getattr(int *lflag, int *oflag, int *iflag) +{ return(-1); } +#else + /*LINUX, SOLARIS, BSD*/ +// #include <curses.h> +static struct termios mytty; +static struct termios ttyold; +static ulong tty_oldflags; +int tty_getattr(int *lflag, int *oflag, int *iflag) +{ + int rv; + static struct termios outtty; + rv = tcgetattr(STDOUT_FILENO, &outtty); + if (rv == 0) { + *lflag = outtty.c_lflag; + *oflag = outtty.c_oflag; + *iflag = outtty.c_iflag; + } + return(rv); +} + +void tty_setraw(int mode) +{ + int i; + // system("stty -echo"); + i = tcgetattr(STDIN_FILENO, &mytty); + if (i == 0) { + tty_oldflags = mytty.c_lflag; + ttyold = mytty; +#ifdef SOLARIS + mytty.c_iflag |= IGNPAR; + mytty.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); + mytty.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL); + mytty.c_lflag &= ~IEXTEN; + /* mytty.c_oflag &= ~OPOST; // this causes NL but no CR on output */ + mytty.c_cc[VMIN] = 1; + mytty.c_cc[VTIME] = 0; + i = tcsetattr(STDIN_FILENO, TCSADRAIN, &mytty); +#else + if (mode == 2) { /*raw mode*/ + mytty.c_lflag &= ~(ICANON | ISIG | ECHO); + // mytty.c_oflag &= ~ONLCR; /* do not map NL to CR-NL on output */ + } else /* (mode==1) just suppress ECHO */ + mytty.c_lflag &= ~ECHO; + i = tcsetattr(STDIN_FILENO, TCSANOW, &mytty); +#endif + } +} +void tty_setnormal(int mode) +{ + // system("stty echo"); + if (mode == 1) + mytty.c_lflag |= ECHO; + else { /*(mode==2)*/ + mytty.c_lflag = tty_oldflags; + mytty = ttyold; + } + tcsetattr(STDIN_FILENO, TCSANOW, &mytty); +#ifdef SOLARIS + tcsetattr(fileno(stdin), TCSADRAIN, &mytty); +#endif +} +#endif + +static char *my_getline(char *prompt, char fwipe) +{ + /* getline is the same format as readline, but much simpler, and portable. */ + static char linebuf[128]; + int c, i; + + if (prompt != NULL) printf("%s\n",prompt); + if (fwipe) tty_setraw(1); + for (i = 0; i < (sizeof(linebuf)-1); i++) + { + c = getc(stdin); + if (c == EOF) break; + if (c == '\n') break; + if ((c < 0x20) || (c > 0x7F)) break; /*out of bounds for ASCII */ + linebuf[i] = c & 0xff; + } + linebuf[i] = 0; + if (fwipe) { + for (c = 0; c < i; c++) putc('*',stdout); + putc('\n',stdout); + tty_setnormal(1); + } + if (i == 0) return NULL; + return(linebuf); +} + +static char *getline_wipe(char *prompt) +{ + return(my_getline(prompt,1)); +} + +void set_debug(void) +{ + fdebug = 1; +} + +char is_remote(void) +{ + return((char)fipmi_lan); +} + +int get_lan_options(char *node, char *user, char *pswd, int *auth, int *priv, + int *cipher, void *addr, int *addr_len) +{ + if (fipmi_lan == 0) return(-1); + if (node != NULL) strcpy(node,gnode); + if (user != NULL) strcpy(user,guser); + if (pswd != NULL) strcpy(pswd,gpswd); + if (auth != NULL) *auth = gauth_type; + if (priv != NULL) *priv = gpriv_level; + if (cipher != NULL) *cipher = gcipher_suite; + if (addr != NULL && gaddr_len != 0) memcpy(addr,gaddr,gaddr_len); + if (addr_len != NULL) *addr_len = gaddr_len; + return(0); +} + +int set_lan_options(char *node, char *user, char *pswd, int auth, int priv, + int cipher, void *addr, int addr_len) +{ + int rv = 0; + if (node != NULL) { gnode = strdup_(node); fipmi_lan = 1; } + if (user != NULL) guser = strdup_(user); + if (pswd != NULL) gpswd = strdup_(pswd); + if (auth > 0 && auth <= 5) gauth_type = auth; + else rv = ERR_BAD_PARAM; + if (priv > 0 && priv <= 5) gpriv_level = priv; + else rv = ERR_BAD_PARAM; + if (cipher >= 0 && cipher <= 17) gcipher_suite = cipher; + else rv = ERR_BAD_PARAM; + if ((addr != NULL) && (addr_len > 15) && (addr_len <= sizeof(gaddr))) { + memcpy(gaddr,addr,addr_len); + gaddr_len = addr_len; + } + ipmi_flush_lan(gnode); + return(rv); +} + +void parse_lan_options(int c, char *popt, char fdebugcmd) +{ +#if defined(EFI) | defined(DOS) + return; +#else + int i; + size_t len; + static int fset_dtype = 0; + uchar sa; + + switch(c) + { + case 'F': /* force driver type */ + i = set_driver_type(popt); + if (i == 0) fset_dtype = 1; + break; + case 'T': /* auth type */ + i = atoi(popt); + if (i >= 0 && i <= 5) gauth_type = i; + fauth_type_set = 1; + break; + case 'V': /* priv level */ + i = atoi(popt); + if (i > 0 && i <= 5) gpriv_level = i; + break; + case 'J': + i = atoi(popt); + if (i >= 0 && i <= 17) gcipher_suite = i; + else printf("-J cipher suite %d > 17, defaults to %d\n", + i,gcipher_suite); + if (fset_dtype == 0) i = set_driver_type("lan2"); + break; + case 'N': gnode = popt; /* nodename */ + fipmi_lan = 1; + break; + case 'U': + guser = strdup_(popt); /*remote username */ + if (!guser) perror("strdup_"); + else { /* Hide username from 'ps' */ + memset(popt, ' ', strlen(popt)); + } + break; + case 'R': + case 'P': + gpswd = strdup_(popt); /*remote password */ + if (!gpswd) perror("strdup_"); + else { /* Hide password from 'ps' */ + len = strlen(popt); + memset(popt, ' ', len); + if (len > PSW_MAX) gpswd[PSW_MAX] = '\0'; + } + break; + case 'E': /* get password from IPMI_PASSWORD environment var */ + gpswd = getenv("IPMI_PASSWORD"); + if (gpswd == NULL) perror("getenv(IPMI_PASSWORD)"); + else { + if (strlen(gpswd) > PSW_MAX) gpswd[PSW_MAX] = '\0'; + if (fdebugcmd) printf("using IPMI_PASSWORD\n"); + } + break; + case 'Y': /* prompt for remote password */ + gpswd = getline_wipe("Enter IPMI LAN Password: "); + if (gpswd != NULL) { + if (strlen(gpswd) > PSW_MAX) gpswd[PSW_MAX] = '\0'; + } + break; + case 'Z': /* set local MC address */ + sa = htoi(&popt[0]); /*device slave address*/ + ipmi_set_mymc(mc->bus, sa, mc->lun, ADDR_IPMB); + break; + default: + if (fdebugcmd) printf("unrecognized option %c\n",c); + break; + } + ipmi_flush_lan(gnode); +#endif +} /*end parse_lan_options*/ + +void print_lan_opt_usage(void) +{ +#if defined(EFI) | defined(DOS) + return; +#else + printf(" -N node Nodename or IP address of target system\n"); + printf(" -U user Username for remote node\n"); + printf(" -P/-R pswd Remote Password\n"); + printf(" -E use password from Environment IPMI_PASSWORD\n"); + printf(" -F force driver type (e.g. imb, lan2)\n"); + printf(" -J 0 use lanplus cipher suite 0: 0 thru 14, 3=default\n"); + printf(" -T 1 use auth Type: 1=MD2, 2=MD5(default), 4=Pswd\n"); + printf(" -V 2 use priVilege level: 2=user(default), 4=admin\n"); + printf(" -Y prompt for remote password\n"); + printf(" -Z set slave address of local MC\n"); +#endif +} /*end parse_lan_options*/ + +char *get_nodename(void) +{ + return(gnode); +} + +extern int lasterr; /*defined in ipmilan.c */ +extern void show_LastError(char *tag, int err); + +void show_outcome(char *prog, int ret) +{ + if (prog == NULL) prog = ""; + if (ret == -1 && lasterr != 0) show_LastError(prog,lasterr); + printf("%s%c %s\n",prog,bcomma,decode_rv(ret)); +} + +/* end ipmicmd.c */ diff --git a/util/ipmicmd.h b/util/ipmicmd.h new file mode 100644 index 0000000..b65e949 --- /dev/null +++ b/util/ipmicmd.h @@ -0,0 +1,543 @@ +/*M* +// PVCS: +// $Workfile: ipmicmd.h $ +// $Revision: 1.0 $ +// $Modtime: 22 Jul 2002 08:51:14 $ +// $Author: arcress $ +// +// 10/24/02 arcress - made cmd param ushort to be more unique +// + *M*/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2002, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#define uchar unsigned char +#define uint32 unsigned int +#define uint64 unsigned long +// #ifdef __USE_MISC +/* Can use compatibility names for C types. (from sys/types.h) */ +// typedef unsigned long int ulong; +// typedef unsigned short int ushort; +// typedef unsigned int uint; +// #else +#ifndef ushort +#define ushort unsigned short +#define ulong unsigned long +#define uint unsigned int +#endif + +#ifdef WIN32 +#define snprintf _snprintf +#define SockType SOCKET +#define SockInvalid INVALID_SOCKET +#else +#define SockType int +#define SockInvalid -1 +#endif + +// Other IPMI values +#define PUBLIC_BUS 0 +#define PRIVATE_BUS 0x03 +#define BMC_SA 0x20 +#define BMC_LUN 0 +#define SMS_LUN 2 +#define HSC_SA 0xC0 +#define ME_SA 0x2C +#define ME_BUS 0x06 + +#define ADDR_SMI 1 +#define ADDR_IPMB 2 + +#define ACCESS_OK 0 +#define IPMI_REQBUF_SIZE 255 +#define IPMI_RSPBUF_SIZE 250 // was 80, then 1024, see MAX_BUFFER_SIZE +#define IPMI_LANBUF_SIZE 200 // see RS_LEN_MAX for IPMI LAN + +// IPMI NetFn types, see Table 5-1 +#define NETFN_CHAS 0x00 // chassis +#define NETFN_BRIDGE 0x02 // bridge +#define NETFN_SEVT 0x04 // sensor/event +#define NETFN_APP 0x06 // application +#define NETFN_FW 0x08 // firmware +#define NETFN_STOR 0x0a // storage +#define NETFN_TRANS 0x0c // transport +#define NETFN_SOL 0x34 // serial-over-lan (in IPMI 2.0, use TRANS) +#define NETFN_PICMG 0x2c // for ATCA PICMG systems + +#ifndef IMBAPI_H__ +// special IMB defines, duplicates if imb_api.h +#define MAX_BUFFER_SIZE 255 +#define MAX_SDR_SIZE 128 +#define GET_DEVICE_ID (0x01 | (NETFN_APP << 8)) +#define WRITE_READ_I2C (0x52 | (NETFN_APP << 8)) /*=MASTER_WRITE_READ*/ +#endif + +#define PSW_MAX 20 /* IPMI Passwords max = 16 or 20 bytes*/ +/* IPMI Commands, see Table 38-8, combined CMD and NETFN in unsigned short */ +#define CMDMASK 0xff /* mask to leave only the command part */ +#define WATCHDOG_RESET (0x22 | (NETFN_APP << 8)) +#define WATCHDOG_SET (0x24 | (NETFN_APP << 8)) +#define WATCHDOG_GET (0x25 | (NETFN_APP << 8)) +#define GET_SYSTEM_GUID (0x37 | (NETFN_APP << 8)) +#define SET_CHANNEL_ACC (0x40 | (NETFN_APP << 8)) +#define GET_CHANNEL_ACC (0x41 | (NETFN_APP << 8)) +#define GET_CHANNEL_INFO (0x42 | (NETFN_APP << 8)) +#define SET_USER_ACCESS (0x43 | (NETFN_APP << 8)) +#define GET_USER_ACCESS (0x44 | (NETFN_APP << 8)) +#define SET_USER_NAME (0x45 | (NETFN_APP << 8)) +#define GET_USER_NAME (0x46 | (NETFN_APP << 8)) +#define SET_USER_PASSWORD (0x47 | (NETFN_APP << 8)) +#define MASTER_WRITE_READ (0x52 | (NETFN_APP << 8)) +// #define SET_PEF_ENABLE 0xA1 /* NETFN_APP (old) */ +#define CHASSIS_STATUS 0x01 /* NETFN_CHAS (=00) */ +#define CHASSIS_CTL 0x02 /* NETFN_CHAS (=00) */ +#define CHASSIS_IDENTIFY 0x04 /* NETFN_CHAS (=00) */ +#define SET_BOOT_OPTIONS 0x08 /* NETFN_CHAS (=00) */ +#define GET_BOOT_OPTIONS 0x09 /* NETFN_CHAS (=00) */ +#define GET_POWERON_HOURS 0x0F /* NETFN_CHAS (=00) */ +#define GET_PEF_CONFIG (0x13 | (NETFN_SEVT << 8)) +#define SET_PEF_CONFIG (0x12 | (NETFN_SEVT << 8)) +#define GET_DEVSDR_INFO (0x20 | (NETFN_SEVT << 8)) +#define GET_DEVICE_SDR (0x21 | (NETFN_SEVT << 8)) +#define RESERVE_DEVSDR_REP (0x22 | (NETFN_SEVT << 8)) +#define SET_SEVT_ENABLE (0x28 | (NETFN_SEVT << 8)) +#define GET_SEVT_ENABLE (0x29 | (NETFN_SEVT << 8)) +#define REARM_SENSOR (0x2A | (NETFN_SEVT << 8)) +#define GET_FRU_INV_AREA (0x10 | (NETFN_STOR << 8)) +#define READ_FRU_DATA (0x11 | (NETFN_STOR << 8)) +#define WRITE_FRU_DATA (0x12 | (NETFN_STOR << 8)) + +#define GET_SENSOR_READING_FACTORS (0x23 | (NETFN_SEVT << 8)) +#define SET_SENSOR_HYSTERESIS (0x24 | (NETFN_SEVT << 8)) +#define GET_SENSOR_HYSTERESIS (0x25 | (NETFN_SEVT << 8)) +#define SET_SENSOR_THRESHOLD (0x26 | (NETFN_SEVT << 8)) +#define GET_SENSOR_THRESHOLD (0x27 | (NETFN_SEVT << 8)) +#define GET_SENSOR_EVT_ENABLE (0x29 | (NETFN_SEVT << 8)) +#define REARM_SENSOR_EVENTS (0x2A | (NETFN_SEVT << 8)) +#define GET_SENSOR_EVT_STATUS (0x2B | (NETFN_SEVT << 8)) +#define GET_SENSOR_READING (0x2D | (NETFN_SEVT << 8)) +#define GET_SENSOR_TYPE (0x2F | (NETFN_SEVT << 8)) + +#define SET_LAN_CONFIG (0x01 | (NETFN_TRANS << 8)) +#define GET_LAN_CONFIG (0x02 | (NETFN_TRANS << 8)) +#define GET_LAN_STATS (0x04 | (NETFN_TRANS << 8)) +#define SET_SER_CONFIG (0x10 | (NETFN_TRANS << 8)) +#define GET_SER_CONFIG (0x11 | (NETFN_TRANS << 8)) +#define SET_SER_MUX (0x12 | (NETFN_TRANS << 8)) +#define GET_SEL_INFO (0x40 | (NETFN_STOR << 8)) +#define GET_SEL_ALLOCATION_INFO (0x41 | (NETFN_STOR << 8)) +#define RESERVE_SEL (0x42 | (NETFN_STOR << 8)) +#define GET_SEL_ENTRY (0x43 | (NETFN_STOR << 8)) +#define CLEAR_SEL (0x47 | (NETFN_STOR << 8)) +#define GET_SEL_TIME (0x48 | (NETFN_STOR << 8)) +#define GET_SDR_REPINFO (0x20 | (NETFN_STOR << 8)) +#define RESERVE_SDR_REP (0x22 | (NETFN_STOR << 8)) +#define GET_SDR (0x23 | (NETFN_STOR << 8)) +#define ACTIVATE_SOL1 (0x01 | (NETFN_SOL << 8)) +#define SET_SOL_CONFIG (0x03 | (NETFN_SOL << 8)) +#define GET_SOL_CONFIG (0x04 | (NETFN_SOL << 8)) +#define ACTIVATE_SOL2 (0x20 | (NETFN_TRANS << 8)) +#define SET_SOL_CONFIG2 (0x21 | (NETFN_TRANS << 8)) +#define GET_SOL_CONFIG2 (0x22 | (NETFN_TRANS << 8)) +#define READ_EVENT_MSGBUF (0x35 | (NETFN_APP << 8)) +#define GET_EVENT_RECEIVER (0x01 | (NETFN_SEVT << 8)) +#define SMS_OS_REQUEST 0x10 /*(0x10 | (NETFN_APP << 8)) */ +#define CMD_GET_SESSION_INFO 0x3D /* NETFN_APP */ +#define CMD_SET_SYSTEM_INFO 0x58 /* NETFN_APP */ +#define CMD_GET_SYSTEM_INFO 0x59 /* NETFN_APP */ +/* + Other commands used for IPMI LAN: + GET_CHAN_AUTH (0x38 | (NETFN_APP << 8)) + GET_SESS_CHAL (0x39 | (NETFN_APP << 8)) + ACT_SESSION (0x3A | (NETFN_APP << 8)) + SET_SESS_PRIV (0x3B | (NETFN_APP << 8)) + CLOSE_SESSION (0x3C | (NETFN_APP << 8)) + */ + +#define IPMB_CLEAR_MSGF 0x30 +#define IPMB_GET_MESSAGE 0x33 +#define IPMB_SEND_MESSAGE 0x34 + +#define PICMG_SLAVE_BUS 0x40 +/* commands under NETFN_PICMG */ +#define PICMG_GET_PROPERTIES 0x00 +#define PICMG_GET_LED_PROPERTIES 0x05 +#define PICMG_SET_LED_STATE 0x07 +#define PICMG_GET_LED_STATE 0x08 +#define PICMG_ID 0x00 + +/* structure used by ipmi_cmd(), not used by ipmi_cmdraw */ +#define NCMDS 62 +typedef struct { + ushort cmdtyp; + uchar sa; + uchar bus; + uchar netfn; + uchar lun; + uchar len; /*length of request data (FYI, but not used here) */ + uchar rslen; /*length of response data expected (not including ccode) */ +} ipmi_cmd_t; + +struct valstr { + ushort val; + const char * str; +}; + +struct oemvalstr { + uint oem; + ushort val; + const char * str; +}; + +/* IPMI driver types returned by get_driver_type() */ +#define NDRIVERS 15 +#define DRV_UNKNOWN 0 +#define DRV_IMB 1 +#define DRV_VA 2 +#define DRV_MV 3 +#define DRV_GNU 4 +#define DRV_LD 5 /*LANDesk*/ +#define DRV_LAN 6 /*IPMI LAN 1.5*/ +#define DRV_KCS 7 /*direct KCS*/ +#define DRV_SMB 8 /*direct SMBus/SSIF*/ +#define DRV_LAN2 9 /*LANplus, IPMI LAN 2.0*/ +#define DRV_MS 10 /*Microsoft ipmidrv.sys*/ +#define DRV_BMC 11 /*Solaris 10 bmc */ +#define DRV_SMC 12 /*SuperMicro Computer LAN mode*/ +#define DRV_LIPMI 13 /*Solaris 8/9 lipmi */ +#define DRV_LAN2I 14 /*LANplus with Intel OEM */ +#define DRV_EFI 15 /*Intel EFI, ipmi.efi*/ +#define DRV_IBM 16 /*LAN with IBM OEM mode*/ +#define DRV_HP 17 /*LANplus with HP OEM mode*/ + +/* Event severity codes, used in ievents.c and oem*.c */ +#define SEV_INFO 0 +#define SEV_MIN 1 +#define SEV_MAJ 2 +#define SEV_CRIT 3 + +/* Errors returned by ipmiutil functions, lan, etc, see decode_rv() */ +#define ERR_BAD_LENGTH -24 /*length < MIN */ +#define ERR_BAD_FORMAT -23 /*bad format*/ +#define ERR_USAGE -22 /*usage/help requested*/ +#define ERR_NOT_FOUND -21 /*requested item not found*/ +#define ERR_FILE_OPEN -20 /*cannot open file*/ +#define LAN_ERR_DROPPED -19 /*Remote BMC dropped the connection*/ +#define ERR_NOT_ALLOWED -18 /*access not allowed*/ +#define ERR_BAD_PARAM -17 /*invalid parameter*/ +#define ERR_NO_DRV -16 /*cannot open IPMI driver*/ +#define LAN_ERR_V2 -15 /*BMC only supports IPMI 2.0*/ +#define LAN_ERR_V1 -14 /*BMC only supports IPMI 1.x*/ +#define LAN_ERR_OTHER -13 +#define LAN_ERR_PING -12 /*error with ping*/ +#define LAN_ERR_HOSTNAME -11 /*error resolving hostname*/ +#define LAN_ERR_TOO_SHORT -10 /*recv data too short */ +#define LAN_ERR_NOTSUPPORT -9 /*slave address != 0x20, not supported now */ +#define LAN_ERR_INVPARAM -8 /*null pointers, etc. */ +#define LAN_ERR_BADLENGTH -7 /*length > MAX */ +#define LAN_ERR_TIMEOUT -6 /*timeout signal(SIGALRM) recvd */ +#define LAN_ERR_ABORT -5 /*abort signal(SIGINT) recvd */ +#define LAN_ERR_CONNECT -4 /*problem connecting to BMC*/ +#define LAN_ERR_RECV_FAIL -3 /*receive failed, usually no response*/ +#define LAN_ERR_SEND_FAIL -2 /*send failed */ +#define ERR_BMC_MSG -504 /*error getting message from BMC*/ + /* see ipmidir.h: ERGETTINGIPMIMESSAGE -504 */ + +/* values used to request AUTHTYPE */ +#define IPMI_SESSION_AUTHTYPE_NONE 0x00 +#define IPMI_SESSION_AUTHTYPE_MD2 0x01 +#define IPMI_SESSION_AUTHTYPE_MD5 0x02 +#define IPMI_SESSION_AUTHTYPE_PASSWORD 0x04 +#define IPMI_SESSION_AUTHTYPE_OEM 0x05 +#define AUTHTYPE_INIT 0xFF /*initial value, not set*/ +/* mask values used for AUTHTYPE support */ +#define IPMI_MASK_AUTHTYPE_NONE 0x01 +#define IPMI_MASK_AUTHTYPE_MD2 0x02 +#define IPMI_MASK_AUTHTYPE_MD5 0x04 +#define IPMI_MASK_AUTHTYPE_PASSWORD 0x10 +#define IPMI_MASK_AUTHTYPE_OEM 0x20 + +#define IPMI_PRIV_LEVEL_OEM 0x05 +#define IPMI_PRIV_LEVEL_ADMIN 0x04 +#define IPMI_PRIV_LEVEL_OPERATOR 0x03 +#define IPMI_PRIV_LEVEL_USER 0x02 +#define IPMI_PRIV_LEVEL_CALLBACK 0x01 + +#define VENDOR_INTEL 0x000157 /*=343.*/ +#define VENDOR_KONTRON 0x003A98 /*=15000*/ +#define VENDOR_NSC 0x000322 +#define VENDOR_LMC 0x000878 +#define VENDOR_TYAN 0x0019FD +#define VENDOR_NEC 0x000077 +#define VENDOR_SUPERMICRO 0x002A7C /*=10876.*/ +#define VENDOR_PEPPERCON 0x0028C5 /*used in SuperMicro AOC-SIMSO*/ +#define VENDOR_FUJITSU 0x002880 /*Fujitsu-Siemens*/ +#define VENDOR_MICROSOFT 0x000137 /* 311. */ +#define VENDOR_SUN 0x00002A +#define VENDOR_DELL 0x0002A2 +#define VENDOR_HP 0x00000B +#define VENDOR_IBM 0x000002 +#define VENDOR_SUPERMICROX 0x00B980 /*=47488. used for Winbond/SuperMicro */ +#define VENDOR_MAGNUM 5593 /* Magnum Technologies, also SuperMicro */ +#define VENDOR_QUANTA 7244 +#define VENDOR_XYRATEX 1993 +#define VENDOR_NEWISYS 9237 +#define VENDOR_CISCO 5771 /*=0x168B*/ + +#define PRODUCT_QUANTA_S99Q 21401 +#define PRODUCT_QUANTA_QSSC_S4R 64 /*0x0040*/ + +#define URNLOOPS 1000 /* default is 300 ms, Urbanna needs 1000 ms */ +#define LOG_MSG_LENGTH 1024 /*max len of log message*/ +#define SZGNODE 80 /* max len of a nodename */ + +#define BDELIM '|' /*delimeter for canonical output*/ +#define BCOMMA ',' /*delimeter for CSV output*/ +#define BCOLON ':' /*delimeter some output with colons*/ +#define BCOMMENT '#' /*delimeter '#' used for comments */ + +#ifndef LOG_WARN +#define LOG_EMERG 0 // system is unusable +#define LOG_ALERT 1 // action must be taken immediately +#define LOG_CRIT 2 // critical conditions +#define LOG_ERR 3 // error conditions +#define LOG_WARN 4 // warning conditions +#define LOG_NOTICE 5 // normal but significant condition +#define LOG_INFO 6 // informational +#define LOG_DEBUG 7 // debug-level messages +#endif + +#ifndef _IPMI_RQ_ +#define _IPMI_RQ_ 1 +/* structure used in ipmi_sendrecv, maps to ipmitool syntax. */ +struct ipmi_rq { + struct { + uchar netfn:6; + uchar lun:2; + uchar cmd; + uchar target_cmd; + ushort data_len; + uchar *data; + } msg; +}; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/* ------------------------ SUBROUTINES ------------------------- */ + +/* + * ipmi_cmd + * ushort cmd (input): (netfn << 8) + command + * uchar *pdata (input): pointer to ipmi data + * int sdata (input): size of ipmi data + * uchar *presp (output): pointer to response data buffer + * int *sresp (input/output): on input, size of response buffer, + * on output, length of response data + * uchar *cc (output): completion code + * char fdebugcmd(input): flag =1 if debug output desired + * returns 0 if successful, <0 if error + */ +int ipmi_cmd(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +/* + * ipmi_cmdraw + * uchar cmd (input): IPMI Command + * uchar netfn (input): IPMI NetFunction + * uchar sa (input): IPMI Slave Address of the MC + * uchar bus (input): BUS of the MC + * uchar lun (input): IPMI LUN + * uchar *pdata (input): pointer to ipmi data + * int sdata (input): size of ipmi data + * uchar *presp (output): pointer to response data buffer + * int *sresp (input/output): on input, size of response buffer, + * on output, length of response data + * uchar *cc (output): completion code + * char fdebugcmd(input): flag =1 if debug output desired + * returns 0 if successful, <0 if error + */ +int ipmi_cmdraw(uchar cmd, uchar netfn, uchar sa, uchar bus, uchar lun, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +/* + * ipmi_close_ + * Called to close an IPMI session. + * returns 0 if successful, <0 if error + */ +int ipmi_close_(void); +int ipmi_close(void); /*ditto*/ +/*-----------------------------------------------------------------* + * These externals are conditionally compiled in ipmicmd.c + ipmi_cmdraw_ia() Intel IMB driver, /dev/imb + ipmi_cmdraw_mv() MontaVista OpenIPMI driver + ipmi_cmdraw_va() VALinux driver + ipmi_cmdraw_ld() LANDesk driver + ipmi_cmdraw_direct() Direct/Driverless KCS or SSIF + ipmi_cmdraw_lan() IPMI LAN + ipmi_cmdraw_lan2() IPMI LANplus (RMCP+ in IPMI 2.0) + *-----------------------------------------------------------------*/ + +/* + * parse_lan_options + * Parse the IPMI LAN options from the command-line getopt. + * int c (input): command-line option from getopt, one of: + case 'F': force driver type + case 'T': auth type + case 'V': priv level + case 'J': cipher suite + case 'N': nodename + case 'U': username + case 'R': remote password + case 'P': remote password + case 'E': get password from IPMI_PASSWORD environment var + case 'Y': prompt for remote password + case 'Z': set local MC address + * char *optarg (input): command-line argument from getopt + * char fdebug (input): show debug messages if =1, default=0 + */ +void parse_lan_options(int c, char *optarg, char fdebug); +/* + * set_lan_options + * Use this routine to set the lan options 'gnode','guser','gpswd', etc. + * This would only be required before opening a new session. + * char *node (input): IP address or nodename of remote node's IPMI LAN + * char *user (input): IPMI LAN username + * char *pswd (input): IPMI LAN password + * int auth (input): IPMI LAN authentication type (1 - 5) + * IPMI_SESSION_AUTHTYPE_NONE 0x00 + * IPMI_SESSION_AUTHTYPE_MD2 0x01 + * IPMI_SESSION_AUTHTYPE_MD5 0x02 + * IPMI_SESSION_AUTHTYPE_PASSWORD 0x04 + * IPMI_SESSION_AUTHTYPE_OEM 0x05 + * int priv (input): IPMI LAN privilege level (1 - 5) + * IPMI_PRIV_LEVEL_CALLBACK 0x01 + * IPMI_PRIV_LEVEL_USER 0x02 + * IPMI_PRIV_LEVEL_OPERATOR 0x03 + * IPMI_PRIV_LEVEL_ADMIN 0x04 + * IPMI_PRIV_LEVEL_OEM 0x05 + * int cipher (input): IPMI LAN cipher suite (0 thru 17, default is 3) + * See table 22-19 in the IPMIv2 spec. + * void *addr (input): Socket Address to use (SOCKADDR_T *) if not NULL + * This is only used in itsol.c because it has an + * existing socket open. Default is NULL for this. + * int addr_len (input): length of Address buffer (128 if ipv6, 16 if ipv4) + * returns 0 if successful, <0 if error + */ +int set_lan_options(char *node, char *user, char *pswd, int auth, int priv, + int cipher, void *addr, int addr_len); +int get_lan_options(char *node, char *user, char *pswd, int *auth, int *priv, + int *cipher, void *addr, int *addr_len); +void print_lan_opt_usage(void); +int ipmi_getdeviceid(uchar *presp, int sresp, char fdebugcmd); +/* int ipmi_open(void); * embedded in ipmi_cmd() */ +int ipmi_getpicmg(uchar *presp, int sresp, char fdebug); +char *show_driver_type(int idx); +int set_driver_type(char *tag); +int get_driver_type(void); +int nodeislocal(char *nodename); +/* These *_mc routines are used to manage changing the mc. + * The local mc (mymc) may be changed via -Z, and + * the remote mc (mc) may be changed with -m. */ +void ipmi_set_mc(uchar bus, uchar sa, uchar lun, uchar type); +void ipmi_get_mc(uchar *bus, uchar *sa, uchar *lun, uchar *type); +void ipmi_restore_mc(void); +void ipmi_set_mymc(uchar bus, uchar sa, uchar lun, uchar type); +void ipmi_get_mymc(uchar *bus, uchar *sa, uchar *lun, uchar *type); +/* ipmi_cmdraw_mc and ipmi_cmd_mc are used in cases where the mc may + * have been changed via ipmi_set_mc. */ +int ipmi_cmdraw_mc(uchar cmd, uchar netfn, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +int ipmi_cmd_mc(ushort icmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +/* ipmi_sendrecv is a wrapper for ipmi_cmdraw which maps to ipmitool syntax */ +int ipmi_sendrecv(struct ipmi_rq * req, uchar *rsp, int *rsp_len); + +/* other common subroutines */ +char * decode_rv(int rv); /*ipmicmd.c*/ +char * decode_cc(ushort icmd, int cc); +void dump_buf(char *tag,uchar *pbuf,int sz, char fshowascii); +int get_lan_channel(uchar chstart, uchar *chan); +void show_fru_picmg(uchar *pdata, int dlen); /* ifru_picmg.c*/ +/* show_outcome outputs the meaning of the return code. */ +void show_outcome(char *prog, int ret); +/* these log routines are primarily for the isol debug log */ +FILE *open_log(char *mname); +void close_log(void); +void flush_log(void); +void print_log( char *pattn, ... ); +void dump_log(FILE *fp,char *tag,uchar *pbuf,int sz, char fshowascii); +void logmsg( char *pname, char *pattn, ... ); + +#ifdef WIN32 +/* Implement the Linux strncasecmp for Windows. */ +int strncasecmp(const char *s1, const char *s2, int n); +#endif +const char *val2str(ushort val, const struct valstr *vs); /*ipmilanplus.c*/ +const char * oemval2str(ushort oem, uchar val, const struct oemvalstr *vs); +void set_debug(void); /*used only by oem_sun.c*/ +void set_iana(int iana); /*ipmicmd.c*/ +void set_mfgid(uchar *devid, int len); +void get_mfgid(int *pvend, int *pprod); +void get_devid_ver(uchar *bmaj, uchar *bmin, uchar *iver); + +char *get_nodename(void); +char is_remote(void); +void show_devid(uchar b1, uchar b2, uchar i1, uchar i2); +int set_max_kcs_loops(int ms); /* ipmicmd.c, calls ipmidir.c if ok */ + +/* These common subroutines are in subs.c */ +int str_icmp(char *s1, char *s2); /*used internally in ipmicmd.c*/ +char * strdup_(const char *instr); /*wrapper for strdup, supports WIN32*/ +int strlen_(const char *s); +uchar htoi(char *inhex); +void os_usleep(int s, int u); +char *get_iana_str(int mfg); /*subs.c*/ +int get_errno(void); /*subs.c*/ +const char * buf2str(uchar * buf, int len); /*subs.c*/ +int str2uchar(char *str_in, uchar *uchr_out); +uchar atob(char *str_in); /* calls str2uchar*/ +void atoip(uchar *array,char *instr); +int get_system_info(uchar parm, char *pbuf, int *szbuf); /*subs.c*/ +int set_system_info(uchar parm, uchar *pbuf, int szbuf); /*subs.c*/ +int ipmi_reserved_user(int vend, int userid); /*subs.c*/ + +/* from mem_if.c */ +int get_BiosVersion(char *str); + +/* see isensor.h for SDR cache routines */ +/* see ievents.h for sensor_type_desc, sel_opts, decode_sel routines */ + +#ifdef __cplusplus +} +#endif +/* end ipmicmd.h */ diff --git a/util/ipmidir.c b/util/ipmidir.c new file mode 100644 index 0000000..4865bc0 --- /dev/null +++ b/util/ipmidir.c @@ -0,0 +1,1513 @@ +/************************************************ + * + * ipmidir.c + * + * Supports direct raw KCS and SMBus user-space I/Os. + * Use this if no other IPMI driver is present. + * This interface would not be sufficient if more + * than one application is using IPMI at a time. + * This code is currently included for Linux, not for + * Windows. Windows requires imbdrv.sys or ipmidrv.sys. + * + * 08/21/06 Andy Cress - added as a new module + * 09/22/06 Andy Cress - improved SMBus base address detection + * 09/27/06 Andy Cress - fixed passing slave addrs other than BMC (0x20) + * 01/16/08 Andy Cress - more DBG messages + * + ************************************************/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2006, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#if defined(STUB_IO) +/* May stub out direct io. For instance, PPC does not support <sys/io.h> */ +#define UCHAR unsigned char +#define UINT16 unsigned short +int ipmi_open_direct(int fdebugcmd) +{ return(-1); } +int ipmi_close_direct(void) +{ return(-1); } +int ipmi_cmdraw_direct(UCHAR cmd, UCHAR netfn, UCHAR lun, UCHAR sa, UCHAR bus, + UCHAR *pdata, int sdata, UCHAR *presp, + int *sresp, UCHAR *pcc, char fdebugcmd) +{ return(-1); } +int ipmi_cmd_direct(UINT16 icmd, UCHAR *pdata, int sdata, UCHAR *presp, + int *sresp, UCHAR *pcc, char fdebugcmd) +{ return(-1); } +int ipmi_set_max_kcs_loops(int ms) +{ return(0); } + +#elif defined(LINUX) || defined(BSD) || defined(DOS) || defined(MACOS) +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <time.h> // for ProcessSendMessage timeout +#include <string.h> +#include <errno.h> +#ifdef DOS +#include <dos.h> +#else +#include <sys/mman.h> +#endif + +#include "imb_api.h" +#include "ipmicmd.h" +#include "ipmidir.h" +/* No special includes for 64-bit are needed. */ + +#if defined(LINUX) +#include <sys/io.h> +#elif defined(BSD) || defined(MACOS) +// #include <machine/cpufunc.h> +int iofd = -1; + +static __inline uchar +inbc(ushort port) +{ + uchar data; +/* from Linux sys/io.h: + * __asm__ __volatile__ ("inb %w1,%0":"=a" (data):"Nd" (port)); + * from BSD machine/cpufunc.h: + * __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((ushort)(port))); + */ + __asm __volatile("inb %1,%0" : "=a" (data) : "d" (port)); + return (data); +} +static __inline void +outbc(ushort port, uchar data) +{ +/* from Linux sys/io.h: + * __asm__ __volatile__ ("outb %b0,%w1": :"a" (data), "Nd" (port)); + * from BSD machine/cpufunc.h: + * __asm __volatile("outb %0,%1" : : "a" (data), "id" ((ushort)(port))); + */ + __asm __volatile("outb %0,%1" : : "a" (data), "d" (port)); +} +static __inline uint +inl(ushort port) +{ + uint data; + + __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port)); + return (data); +} +static __inline void +outl(ushort port, uint data) +{ + __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port)); +} +#endif +/* Linux & BSD define usleep() in unistd.h, but DOS has delay() instead. */ +#if defined(DOS) +void usleep(ulong usec) /*missing from DOS*/ +{ + delay(usec); +} +#endif + + +/* DBGP() is enabled with -x, DBGP2 is enabled if LINUX_DEBUG & -x */ +#define DBGP(fmt, args...) if (fdebugdir) fprintf(stdout,fmt, ##args) +#if defined(DOS) +#define DBGP2() ; /*no extra debug output*/ +#elif defined(LINUX_DEBUG) +#define DBGP2(fmt, args...) if (fdebugdir) fprintf(stderr,fmt, ##args) +#else +#define DBGP2(fmt, args...) ; /*no extra debug output*/ +#endif + +#ifdef ALONE +static int fjustpass = 0; +#else +// DRV_KCS, DRV_SMB types defined in ipmicmd.h +// extern int fDriverTyp; // use set_driver_type() instead +extern ipmi_cmd_t ipmi_cmds[NCMDS]; +extern int fjustpass; +#endif + +/*****************************************************************************/ +/* + * GLOBAL DATA + */ +/* KCS base addr: use 0xca2 for ia32, 0x8a2 for ia64 + * some use 0xca8/0xcac w register spacing + */ +#if defined(__ia64__) +/* gcc defines __ia64__, or Makefile.am defines __IA64__ */ +static UINT16 kcsBaseAddress = 0x8a2; /* for Itanium2 KCS */ +static UINT8 kcs_inc = 1; /*register spacing*/ +#else +static UINT16 kcsBaseAddress = 0xca2; /* for ia32 KCS */ +static UINT8 kcs_inc = 1; /*register spacing*/ +#endif +/* + * SMBus/SSIF: see dmidecode for I2C Slave Address & Base Addr. + * Slave Addr is constant for all Intel SSIF platforms (=0x84). + * 0x0540 base <= PCI ID 24D38086 at 00:1f.3 is JR (ICH5) + * 0x0400 base <= PCI ID 25A48086 at 00:1f.3 is TP (Hance_Rapids) + */ +UINT8 mBMCADDR = 0x84; /* SMBus I2C slave address = (0x42 << 1) */ +UINT16 mBMC_baseAddr = 0x540; /* usu. 0x0540 (JR), or 0x0400 if TP */ +UINT16 BMC_base = 0; /* resulting BMC base address (KCS or SMBus)*/ + +static char lock_dir_file[] = "/var/tmp/ipmiutil_dir_lock"; + +/* SSIF/SMBus defines */ +#define STATUS_REQ 0x60 +#define WR_START 0x61 +#define WR_END 0x62 +#define READ_BYTE 0x68 +#define COMMAND_REG (kcsBaseAddress+kcs_inc) +#define STATUS_REG (kcsBaseAddress+kcs_inc) +#define DATA_IN_REG (kcsBaseAddress) +#define DATA_OUT_REG (kcsBaseAddress) + +#if defined(DOS) +extern unsigned inp(unsigned _port); +extern unsigned outp(unsigned _port, unsigned _value); +#pragma intrinsic(inp, outp) +#define _INB(addr) inp((addr)) +#define _OUTB(data, addr) outp((addr),(data)) +#define _IOPL(data) 0 +#define ReadPortUchar( addr, valp ) (*valp) = inp((addr)) +#define WritePortUchar( addr, val ) outp((addr),(val)) +#define WritePortUlong( addr, val ) ( outp((addr),(val)) ) +#define ReadPortUlong( addr, valp ) (*(valp) = inp((addr)) ) +#elif defined(BSD) || defined(MACOS) +#define _INB(addr) inbc((addr)) +#define _OUTB(data, addr) outbc((addr),(data)) +#define _IOPL(data) 0 +#define ReadPortUchar( addr, valp ) (*valp) = inbc((addr)) +#define WritePortUchar( addr, val ) outbc((addr),(val)) +#define WritePortUlong( addr, val ) ( outl((addr),(val)) ) +#define ReadPortUlong( addr, valp ) (*(valp) = inl((addr)) ) +#else +#define _INB(addr) inb((addr)) +#define _OUTB(data, addr) outb((data),(addr)) +#define _IOPL(data) iopl((data)) +#define ReadPortUchar( addr, valp ) (*valp) = inb((addr)) +#define WritePortUchar( addr, val ) outb((val),(addr)) +#define WritePortUlong( addr, val ) ( outl((val), (addr)) ) +#define ReadPortUlong( addr, valp ) (*(valp) = inl((addr)) ) +#endif +/* Static data for Driver type, BMC type, etc. */ +static int g_DriverType = DRV_KCS; +static UINT16 g_ipmiVersion = IPMI_VERSION_UNKNOWN; +static UINT16 g_bmcType = BMC_UNKNOWN; +struct SMBCharStruct SMBChar; +static int fdebugdir = 0; +static char fDetectedIF = 0; + +/*****************************************************************************/ +/* Subroutine prototypes */ + +#ifdef ALONE +int set_driver_type(char * typ) { return; } +int get_IpmiStruct(UCHAR *iftype, UCHAR *ver, UCHAR *sa, int *base, UCHAR *inc) { return(-1); } +#else +/* extern int set_driver_type(char * typ); in ipmicmd.h */ +extern char fsm_debug; /*in mem_if.c*/ +extern int get_IpmiStruct(UCHAR *iftype, UCHAR *ver, UCHAR *sa, int *base, UCHAR *inc); +#endif +int SendTimedImbpRequest_kcs( IMBPREQUESTDATA *requestData, + unsigned int timeout, UINT8 *resp_data, + int *respDataLen, UINT8 *compCode); +int SendTimedImbpRequest_ssif( IMBPREQUESTDATA *requestData, + unsigned int timeout, UINT8 *resp_data, + int *respDataLen, UINT8 *compCode); +int ImbInit_dir(void); +static int SendmBmcRequest( + unsigned char* request, UINT32 reqLength, + unsigned char* response, UINT32* respLength, + UINT32 ipmiOldFlag); +static int ReadResponse( unsigned char* resp, struct SMBCharStruct* smbChar); +static int SendRequest( unsigned char* req, int length, + struct SMBCharStruct* smbChar ); +static int GetDeviceId(UINT16 *bmcType, UINT16 *ipmiVersion); +static int send_raw_kcs(UINT8 *rqData, int rqLen, UINT8 *rsData, int *rsLen ); +static int ProcessTimedMessage(BMC_MESSAGE *p_reqMsg, BMC_MESSAGE *p_respMsg, const UINT32 timeout); +static int wait_for_SMS_flag(void); + +/*****************************************************************************/ +/* Subroutines */ + +static int ProcessMessage(BMC_MESSAGE *p_reqMsg, BMC_MESSAGE *p_respMsg) +{ + int status = STATUS_OK; + UINT32 timeout = 1000 * GETMSGTIMEOUT; // value is in milliseconds + status = ProcessTimedMessage(p_reqMsg, p_respMsg, timeout); + return status; +} + +static char *BmcDesc(unsigned char drvtype) +{ /* return BMC Driver type description string */ + char *msg; + switch(drvtype) { + case DRV_KCS: msg = "KCS"; break; /*BMC Sahalee KCS*/ + case DRV_SMB: msg = "SMBus"; break; /*mBMC SMBus (SSIF)*/ + default: msg = ""; + } + return(msg); +} + +int get_ipmi_if(void) +{ + /* Only care about Linux since ipmidir is not used for Windows. */ + char *if_file = "/var/lib/ipmiutil/ipmi_if.txt"; + char *if_file2 = "/usr/share/ipmiutil/ipmi_if.txt"; + FILE *fp; + char line[80]; + char *p; + char *r; + int rv = ERR_NO_DRV; + int i, j; + ulong mybase = 0; + int myinc = 1; + // uchar *rgbase; + + fp = fopen(if_file,"r"); + if (fp == NULL) fp = fopen(if_file2,"r"); + if (fp == NULL) { /*error opening ipmi_if file*/ + return -1; + } else { /*read the data from the ipmi_if file*/ + while ( (p = fgets(line,sizeof(line),fp)) != NULL) + { + if (strstr(line,"Interface type:") != NULL) { + if (strstr(line,"KCS") != NULL) { + g_DriverType = DRV_KCS; + } else { + g_DriverType = DRV_SMB; + } + } else if (strstr(line,"Base Address:") != NULL) { + r = strchr(line,':'); + i = strspn(++r," \t"); /* skip leading spaces */ + r += i; + j = strcspn(r," \t\r\n"); /* end at next whitespace */ + r[j] = 0; /*stringify*/ + /* convert the "0x0000000000000401" string to an int */ + if (strncmp(r,"0x",2) == 0) { r += 2; j -= 2; } + DBGP2("base addr 0x: %s, mybase=%x j=%d\n",r,mybase,j); + mybase = strtol(r, NULL, 16); /*hex string is base 16*/ + DBGP2("base addr 0x: %s, mybase=%x \n",r,mybase); + } else if (strstr(line,"Register Spacing:") != NULL) { + r = strchr(line,':'); + i = strspn(++r," \t"); /* skip leading spaces */ + r += i; + j = strcspn(r," \t"); /* end at next whitespace */ + r[j] = 0; /*stringify*/ + myinc = atoi(r); + } + } + fclose(fp); + DBGP("ipmi_if: Driver = %d (%s), Base = 0x%04lx, Spacing = %d\n", + g_DriverType,BmcDesc(g_DriverType),mybase,myinc); + if (g_DriverType == DRV_SMB) { + if (mybase & 0x0001) mybase -= 1; /* 0x0401 -> 0x0400 */ + if (mybase != 0 && (mybase & 0x0F) == 0) { /* valid base address */ + mBMC_baseAddr = mybase; + BMC_base = mBMC_baseAddr; + rv = 0; + } + } else { /*KCS*/ + if (mybase != 0) { /* valid base address */ + kcsBaseAddress = (mybase & 0x0000ffff); + BMC_base = kcsBaseAddress; + if (myinc > 1) kcs_inc = myinc; + rv = 0; + } + } + DBGP2("ipmi_if: BMC_base = 0x%04x, kcs_inc = %d, ret = %d\n", + BMC_base, kcs_inc,rv); + } + return(rv); +} + +static int set_lock_dir(void) +{ + int rv = 0; + FILE *fp; + fp = fopen(lock_dir_file,"w"); + if (fp == NULL) rv = -1; + else { + fclose(fp); + rv = 0; + } + return(rv); +} + +static int clear_lock_dir(void) +{ + int rv = 0; + rv = remove(lock_dir_file); /*same as unlink() */ + if (fdebugdir) printf("clear_lock rv = %d\n",rv); + return(rv); +} + +static int check_lock_dir(void) +{ + int rv = 0; +#ifdef LOCK_OK + FILE *fp; + fp = fopen(lock_dir_file,"r"); + if (fp == NULL) rv = 0; + else { + fclose(fp); + rv = -1; /*error, lock file exists*/ + } +#endif + return(rv); +} + +int ipmi_open_direct(int fdebugcmd) +{ + int status = 0; + //char *dmsg = ""; + int i; + + DBGP2("open_direct(%d) called\n",fdebugcmd); + if (fdebugcmd) { + fdebugdir = fdebugcmd; +#if defined(LINUX_DEBUG) && !defined(ALONE) + fsm_debug = fdebugcmd; +#endif + } + + /* Read ipmi_if config file data, if present. */ + status = get_ipmi_if(); + if (status == -1) { + uchar iftype, iver, sa, inc; + int mybase; + /* Read SMBIOS to get IPMI struct */ + status = get_IpmiStruct(&iftype,&iver,&sa,&mybase,&inc); + if (status == 0) { + if (iftype == 0x04) { + g_DriverType = DRV_SMB; + mBMC_baseAddr = mybase; + } else { /*0x01==KCS*/ + g_DriverType = DRV_KCS; + if (sa == 0x20 && mybase != 0) { /*valid*/ + kcsBaseAddress = mybase; + kcs_inc = inc; + } + } + BMC_base = mybase; + DBGP("smbios: Driver=%d(%s), sa=%02x, Base=0x%04x, Spacing=%d\n", + g_DriverType,BmcDesc(g_DriverType),sa,mybase,inc); + } + } + +#ifndef DOS + /* superuser/root priv is required for direct I/Os */ + i = geteuid(); /*direct is Linux only anyway*/ + if (i > 1) { + fprintf(stdout,"Not superuser (%d)\n", i); + return ERR_NO_DRV; + } +#endif + /* check lock for driverless interface */ + i = check_lock_dir(); + if (i != 0) { + fprintf(stdout,"open_direct interface locked, %s in use\n", + lock_dir_file); + return ERR_NO_DRV; + } + + /* Find the SMBIOS IPMI driver type, data */ + status = ImbInit_dir(); + DBGP2("open_direct Init status = %d\n",status); + DBGP2("open_direct base=%x spacing=%d\n",BMC_base,kcs_inc); + if (status == 0) { + fDetectedIF = 1; /*Successfully detected interface */ + /* Send a command to the IPMI interface */ + if (!fjustpass) + status = GetDeviceId(&g_bmcType,&g_ipmiVersion); + if (status == 0) { + char *typ; + if (g_DriverType == DRV_SMB) typ = "smb"; + else typ = "kcs"; + set_driver_type(typ); + } + } + DBGP("open_direct: status=%d, %s drv, ipmi=%d\n", + status,BmcDesc(g_DriverType),g_ipmiVersion); + + /* set lock for driverless interface */ + i = set_lock_dir(); + return status; +} + +int ipmi_close_direct(void) +{ + int status = 0; +#if defined(BSD) || defined(MACOS) + close(iofd); + iofd = -1; +#endif + /* clear lock for driverless interface */ + status = clear_lock_dir(); + return status; +} + +int ipmi_cmdraw_direct(UCHAR cmd, UCHAR netfn, UCHAR lun, UCHAR sa, UCHAR bus, + UCHAR *pdata, int sdata, UCHAR *presp, + int *sresp, UCHAR *pcc, char fdebugcmd) +{ + BMC_MESSAGE sendMsg; + BMC_MESSAGE respMsg; + int status; + int len = 0; + + if (g_bmcType == BMC_UNKNOWN) { + /* User-specified a driver type, but need open */ + status = ipmi_open_direct(fdebugcmd); + } + fdebugdir = fdebugcmd; + if (sdata > IPMI_REQBUF_SIZE) return(LAN_ERR_BADLENGTH); + if (fjustpass) { + status = send_raw_kcs(pdata, sdata, presp, sresp); + *pcc = 0; + return(status); + } + sendMsg.Bus = bus; + sendMsg.DevAdd = sa; + sendMsg.NetFn = netfn; + sendMsg.LUN = lun; + sendMsg.Cmd = cmd; + sendMsg.Len = sdata; + if (sdata > 0) memcpy(sendMsg.Data,pdata,sdata); + + status = ProcessMessage(&sendMsg, &respMsg); + if (status == STATUS_OK) { + *pcc = respMsg.CompCode; + if (respMsg.Len > 0) { + len = respMsg.Len; + if (len > *sresp) len = *sresp; + } else len = 0; + if (len > 0) + memcpy(presp,respMsg.Data,len); + *sresp = len; + } + return(status); +} + +#ifndef ALONE +int ipmi_cmd_direct(UINT16 icmd, UCHAR *pdata, int sdata, UCHAR *presp, + int *sresp, UCHAR *pcc, char fdebugcmd) +{ + UINT8 cmd, netfn, sa, lun, bus; + int status; + int i; + + fdebugdir = fdebugcmd; + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == icmd) { + cmd = (icmd & 0x00ff); + sa = ipmi_cmds[i].sa; + bus = ipmi_cmds[i].bus; + netfn = ipmi_cmds[i].netfn; + lun = ipmi_cmds[i].lun; + break; + } + } + if (i >= NCMDS) { + DBGP("ipmidir: icmd %04x not found, defaults used\n",icmd); + cmd = (icmd & 0xFF); + netfn = (icmd & 0xFF00) >> 8; + sa = BMC_ADDR; + lun = BMC_LUN; + bus = 0; + } + status = ipmi_cmdraw_direct(cmd, netfn, lun, sa, bus, pdata, sdata, + presp, sresp, pcc, fdebugcmd); + return(status); +} +#endif + +static UINT8 +CalculateChecksum(UINT8* p_buff, int length) +{ + UINT8 sum = 0; + int i; + for (i = 0; i < length; i++) sum+= p_buff[i]; + return (~sum) + 1; +} + +static int +GetDeviceId(UINT16 *bmcType, UINT16 *ipmiVersion) +{ + int status = STATUS_OK; + UINT16 thisBmcType = BMC_UNKNOWN; + BMC_MESSAGE sendMsg; + BMC_MESSAGE respMsg; + + DBGP2("open_direct: detecting interface, bmc: %X ver: %X drv=%s\n", + g_bmcType, g_ipmiVersion, BmcDesc(g_DriverType)); + + // if the BMC type has not yet been detected - detect it + if( g_bmcType == BMC_UNKNOWN ) + { + // Try sending the GetDeviceId command to the default interface + sendMsg.DevAdd = BMC_ADDR; + sendMsg.NetFn = NETFN_APP; + sendMsg.LUN = BMC_LUN; + sendMsg.Cmd = CMD_GET_DEVICE_ID; + sendMsg.Len = 0; + DBGP2("open_direct: Try Get_Device_ID with %s driver\n", + BmcDesc(g_DriverType)); + status = ProcessMessage(&sendMsg, &respMsg); + if (status == STATUS_OK) { + if (g_DriverType == DRV_KCS) thisBmcType = BMC_SAHALEE; + else thisBmcType = BMC_MBMC_87431M; + } else { /*error, switch interfaces*/ + DBGP("open_direct: ProcessMessage(%s) error = %d\n", + BmcDesc(g_DriverType),status); + if (!fDetectedIF) { + /* if not yet detected, try other IF type */ + if (g_DriverType == DRV_KCS) { + DBGP2("open_direct: Not KCS, try SSIF/SMBus\n"); + g_DriverType = DRV_SMB; + } else { + DBGP2("open_direct: Not SSIF, try KCS\n"); + g_DriverType = DRV_KCS; + } + } + } /*end-else error*/ + + // If error, try again with the other interface + if (thisBmcType == BMC_UNKNOWN) + { + // send the command via KCS/SMBus to get the IPMI version. + status = ProcessMessage(&sendMsg, &respMsg); + if (status == STATUS_OK) { + if (g_DriverType == DRV_KCS) thisBmcType = BMC_SAHALEE; + else thisBmcType = BMC_MBMC_87431M; + } else { + // If sending message fails + status = ER_NO_BMC_IF; + } + } + g_bmcType = thisBmcType; + + // if we contacted the BMC, decode its version + if( status == STATUS_OK ) + { + if( g_bmcType == BMC_MBMC_87431M ) + { + // Decode the miniBMC productID + } + if( respMsg.Data[4] == 0x51 ) + g_ipmiVersion = (UINT16)IPMI_VERSION_1_5; + else if( respMsg.Data[4] == 0x02 ) + g_ipmiVersion = IPMI_VERSION_2_0; + } + } /* endif unknown BMC */ + + // set the version info and leave + *ipmiVersion = g_ipmiVersion; + *bmcType = g_bmcType; + + DBGP2("open_direct: AFTER bmc: %X ver: %X\n", + g_bmcType, g_ipmiVersion); + return status; +} + +//***************************************************************************** +#if defined (WIN64) + // Do Nothing for WIN64 as we are not using these functions here +#else +static int ProcessSendMessage(BMC_MESSAGE *p_reqMsg, BMC_MESSAGE *p_respMsg, const UINT8 bus, const UINT8 slave, const UINT32 timeout) +{ + int status = STATUS_OK; + BMC_MESSAGE sendReq; + static UINT8 sendSeq = 1; + static UINT8 incTestCount=0; + BMC_MESSAGE reqMsg,respMsg; + int retryCount; + UINT32 i; + UINT nRetryCount = 0; + int testCount; + + // Windows will be using Async Imb request interface to poll for + // messages in the BMC SMS message queue + + // format the send message packet + sendReq.Cmd = SENDMESSAGE_CMD; + sendReq.DevAdd = BMC_ADDR; + sendReq.LUN = 0; + sendReq.NetFn = NETFN_APP; + + sendReq.Data[0] = bus; + sendReq.Data[1] = slave; + // NetFn is the upper 6 bits of the data byte, the LUN is the lower two + sendReq.Data[2] = ((p_reqMsg->NetFn << 2) | (p_reqMsg->LUN & 0x03)); + sendReq.Data[3] = CalculateChecksum(&sendReq.Data[1], 2); + sendReq.Data[4] = BMC_ADDR; + // NetFn is the upper 6 bits of the data byte, the LUN is the lower two + sendReq.Data[5] = ((sendSeq << 2) | (SMS_MSG_LUN & 0x03)); + // sequence number = 1 << 2 and BMC message response lun = 0x02 + sendReq.Data[6] = p_reqMsg->Cmd; + + // loop to copy the command data to the send message data format + i = 0; + for(i=0; i < p_reqMsg->Len; i++) + sendReq.Data[7+i] = p_reqMsg->Data[i]; + + // create a checksum + sendReq.Data[7+i] = CalculateChecksum(&sendReq.Data[4], p_reqMsg->Len + 3); // send data length plus the values from index 3 - 6 + + // send length plus 0 - 7 and checksum byte + sendReq.Len = p_reqMsg->Len + 8; + /* + * Send the message with retries + * For get Device ID & Read FRU data, retry less, in case + * HSC/LCP is not present, + */ + if (p_reqMsg->NetFn != 0x08 ) + retryCount = BMC_MAX_RETRIES+2; + else + retryCount = BMC_MAX_RETRIES+20; + do + { // send the message + if( (status = ProcessMessage(&sendReq, p_respMsg)) == STATUS_OK ) + { + // some error, maybe because the controller was not ready yet. + if( p_respMsg->CompCode == 0x83 ) { + // Sleep for 1 second and try again + sleep(1); + incTestCount = 1; // true + continue; // try again + } + else if( p_respMsg->CompCode == 0x82 ) { + DBGP("ProcessSendMessage(sa=%02x,%02x,%02x) " + "ccode=82 bus error\n", + slave,p_reqMsg->NetFn,p_reqMsg->Cmd); + status = ERGETTINGIPMIMESSAGE; + break; // exit with error + } + else if( p_respMsg->CompCode != 0x00 ) + continue; //break; // exit with error + + status = wait_for_SMS_flag(); /* new, added */ + if (status == -1) + DBGP("wait_for_SMS_flag timeout\n"); + + // Only for windows we use Imb Asyn interface for polling + // For Unix we issue GetMessage command + // issue a getmessage command + reqMsg.DevAdd = BMC_ADDR; + reqMsg.NetFn = NETFN_APP; + reqMsg.LUN = BMC_LUN; + reqMsg.Cmd = GETMESSAGE_CMD; + reqMsg.Len = 0; + + nRetryCount = 0; + testCount = 100; /* For HSC */ + if (slave == 0x22 || incTestCount == 1) // true + testCount=1000; /*added for LCP */ + do + { + /* Loop here for the response with the correct + * sequence number. */ + if( (status = ProcessMessage( &reqMsg, &respMsg )) != 0 ) { + DBGP("Breaking after Getmsg, Status is %d\n",status); + break; + } + if( slave == 0x22 && p_reqMsg->Cmd == 0x04 ) { + /* give debug if LCP ever gets here. */ + DBGP("LCP get: cnt[%d,%d] seq[%02x,%02x] cc=%02x status=%u\n", + testCount,retryCount, sendSeq, + ((respMsg.Data[4] & 0xFC)>>2), + respMsg.CompCode,status) ; + return STATUS_OK; + } + if (respMsg.CompCode != 0) { + DBGP2("get, cnt[test=%d] slave=%02x, cc==%02x\n", + testCount,slave,respMsg.CompCode); + /* Used to wait 1 ms via usleep(1000), but not needed. */ + // usleep(1000); + } + } while(((respMsg.CompCode == 0x83 ||(respMsg.CompCode == 0x80)) + && --testCount > (int) 0) || (respMsg.CompCode == 0x0 + && ((respMsg.Data[4] & 0xFC) >> 2) != sendSeq) ); + + DBGP("get cnt[test=%d,retry=%d] seq[Send=0x%02x Recv=0x%02x] " + "CompCode=0x%x status=%u\n", testCount,retryCount, + sendSeq,((respMsg.Data[4] & 0xFC)>>2), + respMsg.CompCode,status); + + if( (respMsg.CompCode == 0x00) && (status == STATUS_OK) && + ((respMsg.Data[4] & 0xFC) >> 2 == sendSeq) ) + { + // format the GetMessage response + (*p_respMsg) = (*p_reqMsg); + // The first data byte is the channel number the message + // was sent on + p_respMsg->DevAdd = respMsg.Data[3]; + p_respMsg->NetFn = respMsg.Data[1] >> 2; + p_respMsg->LUN = respMsg.Data[4] & 0x03; + p_respMsg->Cmd = respMsg.Data[5]; + p_respMsg->CompCode = respMsg.Data[6]; // comp code + p_respMsg->Len = respMsg.Len - 8; + // the last data byte is the checksum + if ( p_respMsg->CompCode == 0xCC) { + DBGP2(" Cmd=%d Len=%d ccode=CC ", + p_respMsg->Cmd, p_respMsg->Len); + } + for(i=0; i < p_respMsg->Len; i++) + p_respMsg->Data[i] = respMsg.Data[7+i]; + break; + } + } + // this will retry the read the number of times in retryCount + } while( --retryCount > 0 ); + + if( retryCount <= 0 ) status = ERGETTINGIPMIMESSAGE; + + /* Increment the sequence number + * sequence number can't be greater 63 (6bit number), + * so wrap the counter if it is */ + ++sendSeq; + if( sendSeq >= 64 ) sendSeq = 1; + return status; +} + +#endif /* All other than WIN64 */ + +/* #define MAX_KCS_LOOP 30000 *was 7000*/ +/* Set a failsafe MAX KCS Loops to prevent infinite loop on status reg */ +/* max was 7000, but need longer for ClearSEL cmd */ +static int max_kcs_loop = 30000; /*means 300ms*/ +static int max_sms_loop = 500; /*means 500ms*/ +static int peak_loops = 0; +int ipmi_set_max_kcs_loops(int ms) +{ + max_kcs_loop = ms * 100; /*300 ms * 100 = 30000 loops*/ + max_sms_loop = ms; + return 0; +} + +static int wait_for_SMS_flag(void) +{ + int i = 0; + while((_INB(STATUS_REG) & 0x04) == 0) + { + usleep(2 * 1000); /*sleep for 2 msec*/ + i += 2; + if ( i > max_sms_loop ) return -1; + } + return 0; +} + +static int wait_for_IBF_clear(void) + { + int i = 0; + while ((_INB(STATUS_REG) & 0x02) == 0x02) { + if (i > 0 && (i % 100) == 0) usleep(1000); /*sleep for 1 msec*/ + if (i > max_kcs_loop) { + DBGP("wait_for_IBF_clear: max loop %d\n",i); + return -1; + // break; + } + i++; + } + if (i > peak_loops) peak_loops = i; + return 0; + } + +static int wait_for_OBF_set(void) + { + int i = 0; + while ((_INB(STATUS_REG) & 0x01) == 0x00) { + if (i > 0 && (i % 100) == 0) usleep(1000); /*sleep for 1 msec*/ + if (i > max_kcs_loop) { + DBGP("wait_for_OBF_set: max loop %d\n",i); + return -1; + // break; + } + i++; + } + if (i > peak_loops) peak_loops = i; + return 0; + } + +static inline int get_write_state(void) + { + if ((_INB(STATUS_REG) >> 6) != 0x02) + return -1; + return 0; + } + +static inline int get_read_state(void) + { + if ((_INB(STATUS_REG) >> 6) != 0x01) + return -1; + return 0; + } + +static inline int get_idle_state(void) + { + if ((_INB(STATUS_REG) >> 6) != 0x00) + return -1; + return 0; + } + +UINT8 dummy2; +static inline void clear_OBF(void) +{ + dummy2 = _INB(DATA_IN_REG); +} + +static int +send_raw_kcs (UINT8 *rqData, int rqLen, UINT8 *rsData, int *rsLen ) +{ + int length; + unsigned char dummy; + unsigned char rx_data[64]; + int rxbuf_len; + int rv; + + if (fdebugdir) { + int cnt; + DBGP("send_raw_kcs: "); + for ( cnt=0; cnt < rqLen ; cnt++) + DBGP(" %02x",rqData[cnt]); + DBGP("\n"); + } + wait_for_IBF_clear(); + clear_OBF(); + _OUTB(WR_START,COMMAND_REG); + rv = wait_for_IBF_clear(); + if (get_write_state() != 0) return LAN_ERR_SEND_FAIL; + clear_OBF(); + if (rv != 0) return LAN_ERR_SEND_FAIL; + + for(length = 0;length < rqLen-1;length++) + { + _OUTB(rqData[length],DATA_OUT_REG); + wait_for_IBF_clear(); + if (get_write_state() != 0) + return LAN_ERR_SEND_FAIL; + clear_OBF(); + } + + _OUTB(WR_END,COMMAND_REG); + wait_for_IBF_clear(); + if (get_write_state() != 0) + return LAN_ERR_SEND_FAIL; + clear_OBF(); + _OUTB(rqData[length],DATA_OUT_REG); + + /* write phase complete, start read phase */ + rxbuf_len = *rsLen; + *rsLen = 0; + while(*rsLen <= IPMI_RSPBUF_SIZE) + { + wait_for_IBF_clear(); + if (get_read_state() != 0) + { + if (get_idle_state() != 0) { + DBGP2("not idle in rx_data (%02x)\n",_INB(STATUS_REG)); + // clear_lock_dir(); + return LAN_ERR_RECV_FAIL; + } else { + rv = wait_for_OBF_set(); + if (rv != 0) return LAN_ERR_RECV_FAIL; + dummy = _INB(DATA_IN_REG); + /* done, copy the data */ + for (length=0;length < *rsLen;length++) + rsData[length] = rx_data[length]; + return ACCESS_OK; + } + } else { + rv = wait_for_OBF_set(); + if (rv != 0) return LAN_ERR_RECV_FAIL; + rx_data[*rsLen] = _INB(DATA_IN_REG); + DBGP2("rx_data[%d] is 0x%x\n",*rsLen,rx_data[*rsLen]); + _OUTB(READ_BYTE,DATA_IN_REG); + (*rsLen)++; + } + if (*rsLen > rxbuf_len) { + DBGP("ipmidir: rx buffer overrun, size = %d\n",rxbuf_len); + break; /*stop if user buffer max*/ + } + } /*end while*/ + return ACCESS_OK; +} + +/* + * SendTimedImbpRequest_kcs - write bytes to KCS interface, read response + * The bytes are written in this order: + * 1 netfn + * 2 cmdType + * 3-N data, if any + */ +int +SendTimedImbpRequest_kcs (IMBPREQUESTDATA *requestData, + unsigned int timeout, UINT8 *resp_data, int *respDataLen, + unsigned char *compCode) +{ /*SendTimedImb for KCS*/ + int length; + unsigned char dummy; + unsigned char rx_data[64]; + int rxbuf_len, rv; + + if (fdebugdir) { + int cnt; + DBGP("Send Netfn=%02x Cmd=%02x, raw: %02x %02x %02x %02x", + requestData->netFn, requestData->cmdType, + requestData->busType, requestData->rsSa, + (requestData->netFn<<2), requestData->cmdType); + for ( cnt=0; cnt < requestData->dataLength ; cnt++) + DBGP(" %02x",requestData->data[cnt]); + DBGP("\n"); + } + + rv = wait_for_IBF_clear(); + clear_OBF(); + if (rv != 0) return LAN_ERR_SEND_FAIL; + _OUTB(WR_START,COMMAND_REG); + rv = wait_for_IBF_clear(); + if (get_write_state() != 0) return LAN_ERR_SEND_FAIL; + clear_OBF(); + if (rv != 0) return LAN_ERR_SEND_FAIL; + + _OUTB((requestData->netFn << 2),DATA_OUT_REG); + rv = wait_for_IBF_clear(); + if (get_write_state() != 0) return LAN_ERR_SEND_FAIL; + clear_OBF(); + + if (requestData->dataLength == 0) + { + _OUTB(WR_END,COMMAND_REG); + wait_for_IBF_clear(); + if (get_write_state() != 0) + return LAN_ERR_SEND_FAIL; + clear_OBF(); + + _OUTB(requestData->cmdType,DATA_OUT_REG); + } + else + { + + _OUTB(requestData->cmdType,DATA_OUT_REG); + wait_for_IBF_clear(); + if (get_write_state() != 0) + return LAN_ERR_SEND_FAIL; + clear_OBF(); + + for(length = 0;length < requestData->dataLength-1;length++) + { + _OUTB(requestData->data[length],DATA_OUT_REG); + wait_for_IBF_clear(); + if (get_write_state() != 0) + return LAN_ERR_SEND_FAIL; + clear_OBF(); + } + + _OUTB(WR_END,COMMAND_REG); + wait_for_IBF_clear(); + if (get_write_state() != 0) + return LAN_ERR_SEND_FAIL; + clear_OBF(); + + _OUTB(requestData->data[length],DATA_OUT_REG); + } + +/********************************** WRITE PHASE OVER ***********************/ + +#ifdef TEST_ERROR + if (fdebugdir == 5) { /*introduce an error test case*/ + printf("Aborting after KCS write, before read\n"); + return(rv); + } +#endif +// length = 0; +// usleep(100000); +/********************************** READ PHASE START ***********************/ + rxbuf_len = *respDataLen; + *respDataLen = 0; + + while(*respDataLen <= IPMI_RSPBUF_SIZE) + { + wait_for_IBF_clear(); + if (get_read_state() != 0) + { + if (get_idle_state() != 0) { + DBGP2("not idle in rx_data (%02x)\n",_INB(STATUS_REG)); + // clear_lock_dir(); + return LAN_ERR_RECV_FAIL; + } else { + rv = wait_for_OBF_set(); + if (rv != 0) { return LAN_ERR_RECV_FAIL; } + dummy = _INB(DATA_IN_REG); + /* done, copy the data, if valid */ + if (*respDataLen < 3) { /* data not valid, no cc */ + (*respDataLen) = 0; + *compCode = 0xCA; /*cannot return #bytes*/ + // clear_lock_dir(); + return LAN_ERR_TIMEOUT; + } else { /*valid*/ + requestData->netFn = rx_data[0]; + requestData->cmdType = rx_data[1]; + *compCode = rx_data[2]; + (*respDataLen) -= 3; + for (length=0;length < *respDataLen;length++) + resp_data[length] = rx_data[length+3]; + } + DBGP2("ipmidir: peak_loops = %d\n",peak_loops); + return ACCESS_OK; + } + } else { + rv = wait_for_OBF_set(); + if (rv != 0) { return LAN_ERR_RECV_FAIL; } + rx_data[*respDataLen] = _INB(DATA_IN_REG); + DBGP2("rx_data[%d] is 0x%x\n",*respDataLen,rx_data[*respDataLen]); + _OUTB(READ_BYTE,DATA_IN_REG); + (*respDataLen)++; + } + if (*respDataLen > rxbuf_len) { + DBGP("ipmidir: rx buffer overrun, size = %d\n",rxbuf_len); + break; /*stop if user buffer max*/ + } + } /*end while*/ + return ACCESS_OK; +} /* end SendTimedImbpRequest_kcs */ + + +static int ProcessTimedMessage(BMC_MESSAGE *p_reqMsg, BMC_MESSAGE *p_respMsg, const UINT32 timeout) +{ + int status = STATUS_OK; + IMBPREQUESTDATA requestData = {0}; + int respDataLen = IPMI_RSPBUF_SIZE; + UINT8 compCode = 0; + // static UINT8 sendSeq = 1; + // UINT8 buff[DATA_BUF_SIZE] = {0}; + ACCESN_STATUS accessn; + int i, j; + + j = p_reqMsg->Len; + if (j > IPMI_REQBUF_SIZE) return(LAN_ERR_BADLENGTH); + // Initialize Response Message Data + for(i = 0; i < IPMI_RSPBUF_SIZE; i++) + { + p_respMsg->Data[i] = 0; + } + + /* show the request */ + DBGP("ipmidir Cmd=%02x NetFn=%02x Lun=%02x Sa=%02x Data(%d): ", + p_reqMsg->Cmd, p_reqMsg->NetFn, + p_reqMsg->LUN, p_reqMsg->DevAdd, j); + for (i=0; i<j; i++) DBGP("%02x ",p_reqMsg->Data[i]); + DBGP("\n"); + + j = _IOPL(3); + if (j != 0) { + DBGP("ipmi_direct: iopl errno = %d\n",errno); + return(errno); + } + // Initializes Request Message + + // Call into IPMI + if (p_reqMsg->DevAdd == 0x20) { + requestData.cmdType = p_reqMsg->Cmd; + requestData.rsSa = 0x20; + requestData.busType = 0; + requestData.netFn = p_reqMsg->NetFn; + requestData.rsLun = p_reqMsg->LUN; + requestData.data = p_reqMsg->Data; + requestData.dataLength = (int)p_reqMsg->Len; + + if (g_DriverType == DRV_KCS) /*KCS*/ + accessn = SendTimedImbpRequest_kcs(&requestData, timeout, + p_respMsg->Data, &respDataLen, &compCode); + else if (g_DriverType == DRV_SMB) /*SMBus*/ + accessn = SendTimedImbpRequest_ssif(&requestData, timeout, + p_respMsg->Data, &respDataLen, &compCode); + else { /* should never happen */ + printf("ipmi_direct: g_DriverType invalid [%d]\n",g_DriverType); + return(ERR_NO_DRV); + } + + status = accessn; + // Return Response Message + p_respMsg->DevAdd = p_reqMsg->DevAdd; + p_respMsg->NetFn = requestData.netFn; + p_respMsg->LUN = p_reqMsg->LUN; + p_respMsg->Cmd = requestData.cmdType; + p_respMsg->CompCode = compCode; + p_respMsg->Len = respDataLen; + } else { /*DevAdd != 0x20*/ + status = ProcessSendMessage(p_reqMsg, p_respMsg, p_reqMsg->Bus, + p_reqMsg->DevAdd,10000); + DBGP2("ProcessSendMessage(cmd=%02x,rs,sa=%02x,10000) = %d\n", + p_reqMsg->Cmd,p_reqMsg->DevAdd,status); + } + + /* validate the response data length */ + if (p_respMsg->Len > IPMI_RSPBUF_SIZE) p_respMsg->Len = IPMI_RSPBUF_SIZE; + /* show the response */ + j = p_respMsg->Len; + DBGP("ipmidir Resp(%x,%x): status=%d cc=%02x, Data(%d): ", + (p_respMsg->NetFn >> 2), p_respMsg->Cmd, + status,p_respMsg->CompCode, j); + if (status == 0) + for (i=0; i<j; i++) DBGP("%02x ",p_respMsg->Data[i]); + DBGP("\n"); + + return status; +} + +/* + * ImbInit_dir + * Uses SMBIOS to determine the driver type and base address. + * It also checks the status register if KCS. + */ +int ImbInit_dir(void) +{ + uchar v = 0xff; + + /* Read SMBIOS to get IPMI struct */ + DBGP2("ImbInit: BMC_base = 0x%04x\n",BMC_base); + if (BMC_base == 0) { /*use get_IpmiStruct routine from mem_if.c */ + uchar iftype, iver, sa, inc; + int mybase, status; + char *ifstr; + status = get_IpmiStruct(&iftype,&iver,&sa,&mybase,&inc); + if (status == 0) { + if (iftype == 0x04) { + g_DriverType = DRV_SMB; + ifstr = "SSIF"; + mBMC_baseAddr = mybase; + } else /*0x01==KCS*/ { + g_DriverType = DRV_KCS; + ifstr = "KCS"; + if (sa == BMC_SA && mybase != 0) { /*valid*/ + kcsBaseAddress = mybase; + kcs_inc = inc; + } + } + BMC_base = mybase; + DBGP("SMBIOS IPMI Record found: type=%s sa=%02x base=0x%04x spacing=%d\n", + ifstr, sa, mybase, inc); + } + } + + /* Use KCS here. There are no known SMBus implementations on 64-bit */ + if (BMC_base == 0) { + DBGP("No IPMI Data Structure Found in SMBIOS Table,\n"); + g_DriverType = DRV_KCS; + BMC_base = kcsBaseAddress; + DBGP("Continuing with KCS on Default Port 0x%04x\n",kcsBaseAddress); + } +#if defined(BSD) || defined(MACOS) + iofd = open("/dev/io",O_RDWR); + if (iofd < 0) { + printf("Cannot open /dev/io...Exiting\n"); + return ERR_NO_DRV; + } +#endif + if (g_DriverType == DRV_SMB) { + /* Perhaps add controller type in ipmi_if.txt (?)*/ + /* Intel SSIF: 0x0540=SJR, 0x0400=STP */ + if (mBMC_baseAddr == 0x540 || mBMC_baseAddr == 0x400) + SMBChar.Controller = INTEL_SMBC; + else /*else try ServerWorks*/ + SMBChar.Controller = SW_SMBC; + SMBChar.baseAddr = mBMC_baseAddr; + DBGP("BMC SSIF/SMBus Interface at i2c=%02x base=0x%04x\n", + mBMCADDR,mBMC_baseAddr); + } + if (g_DriverType == DRV_KCS) { + v = _IOPL(3); + v = _INB(STATUS_REG); + DBGP2("inb(%x) returned %02x\n",STATUS_REG,v); + if (v == 0xff) { + printf("No Response from BMC...Exiting\n"); + return ERR_NO_DRV; + } + DBGP("BMC KCS Initialized at 0x%04x\n",kcsBaseAddress); + } + return STATUS_OK; +} + +int +SendTimedImbpRequest_ssif ( IMBPREQUESTDATA *requestData, + unsigned int timeout, UINT8 *resp_data, int *respDataLen, + unsigned char *compCode) +{ /* SendTimedImb for SMBus */ + unsigned char rq[IPMI_REQBUF_SIZE+35] = {0,}; /*SIZE + MAX_ISA_LENGTH=35*/ + unsigned char rp[IPMI_RSPBUF_SIZE+35] = {0,}; /*SIZE + MAX_ISA_LENGTH=35*/ + unsigned int i, rpl=0; + int status; + int respMax, rlen; + + i = _IOPL(3); + rq[0] = ((requestData->netFn << 2) | (requestData->rsLun & 0x03)); + rq[1] = requestData->cmdType; + if (sizeof(rq) < (requestData->dataLength + 2)) return(LAN_ERR_BADLENGTH); + for (i=0;i<=(unsigned int)requestData->dataLength;i++) + rq[i+2] = requestData->data[i]; + + respMax = *respDataLen; + if (respMax == 0) respMax = IPMI_RSPBUF_SIZE; + status = SendmBmcRequest(rq,requestData->dataLength+2,rp,&rpl,0); + if (status == IMB_SEND_ERROR) { + *respDataLen = 0; + return LAN_ERR_SEND_FAIL; + } + + if (rpl < 3) { + *respDataLen = 0; + *compCode = 0xCA; /*cannot return #bytes*/ + return LAN_ERR_TIMEOUT; + } else { + rlen = rpl-3; /* Chop off netfn/LUN , compcode, command */ + if (rlen > respMax) rlen = respMax; + *respDataLen = rlen; + *compCode = rp[2]; + for (i = 0; i < rlen; i++) resp_data[i] = rp[i+3]; + } + return ACCESS_OK; +} + +int SendmBmcRequest ( + unsigned char* request, + UINT32 reqLength, + unsigned char* response, + UINT32 * respLength, + UINT32 ipmiOldFlag + ) +{ + int retries = 5; + + /* Send Request - Retry 5 times at most */ + do{ + if (SendRequest(request, reqLength, &SMBChar) == 0) + break; + } while (0 < retries--); + + if (retries <= 0) { return IMB_SEND_ERROR; } + + /* Read Response - Retry 5 times at most */ + retries = 5; + do{ + if ((*respLength = ReadResponse(response, &SMBChar))!=(-1)) { + break; // Success + } + }while (0 < retries--); + + if (retries <= 0) { return IMB_SEND_ERROR; } + + return IMB_SUCCESS; +} + +static int +SendRequest(unsigned char* req, int length, + struct SMBCharStruct* smbChar) +{ + UINT8 data = 0; + // unsigned char* msgBuf = req; + int i; + UINT8 status = 0; + + // Delay of 50 ms before request is sent + usleep(100000); + + // Handle Intel & ServerWorks Chipsets + // Clear all status bits, Host Status Register + switch (smbChar->Controller) { + // Intel Status Register + case INTEL_SMBC: + status = ICH_HST_STA_ALL_ERRS|ICH_HST_STA_INTR|ICH_HST_STA_BYTE_DONE_STS; + break; + // ServerWorks Status Register + case SW_SMBC: + status = ICH_HST_STA_ALL_ERRS|ICH_HST_STA_INTR; + break; + }// End of Switch + + // Status Register + WritePortUchar( (((smbChar->baseAddr))+ICH_HST_STA), status); + + // Block protocol, Host Control Register + WritePortUchar(((smbChar->baseAddr)+ICH_HST_CNT), (UINT8)(ICH_HST_CNT_SMB_CMD_BLOCK)); + // IPMI command, Host Command Register + WritePortUchar(((smbChar->baseAddr)+ICH_HST_CMD), (UINT8)(0x02)); + // Slave address, Host Address Register + WritePortUchar(((smbChar->baseAddr)+ICH_XMIT_SLVA), (UINT8)(mBMCADDR)); + // Block length, Host DATA0 Register + WritePortUchar(((smbChar->baseAddr)+ICH_D0), (UINT8)(length)); + // Initialize timer + + switch (smbChar->Controller) { + // Handle Intel Chipset + case INTEL_SMBC: + // the first byte + WritePortUchar(((smbChar->baseAddr)+ICH_BLOCK_DB), *(UINT8 *)((UINT8 *)req )); + // Block protocol and Start, Host Control Register + WritePortUchar(((smbChar->baseAddr)+ICH_HST_CNT), ICH_HST_CNT_START | ICH_HST_CNT_SMB_CMD_BLOCK); + // Send byte by byte + for ( i = 1; i < length; i++ ) { + // OsSetTimer(&SendReqTimer); * Start timer * + do { + // Read host status register + ReadPortUchar((smbChar->baseAddr+ICH_HST_STA), &data); + // if (OsTimerTimedout(&SendReqTimer)) return -1; + // Any error or Interrupt bit or byte done bit set ? + } while ((data & status) == 0); + // OsCancelTimer(&SendReqTimer); * End Timer * + // Check for byte completion in block transfer + if ((data & ICH_HST_STA_BYTE_DONE_STS) != ICH_HST_STA_BYTE_DONE_STS) + break; + // Write next byte + WritePortUchar(((smbChar->baseAddr)+ICH_BLOCK_DB), *(UINT8 *)((UINT8 *)req + i)); + // Clear status bits, Host Status Register + WritePortUchar((smbChar->baseAddr), (UINT8)(data & status)); + } // End of for - Send byte by byte + break; // End of Intel Chipset Handling + // Handle ServerWorks Chipset + case SW_SMBC: + // Block length, Host DATA1 Register + WritePortUchar(((smbChar->baseAddr)+ICH_D1), (UINT8)(length)); + // Reset block inex + ReadPortUchar(((smbChar->baseAddr)+ICH_HST_CNT), &data); + // Put all bytes of the message to Block Data Register + for ( i = 0; i < length; i++ ) + WritePortUchar(((smbChar->baseAddr)+ICH_BLOCK_DB), *(UINT8 *)((UINT8 *)req + i)); + // Block protocol and Start, Host Control Register + WritePortUchar(((smbChar->baseAddr)+ICH_HST_CNT), ICH_HST_CNT_START | ICH_HST_CNT_SMB_CMD_BLOCK); + // OsSetTimer(&SendReqTimer); * Start timer * + do { + // Read host status register + ReadPortUchar((smbChar->baseAddr+ICH_HST_STA), &data); + // if (OsTimerTimedout(&SendReqTimer)) return -1; + } while ((data & status) == 0); // Any error or Interrupt bit set ? + // OsCancelTimer(&SendReqTimer); * End Timer * + break; // End of ServerWorks Chipset Handling + } // End of Switch Controller + + // Clear status bits, Host Status Register + WritePortUchar((smbChar->baseAddr), (UINT8)(data & status)); + if (data & ICH_HST_STA_ALL_ERRS) return -1; + + // Success + return 0; +} + +static int +ReadResponse( unsigned char* resp, + struct SMBCharStruct * smbChar) +{ + UINT8 data, dummy, length, status = 0; + UINT8 * msgBuf = (UINT8 *) resp; + int i; //, timeout =0; + // os_timer_t SendReqTimer; + + // Delay current thread - time to delay in uSecs + // 100 msec = 100000 microsec + usleep(100000); + + // Handle Intel & ServerWorks Chipsets + switch (smbChar->Controller) { + case INTEL_SMBC: + status = ICH_HST_STA_ALL_ERRS|ICH_HST_STA_INTR|ICH_HST_STA_BYTE_DONE_STS; + break; + case SW_SMBC: + status = ICH_HST_STA_ALL_ERRS|ICH_HST_STA_INTR; + break; + } // End of Switch + + WritePortUchar(((smbChar->baseAddr)+ICH_HST_STA), status); + // Block protocol, Host Control Register + WritePortUchar(((smbChar->baseAddr)+ICH_HST_CNT), ICH_HST_CNT_SMB_CMD_BLOCK); + // Slave address, Host Address Register + WritePortUchar(((smbChar->baseAddr)+ICH_XMIT_SLVA), (UINT8)(mBMCADDR |ICH_XMIT_SLVA_READ)); + // IPMI command, Host Command Register + WritePortUchar(((smbChar->baseAddr)+ICH_HST_CMD), 0x03); + // Reset block index + ReadPortUchar(((smbChar->baseAddr)+ICH_HST_CNT), &data); + // Block protocol and Start, Host Control Register + WritePortUchar(((smbChar->baseAddr)+ICH_HST_CNT), ICH_HST_CNT_START | ICH_HST_CNT_SMB_CMD_BLOCK); + + // Initialize timer + do { + // Read host status register + ReadPortUchar((smbChar->baseAddr+ICH_HST_STA), &data); + } while ((data & status) == 0); // Any error or Interrupt bit set ? + // End Timer + + // Clear status bits, Host Status Register + WritePortUchar((smbChar->baseAddr), (UINT8)(data & status)); + + if (data & ICH_HST_STA_ALL_ERRS) return -1; + + // Block length, Host DATA0 Register + ReadPortUchar(((smbChar->baseAddr)+ICH_D0), &length); + /* check recv length > MAX (35) */ + if (length > MAX_ISA_LENGTH) length = MAX_ISA_LENGTH; + switch (smbChar->Controller) { + case INTEL_SMBC: + // Read the first byte + ReadPortUchar((smbChar->baseAddr+ICH_BLOCK_DB), &(msgBuf[0])); + // Put all bytes of the message to Block Data Register + for ( i = 1; i < length; i++ ) { + if (i == (length-1)) { + // Set Last Byte bit + ReadPortUchar(((smbChar->baseAddr)+ICH_HST_CNT),&dummy); + WritePortUchar(((smbChar->baseAddr)+ICH_HST_CNT), (UINT8)(dummy | ICH_HST_CNT_LAST_BYTE)); + } + // Clear status bits, Host Status Register + WritePortUchar((smbChar->baseAddr), (UINT8)(data & status)); + + do { + // Read host status register + ReadPortUchar((smbChar->baseAddr+ICH_HST_STA), &data); + } while ((data & status) == 0); // Any error or Interrupt bit set ? + + if (data & ICH_HST_STA_ALL_ERRS) return -1; + ReadPortUchar((smbChar->baseAddr+ICH_BLOCK_DB), &(msgBuf[i])); + } + break; + case SW_SMBC: + // Put all bytes of the message to Block Data Register + for ( i = 0; i < length; i++ ) { + ReadPortUchar((smbChar->baseAddr+ICH_BLOCK_DB), &(msgBuf[i])); + } + break; + } /* end of switch */ + + if (data & ICH_HST_STA_ALL_ERRS) return -1; + + return length; +} +#endif + +/* end ipmidir.c */ diff --git a/util/ipmidir.h b/util/ipmidir.h new file mode 100644 index 0000000..079c6b6 --- /dev/null +++ b/util/ipmidir.h @@ -0,0 +1,301 @@ +/*********************************************** + * ipmidir.h + * + * Definitions and data structures for direct + * user-space IPMI I/Os. + * + ***********************************************/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2006, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ +#ifndef IPMIDIR_H_ +#define IPMIDIR_H_ + + +#define SMB_DATA_ADDRESS = 0x000 + +// +// State bits based on S1 & S0 below +// +#define ISA_STATE_MASK 0xC0 +#define ISA_IDLE_STATE 0x00 +#define ISA_READ_STATE 0x40 +#define ISA_WRITE_STATE 0x80 +#define ISA_ERROR_STATE 0xC0 +// +// Status Register Bits +// +#define ISA_S1_FLAG 0x80 +#define ISA_S0_FLAG 0x40 +// RESERVED 0x20 +// RESERVED 0x10 +#define ISA_CD_FLAG 0x08 +#define ISA_SMS_MSG_FLAG 0x04 +#define ISA_IBF_FLAG 0x02 +#define ISA_OBF_FLAG 0x01 +// +// ISA interface register access defines +// + +#define BMC_SLAVE_ADDR 0x20 +#define MAX_ISA_LENGTH 35 + +#define ISA_SMS_TIMEOUT 5000 // in miliseconds - 1 second +#define ISA_SMM_TIMEOUT 100 // in microseconds +// +// mBMC Address +// +#define IMB_SEND_ERROR 1 +#define IMB_SUCCESS 0 + +// typedef unsigned int DWORD; +// typedef unsigned char BYTE; +// typedef unsigned char UCHAR; * defined in imb_api.h * +// typedef unsigned long ULONG; * defined in imb_api.h * +// typedef unsigned int UINT32; +typedef unsigned short UINT16; +typedef unsigned char UINT8; + +struct SMBCharStruct +{ +unsigned int Controller; +unsigned int baseAddr; +}; + +/*---------------------------------------------------------* + * PCI defines for SMBus + *---------------------------------------------------------*/ + +// PCI related definitions +#define PCI_CONFIG_ADDRESS 0xCF8 +#define PCI_CONFIG_DATA 0xCFC + +// PCI unique identifiers +#define ID_8111 0x746A1022 +#define ID_81801 0x24128086 +#define ID_81801AA 0x24138086 +#define ID_81801AB 0x24238086 +#define ID_82801BA 0x24438086 +#define ID_82801CA 0x24838086 +#define ID_ICH4 0x24C38086 +#define ID_ICH5 0x24D38086 +#define ID_ICH6 0x266A8086 //srini added ICH6 support +#define ID_CSB5 0x02011166 +#define ID_CSB6 0x02031166 +#define ID_OSB4 0x02001166 +#define Hance_Rapids 0x25A48086 //lester 0627 + +// PCI configuration registers +#define ICH_SMB_BASE 0x20 // base address register +#define ICH_HOSTC 0x40 // host config register +#define ICH_HOSTC_I2C_EN 0x04 // enable i2c mode +#define ICH_HOSTC_SMB_SMI_EN 0x02 // SMI# instead of irq +#define ICH_HOSTC_HST_EN 0x01 // enable host cntrlr +#define AMD_SMB_BASE_2 0x10 // base address register of SMBus 2.0 +#define AMD_SMB_BASE_2_EN 0x04 // SMBus 2.0 space enable +#define AMD_SMB_BASE_1 0x58 // base address register of SMBus 1.0 +#define AMD_SMB_BASE_1_EN 0x41 // SMBus 1.0 space enable +#define AMD_SMBUS_1 0xE0 // SMBus 1.0 registers + +// I/O registers +#define ICH_HST_STA 0x00 // host status +#define ICH_HST_STA_BYTE_DONE_STS 0x80 // byte send/rec'd +#define ICH_HST_STA_INUSE_STS 0x40 // device access mutex +#define ICH_HST_STA_SMBALERT_STS 0x20 // SMBALERT# signal +#define ICH_HST_STA_FAILED 0x10 // failed bus transaction +#define ICH_HST_STA_BUS_ERR 0x08 // transaction collision +#define ICH_HST_STA_DEV_ERR 0x04 // misc. smb device error +#define ICH_HST_STA_ALL_ERRS (ICH_HST_STA_FAILED|ICH_HST_STA_BUS_ERR|ICH_HST_STA_DEV_ERR) +#define ICH_HST_STA_INTR 0x02 // command completed ok +#define ICH_HST_STA_HOST_BUSY 0x01 // command is running +#define ICH_HST_CNT 0x02 // host control +#define ICH_HST_CNT_START 0x40 // start command +#define ICH_HST_CNT_LAST_BYTE 0x20 // indicate last byte +#define ICH_HST_CNT_SMB_CMD_QUICK 0x00 // command: quick +#define ICH_HST_CNT_SMB_CMD_BYTE 0x04 // command: byte +#define ICH_HST_CNT_SMB_CMD_BYTE_DATA 0x08 // command: byte data +#define ICH_HST_CNT_SMB_CMD_WORD_DATA 0x0c // command: word data +#define ICH_HST_CNT_SMB_CMD_PROC_CALL 0x10 // command: process call +#define ICH_HST_CNT_SMB_CMD_BLOCK 0x14 // command: block +#define ICH_HST_CNT_SMB_CMD_I2C_READ 0x18 // command: i2c read +#define ICH_HST_CNT_KILL 0x02 // kill current transaction +#define ICH_HST_CNT_INTREN 0x01 // enable interrupt +#define ICH_HST_CMD 0x03 // host command +#define ICH_XMIT_SLVA 0x04 // transmit slave address +#define ICH_XMIT_SLVA_READ 0x01 // direction: read +#define ICH_XMIT_SLVA_WRITE 0x00 // direction: write +#define ICH_D0 0x05 // host data 0 +#define ICH_D1 0x06 // host data 1 +#define ICH_BLOCK_DB 0x07 // block data byte + +// SMBus 1.0 +#define AMD_SMB_1_STATUS 0x00 // SMBus global status +#define AMD_SMB_1_STATUS_SMBS_BSY (1<11) +#define AMD_SMB_1_STATUS_SMBA_STS (1<10) +#define AMD_SMB_1_STATUS_HSLV_STS (1<9) +#define AMD_SMB_1_STATUS_SNP_STS (1<8) +#define AMD_SMB_1_STATUS_TO_STS (1<5) +#define AMD_SMB_1_STATUS_HCYC_STS (1<4) +#define AMD_SMB_1_STATUS_HST_BSY (1<3) +#define AMD_SMB_1_STATUS_PERR_STS (1<2) +#define AMD_SMB_1_STATUS_COL_STS (1<1) +#define AMD_SMB_1_STATUS_ABRT_STS (1<0) +#define AMD_SMB_1_STATUS_ALL_ERRS AMD_SMB_1_STATUS_TO_STS|AMD_SMB_1_STATUS_HST_BSY|AMD_SMB_1_STATUS_PERR_STS|AMD_SMB_1_STATUS_COL_STS +#define AMD_SMB_1_CTL 0x02 // SMBus global control +#define AMD_SMB_1_CTL_SMBA_EN (1<<10) +#define AMD_SMB_1_CTL_HSLV_EN (1<<9) +#define AMD_SMB_1_CTL_SNP_EN (1<<8) +#define AMD_SMB_1_CTL_ABORT (1<<5) +#define AMD_SMB_HCYC_EN (1<<4) +#define AMD_SMB_HOSTSTS (1<<3) +#define AMD_SMB_CYCTYPE_QC 0x0 // quick command +#define AMD_SMB_CYCTYPE_RSB 0x1 // receive/send byte +#define AMD_SMB_CYCTYPE_RWB 0x2 // read/write byte +#define AMD_SMB_CYCTYPE_RWW 0x3 // read/write word +#define AMD_SMB_CYCTYPE_PC 0x4 // process call +#define AMD_SMB_CYCTYPE_RWBL 0x5 // read/write block +#define AMD_SMB_1_ADDR 0x04 // SMBus host address +#define AMD_SMB_1_ADDR_READCYC (1<<0) +#define AMD_SMB_1_DATA 0x06 // SMBus host data +#define AMD_SMB_1_CMD 0x08 // SMBus host command +#define AMD_SMB_1_BLOCK_DATA 0x09 // SMBus block data FIFO access port + +// For SMBus 2.0, see ACPI 2.0 chapter 13 PCI interface definitions + +#define AMD_SMB_BLOCK_WRITE 0xa +#define AMD_SMB_BLOCK_READ 0xb + +// AMD PCI control registers definitions. +#define AMD_PCI_MISC 0x48 +#define AMD_PCI_MISC_SCI 0x04 +#define AMD_PCI_MISC_INT 0x02 +#define AMD_PCI_MISC_SPEEDUP 0x01 + + +// SMBus Controllers +#define INTEL_SMBC 1 // Intel +#define SW_SMBC 2 // ServerWorks +#define VIA_SMBC 3 // VIA +#define AMD_SMBC 4 // AMD + +/************************************************ + * bmc.h + ************************************************/ + +#define STATUS_OK 0 +#define BMC_MAX_RETRIES 3 // Max number of retries if BMC is busy +#define DATA_BUF_SIZE 255 // Max data buffer, see IPMI_REQBUF_SIZE +#define GETMSGTIMEOUT 5 // Time out in sec for send/get message command + +// Product IDs of systems with PC87431 chips (have both Sahalee and mBMC) +#define ID_PC87431_M 0x4311 +#define ID_PC87431_S 0x4312 +#define ID_PC87431_C 0x4315 + +// Available BMC chips that are supported by this library. +#define BMC_UNKNOWN 0 +#define BMC_SAHALEE 1 // Intel Sahalee BMC +#define BMC_MBMC_87431M 2 // mBMC, chip = PC87431M +#define BMC_MBMC_87431S 3 // mBMC, chip = PC87431S +#define BMC_MBMC_87431C 4 // mBMC, chip = PC87431C +#define BMC_BOTH_SAHALEE_MBMC 5 +#define BMC_DUAL_NW 6 // currently not detected +// #define BMC_AMT10 7 + +// Available IPMI versions. There may be full and partial IPMI implementations. +// To figure out what implementation is supported, look at the BMC_TYPE. +#define IPMI_VERSION_UNKNOWN 0 +#define IPMI_VERSION_1_5 1 +#define IPMI_VERSION_2_0 2 +#define IPMI_VERSION_1_0 3 + +//***************************************************************************** +// Message struct for sending and receiving messages from the BMC. Requests +// must have a DevAdd, NetFn, LUN, Cmd, Data, and Len. The response will have +// all fields filled in. In both cases 'Len' is the length of the data buffer. +typedef struct { + UINT8 Bus; + UINT8 DevAdd; + UINT8 NetFn; + UINT8 LUN; + UINT8 Cmd; + UINT8 Data[DATA_BUF_SIZE]; + UINT32 Len; + UINT8 CompCode; +} BMC_MESSAGE; + +/* Internal error codes from BMC or IPMI driver: + * ERR_NO_DRV is defined in ipmicmd.h, and the other + * values below are not used. + */ +#define ER_NO_BMC_IF -400 // could not find the BMC interface +#define ERCANTLOCATEIPMIHANDLE -500 // Unable to locate IPMI handle +#define ERCANTALLOCMEMORYFORIPMI -501 // Unable to allocate memory for IPMI services +#define ERCANTLOADIPMIDRIVER -502 // Unable to dynamically load IPMI driver +#define ERSENDINGIPMIMESSAGE -503 // Error sending request to BMC +#define ERGETTINGIPMIMESSAGE -504 // Error getting request from BMC +#define ERCMDRETURNEDDONTMATCH -505 // Returned command # doesn't match what was sent +#define ERLUNRETURNEDDONTMATCH -506 // Returned LUN # doesn't match what was sent +#define ERCOMPCODEERR -507 // Comp code is not COMPCODE_NORMAL +#define ERSEQNUMBER -508 // Sequence number error. +#define ERCANTCLEARMSGFLAGS -509 // Can not clear message flags +#define ERINVALIDRESPONSELEN -510 // Response length not as expected. +#define ER_NO_PCI_BIOS -511 // No PCI BIOS record exist +#define ER_SMBUSBUSERROR -512 +#define ER_SMBUSTIMEOUT -513 +#define ER_SMBUSOWNERSHIP -514 +#define ER_SMBUSDEVERROR -515 +#define ER_NOTKCS -516 // Not KCS, probably SMBus + +// Device Addresses +#define BMC_ADDR 0x20 // Baseboard Management Controller +#define HSC0_ADDR 0xC0 // Hot Swap Controller 0 +#define HSC1_ADDR 0xC2 // Hot Swap Controller 1 +#define PSC_ADDR 0xC8 // Power Supply Controller +#define CBC_ADDR 0x28 // Chassis Bridge Controller +#define LCP_ADDR 0x22 // LCP(Local Control Panel) Address +#define MBMC_ADDR 0x84 // MINI BMC address + +#define SMBUS_SLAVE_ADDRESS 0x00 +#define ID_VITESSE 0x01 // for HSC +#define ID_GEM 0x02 // for HSC +#define ISA_BUS 0xFF // ISA Bus address + +#define BMC_DEV_ADDR 0x20 // BMC Device Addr for Get Device ID +// #define BMC_LUN 0x00 // BMC commands & event request messages +#define OEM_LUN1 0x01 // OEM LUN 1 +#define SMS_MSG_LUN 0x02 // SMS message LUN +#define OEM_LUN2 0x03 // OEM LUN 2 + +#define NETFN_APP 0x06 +#define GETMESSAGE_CMD 0x33 // IPMI Get Message command +#define SENDMESSAGE_CMD 0x34 // IPMI Send Message command + +#endif // IPMIDIR_H_ diff --git a/util/ipmilan.c b/util/ipmilan.c new file mode 100644 index 0000000..64b6425 --- /dev/null +++ b/util/ipmilan.c @@ -0,0 +1,2430 @@ +/*M* +// PVCS: +// $Workfile: ipmilan.c $ +// $Revision: 1.0 $ +// $Modtime: 2 Feb 2006 15:31:14 $ +// $Author: arcress at users.sourceforge.net $ +// +// This implements support for the IPMI LAN interface natively. +// +// 02/02/06 ARC - created. +// 05/16/06 ARC - more added. +// 06/19/06 ARCress - fixed sequence numbers for 1.7.1 +// 08/08/06 ARCress - fix AUTHTYPE masks +// 08/11/06 ARCress - added lan command retries +// 10/17/06 ARCress - special case for no MsgAuth headers +// 11/28/06 ARCress - added ipmi_cmd_ipmb routine +// 05/08/07 ARCress - added 1.5 SOL data packet format to _send_lan_cmd, +// not working yet. +// 08/21/07 ARCress - handle Dell 1855 blades that return different authcode +// 04/17/08 ARCress - check FD_ISSET in fd_wait + *M*/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2005-2006, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <io.h> +#include <time.h> +#include <signal.h> + +//#define HAVE_IPV6 1 +#ifdef HAVE_IPV6 +#include <winsock2.h> +//#include <ws2tcpip.h> +//#include <tpipv6.h> +#else +#include <winsock.h> +#define MSG_WAITALL 0x100 /* Wait for a full request */ +#endif + +#define INET_ADDRSTRLEN 16 +#define MSG_NONE 0x000 +#define int32_t int +#define u_int32_t unsigned int +#define uint32 unsigned int +#define uchar unsigned char +#define RECV_MSG_FLAGS MSG_NONE +typedef unsigned int socklen_t; + +#elif defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#undef HAVE_LANPLUS + +#else /* Linux */ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netdb.h> +#include <sys/time.h> +#include <time.h> +#include <signal.h> +#define RECV_MSG_FLAGS MSG_WAITALL +#endif +#include "ipmicmd.h" +#include "ipmilan.h" + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#else +#if defined(MACOS) +typedef unsigned int socklen_t; +#endif +#endif + +#if defined(LINUX) +/* TODO: fixups in BSD/Solaris for ipv6 method */ +#define HAVE_IPV6 1 +#endif + +#if defined(CROSS_COMPILE) +#undef HAVE_IPV6 +static struct hostent *xgethostbyname(const char *nstr) +{ + static struct hostent hptr; + if (StrIsIp(nstr)) { /* the string is an IP address */ + hptr.h_name = (char *)nstr; + inet_aton(nstr,(struct in_addr *)&hptr.h_addr); + return(&hptr); + } else { /*the string is a node name */ + return(NULL); + } +} +#else +#define xgethostbyname gethostbyname +#endif + +// #define TEST_LAN 1 /*++++TEST_LAN for DEBUG++++*/ +#if defined(ALLOW_GNU) +#define MD2OK 1 /*use md2.h GPL code*/ +#else +/* if here, ALLOW_GPL is not defined, check for lanplus libcrypto. */ +#if defined(HAVE_LANPLUS) +#define MD2OK 1 /*use MD2 version from lanplus libcrypto */ +#endif +/* if libcrypto does not have EVP_md2, then skip MD2. */ +#if defined(SKIP_MD2) +#undef MD2OK +#endif +#endif + +/* Connection States: + * 0 = init, 1 = socket() complete, 2 = bind/gethost complete, + * 3 = ping sent, 4 = pong received, 5 = session activated. + * see also conn_state_str[] below */ +#define CONN_STATE_INIT 0 +#define CONN_STATE_SOCK 1 +#define CONN_STATE_BIND 2 +#define CONN_STATE_PING 3 +#define CONN_STATE_PONG 4 +#define CONN_STATE_ACTIVE 5 + +#define SOL_DATA 0xFD /*SOL Data command*/ +#define SOL_MSG 0x10000000 /*SOL message type*/ +#define SOL_HLEN 14 +// SZGNODE == 80 +#define SZ_CMD_HDR 4 /*cmd, netfn/lun, sa*/ +#define SWID_REMOTE 0x81 +#define SWID_SMSOS 0x41 + +#pragma pack(1) +typedef struct { /*first 30 bytes conform to IPMI header format*/ + uchar rmcp_ver; + uchar rmcp_res; + uchar rmcp_seq; + uchar rmcp_type; + uchar auth_type; + uint32 seq_num; /*outgoing seq*/ + uint32 sess_id; + uchar auth_code[16]; + uchar msg_len; /* size here = 30 bytes = RQ_HDR_LEN */ + uchar swid; /* usu SWID_REMOTE. From here down, order is changeable */ + uchar swseq; /* outgoing swseq */ + uchar swlun; + uchar priv_level; + uint32 iseq_num; /*incoming seq */ + uchar bmc_addr; /*usu BMC_SA*/ + uchar target_addr; + uchar target_chan; + uchar target_lun; + uchar target_cmd; + uchar target_netfn; + uchar transit_addr; + uchar transit_chan; + uchar bridge_level; + uchar password[16]; + uchar challenge[16]; + } IPMI_HDR; +#pragma pack() + +typedef struct { + int type; + int len; + char *data; + } SOL_RSP_PKT; + +/* extern void atoip(uchar *array,char *instr); *subs.c*/ +extern FILE *open_log(char *mname); /*ipmicmd.c*/ +extern char * get_iana_str(int mfg); /*subs.c*/ + +#define dbglog printf +#define dbg_dump dump_buf +extern FILE *fperr; /*defined in ipmicmd.c, usu stderr */ +extern FILE *fpdbg; /*defined in ipmicmd.c, usu stdout */ +extern int gshutdown; /* from ipmicmd.c */ +extern char gnodename[]; /* from ipmicmd.c */ +extern char *gnode; /* from ipmicmd.c */ +extern char *guser; /* from ipmicmd.c */ +extern char *gpswd; /* from ipmicmd.c */ +extern int fauth_type_set; /* from ipmicmd.c */ +extern int gauth_type; /* from ipmicmd.c */ +extern int gpriv_level; /* from ipmicmd.c */ +extern ipmi_cmd_t ipmi_cmds[NCMDS]; + +static IPMI_HDR ipmi_hdr = { 0x06, 0, 0xFF, 0x07, 0x00, 0, 0, + /*auth_code*/{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0, /*msg_len*/ + /*swid*/SWID_REMOTE, 1,0,0,0, BMC_SA,0,0,0,0,0,0,0,0 /*bridge_level*/ + }; +// static IPMI_HDR *phdr; +static uchar bmc_sa = BMC_SA; /*usu 0x20*/ +static uchar sms_swid = SWID_REMOTE; /*usu 0x81*/ +static int vend_id = 0; +static int prod_id = 0; + +#if defined(DOS) || defined(EFI) +int ipmi_open_lan(char *node, char *user, char *pswd, int fdebugcmd) +{ + printf("IPMI LAN is not supported under DOS.\n"); + return(-1); +} +int ipmi_close_lan(char *node) +{ + printf("IPMI LAN is not supported under DOS.\n"); + return(-1); +} +int ipmi_cmd_lan(char *node, ushort cmd, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd) +{ + printf("IPMI LAN is not supported under DOS.\n"); + return(-1); +} +int ipmi_cmdraw_lan(char *node, uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd) +{ + printf("IPMI LAN is not supported under DOS.\n"); + return(-1); +} +int ipmicmd_lan(char *node, uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd) +{ + printf("IPMI LAN is not supported under DOS.\n"); + return(-1); +} +#else +/* All other OSs can support IPMI LAN */ + +/* + * These variables pertain to ipmilan, for the node given at open time. + * The assumption here is that these are utilities, so no more than one + * node will be open at a given time. + * See also gnode, guser, gpswd in ipmicmd.c + */ +typedef struct { + int connect_state; /*=CONN_STATE_INIT*/ + SockType sockfd; + int finsession; + uint32 session_id; + uint32 in_seq; /*=1*/ + uint32 start_out_seq; /*=1*/ + uchar fMsgAuth; /*0=AuthNone 1=PerMsgAuth 2=UserLevelAuth*/ + uchar auth_type; /*=AUTHTYPE_INIT*/ + } LAN_CONN; /*see also IPMI_HDR below*/ + // static int connect_state = CONN_STATE_INIT; + // static int sockfd = 0; + // static int finsession = 0; + // static uint32 session_id = 0; + // static uint32 in_seq = 0x01; /* inbound sequence num */ + // static uint32 start_out_seq = 0x01; /* initial outbound sequence num */ + // static uchar fMsgAuth = 1; + static uchar auth_type = AUTHTYPE_INIT; /*initial value, not set*/ + static char nodename[SZGNODE+1] = ""; +#if defined(AI_NUMERICSERV) +static int my_ai_flags = AI_NUMERICSERV; /*0x0400 Dont use name resolution NEW*/ +// static int my_ai_flags = AI_NUMERICHOST; /*0x0004 Dont use name resolution*/ +#else +#undef HAVE_IPV6 +#endif + +#ifdef HAVE_IPV6 +#define SOCKADDR_T struct sockaddr_storage +#else +#define SOCKADDR_T struct sockaddr_in +static char _dest_ip[INET_ADDRSTRLEN+1]; +// static char _dest[MAXHOSTNAMELEN+1]; +#endif +static SOCKADDR_T _srcaddr; +static SOCKADDR_T _destaddr; +static int _destaddr_len = 0; +#ifdef TEST_LAN +static int fdebuglan = 3; +#else +static int fdebuglan = 0; +#endif +static int fdoping = 0; /* =1 do ping first, set to 0 b/c no added value*/ +static int fdopoke1 = 0; +static int fdopoke2 = 0; +static int frequireping = 0; /*=1 if ping is required, =0 ignore ping error */ +static LAN_CONN conn = {CONN_STATE_INIT,0,0,0,1,1,1}; +static LAN_CONN *pconn = &conn; +static char *authcode = NULL; +static int authcode_len = 0; +static int ping_timeout = 1; /* timeout: 1 sec */ +static int ipmi_timeout = 2; /* timeout: 10 sec -> 2 sec */ +static int ipmi_try = 4; /* retries: 4 */ +static uchar bridgePossible = 0; +static char *conn_state_str[6] = { + "init state", "socket complete", "bind complete", + "ping sent", "pong received", "session activated" }; +int lasterr = 0; + +static uchar sol_op = 0x80; /* encrypted/not */ +static uchar sol_snd_seq = 0; /* valid if non-zero*/ +static uchar sol_rcv_seq = 0; +static uchar sol_rcv_cnt = 0; +static uchar sol_rcv_ctl = 0x00; +// static uchar sol_offset = 0; +static uchar sol_seed_cnt = 0x01; /* set after activate response */ +static char sol_Encryption = 0; /*for SOL 1.5*/ +static uint32 g_Seed[ 16 ]; /*for SOL 1.5*/ +static uchar g_Cipher[ 16 ][ 16 ]; /*SeedCount x CipherHash for SOL 1.5*/ +#define BUSY_MAX 10 /*for Dell FS12-TY Node Busy errors*/ + +#ifdef WIN32 +int econnrefused = WSAECONNREFUSED; /*=10061.*/ +#else +int econnrefused = ECONNREFUSED; /*=111. from Linux asm/errno.h */ +#endif + +#ifdef WIN32 +WSADATA lan_ws; + +/* See http://msdn2.microsoft.com/en-us/library/ms740668.aspx + * or doc/winsockerr.txt */ +#define NWINERRS 21 +static struct { int err; char *desc; } winerrs[NWINERRS] = { + WSAEINTR /*10004*/, "Interrupted function call", + WSAEBADF /*10009*/, "File handle is not valid", + WSAEACCES /*10013*/, "Permission denied", + WSAEFAULT /*10014*/, "Bad address", + WSAEINVAL /*10022*/, "Invalid argument", + WSAEMFILE /*10024*/, "Too many open files", + WSAENOTSOCK /*10038*/, "Socket operation on nonsocket", + WSAEDESTADDRREQ /*10039*/, "Destination address required", + WSAEMSGSIZE /*10040*/, "Message too long", + WSAEOPNOTSUPP /*10045*/, "Operation not supported", + WSAEADDRINUSE /*10048*/, "Address already in use", + WSAEADDRNOTAVAIL /*10049*/, "Cannot assign requested address", + WSAENETDOWN /*10050*/, "Network is down", + WSAENETUNREACH /*10051*/, "Network is unreachable", + WSAENETRESET /*10052*/, "Network dropped connection on reset", + WSAECONNABORTED /*10053*/, "Software caused connection abort", + WSAECONNRESET /*10054*/, "Connection reset by peer", + WSAENOTCONN /*10057*/, "Socket is not connected", + WSAECONNREFUSED /*10061*/, "Connection refused", + WSAEHOSTDOWN /*10064*/, "Host is down", + WSAEHOSTUNREACH /*10065*/, "No route to host" +}; + +char * strlasterr(int rv) +{ + char *desc; + int i; + for (i = 0; i < NWINERRS; i++) { + if (winerrs[i].err == rv) { + desc = winerrs[i].desc; + break; + } + } + if (i >= NWINERRS) desc = ""; + + return(desc); +} +#endif + +#ifdef MD2OK +extern void md2_sum(uchar *string, int len, uchar *mda); /*from md2.c*/ +#endif +extern void md5_sum(uchar *string, int len, uchar *mda); /*from md5.c*/ + +int _ipmilan_cmd(SockType s, struct sockaddr *to, int tolen, + uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *sdata, int slen, uchar *rdata, int *rlen, + int fdebugcmd); +static int _send_lan_cmd(SockType s, uchar *pcmd, int scmd, uchar *presp, + int *sresp, struct sockaddr *to, int tolen); +static int ipmilan_open_session(SockType sfd, struct sockaddr *destaddr, + int destaddr_len, uchar auth_type, char *username, + char *authcode, int authcode_len, + uchar priv_level, uint32 init_out_seqnum, + uint32 *session_seqnum, uint32 *session_id); +static int ipmilan_close_session(SockType sfd, struct sockaddr *destaddr, + int destaddr_len, uint32 session_id); +uchar cksum(const uchar *buf, register int len); +char *decode_rv(int rv); /*moved to ipmicmd.c*/ + +void show_LastError(char *tag, int err) +{ +#ifdef WIN32 + fprintf(fperr,"%s LastError = %d %s\n",tag,err,strlasterr(err)); +#else + char *s; + s = strerror(err); + if (s == NULL) s = "error"; + fprintf(fperr,"%s errno = %d, %s\n",tag,err,s); +#endif +} + +int get_LastError( void ) +{ +#ifdef WIN32 + lasterr = WSAGetLastError(); +#else + lasterr = errno; +#endif + return(lasterr); +} + +static void cc_challenge(int cc) +{ + switch(cc) { + case 0x81: + printf("GetSessChallenge: Invalid user name\n"); + break; + case 0x82: + printf("GetSessChallenge: Null user name not enabled\n"); + break; + default: + printf("GetSessChallenge: %s\n",decode_cc((ushort)0,cc)); + break; + } +} + +static void cc_session(int cc) +{ + switch(cc) { + case 0x81: + printf("ActivateSession: No session slots available from BMC\n"); + break; + case 0x82: + printf("ActivateSession: No sessions available for this user\n"); + break; + case 0x83: + printf("ActivateSession: No sessions for this user/privilege\n"); + break; + case 0x84: + printf("ActivateSession: Session sequence number out of range\n"); + break; + case 0x85: + printf("ActivateSession: Invalid session ID in request\n"); + break; + case 0x86: + printf("ActivateSession: Privilege level exceeds user/channel limit\n"); + break; + default: + printf("%s\n",decode_cc((ushort)0,cc)); + break; + } + return; +} + +int StrIsIp(char *str) +{ + int i, j, n; + char ipchars[11] = "0123456789."; + int ndot = 0; + int rv = 0; + /* checks if the string looks like an IP address. */ + if (str == NULL) return(rv); + n = (int)strlen(str); + for (i = 0; i < n; i++) { + for (j = 0; j < 11; j++) + if (str[i] == ipchars[j]) break; + if (j >= 11) break; /*some other char, not valid*/ + if (str[i] == '.') ndot++; + } + if ((i == n) && (ndot == 3)) rv = 1; /*valid*/ + return(rv); +} + +void close_sockfd(SockType sfd); +void close_sockfd(SockType sfd) +{ + if (sfd == 0) return; +#ifdef WIN32 + // shutdown(sfd,SD_SEND); /*done sending*/ + closesocket(sfd); /*close lan socket */ + WSACleanup(); +#else + alarm(0); + signal(SIGALRM,SIG_DFL); + signal(SIGINT,SIG_DFL); + close(sfd); /*close lan socket */ +#endif + pconn->sockfd = 0; /*set global to zero */ +} + +int open_sockfd(char *node, SockType *sfd, SOCKADDR_T *daddr, + int *daddr_len, int foutput); +int open_sockfd(char *node, SockType *sfd, SOCKADDR_T *daddr, + int *daddr_len, int foutput) +{ + int rv = 0; + SockType s, _sockfd = -1; +#ifdef HAVE_IPV6 + struct addrinfo hints; + struct addrinfo *res, *res0; + char service[NI_MAXSERV]; +#else + struct hostent *hptr; +#endif + +#ifdef WIN32 + DWORD rvl; + + if (sfd == NULL || daddr == NULL || daddr_len == NULL) + return(-3); /* invalid pointer */ + rvl = WSAStartup(0x0202,&lan_ws); + if (rvl != 0) { + fprintf(fperr,"lan, WSAStartup(2.2) error %ld, try 1.1\n", rvl); + WSACleanup(); + rvl = WSAStartup(0x0101,&lan_ws); + if (rvl != 0) { + fprintf(fperr,"lan, WSAStartup(1.1) error %ld\n", rvl); + WSACleanup(); + return((int)rvl); + } + } +#else + if (sfd == NULL || daddr == NULL || daddr_len == NULL) + return(-3); /* invalid pointer */ +#endif + pconn->connect_state = CONN_STATE_INIT; + +#ifdef HAVE_IPV6 + memset(&_srcaddr, 0, sizeof(_srcaddr)); + memset(daddr, 0, sizeof(_destaddr)); + sprintf(service, "%d", RMCP_PRI_RMCP_PORT); + /* Obtain address(es) matching host/port */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_flags = my_ai_flags; + hints.ai_protocol = IPPROTO_UDP; /* */ + rv = getaddrinfo(node, service, NULL, &res); + if (rv != 0) { + printf("Address lookup for %s failed, getaddrinfo error %d\n", + node,rv); + return rv; + } + + /* getaddrinfo() returns a list of address structures. + * Try each address until we successfully connect(2). + * If socket(2) (or connect(2)) fails, we (close the socket + * and) try the next address. + */ + for (res0 = res; res0 != NULL; res0 = res0->ai_next) { + s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol); + if (s == SockInvalid) continue; + else _sockfd = s; + /* valid protocols are IPPROTO_UDP, IPPROTO_IPV6 */ + if (res0->ai_protocol == IPPROTO_TCP) continue; /*IPMI != TCP*/ + pconn->connect_state = CONN_STATE_SOCK; + rv = connect(_sockfd, res0->ai_addr, res0->ai_addrlen); + if (fdebuglan) printf("socket(%d,%d,%d), connect(%d) rv = %d\n", + res0->ai_family, res0->ai_socktype, + res0->ai_protocol, s,rv); + if (rv != -1) { + memcpy(daddr, res0->ai_addr, res0->ai_addrlen); + *daddr_len = res0->ai_addrlen; + break; /* Success */ + } + close_sockfd(_sockfd); + _sockfd = -1; + } + freeaddrinfo(res); /* Done with addrinfo */ + if (_sockfd < 0) { + printf("Connect to %s failed\n", node); + // ipmi_close_(); + rv = -1; + } +#else + /* Open lan interface (ipv4 method) */ + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s == SockInvalid) return (-1); + else _sockfd = s; + + pconn->connect_state = CONN_STATE_SOCK; + memset(&_srcaddr, 0, sizeof(_srcaddr)); + _srcaddr.sin_family = AF_INET; + _srcaddr.sin_port = htons(0); + _srcaddr.sin_addr.s_addr = htonl(INADDR_ANY); + rv = bind(_sockfd, (struct sockaddr *)&_srcaddr, sizeof(_srcaddr)); + if (rv < 0) { + close_sockfd(_sockfd); + return (rv); + } + + memset(daddr, 0, sizeof(SOCKADDR_T)); + daddr->sin_family = AF_INET; + daddr->sin_port = htons(RMCP_PRI_RMCP_PORT); /*0x26f = 623.*/ + if (StrIsIp(node)) { /* the node string is an IP address */ + uchar in_ip[4]; + atoip(in_ip,node); + memcpy(&daddr->sin_addr.s_addr,in_ip,4); + if ((hptr = xgethostbyname(node)) == NULL) /*gethost error*/ + strncpy(gnodename,node,SZGNODE); /*but not fatal*/ + else strncpy(gnodename,hptr->h_name,SZGNODE); + } + else if ((hptr = xgethostbyname(node)) == NULL) { + if (foutput) { +#ifdef WIN32 + fprintf(fperr,"lan, gethostbyname(%s): errno=%d\n", node,get_errno()); +#elif SOLARIS + fprintf(fperr,"lan, gethostbyname(%s): errno=%d\n", node,get_errno()); +#else + fprintf(fperr,"lan, gethostbyname(%s): %s\n", node,hstrerror(errno)); +#endif + } + close_sockfd(_sockfd); + return(LAN_ERR_HOSTNAME); + } else { /*gethostbyname(name) succeeded*/ + daddr->sin_addr = *((struct in_addr *)hptr->h_addr); + strncpy(gnodename,hptr->h_name,SZGNODE); + } + *daddr_len = sizeof(SOCKADDR_T); +#endif + + *sfd = _sockfd; + return(rv); +} + +static void +sig_timeout(int sig) +{ +#ifndef WIN32 + alarm(0); + signal(SIGALRM,SIG_DFL); +#endif + fprintf(fpdbg,"ipmilan_cmd timeout, after %s\n",conn_state_str[pconn->connect_state]); + _exit(LAN_ERR_TIMEOUT); /*timeout signal*/ +} + +static void +sig_abort(int sig) +{ + static int sig_aborting = 0; + int rv; + // uchar buf_rs[4]; + // uchar *cmd_rs; + + if (sig_aborting == 0) { + sig_aborting = 1; + if (pconn->sockfd != 0) { /* socket is open */ + if (pconn->session_id != 0) { /* session is open */ + // cmd_rs = buf_rs; + rv = ipmilan_close_session(pconn->sockfd, + (struct sockaddr *)&_destaddr, + _destaddr_len, ipmi_hdr.sess_id); + } + close_sockfd(pconn->sockfd); + } + signal(SIGINT,SIG_DFL); + fprintf(fpdbg,"ipmilan_cmd interrupt, after %s\n", conn_state_str[pconn->connect_state]); + _exit(LAN_ERR_ABORT); /*abort signal*/ + } /*endif*/ +} /*end sig_abort*/ + +int fd_wait(SockType fd, int nsec, int usec) +{ + fd_set readfds; + struct timeval tv; + int rv; + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + tv.tv_sec = nsec; + tv.tv_usec = usec; + rv = select((int)(fd+1), &readfds, NULL, NULL, &tv); + if (rv <= 0 || !FD_ISSET(fd,&readfds)) return(-1); + else return(0); +} + +#ifndef WIN32 + /* LINUX, Solaris, BSD */ +/* do_sleep() is currently unused. */ +/* signal handlers + sleep(3) is a bad idea */ +int do_sleep(unsigned int sleep_len) +{ + struct timeval tv; + + if (sleep_len == 0) + return 0; + + tv.tv_sec = sleep_len; + tv.tv_usec = 0; + if (select(1, NULL, NULL, NULL, &tv) < 0) + { + if (errno != EINTR) return(errno); + } + return 0; +} +#endif + +static void h2net(uint h, uchar *net, int n) +{ + int i = 0; + net[i++] = h & 0xff; + net[i++] = (h >> 8) & 0xff; + if (n == 2) return; + net[i++] = (h >> 16) & 0xff; + net[i++] = (h >> 24) & 0xff; + return; +} + +static void net2h(uint *h, uchar *net, int n) +{ + uint v; + v = (net[1] << 8) | net[0]; + if (n == 2) { *h = v; return; } + v |= (net[3] << 24) | (net[2] << 16); + *h = v; + return; +} + +/* + * _ipmilan_cmd + * local routine to send & receive each command. + * called by global ipmicmd_lan() + */ +int _ipmilan_cmd(SockType sockfd, struct sockaddr *hostaddr, int hostaddr_len, + uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *sdata, int slen, uchar *rdata, int *rlen, int fdebugcmd) +{ + uchar cmd_rq[RQ_LEN_MAX+SZ_CMD_HDR]; + uchar cmd_rs[RS_LEN_MAX+SZ_CMD_HDR+1]; + int rv = 0; + int rs_len; + int clen; + uchar cc = 0; + +#ifndef TEST_LAN + fdebuglan = fdebugcmd; +#endif + if (sockfd == 0 || hostaddr == NULL || + sdata == NULL || rdata == NULL) + return(LAN_ERR_INVPARAM);; + + if (fdebuglan > 2) + dbglog("_ipmilan_cmd(%02x,%02x,%02x,%02x,%02x)\n", + cmd,netfn,lun,sa,bus); + clen = SZ_CMD_HDR; + cmd_rq[0] = cmd; + cmd_rq[1] = (netfn << 2) + (lun & 0x03); + cmd_rq[2] = sa; + cmd_rq[3] = bus; + memcpy(&cmd_rq[clen],sdata,slen); + rs_len = sizeof(cmd_rs); + memset(cmd_rs, 0, rs_len); + rv = _send_lan_cmd(sockfd, cmd_rq, slen+clen, cmd_rs, &rs_len, + hostaddr, hostaddr_len); + if (rv == 0 && rs_len == 0) cc = 0; + else cc = cmd_rs[0]; + if (fdebugcmd) fprintf(fpdbg,"_ipmilan_cmd[%02x]: rv = %d, cc=%x rs_len=%d\n", + cmd_rq[0],rv,cc,rs_len); + if (rv == 0 && cc != 0) { /* completion code error */ + if (fdebugcmd) { + dump_buf("cmd_rq",cmd_rq,slen+clen,0); + dump_buf("cmd_rs",cmd_rs,rs_len,0); + } + } + if (rv == 0) { + if (rs_len < 0) rs_len = 0; + if (*rlen <= 0) *rlen = 1; /*failsafe*/ + if (rs_len > 0) { + if (rs_len > *rlen) rs_len = *rlen; + memcpy(rdata,&cmd_rs[0],rs_len); + } else { /*(rs_len == 0)*/ + rv = LAN_ERR_TOO_SHORT; /*no completion code returned*/ + } + } else { + rdata[0] = cc; + if (rs_len < 1) rs_len = 1; + } + *rlen = rs_len; + + return (rv); +} /*end _ipmilan_cmd()*/ + + +static void hash(uchar *pwd, uchar *id, uchar *chaldata, int chlen, uint32 seq, + uchar *mda, uchar md) +{ + uchar pbuf[80]; /* 16 + 4 + 16 + 4 + 16 = 56 */ + int blen, n, i; + + blen = 0; n = 16; + memcpy(&pbuf[blen], pwd,n); /* password */ + blen += n; n = 4; + memcpy(&pbuf[blen],id,n); /* session id */ + blen += n; + memcpy(&pbuf[blen],chaldata,chlen); /* ipmi msg data, incl challenge */ + blen += chlen; n = 4; + h2net(seq,&pbuf[blen],n); /* in_seq num */ + blen += n; n = 16; + memcpy(&pbuf[blen],pwd,n); /* password */ + blen += n; + if (md == IPMI_SESSION_AUTHTYPE_MD2) i = 2; + else i = 5; +#ifdef TEST_AUTH + if (fdebuglan) { + fprintf(fpdbg,"hash: calling md%d_sum with seq %u\n",i,seq); + dump_buf("pbuf",pbuf,blen,0); + } +#endif +#ifdef MD2OK + if (md == IPMI_SESSION_AUTHTYPE_MD2) + md2_sum(pbuf,blen,mda); + else /* assume md5 */ +#endif + md5_sum(pbuf,blen,mda); +#ifdef TEST_AUTH + if (fdebuglan) { + fprintf(fpdbg,"Hashed MD%d AuthCode: \n",i); + dump_buf("AuthCode",mda,16,0); + } +#endif +} /* end hash() */ + +static void hash_special(uchar *pwd, uchar *chaldata, uchar *mda) +{ + uchar md_pwd[16]; + uchar challenge[16]; + int i; + /* Only used by SuperMidro, must be MD5 auth_type */ + memset(md_pwd, 0, 16); + md5_sum(pwd,16,md_pwd); + memset(challenge, 0, 16); + for (i = 0; i < 16; i++) + challenge[i] = chaldata[i] ^ md_pwd[i]; + memset(mda, 0, 16); + md5_sum(challenge,16,mda); +} + +static int ipmilan_sendto(SockType s, const void *msg, size_t len, int flags, + const struct sockaddr *to, int tolen) +{ + int fusepad = 0; + int n; + if (fdebuglan > 2) { + dbg_dump("ipmilan_sendto",(uchar *)msg,(int)len,0); + } + /* Check whether we need a pad byte */ + /* Note from Table 12-8, RMCP Packet for IPMI via Ethernet footnote. */ + if (len == 56 || len == 84 || len == 112 || len == 128 || len == 156) { + /* include pad byte at end, require input buffer to have one extra */ + fusepad = 1; + len += 1; + } + n = (int)sendto(s,msg,len,flags,to,(socklen_t)tolen); + if (fusepad && (n > 0)) n--; + return(n); +} + +static int ipmilan_recvfrom(SockType s, void *buf, size_t len, int flags, + struct sockaddr *from, int *fromlen) +{ + int rv; + rv = (int)recvfrom(s,buf,len,flags,from,(socklen_t *)fromlen); +#ifdef OLD + /* Sometimes the OS sends an ECONNREFUSED error, but + * retrying will catch the BMC's reply packet. */ + if (rv < 0) { + int err; + err = get_LastError(); + if (err == econnrefused) { + if (fdebuglan) + fprintf(fpdbg,"ipmilan_recvfrom rv=%d econnrefused, retry\n",rv); + rv = recvfrom(s,buf,len,flags,from,(socklen_t *)fromlen); + } + } +#endif + return(rv); +} + +static int ipmilan_poke1(SockType sfd, struct sockaddr *destaddr, int destlen) +{ + int rv; + uchar asfpkt[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x20, 0x18, 0xc8, 0xc2, 0x01, 0x01, 0x3c }; + if (fdebuglan) fprintf(fpdbg,"sending ipmilan poke1\n"); + rv = ipmilan_sendto(sfd, asfpkt, 16, 0, destaddr, destlen); + os_usleep(0,100); + return rv; +} + +static int ipmilan_poke2(SockType sfd, struct sockaddr *destaddr, int destlen) +{ + int rv; + uchar asfpkt[16] = "poke2"; /*any junk*/ + if (fdebuglan) fprintf(fpdbg,"sending ipmilan poke2\n"); + rv = ipmilan_sendto(sfd, asfpkt, 10, 0, destaddr, destlen); + os_usleep(0,100); + return rv; +} + + +static void do_hash(uchar *password, uchar *sessid, uchar *pdata, int sdata, + uint32 seq_num, uchar auth_type, uchar *auth_out) +{ + /* finish header with auth_code */ + if (auth_type != IPMI_SESSION_AUTHTYPE_NONE) { /*fdoauth==1*/ + if (auth_type == IPMI_SESSION_AUTHTYPE_MD5) + hash(password, sessid, pdata, sdata, seq_num, + auth_out,IPMI_SESSION_AUTHTYPE_MD5); +#ifdef MD2OK + else if (auth_type == IPMI_SESSION_AUTHTYPE_MD2) + hash(password, sessid, pdata, sdata, seq_num, + auth_out,IPMI_SESSION_AUTHTYPE_MD2); +#endif + else /* IPMI_SESSION_AUTHTYPE_PASSWORD */ + memcpy(auth_out,password,16); + } +} + +static uint32 inc_seq_num(uint32 seq) +{ + seq++; + if (seq == 0) seq = 1; + return(seq); +} + +static int inc_sol_seq(int seq) +{ + seq++; + if (seq > 0x0f) seq = 1; /*limit to 4 bits*/ + return(seq); +} + +void ipmi_lan_set_timeout(int ipmito, int tries, int pingto) +{ + ipmi_timeout = ipmito; /*default 2*/ + ipmi_try = tries; /*default 4*/ + ping_timeout = pingto; /*default 1*/ +} + +/* + * _send_lan_cmd + * Internal routine called by local _ipmilan_cmd() and by + * ipmilan_open_session(). + * Writes the data to the lan socket in IPMI LAN format. + * Authentication, sequence numbers, checksums are handled here. + * + * Input Parameters: + * s = socket descriptor for this session + * pcmd = buffer for the command and data + * Arbitrary pcmd format: + * cmd[0] = IPMI command + * cmd[1] = NETFN/LUN byte + * cmd[2] = Slave Address (usu 0x20) + * cmd[3] = Bus (usu 0x00) + * cmd[4-N] = command data + * scmd = size of command buffer (3+sdata) + * presp = pointer to existing response buffer + * sresp = On input, size of response buffer, + * On output, length of response data. + * to = sockaddr structure for to/destination + * tolen = length of to sockaddr + */ +static int _send_lan_cmd(SockType s, uchar *pcmd, int scmd, uchar *presp, + int *sresp, struct sockaddr *to, int tolen) +{ + uchar cbuf[SEND_BUF_SZ]; + uchar rbuf[RECV_BUF_SZ]; + // uint32 out_seq = 0; /* outbound */ + int clen, rlen, hlen, msglen; + int flags; + int sz, n, i, j; + int cs1, cs2, cs3 = 0, cs4 = 0; + uchar *pdata; + int sdata; + IPMI_HDR *phdr; + uchar *psessid; + uchar iauth[16]; + int fdoauth = 1; + uint32 sess_id_tmp; + int rv = 0; + int itry; + uchar fsentok; + + /* set up LAN req hdr */ + phdr = &ipmi_hdr; + hlen = RQ_HDR_LEN; + /* phdr->bmc_addr set in open_session */ + phdr->target_addr = pcmd[2]; + phdr->target_chan = pcmd[3]; + phdr->target_lun = (pcmd[1] & 0x03); + phdr->target_netfn = (pcmd[1] >> 2); + phdr->target_cmd = pcmd[0]; + + if (phdr->seq_num != 0) pconn->finsession = 1; + if ( ((phdr->target_cmd == CMD_ACTIVATE_SESSION) || + (phdr->target_cmd == CMD_SET_SESSION_PRIV)) && + (phdr->target_netfn == NETFN_APP) ) { + pconn->finsession = 1; /*so do seq_num*/ + fdoauth = 1; /*use msg auth*/ + } + if (phdr->auth_type == IPMI_SESSION_AUTHTYPE_NONE) fdoauth = 0; + else if (pconn->finsession && (pconn->fMsgAuth == 0)) { + /* Forcing the type may be necessary with IBM eServer 360S. */ + if (fauth_type_set) fdoauth = 1; /*user set it, so try anyway*/ + else fdoauth = 0; /*auth not supported*/ + } + if (fdoauth == 0) hlen = RQ_HDR_LEN - 16; + + /* copy command */ + if (scmd < SZ_CMD_HDR) return(LAN_ERR_INVPARAM); + sdata = scmd - SZ_CMD_HDR; /* scmd = 4 + datalen */ + msglen = 7 + sdata; + if (fdebuglan > 2) { + dbglog("_send_lan_cmd: cmd=%02x, hlen=%d, msglen=%02x, authtype=%02x\n", + pcmd[0], hlen, msglen, phdr->auth_type); + } + clen = hlen + msglen; + if (clen > sizeof(cbuf)) { + fprintf(fpdbg,"message size %d > buffer size %d\n",clen,sizeof(cbuf)); + return(LAN_ERR_TOO_SHORT); + } + + if ((phdr->target_cmd == SOL_DATA) && + (phdr->target_netfn == NETFN_SOL) ) /*SOL 1.5 data packet*/ + { + hlen = SOL_HDR_LEN; /*RMCP header + 26 */ + if (fdoauth == 0) hlen = SOL_HDR_LEN - 16; + msglen = sdata; + memcpy(&cbuf[0], phdr, 4); /* copy RMCP header to buffer */ + pdata = &cbuf[4]; + pdata[0] = phdr->auth_type; + memcpy(&pdata[1],&phdr->seq_num,4); + sess_id_tmp = phdr->sess_id | SOL_MSG; + memcpy(&pdata[5],&sess_id_tmp,4); + if (fdebuglan > 2) + dbglog("auth_type=%x/%x fdoauth=%d hlen=%d seq_num=%x\n", /*SOL*/ + phdr->auth_type,gauth_type,fdoauth,hlen,phdr->seq_num); + if (fdoauth) { + psessid = (uchar *)&sess_id_tmp; + do_hash(phdr->password, psessid, &cbuf[hlen],msglen, + phdr->seq_num, phdr->auth_type, iauth); + /* copy hashed authcode to header */ + memcpy(&pdata[9],iauth,16); + } + // pdata[hlen-1] = msglen; + pdata = &cbuf[hlen]; + memcpy(pdata,&pcmd[SZ_CMD_HDR],msglen); /*copy the data*/ + clen = hlen + msglen; + if (fdebuglan > 2) + dbg_dump("sol data, before",pdata,sdata,1); /*SOL TEST*/ + } else { /*not SOL packet, normal IPMI packet*/ + pdata = &cbuf[hlen]; + j = cs1 = 0; + if ((phdr->target_addr == phdr->bmc_addr) || !bridgePossible || + (phdr->target_addr == SWID_REMOTE) || + (phdr->target_addr == SWID_SMSOS)) { + phdr->bridge_level = 0; + msglen = sdata + 7; + clen = hlen + msglen; + } else { + phdr->bridge_level = 1; + if (phdr->transit_addr != 0 && phdr->transit_addr != phdr->bmc_addr) + { + msglen = sdata + 15 + 8; + phdr->bridge_level++; + } else { + msglen = sdata + 15; + } + if (fdebuglan > 2) { + dbglog("bridge_level=%d cmd=%02x target=%02x transit=%02x\n", + phdr->bridge_level, phdr->target_cmd, + phdr->target_addr, phdr->transit_addr); + dbglog("bridge target_ch=%x transit_ch=%x\n", + phdr->target_chan, phdr->transit_chan); + } + clen = hlen + msglen; + pdata[j++] = bmc_sa; /*[0]=sa */ + pdata[j++] = (NETFN_APP << 2); /*[1]=netfn/lun*/ + pdata[j] = cksum(&pdata[cs1],j-cs1); /*[2]=cksum1*/ + j++; + cs3 = j; /*start for cksum3*/ + pdata[j++] = phdr->swid; /*[3]=swid, usu SWID_REMOTE */ + pdata[j++] = (phdr->swseq << 2); /*[4]=swseq/lun*/ + pdata[j++] = CMD_SEND_MESSAGE; /*[5]=cmd*/ + if (phdr->bridge_level == 1) { + pdata[j++] = (0x40|phdr->target_chan); /*channel*/ + } else { /*double bridge*/ + pdata[j++] = (0x40|phdr->transit_chan); /*channel*/ + cs1 = j; + pdata[j++] = phdr->transit_addr; /*[0]=sa */ + pdata[j++] = (NETFN_APP << 2); /*[1]=netfn/lun*/ + pdata[j] = cksum(&pdata[cs1],j-cs1); /*[2]=cksum1*/ + j++; + cs4 = j; /*start for cksum4*/ + pdata[j++] = bmc_sa; /*[3]=swid */ + pdata[j++] = (phdr->swseq << 2); /*[4]=swseq/lun*/ + pdata[j++] = CMD_SEND_MESSAGE; /*[5]=cmd*/ + pdata[j++] = (0x40|phdr->target_chan); /*channel*/ + } + } /*end-else bridged*/ + /* normal IPMI LAN commmand packet */ + cs1 = j; /*start for cksum1*/ + pdata[j++] = pcmd[2]; /*[0]=sa (phdr->target_addr)*/ + pdata[j++] = pcmd[1]; /*[1]=netfn/lun*/ + pdata[j] = cksum(&pdata[cs1],j-cs1); /*[2]=cksum1*/ + j++; + cs2 = j; /*start for cksum2*/ + if (phdr->bridge_level == 0) + pdata[j++] = phdr->swid; /*[3]=swid*/ + else /*bridged message*/ + pdata[j++] = phdr->bmc_addr; /*[3]=swid*/ + pdata[j++] = (phdr->swseq << 2) + phdr->swlun; /*[4]=swseq/lun*/ + pdata[j++] = phdr->target_cmd; /*[5]=cmd (pcmd[0])*/ + if (sdata > 0) { + memcpy(&pdata[j],&pcmd[SZ_CMD_HDR],sdata); /*[6]=data*/ + j += sdata; + } + pdata[j] = cksum(&pdata[cs2],j-cs2); /*cksum2*/ + j++; + + if (phdr->bridge_level > 0) { + if (phdr->bridge_level > 1) { + pdata[j] = cksum(&pdata[cs4],j-cs4); /*cksum4*/ + j++; + } + pdata[j] = cksum(&pdata[cs3],j-cs3); /*cksum3*/ + j++; + } + if (fdebuglan && (msglen != j)) + fprintf(fpdbg,"warning: msglen(%d)!=j(%d), hlen=%d clen=%d\n", + msglen,j,hlen,clen); + + if (fdoauth) { + psessid = (uchar *)&phdr->sess_id; + do_hash(phdr->password, psessid, &cbuf[hlen],msglen, + phdr->seq_num, phdr->auth_type, iauth); + /* copy hashed authcode to header */ + memcpy(phdr->auth_code,iauth,16); + } + memcpy(&cbuf[0], phdr, hlen); /* copy header to buffer */ + } /*end-else normal IPMI */ + + if (fdoauth == 0 && phdr->auth_type != IPMI_SESSION_AUTHTYPE_NONE) { + /* force the packet auth type to NONE (0) */ + IPMI_HDR *pchdr; + pchdr = (IPMI_HDR *)&cbuf[0]; + pchdr->auth_type = IPMI_SESSION_AUTHTYPE_NONE; + // memset(phdr->auth_code,0,16); + } + cbuf[hlen-1] = (uchar)msglen; /* IPMI Message Length = 7 + data */ + if (fdebuglan > 2) { + if ((phdr->target_cmd == SOL_DATA) && + (phdr->target_netfn == NETFN_SOL) ) { + // phdr->sess_id = sess_id_sav; /*restore sess_id*/ + if (fdebuglan) fprintf(fpdbg,"sending lan sol data (len=%d)\n",clen); + } else { + if (fdebuglan) fprintf(fpdbg,"sending ipmi lan data (len=%d)\n",clen); + } + } + flags = 0; + rlen = 0; + + if ((fdebuglan > 2) && + (phdr->target_cmd == CMD_GET_CHAN_AUTH_CAP) && + (phdr->target_netfn == NETFN_APP) ) + dbg_dump("get_chan_auth_cap command",cbuf,clen,1); + memset(rbuf,0,sizeof(rbuf)); + fsentok = 0; + for (itry = 0; (itry < ipmi_try) && (rlen == 0); itry++) + { + if (fdebuglan > 2) + dbglog("ipmilan_cmd(seq=%x) fsentok=%d itry=%d\n", + phdr->seq_num, fsentok, itry); + if (fsentok == 0) { + if (fdebuglan) + fprintf(fpdbg,"ipmilan_sendto(seq=%x,clen=%d)\n", + phdr->seq_num, clen); + sz = ipmilan_sendto(s,cbuf,clen,flags,to,tolen); + if (sz < 1) { + lasterr = get_LastError(); + if (fdebuglan) show_LastError("ipmilan_sendto",lasterr); + rv = LAN_ERR_SEND_FAIL; + os_usleep(0,5000); + continue; /* retry */ + } + fsentok = 1; /*sent ok, no need to resend*/ + } + + /* receive the response */ + rv = fd_wait(s, ipmi_timeout,0); + if (rv != 0) { + if (fdebuglan) + fprintf(fpdbg,"ipmilan_cmd timeout, after request, seq=%x itry=%d\n", + phdr->seq_num, itry); + rv = LAN_ERR_RECV_FAIL; + if (fdopoke2) ipmilan_poke2(s, to, tolen); + os_usleep(0,5000); + continue; /* retry */ + } + flags = RECV_MSG_FLAGS; + rlen = ipmilan_recvfrom(s,rbuf,sizeof(rbuf),flags,to,&tolen); + if (rlen < 0) { + lasterr = get_LastError(); + if (fdebuglan) { + fprintf(fpdbg,"ipmilan_recvfrom rlen=%d, err=%d iseq=%x itry=%d\n", + rlen,lasterr,phdr->iseq_num,itry); + show_LastError("ipmilan_recvfrom",lasterr); + } + rv = rlen; /* -3 = LAN_ERR_RECV_FAIL */ + rlen = 0; + *sresp = rlen; + /* Sometimes the OS sends an ECONNREFUSED error, but + * retrying will catch the BMC's reply packet. */ + if (lasterr == econnrefused) continue; /*try again*/ + else break; /* goto EXIT; */ + } else { /* successful receive */ + net2h(&phdr->iseq_num,&rbuf[5],4); /*incoming seq_num from hdr*/ + if (fdebuglan) { + fprintf(fpdbg,"ipmilan_recvfrom rlen=%d, iseq=%x\n", + rlen,phdr->iseq_num); + if (fdebuglan > 2) + dbg_dump("ipmilan_recvfrom", rbuf,rlen,1); + } + + /* incoming auth_code may differ from request auth code, (Dell 1855)*/ + if (rbuf[4] == IPMI_SESSION_AUTHTYPE_NONE) { /* if AUTH_NONE */ + phdr->auth_type = IPMI_SESSION_AUTHTYPE_NONE; + hlen = RQ_HDR_LEN - 16; /*RMCP header + 10*/ + } else { + hlen = RQ_HDR_LEN; /*RMCP header + 26 */ + // memcpy(phdr->iauth_code,&rbuf[13],16); /*iauthcode*/ + } + + i = hlen + 6; + if (rlen <= i) rv = LAN_ERR_TOO_SHORT; + else { /* successful */ + n = rlen - i - 1; + if (bridgePossible && (phdr->target_addr != bmc_sa)) { + if (phdr->bridge_level && + ((rbuf[hlen+1] >> 2) == (NETFN_APP + 1)) && /*0x07*/ + rbuf[hlen+5] == CMD_SEND_MESSAGE) /*0x34*/ + { + phdr->bridge_level--; + if (n <= 1) { /* no data, wait for next */ + if (fdebuglan) + fprintf(fpdbg,"bridged response empty, cc=%x\n",rbuf[i]); + if (rbuf[i] == 0) { /* if sendmsg cc==0, recv again*/ + rlen = 0; + continue; + } /*else done*/ + } else { /* has data, copy it*/ + //if (fdebuglan) fprintf(fpdbg,"bridged response, n=%d\n",n); + // memmove(&rbuf[i-7],&rbuf[i],n); + phdr->swseq = rbuf[i-3] >> 2; /*needed?*/ + rbuf[i-8] -= 8; + n -= 8; + i -= 7; + if (fdebuglan) dump_buf("bridged response",&rbuf[i],n,1); + continue; /*recv again*/ + } + } + } /*endif bridge*/ + if (n > *sresp) n = *sresp; + memcpy(presp,&rbuf[i],n); + *sresp = n; + rv = 0; + } + } /*end else success*/ + } /*end for loop*/ +// EXIT: +#ifdef NOT + /* do not increment sequence numbers for SEND_MESSAGE command */ + if ((phdr->target_cmd == IPMB_SEND_MESSAGE) && + (phdr->target_netfn == NETFN_APP) ) + pconn->finsession = 0; +#endif + if (pconn->finsession) { + /* increment seqnum - even if error */ + phdr->seq_num = inc_seq_num( phdr->seq_num ); + if (rlen > 0) pconn->in_seq = phdr->iseq_num; + else pconn->in_seq = inc_seq_num(pconn->in_seq); + phdr->swseq = (uchar)inc_seq_num(phdr->swseq); + } + return(rv); +} /*end _send_lan_cmd*/ + +static char *auth_type_str(int authcode) +{ + char *pstr; + switch(authcode) { + case IPMI_SESSION_AUTHTYPE_MD5: pstr = "MD5"; break; + case IPMI_SESSION_AUTHTYPE_MD2: pstr = "MD2"; break; + case IPMI_SESSION_AUTHTYPE_PASSWORD: pstr = "PSWD"; break; + case IPMI_SESSION_AUTHTYPE_OEM: pstr = "OEM"; break; + case IPMI_SESSION_AUTHTYPE_NONE: pstr = "NONE"; break; + default: pstr = "Init"; break; /* AUTHTYPE_INIT, etc. */ + } + return (pstr); +} + +#ifdef NOT_USED +static uchar auth_type_mask(int authcode, uchar allowed) +{ + uchar mask; + switch(authcode) { + case IPMI_SESSION_AUTHTYPE_MD5: + mask = IPMI_MASK_AUTHTYPE_MD5; + break; + case IPMI_SESSION_AUTHTYPE_MD2: + mask = IPMI_MASK_AUTHTYPE_MD2; + break; + case IPMI_SESSION_AUTHTYPE_PASSWORD: + mask = IPMI_MASK_AUTHTYPE_PASSWORD; + break; + case IPMI_SESSION_AUTHTYPE_OEM: + mask = IPMI_MASK_AUTHTYPE_OEM; + break; + case IPMI_SESSION_AUTHTYPE_NONE: + mask = IPMI_MASK_AUTHTYPE_NONE; + break; + default: /* AUTHTYPE_INIT, etc. */ + mask = 0; + break; + } + return (mask); +} +#endif + +/* + * ipmilan_open_session + * Performs the various command/response sequence needed to + * initiate an IPMI LAN session. + */ +static int ipmilan_open_session(SockType sfd, struct sockaddr *destaddr, + int destaddr_len, uchar auth_type, char *username, + char *authcode, int authcode_len, + uchar priv_level, uint32 init_out_seqnum, + uint32 *session_seqnum, uint32 *session_id) +{ + int rv = 0; + uchar ibuf[RQ_LEN_MAX+3]; + uchar rbuf[RS_LEN_MAX+4]; + uint32 iseqn; + uchar ipasswd[16]; + uchar iauthtype; + uchar iauthcap, imsgauth; + int rlen, ilen; + IPMI_HDR *phdr; + uchar cc; + int busy_tries = 0; + + if (fdebuglan) + fprintf(fpdbg,"ipmilan_open_session(%d,%02x,%s,%02x,%x) called\n", + sfd,auth_type,username,priv_level,init_out_seqnum); + if (sfd == 0 || destaddr == NULL) return LAN_ERR_INVPARAM; + phdr = &ipmi_hdr; + /* Initialize ipmi_hdr fields */ + memset(phdr,0,sizeof(ipmi_hdr)); + phdr->rmcp_ver = 0x06; + phdr->rmcp_res = 0x00; + phdr->rmcp_seq = 0xFF; + phdr->rmcp_type = 0x07; + phdr->swid = sms_swid; + phdr->swseq = 1; + phdr->priv_level = priv_level; + + /* Get Channel Authentication */ + phdr->auth_type = IPMI_SESSION_AUTHTYPE_NONE; /*use none(0) at first*/ + ibuf[0] = 0x0e; /*this channel*/ + ibuf[1] = phdr->priv_level; + rlen = sizeof(rbuf); + if (fdebuglan) + fprintf(fpdbg,"GetChanAuth(sock %x, level %x) called\n",sfd,ibuf[1]); + rv = _ipmilan_cmd(sfd, destaddr, destaddr_len, CMD_GET_CHAN_AUTH_CAP, + NETFN_APP,BMC_LUN,bmc_sa, PUBLIC_BUS, + ibuf,2, rbuf,&rlen, fdebuglan); + if (rv != 0) { /*retry if error*/ + rv = _ipmilan_cmd(sfd, destaddr, destaddr_len, CMD_GET_CHAN_AUTH_CAP, + NETFN_APP,BMC_LUN,bmc_sa, PUBLIC_BUS, + ibuf,2, rbuf,&rlen, fdebuglan); + } + cc = rbuf[0]; + if (fdebuglan) + fprintf(fpdbg,"GetChanAuth rv = %d, cc=%x rbuf: %02x %02x %02x " + "%02x %02x %02x %02x\n", + rv, rbuf[0],rbuf[1],rbuf[2],rbuf[3], + rbuf[4],rbuf[5],rbuf[6],rbuf[7]); + if (rv != 0 || cc != 0) goto ERREXIT; + + /* Check Channel Auth params */ + if ((rbuf[2] & 0x80) != 0) { /*have IPMI 2.0 extended capab*/ + if ( ((rbuf[4]&0x02) != 0) && ((rbuf[4]&0x01) == 0) ) { + if (fdebuglan) + fprintf(fpdbg,"GetChanAuth reports only v2 capability\n"); + rv = LAN_ERR_V2; /*try v2 instead*/ + goto ERREXIT; + } + } + /* Check authentication support */ + imsgauth = rbuf[3]; + if ((imsgauth & 0x10) == 0) pconn->fMsgAuth = 1; /*per-message auth*/ + else if ((imsgauth & 0x08) == 0) pconn->fMsgAuth = 2; /*user-level auth*/ + else pconn->fMsgAuth = 0; /*no auth support*/ + iauthcap = rbuf[2] & 0x3f; + if (fauth_type_set) { + iauthtype = (uchar)gauth_type; // set by user + auth_type = iauthtype; + } else { + iauthtype = AUTHTYPE_INIT; /*initial value, not set*/ + } + if (auth_type != iauthtype) { + /* default of MD5 is preferred, but try what BMC allows */ + if (iauthcap & IPMI_MASK_AUTHTYPE_MD5) { + iauthtype = IPMI_SESSION_AUTHTYPE_MD5; + auth_type = iauthtype; +#ifdef MD2OK + } else if (iauthcap & IPMI_MASK_AUTHTYPE_MD2) { + iauthtype = IPMI_SESSION_AUTHTYPE_MD2; + auth_type = iauthtype; + if (fdebuglan) + fprintf(fpdbg,"auth_type set to MD2 (%02x)\n",iauthtype); +#endif + } else if (iauthcap & IPMI_MASK_AUTHTYPE_PASSWORD) { + iauthtype = IPMI_SESSION_AUTHTYPE_PASSWORD; + auth_type = iauthtype; + if (fdebuglan) + fprintf(fpdbg,"auth_type set to Password (%02x)\n",iauthtype); + } else { + if (fdebuglan) fprintf(fpdbg, + "auth_type set to %02x, using None\n",auth_type); + iauthtype = IPMI_SESSION_AUTHTYPE_NONE; + auth_type = iauthtype; + } + } + if (fdebuglan) fprintf(fpdbg, + "auth_type=%02x(%s) allow=%02x iauthtype=%02x msgAuth=%d(%02x)\n", + auth_type,auth_type_str(auth_type),iauthcap,iauthtype, + pconn->fMsgAuth,imsgauth); + + /* get session challenge */ + phdr->auth_type = IPMI_SESSION_AUTHTYPE_NONE; + memset(ibuf,0,17); + ibuf[0] = iauthtype; + if (username != NULL) + strncpy(&ibuf[1],username,16); + while (busy_tries < BUSY_MAX) { + rlen = sizeof(rbuf); + rv = _ipmilan_cmd(sfd, destaddr,destaddr_len, CMD_GET_SESSION_CHALLENGE, + NETFN_APP,BMC_LUN,bmc_sa, PUBLIC_BUS, + ibuf,17, rbuf,&rlen, fdebuglan); + cc = rbuf[0]; + if (rv != 0) break; + else if (cc == 0xc0) busy_tries++; + else break; + } + if (fdebuglan) { + if ((rv == 0) && (cc == 0)) + dump_buf("GetSessionChallenge rv=0, rbuf",rbuf,rlen,0); + else + fprintf(fpdbg,"GetSessionChallenge rv=%d cc=%x rlen=%d tries=%d\n", + rv, cc, rlen,busy_tries); + } + if (rv != 0) goto ERREXIT; + else if (cc != 0) { cc_challenge(cc); goto ERREXIT; } + + /* save challenge response data */ + memcpy(&phdr->sess_id, &rbuf[1], 4); + memcpy(phdr->challenge, &rbuf[5], 16); + + /* Save authtype/authcode in ipmi_hdr for later use in _send_lan_cmd. */ + phdr->bmc_addr = bmc_sa; + phdr->auth_type = iauthtype; + if (authcode_len > 16 || authcode_len < 0) authcode_len = 16; + memset(&ipasswd,0,16); + if (authcode != NULL && authcode_len > 0) + memcpy(&ipasswd,(uchar *)authcode,authcode_len); /* AuthCode=passwd */ + memcpy(phdr->password,&ipasswd,16); /* save password */ + + /* ActivateSession request */ + ibuf[0] = phdr->auth_type; + ibuf[1] = phdr->priv_level; + if (vend_id == VENDOR_SUPERMICRO) { + /* if supermicro, do special auth logic here */ + hash_special(phdr->password, phdr->challenge, ipasswd); + memcpy(phdr->password,ipasswd,16); + memset(&ibuf[2],0,16); /*zero challenge string here*/ + if (fdebuglan) printf("Using supermicro OEM challenge\n"); + } else { + memcpy(&ibuf[2],phdr->challenge,16); /*copy challenge string to data*/ + } + phdr->seq_num = 0; + iseqn = init_out_seqnum; + h2net(iseqn,&ibuf[18],4); /* write iseqn to buffer */ + ilen = 22; + if (fdebuglan) dump_buf("ActivateSession req",ibuf,ilen,0); + + rlen = sizeof(rbuf); + rv = _ipmilan_cmd(sfd,destaddr,destaddr_len,CMD_ACTIVATE_SESSION, + NETFN_APP,BMC_LUN,bmc_sa, PUBLIC_BUS, + ibuf, ilen, rbuf, &rlen, fdebuglan); + cc = rbuf[0]; + if (fdebuglan) { + if (rv > 0) fprintf(fpdbg,"ActivateSession rv = 0x%02x\n",rv); /*cc*/ + else fprintf(fpdbg,"ActivateSession rv = %d\n",rv); + } + if (rv != 0) goto ERREXIT; + else if (cc != 0) { cc_session(cc); goto ERREXIT; } + + if (pconn->fMsgAuth == 2) /*user-level auth*/ + phdr->auth_type = IPMI_SESSION_AUTHTYPE_NONE; + + memcpy(&phdr->sess_id,&rbuf[2],4); /* save new session id */ + net2h(&iseqn, &rbuf[6],4); /* save returned out_seq_num */ + if (iseqn == 0) iseqn = inc_seq_num(iseqn); /* was ++iseqn */ + phdr->seq_num = iseqn; /* new session seqn */ + if (fdebuglan) + fprintf(fpdbg,"sess_id=%x seq_num=%x priv_allow=%x priv_req=%x\n", + phdr->sess_id,phdr->seq_num,rbuf[10],phdr->priv_level); + + /* set session privileges (set_session_privilege_level) */ + ibuf[0] = phdr->priv_level; + rlen = sizeof(rbuf); + rv = _ipmilan_cmd(sfd, destaddr, destaddr_len, CMD_SET_SESSION_PRIV, + NETFN_APP,BMC_LUN,bmc_sa, PUBLIC_BUS, + ibuf,1, rbuf,&rlen, fdebuglan); + cc = rbuf[0]; + if (fdebuglan) fprintf(fpdbg,"SetSessionPriv(%x) rv = %d\n",ibuf[0], rv); + + bridgePossible = 1; + *session_id = phdr->sess_id; + *session_seqnum = phdr->seq_num; +ERREXIT: + if (rv == 0 && cc != 0) rv = cc; + return(rv); +} /*end ipmilan_open_session*/ + +/* + * ipmilan_close_session + */ +static int ipmilan_close_session(SockType sfd, struct sockaddr *destaddr, + int destaddr_len, uint32 session_id) +{ + uchar ibuf[RQ_LEN_MAX+3]; + uchar rbuf[RS_LEN_MAX+4]; + int rlen; + int rv = 0; + + if (session_id == 0) return(0); + /* send close session command */ + memcpy(ibuf,&session_id,4); + rlen = sizeof(rbuf); + bridgePossible = 0; + rv = _ipmilan_cmd(sfd, destaddr, destaddr_len, CMD_CLOSE_SESSION, + NETFN_APP,BMC_LUN,bmc_sa,PUBLIC_BUS, + ibuf,4, rbuf,&rlen, fdebuglan); + if (fdebuglan) fprintf(fpdbg,"CloseSession rv = %d, cc = %02x\n", + rv, rbuf[0]); + if (rbuf[0] != 0) rv = rbuf[0]; /*comp code*/ + if (rv == 0) pconn->session_id = 0; + ipmi_hdr.seq_num = 0; + ipmi_hdr.swseq = 1; + ipmi_hdr.iseq_num = 0; + ipmi_hdr.sess_id = 0; + pconn->finsession = 0; + return(rv); +} + + +int rmcp_ping(SockType sfd, struct sockaddr *saddr, int saddr_len, int foutput) +{ + /* The ASF spec says to use network byte order */ + uchar asf_pkt[40] = {06,0,0xFF,06,0x00,0x00,0x11,0xBE,0x80,0,0,0 }; + struct sockaddr from_addr; + int from_len; + int rv; + int iana; + + /* Send RMCP ASF ping to verify IPMI LAN connection. */ + asf_pkt[9] = 1; /*tag*/ + rv = ipmilan_sendto(sfd, asf_pkt, 12, 0, saddr, saddr_len); + if (foutput) + fprintf(fpdbg,"ipmilan ping, sendto len=%d\n",rv); + if (rv < 0) return(LAN_ERR_PING); + pconn->connect_state = CONN_STATE_PING; /*ping was sent ok*/ + + from_len = sizeof(struct sockaddr); + rv = fd_wait(sfd,ping_timeout,0); + if (rv != 0) { + fprintf(fpdbg,"ping timeout, after %s\n", + conn_state_str[pconn->connect_state]); + rv = LAN_ERR_CONNECT; + } else { + rv = ipmilan_recvfrom(sfd, asf_pkt, sizeof(asf_pkt), 0, + &from_addr,&from_len); + if (foutput) { + fprintf(fpdbg,"ipmilan pong, recvfrom len=%d\n", rv); + if (rv > 0) { + iana = asf_pkt[15] + (asf_pkt[14] << 8) + + (asf_pkt[13] << 16) + (asf_pkt[12] << 24); + dump_buf("ping response",asf_pkt, rv,0); + printf("ping IANA = %d (%s)\n",iana,get_iana_str(iana)); + } + } + if (rv < 0) return(LAN_ERR_CONNECT); + } + return(0); +} + +int ping_bmc(char *node, int fdebugcmd) +{ + SOCKADDR_T toaddr; + int toaddr_len; + SockType sfd; + int rv; + + rv = open_sockfd(node,&sfd, &toaddr, &toaddr_len, fdebugcmd); + if (rv != 0) return(rv); + + rv = rmcp_ping(sfd, (struct sockaddr *)&toaddr,toaddr_len, fdebugcmd); + + close_sockfd(sfd); + return(rv); +} + +static int get_rand(void *data, int len) +{ + int rv = 0; + int fd; + +#if defined(LINUX) + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0 || len < 0) return errno; + rv = read(fd, data, len); + close(fd); +#else + fd = rand(); + if (fd == 0) fd = 1; + if (len > sizeof(int)) len = sizeof(int); + memcpy(data,&fd,len); +#endif + return rv; +} + +/* + * ipmi_open_lan + */ +int ipmi_open_lan(char *node, char *user, char *pswd, int fdebugcmd) +{ + char *username; + uchar priv_level; + int rv = -1; +#ifndef HAVE_IPV6 + char *temp; +#endif + +#ifndef TEST_LAN + fdebuglan = fdebugcmd; + if (fdebugcmd) fprintf(fpdbg,"ipmi_open_lan: fdebug = %d\n",fdebugcmd); +#endif + if (fdebugcmd > 2) fdoping = 1; + get_mfgid(&vend_id,&prod_id); + if (nodeislocal(node)) { + fprintf(fpdbg,"ipmi_open_lan: node %s is local!\n",node); + rv = LAN_ERR_INVPARAM; + goto EXIT; + } else { + + if ((gshutdown==0) || fdebugcmd) + fprintf(fpdbg,"Opening lan connection to node %s ...\n",node); + /* save nodename for sig_abort later */ + if (strlen(node) > SZGNODE) { + strncpy(nodename, node, SZGNODE); nodename[SZGNODE] = 0; + } else strcpy(nodename, node); + + rv = open_sockfd(node, &(pconn->sockfd), &_destaddr, &_destaddr_len, 1); + if (fdebugcmd) + printf("open_sockfd returned %d, fd=%d\n", rv, pconn->sockfd); + if (rv != 0) goto EXIT; + +#ifdef HAVE_IPV6 + strcpy(gnodename,nodename); + fprintf(fpdbg,"Connecting to node %s\n",gnodename); +#else +#ifdef WIN32 + /* check for ws2_32.lib(getnameinfo) resolution */ + gnodename[0] = 0; +/* + int getnameinfo( const struct sockaddr * sa, socklen_t salen, + char * host, DWORD hostlen, + char * serv, DWORD servlen, + int flags); + rv = getnameinfo((SOCKADDR *)&_destaddr, _destaddr_len, + gnodename,SZGNODE, NULL,0,0); +*/ +#else + rv = getnameinfo((struct sockaddr *)&_destaddr, _destaddr_len, + gnodename,SZGNODE, NULL,0,0); +#endif + if (rv != 0) { + if (fdebugcmd) + fprintf(fpdbg,"ipmi_open_lan: getnameinfo rv = %d\n",rv); + gnodename[0] = 0; + } + temp = inet_ntoa(_destaddr.sin_addr); + fprintf(fpdbg,"Connecting to node %s %s\n",gnodename, temp); + strncpy(_dest_ip, temp, INET_ADDRSTRLEN); + _dest_ip[INET_ADDRSTRLEN] = 0; +#endif + +#ifndef WIN32 + /* Linux: Set up signals to handle errors & timeouts. */ + signal(SIGINT,sig_abort); + signal(SIGALRM,sig_timeout); +#endif + + pconn->connect_state = CONN_STATE_BIND; + + if (fdoping) { + rv = rmcp_ping(pconn->sockfd,(struct sockaddr *)&_destaddr, + _destaddr_len, fdebugcmd); + if (fdopoke1 && rv != 0) { + /* May sometimes need a poke to free up the BMC (cant hurt) */ + ipmilan_poke1(pconn->sockfd,(struct sockaddr *)&_destaddr, + _destaddr_len); + } + + if (rv != 0) { + if (rv == LAN_ERR_CONNECT && frequireping == 0) { + /* keep going even if ping/pong failure */ + rv = 0; + } else { + close_sockfd(pconn->sockfd); + rv = LAN_ERR_CONNECT; + goto EXIT; + } + } + pconn->connect_state = CONN_STATE_PONG; + } + + { + auth_type = (uchar)gauth_type; + priv_level = (uchar)gpriv_level; + username = user; + authcode = pswd; + authcode_len = (pswd) ? strlen_(authcode) : 0; + if ((vend_id == VENDOR_INTEL) || (vend_id == VENDOR_IBM)) + pconn->start_out_seq = 1; + else { + if (fdebugcmd) + printf("calling get_rand(%d)\n", pconn->start_out_seq); + get_rand(&pconn->start_out_seq,sizeof(pconn->start_out_seq)); + } + } + rv = ipmilan_open_session(pconn->sockfd, (struct sockaddr *)&_destaddr, + _destaddr_len, auth_type, username, + authcode, authcode_len,priv_level, pconn->start_out_seq, + &pconn->in_seq, &pconn->session_id); + if (rv == 0) { /* successful (session active) */ + pconn->connect_state = CONN_STATE_ACTIVE; /*set connection state to active*/ + } else { /* open_session rv != 0 */ + if ((gshutdown==0) || fdebugcmd) { + if (rv < 0) + fprintf(fpdbg,"ipmilan_open_session error, rv = %d\n",rv); + else fprintf(fpdbg,"ipmilan_open_session error, rv = 0x%x\n",rv); + } + close_sockfd(pconn->sockfd); + } + } +EXIT: + if (rv != 0) { + // if ((gshutdown==0) || fdebugcmd) + printf("ipmilan %s\n",decode_rv(rv)); + if (rv == -1 && lasterr != 0) show_LastError("ipmilan",lasterr); + } + return(rv); +} + +int ipmi_flush_lan(char *node) +{ + int rv = 0; + /* could match node via pconn = find_conn(node); */ + if (!nodeislocal(node)) { /* ipmilan, need to close & cleanup */ + if (pconn->sockfd != 0) close_sockfd(pconn->sockfd); + } else { /* kcs cleanup */ +#ifndef WIN32 + alarm(0); + signal(SIGALRM,SIG_DFL); +#endif + } /* endif */ + pconn->connect_state = CONN_STATE_INIT; + pconn->finsession = 0; + pconn->session_id = 0; + pconn->sockfd = 0; + pconn->in_seq = 1; + pconn->start_out_seq = 1; + pconn->fMsgAuth = 1; /*1=PerMsgAuth*/ + pconn->auth_type = AUTHTYPE_INIT; + return (rv); +} + +int ipmi_close_lan(char *node) +{ + int rv = 0; + + /* could match node via pconn = find_conn(node); */ + if (!nodeislocal(node)) { /* ipmilan, need to close & cleanup */ + if (pconn->sockfd != 0) { /* socket is open */ + if (gshutdown) pconn->session_id = 0; + if (pconn->session_id != 0) { /* session is open */ + // cmd_rs = buf_rs; + rv = ipmilan_close_session(pconn->sockfd, + (struct sockaddr *)&_destaddr, + _destaddr_len, ipmi_hdr.sess_id); + /* flush session_id even if error, let it time out */ + pconn->session_id = 0; + } + close_sockfd(pconn->sockfd); + pconn->sockfd = 0; + } + pconn->connect_state = CONN_STATE_INIT; + pconn->finsession = 0; + } else { /* kcs cleanup */ +#ifndef WIN32 + alarm(0); + signal(SIGALRM,SIG_DFL); +#endif + } /* endif */ + return (rv); +} + +/* + * ipmicmd_lan + * This is called by ipmi_cmd_lan, all commands come through here. + */ +int ipmicmd_lan(char *node, + uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd) +{ + uchar rq_data[RQ_LEN_MAX+3]; + uchar cmd_rs[RS_LEN_MAX+4]; + uchar cc = 0; + int rlen; + int rv = -1; + +#ifndef TEST_LAN + fdebuglan = fdebugcmd; +#endif + /* check sdata/sresp against MAX_ */ + if (sdata > RQ_LEN_MAX) { + if (fdebugcmd) printf("cmd %x sdata(%d) > RQ_LEN_MAX(%d)\n", + cmd,sdata,RQ_LEN_MAX); + return(LAN_ERR_BADLENGTH); + } + if (*sresp > RS_LEN_MAX) { + if (fdebugcmd) printf("cmd %x sresp(%d) > RS_LEN_MAX(%d), use less\n", + cmd,*sresp,RS_LEN_MAX); + /* This is ok, just receive up to the max. */ + *sresp = RS_LEN_MAX; + } + if (pdata == NULL) { pdata = rq_data; sdata = 0; } + rlen = *sresp; + + if (nodeislocal(node)) { /*local, use kcs*/ + fprintf(fpdbg,"ipmicmd_lan: node %s is local", node); + goto EXIT; + } else { /* ipmilan */ + if (pconn->sockfd == 0) { /* closed, do re-open */ + if (fdebugcmd) + fprintf(fpdbg,"sockfd==0, node %s needs re-open\n",node); + rv = ipmi_open_lan(gnode, guser, gpswd, fdebugcmd); + if (rv != 0) goto EXIT; + } + if (fdebugcmd) { + fprintf(fpdbg,"lan_cmd(seq=%x) %02x %02x %02x %02x, (dlen=%d): ", + ipmi_hdr.seq_num, cmd,netfn,lun,sa,sdata); + dump_buf("cmd data",pdata,sdata,0); + } + if (fdebuglan > 2) + dbglog("calling _ipmilan_cmd(%02x,%02x)\n",cmd,netfn); + rlen = sizeof(cmd_rs); + rv = _ipmilan_cmd(pconn->sockfd, (struct sockaddr *)&_destaddr, + _destaddr_len, cmd, netfn, lun, sa, bus, pdata, sdata, + cmd_rs, &rlen, fdebugcmd); + } + + cc = cmd_rs[0]; + if (rv == 0 && cc == 0) { /* success */ + if (fdebugcmd) { + fprintf(fpdbg,"lan_rsp rv=0 cc=0 (rlen=%d): ",rlen); + dump_buf("cmd rsp",cmd_rs,rlen,0); + } + rlen--; + if (rlen > *sresp) { /*received data > receive buffer*/ + if (fdebugcmd) + printf("rlen(%d) > sresp(%d), truncated\n",rlen,*sresp); + rlen = *sresp; + } + memcpy(presp,&cmd_rs[1],rlen); + *sresp = rlen; + } else { /* error */ + if (fdebugcmd) + fprintf(fpdbg,"ipmicmd_lan: cmd=%02x rv=%d, cc=%02x, rlen=%d\n", + cmd,rv,cc,rlen); + presp[0] = 0; /*memset(presp,0,*sresp);*/ + *sresp = 0; + } + +EXIT: + *pcc = cc; + return(rv); +} /*end ipmicmd_lan()*/ + +/* + * ipmi_cmd_lan + * This is the entry point, called from ipmicmd.c + */ +int ipmi_cmd_lan(char *node, ushort cmd, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd) +{ + int rc, i; + uchar mycmd; + + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == cmd) break; + } + if (i >= NCMDS) { + fprintf(fperr, "ipmi_cmd_lan: Unknown command %x\n",cmd); + return(-1); + } + if (cmd >= CMDMASK) mycmd = (uchar)(cmd & CMDMASK); /* unmask it */ + else mycmd = (uchar)cmd; + if (fdebuglan > 2) + dbglog("ipmi_cmd_lan: cmd=%04x, mycmd=%02x\n",cmd,mycmd); + rc = ipmicmd_lan(node,mycmd,ipmi_cmds[i].netfn,ipmi_cmds[i].lun, + ipmi_cmds[i].sa, ipmi_cmds[i].bus, + pdata,sdata,presp,sresp,pcc,fdebugcmd); + return (rc); +} + +int ipmi_cmdraw_lan(char *node, uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd) +{ + int rc; + if (fdebuglan > 2) + dbglog("ipmi_cmdraw_lan: cmd=%02x, netfn=%02x\n",cmd,netfn); + /* bus is not used for lan */ + rc = ipmicmd_lan(node, cmd, netfn, lun, sa, bus, + pdata,sdata,presp,sresp,pcc,fdebugcmd); + return (rc); +} + + +SockType lan_get_fd(void) +{ + return(pconn->sockfd); +} + +/* static SOL v1.5 encryption routines */ + +static void sol15_cipherinit( uchar SeedCount, char *password, uint32 out_seq) +{ + uchar temp[ 40 ]; /* 16 + 4 + 8 + 4 = 32 bytes */ + int i; + + i = SeedCount & 0x0f; + + srand((unsigned int)time(NULL)); + g_Seed[i] = (int32_t)rand(); + + if (password == NULL) + memset(&temp[0], 0, 16); + else memcpy(&temp[0], password,16); /*16-byte password*/ + h2net(g_Seed[i],&temp[16],4); /*4-byte seed */ + memset(&temp[20], 0, 8 ); /*8-byte pad*/ + h2net(out_seq,&temp[28],4); /*4-byte seq num */ + md5_sum(temp,32, g_Cipher[i]); +} + +#ifdef NOT_USED +static void sol15_encrypt( uchar *dst, uchar *src, int len, uchar SeedCount ) +{ + uchar cipher; + unsigned int val; + int i; + + SeedCount &= 0x0f; + if ( sol_Encryption ) { + for (i = 0; i < len; i++, dst++, src++) { + cipher = g_Cipher[ SeedCount ][ (i & 0x0f) ]; + val = (*src) << (cipher & 0x07); + *dst = (uchar)((val | (val >> 8)) ^ cipher); + } + } else { + memcpy( dst, src, len ); + } +} + +static void sol15_decrypt( uchar *dst, uchar *src, int len, uchar SeedCount ) +{ + uchar cipher; + unsigned int val; + int i; + SeedCount &= 0x0f; + if ( sol_Encryption ) { + for (i = 0; i < len; i++, dst++, src++) { + cipher = g_Cipher[ SeedCount ][ (i & 0x0f) ]; + val = ((*src) ^ cipher) << 8; + val >>= (cipher & 0x07); + *dst = (uchar)((val >> 8) | val); + } + } else { + memcpy( dst, src, len ); + } +} +#endif + +/* + * lan_get_sol_data + * Called before ACTIVATE_SOL1 command + */ +void lan_get_sol_data(uchar fEnc, uchar seed_cnt, uint32 *seed) +{ + if (seed_cnt != sol_seed_cnt && (seed_cnt < 16)) + sol_seed_cnt = seed_cnt; + pconn->start_out_seq = ipmi_hdr.seq_num; + sol_snd_seq = (uchar)pconn->start_out_seq; + sol15_cipherinit(sol_seed_cnt, gpswd, pconn->start_out_seq); + *seed = g_Seed[sol_seed_cnt]; + if (fdebuglan > 2) + dbglog("lan_get_sol_data: %02x %02x %02x\n", /*SOL*/ + fEnc, seed_cnt, ipmi_hdr.seq_num); +} + +/* + * lan_set_sol_data + * Called after ACTIVATE_SOL1 response received + */ +void lan_set_sol_data(uchar fenc, uchar auth, uchar seed_cnt, + int insize, int outsize) +{ + if (fdebuglan > 2) + dbglog("lan_set_sol_data: %02x %02x %02x %02x\n", /*SOL*/ + auth,seed_cnt,insize,outsize); + if (fenc || (auth & 0x07) == 1) { + sol_op = 0x80; /*OEM encryption*/ + sol_Encryption = 1; + } else { + sol_op = 0x00; /*no encryption*/ + sol_Encryption = 0; + } + if (seed_cnt != sol_seed_cnt && (seed_cnt < 16)) { + /* if seed count changed, re-init the cipher. */ + sol_seed_cnt = seed_cnt; + sol15_cipherinit(sol_seed_cnt, gpswd, pconn->start_out_seq); + } +} + +/* + * lan_send_sol + * buffer contains characters entered at console. + * build an SOL data frame, which ends up + * calling _send_lan_cmd(). + * + * SOL 1.5 Message Format + * 0 : Packet Sequence Number + * 1 : Packet ack/nak seq num (recvd) + * 2 : Character offset (of recvd) + * 3 : Seed count + * 4 : Operation/Status + */ +int lan_send_sol( uchar *buffer, int len, SOL_RSP_PKT *rsp) +{ + int rv = -1; + int ilen; + uchar idata[IPMI_REQBUF_SIZE]; /*=80 bytes*/ + uchar *pdata; + int hlen, msglen; + int sz; + IPMI_HDR *phdr; + int fdoauth = 1; + uchar iauth[16]; + uint32 sess_id_tmp; + uchar *psessid; + int flags; + + phdr = &ipmi_hdr; + hlen = 4 + 10 + 16; // was SOL_HLEN (14); + + pdata = &idata[0]; + memset(pdata,0,hlen); + memcpy(&pdata[0], phdr, 4); /* copy RMCP header to buffer */ + if (phdr->auth_type == IPMI_SESSION_AUTHTYPE_NONE) fdoauth = 0; + else fdoauth = 1; + if (fdoauth == 0 && phdr->auth_type != IPMI_SESSION_AUTHTYPE_NONE) + pdata[4] = IPMI_SESSION_AUTHTYPE_NONE; + else pdata[4] = phdr->auth_type; + memcpy(&pdata[5],&phdr->seq_num,4); /*session sequence number*/ + sess_id_tmp = phdr->sess_id | SOL_MSG; + memcpy(&pdata[9],&sess_id_tmp,4); /*session id*/ + if (fdoauth == 0) hlen -= 16; + + pdata = &idata[hlen]; + if (len == 0) { + pdata[0] = 0x00; /*ack for keepalive*/ + } else { + sol_snd_seq = (uchar)inc_sol_seq(sol_snd_seq); + pdata[0] = sol_snd_seq; + // sol15_encrypt(&pdata[5],buffer,len, sol_seed_cnt); + memcpy(&pdata[5],buffer,len); + } + pdata[1] = sol_rcv_seq; /* seq to ack*/ + pdata[2] = sol_rcv_cnt; /* num bytes ack'd */ + pdata[3] = sol_seed_cnt; + pdata[4] = 0x00; /*Operation/Status*/ + msglen = len + 5; + { + if (fdebuglan > 2) { /*SOL*/ + dbg_dump("lan_send_sol input", buffer,len,1); + dbglog("auth_type=%x/%x fdoauth=%d hlen=%d seq_num=%x enc=%d\n", + phdr->auth_type,gauth_type,fdoauth,hlen,phdr->seq_num, + sol_Encryption); + dbg_dump("send_sol buf", pdata,msglen,1); + } + if (fdoauth) { + psessid = (uchar *)&sess_id_tmp; + do_hash(phdr->password, psessid, &idata[hlen],msglen, + phdr->seq_num, phdr->auth_type, iauth); + /* copy hashed authcode to header */ + memcpy(&pdata[13],iauth,16); + } + } + idata[hlen-1] = (uchar)msglen; + ilen = hlen + msglen; + // rlen = sizeof(rdata);; + + if (fdebuglan > 2) + dbg_dump("lan_send_sol sendto",idata,ilen,1); + flags = 0; + sz = ipmilan_sendto(pconn->sockfd,idata,ilen,flags, + (struct sockaddr *)&_destaddr,_destaddr_len); + if (fdebuglan) dbglog("lan_send_sol, sent %d bytes\n",sz); + if (sz < 1) { + lasterr = get_LastError(); + if (fdebuglan) show_LastError("lan_send_sol",lasterr); + rv = LAN_ERR_SEND_FAIL; + os_usleep(0,5000); + } + else { + phdr->seq_num = inc_seq_num( phdr->seq_num ); + rv = 0; + } + + if (rsp != NULL) { + rsp->len = 0; +#ifdef RCV_EXTRA + if (rv == 0) { /*send was ok, try to receive*/ + rv = lan_recv_sol( rsp ); + if (fdebuglan) printf("lan_recv_sol ret = %d, len = %d\n",rv,rsp->len); + } +#endif + } + return(rv); +} + +int lan_keepalive( uchar bType ) +{ + int rv = 0; +#ifdef KAL_OK + if (bType == 2) { + /* don't try if no data sent yet */ + if (sol_snd_seq == 0) return(rv); + /* use lan_send_sol, but with 0 length data */ + rv = lan_send_sol(NULL,0,NULL); + } + else +#endif + { + uchar devrec[16]; + rv = ipmi_getdeviceid(devrec,16,0); + } + return(rv); +} + +int lan_recv_sol( SOL_RSP_PKT *rsp ) +{ + static uchar rsdata[MAX_BUFFER_SIZE]; /*LANplus allows 1024*/ + uchar rdata[MAX_BUFFER_SIZE]; + int rlen, hlen; + IPMI_HDR *phdr; + int fdoauth = 1; + uchar *pdata; + int itry; + int flags; + int rv = -1; + + phdr = &ipmi_hdr; + rsp->data = rsdata; + fdoauth = 0; + hlen = SOL_HLEN; + rlen = 0; + if (fdebuglan) + printf("lan_recv_sol, fdebug=%d, fpdbg=%p\n",fdebuglan,fpdbg); + // for (itry = 0; (itry < ipmi_try) && (rlen == 0); itry++) + for (itry = 0; (itry < 1) && (rlen == 0); itry++) + { + /* receive the response */ + rv = fd_wait(pconn->sockfd, ipmi_timeout,0); + if (rv != 0) { + if (fdebuglan) fprintf(fpdbg,"lan_recv_sol timeout\n"); + rv = LAN_ERR_RECV_FAIL; + os_usleep(0,5000); + continue; /* ok to retry */ + } + flags = RECV_MSG_FLAGS; + rlen = ipmilan_recvfrom(pconn->sockfd,rdata,sizeof(rdata),flags, + (struct sockaddr *)&_destaddr,&_destaddr_len); + if (rlen < 0) { + lasterr = get_LastError(); + if (fdebuglan) show_LastError("ipmilan_recvfrom",lasterr); + rv = rlen; /* -3 = LAN_ERR_RECV_FAIL */ + rlen = 0; + rsp->len = rlen; + if (lasterr == econnrefused) continue; /*try again*/ + else break; /* goto EXIT; */ + } else { /* successful receive */ + rv = 0; + if (fdebuglan) { + dump_buf("lan_recv_sol rdata",rdata,rlen,1); /*SOL*/ + } + if (rdata[4] == IPMI_SESSION_AUTHTYPE_NONE) { /* if AUTH_NONE */ + /* may have tried with auth, but denied, Dell 1855 */ + phdr->auth_type = IPMI_SESSION_AUTHTYPE_NONE; + hlen = SOL_HLEN; + } + net2h(&phdr->iseq_num,&rdata[5],4); /*incoming seq_num from hdr*/ + if (rlen >= hlen) { + pdata = &rdata[hlen]; + if (fdebuglan) + dump_buf("lan_recv_sol rsp",rdata,rlen,1); /*SOL*/ + rlen -= hlen; + if (rlen >= 5) { /*have some data*/ + /* 0=seq, 1=ack, 2=cnt, 3=ctl, 4=rsv */ + sol_rcv_seq = pdata[0]; + sol_rcv_ctl = pdata[3]; + pdata = &rdata[hlen+5]; + rlen -= 5; + /* rlen should match rdata[hlen-1] */ + sol_rcv_cnt = (uchar)rlen; + } + rsp->type = PAYLOAD_TYPE_SOL; + rsp->len = rlen; + // sol15_decrypt(rsp->data,pdata,rlen, sol_seed_cnt); + memcpy(rsp->data,pdata,rlen); + } else { + if (fdebuglan) + printf("lan_recv_sol rlen %d < %d\n",rlen,hlen); /*fpdbg*/ + rsp->type = PAYLOAD_TYPE_SOL; + rsp->len = 0; + } + break; + } + } /*end for*/ + return(rv); +} +#endif + +uchar +cksum(const uchar *buf, register int len) +{ + register uchar csum; + register int i; + + /* 8-bit 2s compliment checksum */ + csum = 0; + for (i = 0; i < len; i++) + csum = (csum + buf[i]) % 256; + csum = -csum; + return(csum); +} + +/* + * ipmi_cmd_ipmb() + * This is an entry point for IPMB indirect commands. + * Embed the command withn a SendMessage command. + * + * The iseq value needs to be the same as ipmi_hdr.swseq if + * the session is ipmilan, so this routine was moved here. + * However, ipmi_cmd_ipmb will also work ok via ipmi_cmdraw + * for local commands. + */ +int ipmi_cmd_ipmb(uchar cmd, uchar netfn, uchar sa, uchar bus, uchar lun, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + int rc, i, j; + uchar idata[IPMI_REQBUF_SIZE]; + uchar rdata[MAX_BUFFER_SIZE]; + uchar ilen; + int rlen; + uchar iseq; + IPMI_HDR *phdr; + char *pstr; + uchar fneedclear = 0; + uchar cc; + + if (fdebugcmd) printf("ipmi_cmd_ipmb(%02x,%02x,%02x,%02x,%02x) sdata=%d\n", + cmd,netfn,sa,bus,lun,sdata); + phdr = &ipmi_hdr; + iseq = phdr->swseq; + i = 0; + idata[i++] = bus; + j = i; + idata[i++] = sa; /*rsAddr (target)*/ + idata[i++] = (netfn << 2) | (lun & 0x03); /*metFm/rsLUN*/ + idata[i++] = cksum(&idata[j],2); + j = i; + idata[i++] = bmc_sa; /* rqAddr (main sa) */ + idata[i++] = (iseq << 2) | SMS_LUN; /*rqSeq num, SMS Message LUN = 0x02*/ + idata[i++] = cmd; + if (sdata > 0) { + memcpy(&idata[i],pdata,sdata); + i += sdata; + } + idata[i] = cksum(&idata[j],(i - j)); + ilen = ++i; + rlen = sizeof(rdata); + rc = ipmi_cmdraw(IPMB_SEND_MESSAGE,NETFN_APP, bmc_sa,PUBLIC_BUS,BMC_LUN, + idata, ilen, rdata, &rlen, pcc, fdebugcmd); + if (rc == 0x83 || *pcc == 0x83) { /*retry*/ + rlen = sizeof(rdata); + rc = ipmi_cmdraw(IPMB_SEND_MESSAGE,NETFN_APP, bmc_sa,PUBLIC_BUS,BMC_LUN, + idata, ilen, rdata, &rlen, pcc, fdebugcmd); + } + if (fdebugcmd) { + if (rc == 0 && *pcc == 0) + dump_buf("ipmb sendmsg ok",rdata,rlen,0); + else { + if (*pcc == 0x80) { pstr = "Invalid session handle"; } + else if (*pcc == 0x81) pstr = "Lost Arbitration"; + else if (*pcc == 0x82) pstr = "Bus Error"; + else if (*pcc == 0x83) pstr = "NAK on Write"; + else pstr = ""; + fprintf(fpdbg,"ipmb sendmsg error %d, cc %x %s\n",rc,*pcc,pstr); + } + } + if (presp == NULL || sresp == NULL) return(LAN_ERR_INVPARAM); + if (rc != 0 || *pcc != 0) { *sresp = 0; return(rc); } + if (*sresp < 0) return(LAN_ERR_TOO_SHORT); + + /* sent ok, now issue a GET_MESSAGE command to get the response. */ + for (i = 0; i < 10; i++) + { + rlen = sizeof(rdata); + rc = ipmi_cmdraw(IPMB_GET_MESSAGE,NETFN_APP, bmc_sa,PUBLIC_BUS,BMC_LUN, + idata, 0, rdata, &rlen, pcc, fdebugcmd); + if (fdebugcmd) printf("ipmb get_message rc=%d cc=%x\n",rc,*pcc); + if (rc == 0x80 || *pcc == 0x80) /*empty, so retry*/; + else if (rc == 0x83 || *pcc == 0x83) /*busy, so retry*/; + else break; /* done w success or error */ +#ifdef DOS + ; /*short wait*/ +#else + fd_wait(0,0,10); /* wait 1 msec before retry */ +#endif + /* will retry up to 10 msec for a get_message response on ipmb */ + } + if (rc == 0 && *pcc == 0) { + if (fdebugcmd) + dump_buf("ipmb getmsg ok",rdata,rlen,0); + i = 0; + if (rlen >= 8) { /* strip out the getmsg header */ + *pcc = rdata[6]; + rlen -= 8; + i = 7; + } + /* copy the data */ + if (rlen > *sresp) rlen = *sresp; + memcpy(presp,&rdata[i],rlen); + } else { + if (*pcc == 0x80) pstr = "buffer empty"; + else { fneedclear = 1; pstr = ""; } + if (fdebugcmd) + fprintf(fpdbg,"ipmb getmsg[%d] error %d, cc %x %s\n",i,rc,*pcc,pstr); + if (fneedclear) { /* Clear pending message flags */ + idata[0] = 0x03; /* clear EvtMsgBuf & RecvMsgQueue */ + rlen = 16; + rc = ipmi_cmdraw(IPMB_CLEAR_MSGF, NETFN_APP, + bmc_sa, PUBLIC_BUS,BMC_LUN, + idata, 1, rdata, &rlen, &cc, fdebugcmd); + } + rlen = 0; + } + *sresp = rlen; + return(rc); +} +/* end ipmilan.c */ + diff --git a/util/ipmilan.h b/util/ipmilan.h new file mode 100644 index 0000000..9e92e55 --- /dev/null +++ b/util/ipmilan.h @@ -0,0 +1,83 @@ +/*********************************************** + * ipmilan.h + * + * Definitions and data structures for the + * IPMI LAN interface + * + ***********************************************/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2006, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ +#ifndef IPMILAN_H_ +#define IPMILAN_H_ + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif +#define SOL_HDR_LEN 30 /*SOL 1.5 HDR: 4(rmcp) + 9 + 1 + 5(sol) */ +#define RQ_HDR_LEN 30 +#define RQ_LEN_MAX 200 /*see IPMI_REQBUF_SIZE, was 25 */ +#define RS_LEN_MAX 200 /*see IPMI_RSPBUF_SIZE */ +/* Note that the send buffer is [RQ_LEN_MAX+RQ_HDR_LEN+7] = 62 */ +/* Note that the receive buffer is [RS_LEN_MAX+RQ_HDR_LEN+7] = 237 */ +#define SEND_BUF_SZ (RQ_LEN_MAX+RQ_HDR_LEN+7+8+8) /*RQ_LEN+53= 78*/ +#define RECV_BUF_SZ (RS_LEN_MAX+RQ_HDR_LEN+7+8+8) /*RS_LEN+53=253*/ +/* #define IPMI_LAN_SEQ_NUM_MAX 0x3F * only for gnulan */ +#define RMCP_PRI_RMCP_PORT 0x26F + +#define PAYLOAD_TYPE_SOL 0x01 + +/* IPMI commands used for LAN sessions */ +#define CMD_GET_CHAN_AUTH_CAP 0x38 +#define CMD_GET_SESSION_CHALLENGE 0x39 +#define CMD_ACTIVATE_SESSION 0x3A +#define CMD_SET_SESSION_PRIV 0x3B +#define CMD_CLOSE_SESSION 0x3C +#define CMD_GET_MESSAGE 0x33 +#define CMD_SEND_MESSAGE 0x34 + +/* see ipmicmd.h for LAN_ERR definitions */ + +int ipmi_open_lan(char *node, char *user, char *pswd, int fdebugcmd); +int ipmi_close_lan(char *node); +int ipmi_flush_lan(char *node); +int ipmi_cmd_lan(char *node, ushort cmd, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +int ipmi_cmdraw_lan(char *node, uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd); +int ipmicmd_lan(char *node, uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd); +int ipmi_cmd_ipmb(uchar cmd, uchar netfn, uchar sa, uchar bus, uchar lun, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); + +#endif // IPMILAN_H_ diff --git a/util/ipmilan2.c b/util/ipmilan2.c new file mode 100644 index 0000000..0ff2fac --- /dev/null +++ b/util/ipmilan2.c @@ -0,0 +1,68 @@ +/* + * ipmilan2.c + * + * Interface to call libintf_lanplus from ipmitool to do RMCP+ protocol. + * + * 01/09/07 Andy Cress - created + * 02/22/07 Andy Cress - initialize cipher_suite to 3 (was 0) + */ +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> +#if defined(LINUX) || defined(BSD) +#include <sys/time.h> +#endif + +#undef HAVE_LANPLUS + +// #define DEBUG 1 +#ifndef HAVE_LANPLUS +/* No lanplus, so stub these functions returning errors. */ +#define uchar unsigned char +#define ushort unsigned short +#define LAN_ERR_INVPARAM -8 +#define LOG_WARN 4 +#define LOG_MSG_LENGTH 1024 /*usu. ipmicmd.h*/ +int verbose = 0; +char fdbglog = 0; +void set_loglevel(int level); +void lprintf(int level, const char * format, ...); + +int ipmi_open_lan2(char *node, char *user, char *pswd, int fdebugcmd) +{ if (fdebugcmd) verbose = 1; return(LAN_ERR_INVPARAM); } + +int ipmi_close_lan2(char *node) +{ return(LAN_ERR_INVPARAM); } + +int ipmi_cmdraw_lan2(char *node, uchar cmd, uchar netfn, uchar lun, + uchar sa, uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd) +{ return(LAN_ERR_INVPARAM); } + +int ipmi_cmd_lan2(char *node, ushort cmd, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd) +{ return(LAN_ERR_INVPARAM); } + +int lan2_send_sol( uchar *payload, int len, void *rsp) +{ return(LAN_ERR_INVPARAM); } +int lan2_recv_sol( void *rsp ) +{ return(LAN_ERR_INVPARAM); } +int lan2_keepalive(int type, void *rsp) +{ return(LAN_ERR_INVPARAM); } +void lan2_recv_handler( void *rs ) +{ return; } +void lan2_set_sol_data(int insize, int outsize, int port, void *handler, + char esc_char) +{ return; } +int lan2_get_fd(void) { return(1); } +void lanplus_set_recvdelay( int delay ) { return; } +long lan2_get_latency( void ) { return(1); } +int lan2_send_break( void *rsp) { return(LAN_ERR_INVPARAM); } +int lan2_send_ctlaltdel( void *rsp) { return(LAN_ERR_INVPARAM); } + +#else /* else HAVE_LANPLUS is defined */ + +#endif + +/* end ipmilan2.c */ diff --git a/util/ipmilan2.h b/util/ipmilan2.h new file mode 100644 index 0000000..aaa5318 --- /dev/null +++ b/util/ipmilan2.h @@ -0,0 +1,62 @@ +/*********************************************** + * ipmilan2.h + * + * Definitions and data structures for the + * IPMI 2.0 LAN interface + * + ***********************************************/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2006, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ +#ifndef IPMILAN2_H_ +#define IPMILAN2_H_ + +#include "ipmilan.h" + +#define IPMI_AUTH_RAKP_NONE 0x00 +#define IPMI_INTEGRITY_NONE 0x00 +#define IPMI_CRYPT_NONE 0x00 + +int ipmi_open_lan2(char *node, char *user, char *pswd, int fdebugcmd); +int ipmi_close_lan2(char *node); +int ipmi_cmd_lan2(char *node, ushort cmd, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +int ipmi_cmdraw_lan2(char *node, uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd); +int ipmicmd_lan2(char *node, uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd); +int ipmi_cmd_ipmb2(uchar cmd, uchar netfn, uchar sa, uchar bus, uchar lun, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); + + +#endif // IPMILAN2_H_ diff --git a/util/ipmilanplus.c b/util/ipmilanplus.c new file mode 100644 index 0000000..771c7e7 --- /dev/null +++ b/util/ipmilanplus.c @@ -0,0 +1,790 @@ +/* + * ipmilanplus.c + * + * Interface to call libintf_lanplus from ipmitool to do RMCP+ protocol. + * + * 01/09/07 Andy Cress - created + * 02/22/07 Andy Cress - initialize cipher_suite to 3 (was 0) + */ +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> +#if defined(LINUX) || defined(BSD) || defined(MACOS) +#include <sys/time.h> +#endif + +// #define DEBUG 1 +int verbose = 0; +char fdbglog = 0; + +#ifndef HAVE_LANPLUS +#ifdef WIN32 +#include <windows.h> +extern int strncasecmp(char *s1, char *s2, int n); /*ipmicmd.c*/ +#define snprintf _snprintf +#define SockType SOCKET +#else +#define SockType int +#endif +/* No lanplus, so stub these functions returning errors. */ +#define uchar unsigned char +#define ushort unsigned short +#define LAN_ERR_INVPARAM -8 +#define LOG_MSG_LENGTH 1024 /*usu. ipmicmd.h*/ +struct valstr { /*usually in ipmicmd.h*/ + ushort val; + char * str; +}; +struct oemvalstr { + unsigned int oem; + ushort val; + const char * str; +}; +int ipmi_open_lan2(char *node, char *user, char *pswd, int fdebugcmd) +{ if (fdebugcmd) verbose = 1; return(LAN_ERR_INVPARAM); } + +int ipmi_close_lan2(char *node) +{ return(LAN_ERR_INVPARAM); } + +int ipmi_cmdraw_lan2(char *node, uchar cmd, uchar netfn, uchar lun, + uchar sa, uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd) +{ return(LAN_ERR_INVPARAM); } + +int ipmi_cmd_lan2(char *node, ushort cmd, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd) +{ return(LAN_ERR_INVPARAM); } + +int lan2_send_sol( uchar *payload, int len, void *rsp) +{ return(LAN_ERR_INVPARAM); } +int lan2_recv_sol( void *rsp ) +{ return(LAN_ERR_INVPARAM); } +int lan2_keepalive(int type, void *rsp) +{ return(LAN_ERR_INVPARAM); } +void lan2_recv_handler( void *rs ) +{ return; } +void lan2_set_sol_data(int insize, int outsize, int port, void *handler, + char esc_char) +{ return; } +SockType lan2_get_fd(void) { return(1); } +void lanplus_set_recvdelay( int delay ) { return; } +long lan2_get_latency( void ) { return(1); } +int lan2_send_break( void *rsp) { return(LAN_ERR_INVPARAM); } +int lan2_send_ctlaltdel( void *rsp) { return(LAN_ERR_INVPARAM); } + +#else /* else HAVE_LANPLUS is defined */ + +#include "ipmilanplus.h" +#include "ipmicmd.h" +void set_loglevel(int level); /*defined in subs.c*/ +void lprintf(int level, const char * format, ...); +// #define LOG_WARN 4 +// #define LOG_INFO 6 + +#ifdef METACOMMAND +extern void dbglog( char *pattn, ... ); /*from isolconsole.c*/ +extern void sol_output_handler(void *rsp); /*from isolconsole.c*/ +extern void dbg_dump(char *tag, uchar *pdata, int len, int fascii); +#else +static void dbglog( char *pattn, ... ) { return; } +static void sol_output_handler(void *rsp) { return; } +static void dbg_dump(char *tag, uchar *pdata, int len, int fascii) { return; } +#endif +int ipmi_close_lan2(char *node); /*prototype*/ +extern char *gnode; /* from ipmicmd.c */ +extern char *guser; /* from ipmicmd.c */ +extern char *gpswd; /* from ipmicmd.c */ +extern int gauth_type; /* from ipmicmd.c */ +extern int gpriv_level; /* from ipmicmd.c */ +extern int gshutdown; /* from ipmicmd.c */ +extern int gcipher_suite; /*from ipmicmd.c, see table 22-19 IPMI 2.0 spec*/ +extern FILE *fpdbg; /* == stdout, from ipmicmd.c */ +extern FILE *fperr; /* == stderr, from ipmicmd.c */ +extern FILE *fplog; /* from ipmicmd.c */ +extern ipmi_cmd_t ipmi_cmds[]; /* from ipmicmd.c */ +//extern char lan2_nodename[]; /*from lib/lanplus/lanplus.c */ +extern struct ipmi_intf ipmi_lanplus_intf; /*from libintf_lanplus.a*/ + +typedef struct { + int type; + int len; + char *data; + } SOL_RSP_PKT; +typedef struct { + struct ipmi_intf *intf; + SockType lan2_fd; + uchar sol_seq; /*sending SOL sequence num, will call inc_sol_seq*/ + uchar sol_len; /*sending SOL num chars */ + uchar sol_seq_acked; /*last acked sent SOL sequence num*/ + uchar sol_rseq; /*received SOL sequence num*/ + uchar sol_rlen; /*received SOL num chans*/ + } LAN2_CONN; /*see also IPMI_HDR below*/ + +static int loglvl = LOG_WARN; /*3=LOG_ERR 4=LOG_WARN 6=LOG_INFO 7=LOG_DEBUG*/ +static LAN2_CONN conn = {NULL,0,0,0,0,0,0}; +static LAN2_CONN *pconn = &conn; +// static SockType lan2_fd = 0; +// static struct ipmi_intf *intf = NULL; +static uchar sol_seq = 0; /*sending SOL sequence num, will call inc_sol_seq*/ +static uchar sol_len = 0; /*sending SOL num chars */ +static uchar sol_seq_acked = 0; /*last acked sent SOL sequence num*/ +static uchar sol_rseq = 0; /*received SOL sequence num*/ +static uchar sol_rlen = 0; /*received SOL num chans*/ +static uchar chars_to_resend = 0; +static long lan2_latency = 0; + +// #define LAN_ERR_INVPARAM -8 +#define PSWD_MAX 16 + +#if defined(WIN32) +/* Windows does not have gettimeofday, so do it here */ +#include <windows.h> +#define UNIX_EPOCH_USEC 11644473600000000ULL +struct timezone +{ + int tz_minuteswest; + int tz_dsttime; +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + unsigned __int64 nusec, tmpres = 0; + static int tzflag = 0; + + if (tv != NULL) { + GetSystemTimeAsFileTime(&ft); + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + nusec = tmpres / 10; /*convert 100-nanosec into microseconds*/ + nusec -= UNIX_EPOCH_USEC; /*windows -> unix epoch*/ + tv->tv_sec = (long)(nusec / 1000000UL); + tv->tv_usec = (long)(nusec % 1000000UL); + } + + if (tz != NULL) { + if (!tzflag) { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + return 0; +} +#endif + +#if defined(WIN32) || defined(SOLARIS) +#ifdef OLD +/* Now moved to lib/lanplus/lanplus.c */ +void ipmilanplus_init(struct ipmi_intf *intf) +{ + strcpy(intf->name,"lanplus"); + intf->setup = ipmi_lanplus_setup; + intf->open = ipmi_lanplus_open; + intf->close = ipmi_lanplus_close; + intf->sendrecv = ipmi_lanplus_send_ipmi_cmd; + intf->recv_sol = ipmi_lanplus_recv_sol; + intf->send_sol = ipmi_lanplus_send_sol; + intf->keepalive = ipmi_lanplus_keepalive; + intf->target_addr = IPMI_BMC_SLAVE_ADDR; /*0x20*/ + intf->my_addr = IPMI_BMC_SLAVE_ADDR; /*0x20*/ +} +#else +extern void ipmilanplus_init(struct ipmi_intf *intf); +#endif +#endif + +struct ipmi_intf * ipmi_intf_load(char * name) +{ + if (strcmp(name,"lanplus") == 0) { +#if defined(WIN32) || defined(SOLARIS) + /* initialize the intf */ + ipmilanplus_init(&ipmi_lanplus_intf); +#endif + return (&ipmi_lanplus_intf); + } + else return (NULL); +} + +long lan2_get_latency(void) +{ + return(lan2_latency); +} + +static void set_latency( struct timeval *t1, struct timeval *t2, long *latency) +{ + long nsec; + nsec = t2->tv_sec - t1->tv_sec; + if ((ulong)(nsec) > 1) nsec = 1; + *latency = nsec*1000 + (t2->tv_usec - t1->tv_usec)/1000; +} + +/* + * ipmi_open_lan2 + */ +int ipmi_open_lan2(char *node, char *puser, char *pswd, int fdebugcmd) +{ + char *user = ""; + int rv = -1; + size_t n; + struct ipmi_intf *intf; + + if (puser != NULL) user = puser; +#ifdef DEBUG + if (fdbglog && fdebugcmd) fdebugcmd = 3; /*full debug*/ + else if (fdbglog) fdebugcmd = 2; /*special log only from isolconsole.c*/ + else if (fdebugcmd) fdebugcmd = 1; /*debug, no packets*/ + if (fdebugcmd) fdebugcmd = 4; /*max debug*/ +#endif + switch (fdebugcmd) { + case 4: /* max debug */ + loglvl = 8; /* 8=(LOG_DEBUG=1, max), 7=LOG_DEBUG */ + verbose = 8; /* usually 0 or 1, but max is 8. */ + break; + case 3: /* full debug */ + loglvl = 7; /* 7=LOG_DEBUG; max=8 (LOG_DEBUG+1) */ + verbose = 4; /* show packets */ + break; + case 2: /* debug log file only*/ + loglvl = 6; /* 6=LOG_INFO, 4=LOG_WARN */ + verbose = 1; /* usually 0 or 1, but could be up to 8. */ + break; + case 1: /* debug, no packets */ + loglvl = 7; /* 7=LOG_DEBUG; max=8 (LOG_DEBUG+1) */ + verbose = 1; /* usually 0 or 1, but could be up to 8. */ + break; + case 0: /* no debug*/ + /* by default loglevel = 4; (4=LOG_WARN) verbose = 0; */ + default: break; + } + if (fdbglog) + dbglog("ipmi_open_lan2(%s,%s,%p,%d) verbose=%d loglevel=%d\n", + node,user,pswd,fdebugcmd,verbose,loglvl); + else if (fdebugcmd) + fprintf(fpdbg,"ipmi_open_lan2(%s,%s,%p,%d) verbose=%d loglevel=%d\n", + node,user,pswd,fdebugcmd,verbose,loglvl); + set_loglevel(loglvl); + intf = pconn->intf; + + if (nodeislocal(node)) { + fprintf(fpdbg,"ipmi_open_lan2: node %s is local!\n",node); + rv = LAN_ERR_INVPARAM; + goto EXIT; + } else { + /* if attempting re-open to a new node, close the previous one. */ + if (intf != NULL) { + if ((intf->session != NULL) && + (strcmp(intf->session->hostname,node) != 0)) { + rv = ipmi_close_lan2(intf->session->hostname); + } + } + if ((gshutdown==0) || fdebugcmd) + fprintf(fpdbg,"Opening lanplus connection to node %s ...\n",node); + + rv = 0; + if (intf == NULL) { + /* fill in the intf structure */ + intf = ipmi_intf_load("lanplus"); + if (intf == NULL) return(-1); + } + if (intf->session == NULL && intf->opened == 0) { + if (intf->setup == NULL) return(-1); + rv = intf->setup(intf); /*allocates session struct*/ + if (fdebugcmd) printf("lan2 intf setup returned %d\n",rv); + } + + if (rv == 0) { + if (intf->open == NULL) return(-1); + if (intf->session == NULL) return(-1); + intf->session->authtype_set = (uchar)gauth_type; + intf->session->privlvl = (uchar)gpriv_level; + intf->session->cipher_suite_id = (uchar)gcipher_suite; + if (node != NULL) { strcpy(intf->session->hostname,node); } + if (user != NULL) { strcpy(intf->session->username,user); } + if (pswd == NULL || pswd[0] == 0) + intf->session->password = 0; + else { + intf->session->password = 1; + n = strlen(pswd); + if (n > PSWD_MAX) n = PSWD_MAX; + memset(intf->session->authcode,0,PSWD_MAX); + strncpy(intf->session->authcode, pswd, n); + } + rv = intf->open(intf); + if (fdebugcmd) + printf("lan2 open.intf(auth=%d,priv=%d,cipher=%d) returned %d\n", + gauth_type,gpriv_level,gcipher_suite, rv); + if (rv != -1) { /*success is >= 0*/ + sol_seq = 0; /*init new session, will call inc_sol_seq*/ + sol_len = 0; + sol_seq_acked = 0; + pconn->lan2_fd = intf->fd; /*not same as rv if Windows*/ + rv = 0; + } + } + pconn->intf = intf; + } +EXIT: + if (rv != 0) { + if ((gshutdown == 0) || fdebugcmd) + fprintf(fperr, "ipmi_open_lan2 error %d\n",rv); + } + return(rv); +} + +int ipmi_close_lan2(char *node) +{ + int rv = 0; + struct ipmi_intf *intf; + + intf = pconn->intf; + if (!nodeislocal(node)) { /* ipmilan, need to close & cleanup */ + if (fdbglog) dbglog("ipmi_close_lan2(%s) intf=%p\n",node,intf); + if (intf != NULL) { + if (intf->opened > 0 && intf->close != NULL) { + intf->close(intf); /* do the close */ + intf->fd = -1; + intf->opened = 0; + } + } + pconn->lan2_fd = -1; + sol_seq = 0; sol_len = 0; + sol_rseq = 0; sol_rlen = 0; + sol_seq_acked = 0; + } + return (rv); +} + +int ipmi_cmdraw_lan2(char *node, uchar cmd, uchar netfn, uchar lun, + uchar sa, uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd) +{ + int rc, n; + struct ipmi_rq req; + struct ipmi_rs *rsp; + struct timeval t1, t2; + struct ipmi_intf *intf = pconn->intf; + + if (fdebugcmd) verbose = 5; /* show packets */ +#ifdef DEBUG + if (fdebugcmd) verbose = 8; +#endif + if (intf == NULL || (intf->opened == 0)) { + rc = ipmi_open_lan2(node,guser,gpswd,fdebugcmd); + if (rc != 0) { + if (fdebugcmd) + fprintf(fperr, "ipmi_cmd_lan2: interface open error %d\n",rc); + return(rc); + } + intf = pconn->intf; + } + + /* do the command */ + memset(&req, 0, sizeof(req)); + req.msg.cmd = cmd; + req.msg.netfn = netfn; + req.msg.lun = lun; + req.msg.target_cmd = cmd; + req.msg.data = pdata; + req.msg.data_len = sdata; + intf->target_addr = sa; /*usu 0x20*/ + intf->target_lun = lun; + intf->target_channel = bus; + + + gettimeofday(&t1, NULL); + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) rc = -1; + else { + *pcc = rsp->ccode; + rc = rsp->ccode; + } + gettimeofday(&t2, NULL); + set_latency(&t1,&t2,&lan2_latency); + if (rc == 0) { + /* copy data */ + if (rsp->data_len > *sresp) n = *sresp; + else n = rsp->data_len; + memcpy(presp,rsp->data,n); + *sresp = n; + } else { + *sresp = 0; + if (fdebugcmd) + fprintf(fperr, "ipmi_cmd_lan2 error %d\n",rc); + } + return (rc); +} + +/* + * ipmi_cmd_lan2 + * This is the entry point, called from ipmicmd.c + */ +int ipmi_cmd_lan2(char *node, ushort cmd, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd) +{ + int rc, i; + uchar mycmd; + + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == cmd) break; + } + if (i >= NCMDS) { + fprintf(fperr, "ipmi_cmd_lan2: Unknown command %x\n",cmd); + return(-1); + } + if (cmd >= CMDMASK) mycmd = (uchar)(cmd & CMDMASK); /* unmask it */ + else mycmd = (uchar)cmd; + + rc = ipmi_cmdraw_lan2(node,mycmd, ipmi_cmds[i].netfn, ipmi_cmds[i].lun, + ipmi_cmds[i].sa, ipmi_cmds[i].bus, + pdata, sdata, presp, sresp, pcc, fdebugcmd); + return(rc); +} + + + +#define NOEM 4 +static struct { int id; char *name; } oem_list[NOEM] = { + {0x000157, "intelplus"}, /*VENDOR_INTEL*/ + {0x002A7C, "supermicro"}, /*VENDOR_SUPERMICRO*/ + /* { 0, "icts"}, *ICTS testware, needs user option*/ + {0x00000B, "hp"}, /*VENDOR_HP*/ + {0x000002, "ibm"} /*VENDOR_IBM*/ +}; +#ifdef METACOMMAND +extern int is_lan2intel(int vend, int prod); /*oem_intel.c*/ +#else +static int is_lan2intel(int vend, int prod) { + int rv = 0; + /* Older Intel BMCs use oem lan2i method, newer Intel FW uses lan2. */ + if (vend == VENDOR_INTEL) + if ((prod < 0x0030) || (prod == 0x0811)) rv = 1; + return(rv); +} +#endif + +int ipmi_oem_active(struct ipmi_intf * intf, const char * oemtype) +{ + int i, vend, prod, dtype; + get_mfgid(&vend,&prod); + dtype = get_driver_type(); + if (verbose) + lprintf(LOG_INFO,"oem_active(is_type==%s ?) vend=%x prod=%x", oemtype,vend,prod); + if (strncmp("intelplus", oemtype, strlen(oemtype)) == 0) { + /* special case to detect intelplus, not all Intel platforms */ + if (dtype == DRV_LAN2I) { + i = 1; + } else { + if (is_lan2intel(vend,prod)) { + i = 1; + set_driver_type("lan2i"); + } else { /* If iBMC, does not use intelplus */ + if (verbose) lprintf(LOG_WARN,"detected as not intelplus"); + i = 0; + } + } + if (verbose && i == 1) lprintf(LOG_WARN,"intelplus detected, vend=%x prod=%x",vend, prod); + return i; + } else { + // if (intf->oem == NULL) return 0; + for (i = 0; i < NOEM; i++) { + if (strncmp(oem_list[i].name,oemtype,strlen(oemtype)) == 0) + if (oem_list[i].id == vend) { + if (verbose) lprintf(LOG_WARN,"%s detected, vend=%x",oemtype,vend); + return 1; + } + } + } + return 0; +} + +/* + * lan2_validate_solrcv() + * Validate the SOL receive packet, and save received SOL info + * (recv seq num, char count) for use in send_sol header. + * return value (bitwise): + * 0x01 bit set: received packet is present with data len > 0 + * 0x02 bit set: received packet flags error in the previously sent packet + * 0x04 bit set: received packet is a retry of previous + * 0x08 bit set: break detected + */ +static int lan2_validate_solrcv(struct ipmi_rs * rs) +{ + int rv = 0; + if (rs == NULL) return(rv); + if (verbose > 4) + dbg_dump("rs_sol_hdr", + (uchar *)&rs->payload.sol_packet.packet_sequence_number,8,1); + chars_to_resend = 0; + sol_rlen = (uchar)rs->data_len; + if (sol_rlen > 4) sol_rlen -= 4; + else sol_rlen = 0; + if (sol_rlen > 0) rv |= 0x01; /* have a receive packet with dlen > 0 */ + if (rs->payload.sol_packet.packet_sequence_number != 0) { + if (rs->payload.sol_packet.packet_sequence_number == sol_rseq) { + lprintf(LOG_INFO,"received retry of sol_rseq %d, rlen=%d", + sol_rseq,sol_rlen); + /* do nothing because rs->data_len was set to 4 in lanplus */ + // rv |= 0x04; + /* return, don't process this again */ + return(rv); + } else sol_rseq = rs->payload.sol_packet.packet_sequence_number; + } + /* check for errors in previously sent packet */ + if (rs->payload.sol_packet.acked_packet_number != 0) { + if (rs->payload.sol_packet.acked_packet_number != sol_seq) rv |= 0x02; + else if ((rs->payload.sol_packet.accepted_character_count < sol_len) + && (sol_seq_acked < sol_seq)) { + lprintf(LOG_INFO,"partial_ack, seq=%d: acked=%d < sent=%d", + sol_seq,rs->payload.sol_packet.accepted_character_count, + sol_len); + chars_to_resend = sol_len - + rs->payload.sol_packet.accepted_character_count; + rv |= 0x02; + } + sol_seq_acked = rs->payload.sol_packet.acked_packet_number; + } + if (sol_seq != 0) { /*if we have sent something*/ + if (rs->payload.sol_packet.is_nack) rv |= 0x02; + if (rs->payload.sol_packet.transfer_unavailable) rv |= 0x02; + if (rs->payload.sol_packet.sol_inactive) rv |= 0x02; + if (rs->payload.sol_packet.transmit_overrun) rv |= 0x02; + } + if (rs->payload.sol_packet.break_detected) rv |= 0x08; + if (rv & 0x02) { + if (sol_seq_acked < sol_seq) { /*not already acked, needs retry*/ + lprintf(LOG_INFO,"need to retry sol_seq=%d, acked=%d len=%d rv=%x", + sol_seq,sol_seq_acked,sol_len,rv); + if (chars_to_resend == 0) chars_to_resend = sol_len; + } else rv &= 0xFD; + } + return(rv); +} + +/* + * lan2_set_sol_data + * called from isolconsole when SOL 2.0 session is activated. + */ +void lan2_set_sol_data(int insize, int outsize, int port, void *handler, + char esc_char) +{ + struct ipmi_intf *intf = pconn->intf; + if (intf == NULL) return; + lprintf(LOG_INFO,"setting lanplus intf params(%d,%d,%d,%p,%c)", + insize,outsize,port,handler,esc_char); + intf->session->sol_data.max_inbound_payload_size = (ushort)insize; + intf->session->sol_data.max_outbound_payload_size = (ushort)outsize; + intf->session->sol_data.port = (ushort)port; + intf->session->sol_data.sol_input_handler = handler; + intf->session->timeout = 1; /* lib/.../lanplus.h: IPMI_LAN_TIMEOUT =1sec*/ + intf->session->sol_escape_char = esc_char; /*usu '~'*/ +} + +int lan2_keepalive(int type, SOL_RSP_PKT *rsp) +{ + int rv = 0; + struct ipmi_intf *intf = pconn->intf; + if (fdbglog) dbglog("lan2_keepalive(%d,%p) called\n",type,rsp); /*++++*/ + if (intf == NULL) return -1; + if (rsp) rsp->len = 0; + if (type == 2) { /*send empty SOL data*/ + struct ipmi_v2_payload v2_payload; + struct ipmi_rs * rs = NULL; + memset(&v2_payload, 0, sizeof(v2_payload)); + v2_payload.payload.sol_packet.packet_sequence_number = 0; + v2_payload.payload.sol_packet.character_count = 0; + v2_payload.payload.sol_packet.acked_packet_number = 0; + v2_payload.payload.sol_packet.accepted_character_count = 0; + rs = intf->send_sol(intf, &v2_payload); + if (rs == NULL) { + rv = -1; + } else { /*may sometimes get data back*/ + rsp->type = rs->session.payloadtype; + rsp->len = rs->data_len; + rsp->data = rs->data; + lprintf(LOG_INFO, + "keepalive: rq_seq=%d rs_seq=%d (0x%02x) rseq=%d rlen=%d", + // v2_payload.payload.ipmi_request.rq_seq, + v2_payload.payload.sol_packet.packet_sequence_number, + rs->session.seq, rs->session.seq, + rs->payload.sol_packet.packet_sequence_number,rs->data_len); + rv = lan2_validate_solrcv(rs); + if (rv > 1) lprintf(LOG_INFO, + "keepalive: rv=%x need retry of sol_seq=%d(%d) sol_len=%d(%d)", + rv,v2_payload.payload.sol_packet.packet_sequence_number, + sol_seq,v2_payload.payload.sol_packet.character_count,sol_len); + rv = 0; /* 0 = have recv buffer to process*/ + } + } else { + rv = intf->keepalive(intf); /*get_device_id*/ + } + if (fdbglog) dbglog("lan2_keepalive rv = %d\n",rv); /*++++*/ + return(rv); +} + +static uchar inc_sol_seq( uchar lastseq ) +{ + uchar seq; + seq = lastseq + 1; + if (seq > 15) seq = 1; + pconn->intf->session->sol_data.sequence_number = seq; + return(seq); +} + +int lan2_send_break( SOL_RSP_PKT *rsp) +{ + struct ipmi_rs *rs; + static struct ipmi_v2_payload v2_payload; + int rv = 0; + struct ipmi_intf *intf = pconn->intf; + + if (intf == NULL) return -1; + if (rsp == NULL) return -1; + rsp->len = 0; /*just in case*/ + memset(&v2_payload, 0, sizeof(v2_payload)); + v2_payload.payload.sol_packet.character_count = 0; + v2_payload.payload.sol_packet.generate_break = 1; + + rs = intf->send_sol(intf, &v2_payload); + if (rs == NULL) { + rv = -1; + lprintf(LOG_INFO,"send_break error"); + } else { + rv = 0; + rsp->type = rs->session.payloadtype; + rsp->len = rs->data_len; + rsp->data = rs->data; + lprintf(LOG_INFO,"send_break(rs): sol_seq=%d rs_sol=%d " + "rs_seq=%d (0x%02x) rseq=%d rlen=%d", + v2_payload.payload.sol_packet.packet_sequence_number, + rs->payload.sol_packet.packet_sequence_number, + rs->session.seq, rs->session.seq, + rs->payload.sol_packet.packet_sequence_number,rs->data_len); + } + return(rv); +} + +int lan2_send_sol( uchar *payload, int len, SOL_RSP_PKT *rsp) +{ + struct ipmi_rs *rs; + static struct ipmi_v2_payload v2_payload; + int rv = 0; + struct ipmi_intf *intf = pconn->intf; + + if (rsp) rsp->len = 0; /*just in case*/ + if (intf == NULL) return -1; + memset(&v2_payload, 0, sizeof(v2_payload)); + memcpy(v2_payload.payload.sol_packet.data,payload,len); + sol_seq = inc_sol_seq(sol_seq); + sol_len = (uchar)len; + v2_payload.payload.sol_packet.packet_sequence_number = sol_seq; + v2_payload.payload.sol_packet.character_count = (uchar)len; +#ifdef TEST + /* Note that the lanplus layer already did auto-ack of sol recv pkts, + * but we can put the info in send_sol also for completeness. */ + /* Further debug shows that this doesn't matter, so skip it. */ + v2_payload.payload.sol_packet.acked_packet_number = sol_rseq; + v2_payload.payload.sol_packet.accepted_character_count = sol_rlen; + /* These flags were initialized to zero above via memset. */ + v2_payload.payload.sol_packet.is_nack = 0; + v2_payload.payload.sol_packet.assert_ring_wor = 0; + v2_payload.payload.sol_packet.generate_break = 0; + v2_payload.payload.sol_packet.deassert_cts = 0; + v2_payload.payload.sol_packet.deassert_dcd_dsr = 0; + v2_payload.payload.sol_packet.flush_inbound = 0; + v2_payload.payload.sol_packet.flush_outbound = 0; +#endif + lprintf(LOG_INFO,"send_sol(rq): sol_seq=%d acked=%d chars=%d len=%d", + v2_payload.payload.sol_packet.packet_sequence_number, + v2_payload.payload.sol_packet.acked_packet_number, + v2_payload.payload.sol_packet.accepted_character_count,len); + if (verbose > 4) + dbg_dump("rq_sol_hdr", + (uchar *)&v2_payload.payload.sol_packet.packet_sequence_number, + 10,1); + rs = intf->send_sol(intf, &v2_payload); + if (rs == NULL) { + rv = -1; + lprintf(LOG_INFO,"send_sol error (%d bytes)",len); + } else { + rsp->type = rs->session.payloadtype; + rsp->len = rs->data_len; + rsp->data = rs->data; + lprintf(LOG_INFO,"send_sol(rs): sol_seq=%d rs_sol=%d rs_seq=%d (0x%02x)" + " rseq=%d rlen=%d", + v2_payload.payload.sol_packet.packet_sequence_number, + // v2_payload.payload.sol_packet.acked_packet_number, + rs->payload.sol_packet.packet_sequence_number, + rs->session.seq, rs->session.seq, + rs->payload.sol_packet.packet_sequence_number,rs->data_len); + rv = lan2_validate_solrcv(rs); + if (rv > 1) lprintf(LOG_INFO, + "send_sol: rv=%x sol_seq=%d(%d) sol_len=%d(%d) not acked", + rv,v2_payload.payload.sol_packet.packet_sequence_number, + sol_seq,v2_payload.payload.sol_packet.character_count,sol_len); + rv = 0; /* 0 = have recv buffer to process*/ + } + return(rv); +} + +int lan2_recv_sol( SOL_RSP_PKT *rsp ) +{ + struct ipmi_rs * rs; + int rv; + struct ipmi_intf *intf = pconn->intf; + + if (rsp == NULL) return -1; + rsp->len = 0; + if (intf == NULL) return -1; + rs = intf->recv_sol(intf); + if (rs == NULL) return -1; + rsp->type = rs->session.payloadtype; + rsp->len = rs->data_len; + rsp->data = rs->data; + lprintf(LOG_INFO,"recv_sol: rs_sol=%d rs_seq=%d (0x%02x) rseq=%d rlen=%d", + rs->payload.sol_packet.packet_sequence_number, + rs->session.seq, rs->session.seq, + rs->payload.sol_packet.packet_sequence_number,rs->data_len); + rv = lan2_validate_solrcv(rs); + if (rv > 1) { + lprintf(LOG_INFO, + "recv_sol: rv=%x sol_seq=%d sol_len=%d not acked", + rv,sol_seq,sol_len); + } + return(rsp->len); +} + +void lan2_recv_handler( void *rs0) +{ + struct ipmi_rs *rs = rs0; + SOL_RSP_PKT rsp; + int rv; + + rsp.len = 0; + rsp.type = 0; + if (rs == NULL) return; + lprintf(LOG_INFO,"recv_handler: len=%d rs_seq=%d (0x%02x) rseq=%d rlen=%d", + rs->data_len, rs->session.seq, rs->session.seq, + rs->payload.sol_packet.packet_sequence_number,rs->data_len); + rsp.type = rs->session.payloadtype; + rsp.len = rs->data_len; + rsp.data = rs->data; + rv = lan2_validate_solrcv(rs); + if (rv > 1) lprintf(LOG_INFO, + "recv_handler: rv=%x sol_seq=%d sol_len=%d not acked", + rv,sol_seq,sol_len); + sol_output_handler(&rsp); + return; +} + +SockType lan2_get_fd(void) +{ + if (pconn->intf == NULL) return pconn->lan2_fd; + return(pconn->intf->fd); +} +#endif + +/* end ipmilanplus.c */ diff --git a/util/ipmilanplus.h b/util/ipmilanplus.h new file mode 100644 index 0000000..0003cf0 --- /dev/null +++ b/util/ipmilanplus.h @@ -0,0 +1,64 @@ +/* + * ipmilanplus.h: (a copy of ipmitool/ipmi_intf.h) + * + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef IPMILANPLUS_H +#define IPMILANPLUS_H + +#ifdef WIN32 +#include <windows.h> +#include <winsock.h> +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef int int32_t; +typedef uint32_t socklen_t; + +#else +#include <arpa/inet.h> +#include <sys/socket.h> +#include <netinet/in.h> +#endif + +/**************************************/ + +#define IPMI_BMC_SLAVE_ADDR 0x20 +#define IPMI_BUF_SIZE 1024 + +#ifdef HAVE_LANPLUS +#include "../lib/lanplus/lanplus_defs.h" +#endif + +void lanplus_set_sol_data(int insize, int outsize, int port); + +#endif /* IPMILANPLUS_H */ diff --git a/util/ipmild.c b/util/ipmild.c new file mode 100644 index 0000000..5ad54f2 --- /dev/null +++ b/util/ipmild.c @@ -0,0 +1,250 @@ +/*M* +// PVCS: +// $Workfile: ipmild.c $ +// $Revision: 1.0 $ +// $Modtime: 23 Feb 2005 15:20:14 $ +// $Author: arcress at users.sourceforge.net $ +// +// This implements support for the /dev/ldipmi native interface from +// the LanDesk IPMI driver. +// Requires linking with libldipmi.a, or equivalent. +// +// 02/23/05 ARC - created, but stubbed out, since the +// LanDesk libipmiapi.a isn't clean yet. + *M*/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2005, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#ifdef LINUX +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "ipmicmd.h" /* for uchar, NCMDS */ +// #define uchar unsigned char +#define MAX_NO_OF_RETRIES 3 + +// Request structure provided to SendTimedImbpRequest() +#pragma pack(1) +typedef struct { + uchar cmdType; // IMB command + uchar rsSa; // command destination address + uchar busType; // not used + uchar netFn; // IMB command class (network function) + uchar rsLun; // subsystem on destination + uchar * data; // command body + int dataLength; // body size +} IMBPREQUESTDATA; +#pragma pack() + +#ifdef LINK_LANDESK +/* typedef enum { 0, 1, 2, 3, 4, 5, 6 } ACCESN_STATUS; */ +/* Note that this routine name conflicts with ia_ imb routine. */ +extern int SendTimedImbpRequest ( + IMBPREQUESTDATA *reqPtr, + int timeOut, + uchar * respDataPtr, + int * respDataLen, + uchar * completionCode); +extern int initIPMI(); +extern int termIPMI(); +static int ipmi_timeout_ld = 100000; /*100 * 1000 ms = 100 sec */ +#endif + +extern FILE *fperr; /*defined in ipmicmd.c*/ +extern FILE *fpdbg; /*defined in ipmicmd.c*/ +extern ipmi_cmd_t ipmi_cmds[NCMDS]; +#ifdef TEST +static int ipmi_fd = -1; +#endif + +int ipmi_open_ld(char fdebugcmd) +{ + int rc = -1; +#ifdef TEST + char *pdev; + + if (ipmi_fd != -1) return(0); + pdev = "/dev/ldipmi"; + ipmi_fd = open(pdev, O_RDWR); + if (ipmi_fd == -1) { + if (fdebugcmd) printf("ipmi_open_ld: cannot open %s\n",pdev); + pdev = "/dev/ldipmi/0"; + ipmi_fd = open(pdev, O_RDWR); + } +#endif +#ifdef LINK_LANDESK + rc = initIPMI(); + if (rc != 0) { + if (fdebugcmd) printf("ipmi_open_ld: cannot open ldipmi, rc=%d errno=%d\n",rc,errno); + return(-1); + } + ipmi_fd = 1; /*show that open was ok*/ + if (fdebugcmd) printf("ipmi_open_ld: successfully opened ldipmi\n"); +#endif + return(rc); +} + +int ipmi_close_ld(void) +{ + int rc = 0; +#ifdef LINK_LANDESK + if (ipmi_fd != -1) { + termIPMI(); + ipmi_fd = -1; + } +#endif + return(rc); +} + +int ipmicmd_ld( uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd) +{ +#ifdef LINK_LANDESK + IMBPREQUESTDATA requestData; + int status = 0; + uchar * pc; + int sz, i; + + requestData.cmdType = cmd; + requestData.rsSa = sa; + requestData.busType = bus; + requestData.netFn = netfn; + requestData.rsLun = lun; + requestData.dataLength = sdata; + requestData.data = pdata; + + if (fdebugcmd) { + sz = sizeof(IMBPREQUESTDATA); + pc = (uchar *)&requestData.cmdType; + fprintf(fpdbg,"ipmicmd_ld: request (len=%d): ",sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + pc = requestData.data; + sz = requestData.dataLength; + fprintf(fpdbg," req.data=%p, dlen=%d: ", pc, sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + } + + if (ipmi_fd == -1) { + status = ipmi_open_ld(fdebugcmd); + if (status != 0) return(status); + } + + { + sz = *sresp; /* note that sresp must be pre-set */ + memset(presp, 0, sz); + for ( i =0 ; i < MAX_NO_OF_RETRIES; i++) + { + *sresp = sz; /* retries may need to re-init *sresp */ + if((status =SendTimedImbpRequest(&requestData, + ipmi_timeout_ld, presp, sresp, + pcc)) == 0 ) { + break; + } + if (fdebugcmd) // only gets here if error + fprintf(fpdbg,"ipmi_cmd_ld: sendImbRequest error status=%x, ccode=%x\n", + (uint)status, *pcc); + } + } + + if (fdebugcmd) { /* if debug, show both good and bad statuses */ + fprintf(fpdbg,"ipmi_cmd_ld: sendImbRequest status=%x, ccode=%x\n", + (uint)status, *pcc); + if (status == 0) { + uchar * pc; int sz; + sz = *sresp; + pc = (uchar *)presp; + fprintf(fpdbg,"ipmi_cmd_ld: response (len=%d): ",sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + } + } + + return(status); +#else + return(-1); +#endif +} /* end ipmicmd_ld() */ + +int ipmi_cmdraw_ld( uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd) +{ + int rc; + rc = ipmicmd_ld(cmd, netfn, lun, sa, bus, + pdata,sdata,presp,sresp,pcc,fdebugcmd); + return(rc); +} + +int ipmi_cmd_ld(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + int rc, i; + + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == cmd) break; + } + if (i >= NCMDS) { + fprintf(fperr, "ipmi_cmd_ld: Unknown command %x\n",cmd); + return(-1); + } + if (cmd >= CMDMASK) cmd = cmd & CMDMASK; /* unmask it */ + rc = ipmicmd_ld(cmd, ipmi_cmds[i].netfn, ipmi_cmds[i].lun, + ipmi_cmds[i].sa, ipmi_cmds[i].bus, + pdata,sdata,presp,sresp,pcc,fdebugcmd); + return(rc); +} + +#ifdef LINK_LANDESK +/* define extra stuff that the LanDesk library needs */ +void * _Unwind_Resume(void *context) +{ + printf("called Unwind_Resume\n"); + return(NULL); +} + +int __gxx_personality_v0(void *a) +{ + return(0); +} + +#endif + +#endif + diff --git a/util/ipmilipmi.c b/util/ipmilipmi.c new file mode 100644 index 0000000..89fa12e --- /dev/null +++ b/util/ipmilipmi.c @@ -0,0 +1,182 @@ +/*M* +// $Workfile: ipmilipmi.c $ +// $Revision: 0.1 $ +// $Modtime: 18 Oct 2010 15:20:14 $ +// $Author: arcress at users.sourceforge.net $ +// +// This implements support for the /dev/lipmi interface from +// the Solaris 8 & 9 LIPMI driver. +// +// 10/18/10 ARC - created + *M*/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2010 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#ifdef SOLARIS +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stropts.h> + +#include "ipmicmd.h" /* for uchar, NCMDS */ + +#define MAX_SEND_SIZE 34 +#define MAX_RECV_SIZE 33 /*TODO: compare with RECV_MAX_PAYLOAD_SIZE */ +#define IOCTL_IPMI_KCS_ACTION 0x01 +/* I_STR should be defined in stropts.h */ + +extern ipmi_cmd_t ipmi_cmds[NCMDS]; +static int ipmi_fd = -1; +static char *pdev = "/dev/lipmi"; + +#ifndef _SYS_STROPTS_H +/* see sys/stropts.h, sys/lipmi/lipmi_intf.h*/ +typedef struct strioctl { + int ic_cmd; + int ic_timout; + int ic_len; + char *ic_dp; +} strioctl_t; +#endif + +typedef struct bmc_req { + uchar fn; + uchar lun; + uchar cmd; + uchar datalength; + uchar data[MAX_SEND_SIZE]; +} bmc_req_t; + +typedef struct bmc_rsp { + uchar fn; + uchar lun; + uchar cmd; + uchar ccode; + uchar datalength; + uchar data[MAX_RECV_SIZE]; +} bmc_rsp_t; + +typedef struct lipmi_reqrsp { /*TODO: see sys/lipmi/lipmi_intf.h*/ + bmc_req_t req; + bmc_rsp_t rsp; +} lipmi_reqrsp_t; + + +int ipmi_open_lipmi(char fdebugcmd) +{ + int rc = -1; + + if (ipmi_fd != -1) return(0); + ipmi_fd = open(pdev, O_RDWR); + if (ipmi_fd < 0) { + if (fdebugcmd) printf("ipmi_open_lipmi: cannot open %s, errno=%d\n", + pdev,errno); + return(rc); + } + rc = 0; + if (fdebugcmd) printf("ipmi_open_lipmi: successfully opened\n"); + return(rc); +} + +int ipmi_close_lipmi(void) +{ + int rc = 0; + if (ipmi_fd != -1) { + close(ipmi_fd); + ipmi_fd = -1; + } + return(rc); +} + +int ipmi_cmdraw_lipmi( uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd) +{ + int rv = -1; + struct strioctl istr; + static struct lipmi_reqrsp reqrsp; + int len; + uchar cc; + + if (ipmi_fd == -1) return -1; + + memset(&reqrsp, 0, sizeof(reqrsp)); + reqrsp.req.fn = netfn; + reqrsp.req.lun = lun; + reqrsp.req.cmd = cmd; + reqrsp.req.datalength = sdata; + memcpy(reqrsp.req.data, pdata, sdata); + reqrsp.rsp.datalength = MAX_RECV_SIZE; + + istr.ic_cmd = IOCTL_IPMI_KCS_ACTION; + istr.ic_timout = 0; + istr.ic_dp = (char *)&reqrsp; + istr.ic_len = sizeof(struct lipmi_reqrsp); + + rv = ioctl(ipmi_fd, I_STR, &istr); + if (rv < 0) { + perror("LIPMI IOCTL: I_STR"); + return rv; + } + + cc = reqrsp.rsp.ccode; + len = reqrsp.rsp.datalength; + *pcc = cc; + *sresp = len; + if (cc == 0 && len > 0) + memcpy(presp, reqrsp.rsp.data, len); + return(rv); +} + +int ipmi_cmd_lipmi(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + int rc, i; + + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == cmd) break; + } + if (i >= NCMDS) { + printf("ipmi_cmd_lipmi: Unknown command %x\n",cmd); + return(-1); + } + if (cmd >= CMDMASK) cmd = cmd & CMDMASK; /* unmask it */ + rc = ipmi_cmdraw_lipmi(cmd, ipmi_cmds[i].netfn, ipmi_cmds[i].lun, + ipmi_cmds[i].sa, ipmi_cmds[i].bus, + pdata,sdata,presp,sresp,pcc,fdebugcmd); + return(rc); +} +#endif +/* end of ipmilipmi.c */ diff --git a/util/ipmims.cpp b/util/ipmims.cpp new file mode 100644 index 0000000..2ba0611 --- /dev/null +++ b/util/ipmims.cpp @@ -0,0 +1,638 @@ +/*M* +// $Workfile: ipmims.cpp $ +// $Revision: 1.0 $ +// $Modtime: 08 Sep 2008 13:31:14 $ +// $Author: arcress at users.sourceforge.net $ +// +// This implements support for the Microsoft Windows 2003 R2 IPMI driver. +// Note that this should be compiled with /TP (as C++). +// +// 09/08/08 ARCress - created. +// 04/27/11 Jay Krell - fixed WIN64-unsafe logic +// 09/30/13 ARCress - fixed Win2012 x64 SafeArrayDestroy fault +// + *M*/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2008, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +Copyright (c) 2013 Andy Cress <arcress at users.sourceforge.net> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#ifdef WIN32 +/* Microsoft IPMI drver is only valid in Windows */ +#define _WIN32_DCOM +#pragma once +#include <windows.h> +#include <stdio.h> +#include <iostream> //deprecated iostream.h +#include <Objbase.h> //ole32.lib +#include <comutil.h> +#include <Wbemcli.h> + +#ifdef ALONE +#define uchar unsigned char +#define ushort unsigned short +#define ulong unsigned long +#else +#include "ipmicmd.h" +extern "C" { extern ipmi_cmd_t ipmi_cmds[NCMDS]; } +#endif +static char fmsopen = 0; +static char fdebugms = 0; +static IWbemLocator *pLoc = 0; +static IWbemServices *pSvc = 0; +static IWbemClassObject* pClass = NULL; +static IEnumWbemClassObject* pEnumerator = NULL; +static IWbemClassObject* pInstance = NULL; +static VARIANT varPath; +#define NVAR 32 +/* Wbem error return codes, returned by WMI */ +#ifdef RES_ALL +#define NRES 82 +#else +#define NRES 10 +#endif +static struct { char *desc; int val; } res_list[NRES] = { +{"WBEM_E_FAILED", 0x80041001 }, +{"WBEM_E_NOT_FOUND", 0x80041002 }, +{"WBEM_E_ACCESS_DENIED", 0x80041003 }, +{"WBEM_E_PROVIDER_FAILURE", 0x80041004 }, +{"WBEM_E_TYPE_MISMATCH", 0x80041005 }, +{"WBEM_E_OUT_OF_MEMORY", 0x80041006 }, +{"WBEM_E_INVALID_CONTEXT", 0x80041007 }, +{"WBEM_E_INVALID_PARAMETER", 0x80041008 }, +{"WBEM_E_NOT_AVAILABLE", 0x80041009 }, +{"WBEM_E_CRITICAL_ERROR", 0x8004100A } +#ifdef RES_ALL +, +{"WBEM_E_CRITICAL_ERROR", 0x8004100A } , +{"WBEM_E_INVALID_STREAM", 0x8004100B }, +{"WBEM_E_NOT_SUPPORTED", 0x8004100C }, +{"WBEM_E_INVALID_SUPERCLASS", 0x8004100D }, +{"WBEM_E_INVALID_NAMESPACE", 0x8004100E }, +{"WBEM_E_INVALID_OBJECT", 0x8004100F }, +{"WBEM_E_INVALID_CLASS", 0x80041010 }, +{"WBEM_E_PROVIDER_NOT_FOUND", 0x80041011 }, +{"WBEM_E_INVALID_PROVIDER_REGISTRATION", 0x80041012 }, +{"WBEM_E_PROVIDER_LOAD_FAILURE", 0x80041013 }, +{"WBEM_E_INITIALIZATION_FAILURE", 0x80041014 }, +{"WBEM_E_TRANSPORT_FAILURE", 0x80041015 }, +{"WBEM_E_INVALID_OPERATION", 0x80041016 }, +{"WBEM_E_INVALID_QUERY", 0x80041017 }, +{"WBEM_E_INVALID_QUERY_TYPE", 0x80041018 }, +{"WBEM_E_ALREADY_EXISTS", 0x80041019 }, +{"WBEM_E_OVERRIDE_NOT_ALLOWED", 0x8004101A }, +{"WBEM_E_PROPAGATED_QUALIFIER", 0x8004101B }, +{"WBEM_E_PROPAGATED_PROPERTY", 0x8004101C }, +{"WBEM_E_UNEXPECTED", 0x8004101D }, +{"WBEM_E_ILLEGAL_OPERATION", 0x8004101E }, +{"WBEM_E_CANNOT_BE_KEY", 0x8004101F }, +{"WBEM_E_INCOMPLETE_CLASS", 0x80041020 }, +{"WBEM_E_INVALID_SYNTAX", 0x80041021 }, +{"WBEM_E_NONDECORATED_OBJECT", 0x80041022 }, +{"WBEM_E_READ_ONLY", 0x80041023 }, +{"WBEM_E_PROVIDER_NOT_CAPABLE", 0x80041024 }, +{"WBEM_E_CLASS_HAS_CHILDREN", 0x80041025 }, +{"WBEM_E_CLASS_HAS_INSTANCES", 0x80041026 }, +{"WBEM_E_QUERY_NOT_IMPLEMENTED", 0x80041027 }, +{"WBEM_E_ILLEGAL_NULL", 0x80041028 }, +{"WBEM_E_INVALID_QUALIFIER_TYPE", 0x80041029 }, +{"WBEM_E_INVALID_PROPERTY_TYPE", 0x8004102A }, +{"WBEM_E_VALUE_OUT_OF_RANGE", 0x8004102B }, +{"WBEM_E_CANNOT_BE_SINGLETON", 0x8004102C }, +{"WBEM_E_INVALID_CIM_TYPE", 0x8004102D }, +{"WBEM_E_INVALID_METHOD", 0x8004102E }, +{"WBEM_E_INVALID_METHOD_PARAMETERS", 0x8004102F }, +{"WBEM_E_SYSTEM_PROPERTY", 0x80041030 }, +{"WBEM_E_INVALID_PROPERTY", 0x80041031 }, +{"WBEM_E_CALL_CANCELLED", 0x80041032 }, +{"WBEM_E_SHUTTING_DOWN", 0x80041033 }, +{"WBEM_E_PROPAGATED_METHOD", 0x80041034 }, +{"WBEM_E_UNSUPPORTED_PARAMETER", 0x80041035 }, +{"WBEM_E_MISSING_PARAMETER_ID", 0x80041036 }, +{"WBEM_E_INVALID_PARAMETER_ID", 0x80041037 }, +{"WBEM_E_NONCONSECUTIVE_PARAMETER_IDS", 0x80041038 }, +{"WBEM_E_PARAMETER_ID_ON_RETVAL", 0x80041039 }, +{"WBEM_E_INVALID_OBJECT_PATH", 0x8004103A }, +{"WBEM_E_OUT_OF_DISK_SPACE", 0x8004103B }, +{"WBEM_E_BUFFER_TOO_SMALL", 0x8004103C }, +{"WBEM_E_UNSUPPORTED_PUT_EXTENSION", 0x8004103D }, +{"WBEM_E_UNKNOWN_OBJECT_TYPE", 0x8004103E }, +{"WBEM_E_UNKNOWN_PACKET_TYPE", 0x8004103F }, +{"WBEM_E_MARSHAL_VERSION_MISMATCH", 0x80041040 }, +{"WBEM_E_MARSHAL_INVALID_SIGNATURE", 0x80041041 }, +{"WBEM_E_INVALID_QUALIFIER", 0x80041042 }, +{"WBEM_E_INVALID_DUPLICATE_PARAMETER", 0x80041043 }, +{"WBEM_E_TOO_MUCH_DATA", 0x80041044 }, +{"WBEM_E_SERVER_TOO_BUSY", 0x80041045 }, +{"WBEM_E_INVALID_FLAVOR", 0x80041046 }, +{"WBEM_E_CIRCULAR_REFERENCE", 0x80041047 }, +{"WBEM_E_UNSUPPORTED_CLASS_UPDATE", 0x80041048 }, +{"WBEM_E_CANNOT_CHANGE_KEY_INHERITANCE", 0x80041049 }, +{"WBEM_E_CANNOT_CHANGE_INDEX_INHERITANCE", 0x80041050 }, +{"WBEM_E_TOO_MANY_PROPERTIES", 0x80041051 }, +{"WBEM_E_UPDATE_TYPE_MISMATCH", 0x80041052 }, +{"WBEM_E_UPDATE_OVERRIDE_NOT_ALLOWED", 0x80041053 }, +{"WBEM_E_UPDATE_PROPAGATED_METHOD", 0x80041054 }, +{"WBEM_E_METHOD_NOT_IMPLEMENTED", 0x80041055 }, +{"WBEM_E_METHOD_DISABLED", 0x80041056 }, +{"WBEMESS_E_REGISTRATION_TOO_BROAD", 0x80042001 }, +{"WBEMESS_E_REGISTRATION_TOO_PRECISE", 0x80042002 } +#endif +}; + +/* + * Microsoft_IPMI methods: + * void RequestResponse( + * [in] uint8 Command, + * [out] uint8 CompletionCode, + * [in] uint8 Lun, + * [in] uint8 NetworkFunction, + * [in] uint8 RequestData[], + * [out] uint32 ResponseDataSize, + * [in] uint32 RequestDataSize, + * [in] uint8 ResponderAddress, + * [out] uint8 ResponseData + * ); + * + * void SMS_Attention( + * [out] boolean AttentionSet, + * [out] uint8 StatusRegisterValue + * ); + */ + +static void cleanup_wmi(void) +{ + VariantClear(&varPath); + if (pInstance != NULL) pInstance->Release(); + if (pEnumerator != NULL) pEnumerator->Release(); + if (pClass != NULL) pClass->Release(); + if (pSvc != 0) pSvc->Release(); + if (pLoc != 0) pLoc->Release(); + CoUninitialize(); +} + +static void dumpbuf(uchar *p, int len, char fwrap) +{ + int i; + for (i = 0; i < len; i++) { + if (fwrap) { + if ((i % 16) == 0) printf("\n%04x: ",i); + } + printf(" %02x",p[i]); + } + printf("\n"); + return; +} + +static char *res_str(HRESULT res) +{ + char *pstr = ""; + int i; + for (i = 0; i < NRES; i++) { + if (res_list[i].val == res) { + pstr = &res_list[i].desc[0]; + break; + } + } + return (pstr); +} + +extern "C" { + +int ipmi_open_ms(char fdebugcmd) +{ + int bRet = -1; + HRESULT hres; + ULONG dwCount = NULL; + + fdebugms = fdebugcmd; + // Initialize COM. + hres = CoInitializeEx(0, COINIT_MULTITHREADED); + if (FAILED(hres)) { + if (fdebugcmd) printf("ipmi_open_ms: CoInitializeEx error\n"); + return bRet; + } + + // Obtain the initial locator to Windows Management + // on a particular host computer. + hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID *) &pLoc); + if (FAILED(hres)) { + CoUninitialize(); + if (fdebugcmd) printf("ipmi_open_ms: CreateInstance(WbemLoc) error\n"); + return bRet; + } + + + // Connect to the root\cimv2 namespace with the current user + // and obtain pointer pSvc to make IWbemServices calls. + hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\WMI"), NULL, NULL, 0, + NULL, 0, 0, &pSvc ); + if (FAILED(hres)) { + pLoc->Release(); + CoUninitialize(); + if (fdebugcmd) printf("ipmi_open_ms: ConnectServer error\n"); + return bRet; + } + + // Set the IWbemServices proxy so that impersonation + // of the user (client) occurs. + hres = CoSetProxyBlanket( pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, + NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, EOAC_NONE ); + if (FAILED(hres)) { + if (fdebugcmd) printf("ipmi_open_ms: Cannot SetProxyBlanket\n"); + cleanup_wmi(); + return bRet; // Program has failed. + } + + hres = pSvc->GetObject( L"Microsoft_IPMI", 0, NULL, &pClass, NULL); + if (FAILED(hres)) { + cleanup_wmi(); + if (fdebugcmd) + printf("ipmi_open_ms: cannot open microsoft_ipmi driver (ipmidrv.sys)\n"); + return bRet; + } + + hres = pSvc->CreateInstanceEnum( L"microsoft_ipmi", 0, NULL, &pEnumerator); + if (FAILED(hres)) { + cleanup_wmi(); + if (fdebugcmd) + printf("ipmi_open_ms: cannot open microsoft_ipmi Enum\n"); + return bRet; + } + + hres = pEnumerator->Next( WBEM_INFINITE, 1, &pInstance, &dwCount); + if (FAILED(hres)) { + if (fdebugcmd) + printf("ipmi_open_ms: Cannot get microsoft_ipmi instance\n"); + cleanup_wmi(); + return bRet; + } + VariantInit(&varPath); + hres = pInstance->Get(_bstr_t(L"__RelPath"), 0, &varPath, NULL, 0); + if (FAILED(hres)) { + if (fdebugcmd) + printf("ipmi_open_ms: Cannot get instance Path %s\n","__RelPath"); + cleanup_wmi(); + return bRet; + } else { /*success*/ + if (fdebugcmd) + printf("ipmi_open_ms: ObjectPath: %ls\n",V_BSTR(&varPath)); + // usually L"Microsoft_IPMI.InstanceName=\"Root\\SYSTEM\\0003_0\"", + fmsopen = 1; + bRet = 0; + } + + return bRet; +} + +int ipmi_close_ms(void) +{ + int bRet = -1; + if (fmsopen) { + cleanup_wmi(); + fmsopen = 0; + bRet = 0; + } + return bRet; +} + +int ipmi_cmdraw_ms(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd) +{ + int bRet; + HRESULT hres; + IWbemClassObject* pInParams = NULL; /*class definition*/ + IWbemClassObject* pInReq = NULL; /*instance*/ + IWbemClassObject* pOutResp = NULL; + VARIANT varCmd, varNetfn, varLun, varSa, varSize, varData; + SAFEARRAY* psa = NULL; + long i; + uchar *p; + + fdebugms = fdebugcmd; + if (!fmsopen) { + bRet = ipmi_open_ms(fdebugcmd); + if (bRet != 0) return(bRet); + } + bRet = -1; + + + hres = pClass->GetMethod(L"RequestResponse",0,&pInParams,NULL); + if (FAILED(hres)) { + if (fdebugcmd) + printf("ipmi_cmdraw_ms: Cannot get RequestResponse method\n"); + return (bRet); + } + +#ifdef WDM_FIXED + /* see http://support.microsoft.com/kb/951242 for WDM bug info */ + hres = pInParams->SpawnInstance(0,&pInReq); + if (FAILED(hres)) { + if (fdebugcmd) + printf("ipmi_cmdraw_ms: Cannot get RequestResponse instance\n"); + return (bRet); + } + // also substitute pInReq for pInParams below if this gets fixed. +#endif + + VariantInit(&varCmd); + varCmd.vt = VT_UI1; + varCmd.bVal = cmd; + hres = pInParams->Put(_bstr_t(L"Command"), 0, &varCmd, 0); + // VariantClear(&varCmd); + if (FAILED(hres)) goto MSRET; + + VariantInit(&varNetfn); + varNetfn.vt = VT_UI1; + varNetfn.bVal = netfn; + hres = pInParams->Put(_bstr_t(L"NetworkFunction"), 0, &varNetfn, 0); + // VariantClear(&varNetfn); + if (FAILED(hres)) goto MSRET; + + VariantInit(&varLun); + varLun.vt = VT_UI1; + varLun.bVal = lun; + hres = pInParams->Put(_bstr_t(L"Lun"), 0, &varLun, 0); + // VariantClear(&varLun); + if (FAILED(hres)) goto MSRET; + + VariantInit(&varSa); + varSa.vt = VT_UI1; + varSa.bVal = sa; + hres = pInParams->Put(_bstr_t(L"ResponderAddress"), 0, &varSa, 0); + // VariantClear(&varSa); + if (FAILED(hres)) goto MSRET; + + VariantInit(&varSize); + varSize.vt = VT_I4; + varSize.lVal = sdata; + hres = pInParams->Put(_bstr_t(L"RequestDataSize"), 0, &varSize, 0); + // VariantClear(&varSize); + if (FAILED(hres)) goto MSRET; + + SAFEARRAYBOUND rgsabound[1]; + rgsabound[0].cElements = sdata; + rgsabound[0].lLbound = 0; + psa = SafeArrayCreate(VT_UI1,1,rgsabound); + if(!psa) { + printf("ipmi_cmdraw_ms: SafeArrayCreate failed\n"); + goto MSRET; + } +#ifdef SHOULD_WORK_BUT_NO + /* The SafeArrayPutElement does not put the data in the right + * place, so skip this and copy the raw data below. */ + VARIANT tvar; + if (fdebugcmd && sdata > 0) + { printf("psa1(%p):",psa); dumpbuf((uchar *)psa,42,1); } + + for(i =0; i< sdata; i++) + { + VariantInit(&tvar); + tvar.vt = VT_UI1; + tvar.bVal = pdata[i]; + hres = SafeArrayPutElement(psa, &i, &tvar); + // VariantClear(&tvar); + if (FAILED(hres)) { + printf("ipmi_cmdraw_ms: SafeArrayPutElement(%d) failed\n",i); + goto MSRET; + } + } /*end for*/ + if (fdebugcmd && sdata > 0) + { printf("psa2(%p):",psa); dumpbuf((uchar *)psa,42,1); } +#endif + + /* Copy the real RequestData into psa */ + memcpy(psa->pvData,pdata,sdata); + + VariantInit(&varData); + varData.vt = VT_ARRAY | VT_UI1; + varData.parray = psa; + hres = pInParams->Put(_bstr_t(L"RequestData"), 0, &varData, 0); + // VariantClear(&varData); + if (FAILED(hres)) { + printf("Put(RequestData) error %x\n",hres); + goto MSRET; + } + +#ifdef TEST_METHODS + IWbemClassObject* pOutSms = NULL; + if (fdebugcmd) printf("ipmi_cmdraw_ms: calling SMS_Attention(%ls)\n", + V_BSTR(&varPath)); + hres = pSvc->ExecMethod( V_BSTR(&varPath), _bstr_t(L"SMS_Attention"), + 0, NULL, NULL, &pOutSms, NULL); + if (FAILED(hres)) { + printf("ipmi_cmdraw_ms: SMS_Attention method error %x\n",hres); + goto MSRET; + } + if (fdebugcmd) printf("ipmi_cmdraw_ms: SMS_Attention method ok\n"); + /* This does work, without input parameters */ + pOutSms->Release(); +#endif + + hres = pSvc->ExecMethod( V_BSTR(&varPath), _bstr_t(L"RequestResponse"), + 0, NULL, pInParams, &pOutResp, NULL); + if (fdebugcmd) { + printf("ipmi_cmdraw_ms(cmd=%x,netfn=%x,lun=%x,sa=%x,sdata=%d)" + " RequestResponse ret=%x\n", cmd,netfn,lun,sa,sdata,hres); + if (sdata > 0) { + printf("ipmi_cmdraw_ms: req data(%d):",sdata); + dumpbuf(pdata,sdata,0); + } + } + if (FAILED(hres)) { + printf("ipmi_cmdraw_ms: RequestResponse error %x %s\n", + hres,res_str(hres)); +#ifdef EXTRA_DESC + /* This does not usually add any meaning for IPMI. */ + BSTR desc; + IErrorInfo *pIErrorInfo; + GetErrorInfo(0,&pIErrorInfo); + pIErrorInfo->GetDescription(&desc); + printf("ipmi_cmdraw_ms: ErrorInfoDescr: %ls\n",desc); + SysFreeString(desc); +#endif + bRet = -1; + /*fall through for cleanup and return*/ + } + else { /*successful, get ccode and response data */ + VARIANT varByte, varRSz, varRData; + VariantInit(&varByte); + VariantInit(&varRSz); + VariantInit(&varRData); + long rlen; + + hres = pOutResp->Get(_bstr_t(L"CompletionCode"),0, &varByte, NULL, 0); + if (FAILED(hres)) goto MSRET; + if (fdebugcmd) printf("ipmi_cmdraw_ms: CompletionCode %x returned\n", + V_UI1(&varByte) ); + *pcc = V_UI1(&varByte); + + hres = pOutResp->Get(_bstr_t(L"ResponseDataSize"),0, &varRSz, NULL, 0); + if (FAILED(hres)) goto MSRET; + rlen = V_I4(&varRSz); + if (rlen > 1) rlen--; /*skip cc*/ + if (rlen > *sresp) { + if (fdebugcmd) printf("ResponseData truncated from %d to %d\n", + rlen,*sresp); + rlen = *sresp; /*truncate*/ + } + *sresp = (int)rlen; + + hres = pOutResp->Get(_bstr_t(L"ResponseData"),0, &varRData, NULL,0); + if (FAILED(hres)) { /*ignore failure */ + if (fdebugcmd) printf("Get ResponseData error %x\n",hres); + } else { /* success */ +#ifdef SHOULD_WORK_BUT_NO + uchar *pa; + p = (uchar*)varRData.parray->pvData; + pa = (uchar*)varRData.parray; + printf("pa=%p, pa+12=%p p=%p\n",pa,(pa+12),p); + if (fdebugcmd) { + printf("Data.vt = %04x, Data.parray(%p):", + varRData.vt, varRData.parray); + // 0x2011 means VT_ARRAY | VT_UI1 + dumpbuf((uchar *)varRData.parray,40,1); + } + /* The SafeArrayGetElement does not get the data from the right + * place, so skip this and copy the raw data below. */ + VARIANT rgvar[NVAR]; + if (rlen > NVAR) *pcc = 0xEE; + for (i = 0; i <= rlen; i++) + VariantInit(&rgvar[i]); + /* copy the response data from varRData to presp */ + for( i = 0; i <= rlen; i++) + { + hres = SafeArrayGetElement(varRData.parray, &i, &rgvar[i]); + if (FAILED(hres)) { + if (fdebugcmd) + printf("ipmi_cmdraw_ms: SafeArrayGetElement(%d) failed\n",i); + break; + } + if (fdebugcmd) { + printf("Data[%d] vt=%02x val=%02x, rgvar(%p):",i, + rgvar[i].vt, V_UI1(&rgvar[i]),&rgvar[i]); + dumpbuf((uchar *)&rgvar[i],12,0); + } + /* skip the completion code */ + // if (i > 0) presp[i-1] = V_UI1(&rgvar[i]); + } /*end for*/ +#endif + /* + * parray from a GetDeviceId response: + * 0015CEE0: 01 00 80 00 01 00 00 00 00 00 00 00 00 cf 15 00 + * 0015CEF0: 10 00 00 00 00 00 00 00 03 00 06 00 95 01 08 00 + * ^- datalen=0x10 + * 0015CF00: 00 20 01 00 19 02 9f 57 01 ... + * ^- start of data (cc=00, ...) + */ + /* Copy the real ResponseData into presp. */ + p = (uchar*)varRData.parray->pvData; + for( i = 0; i <= rlen; i++) { + /* skip the completion code */ + if (i > 0) presp[i-1] = p[i]; + } + if (fdebugcmd) { + printf("ipmi_cmdraw_ms: resp data(%d):",rlen+1); + dumpbuf(p,rlen+1,0); + } + } + bRet = 0; + } + +MSRET: +#define CLEAN_OK 1 +#ifdef CLEAN_OK + /* VariantClear(&var*) should be done by pInParams->Release() */ + if (psa != NULL) SafeArrayDestroy(psa); + if (pInParams != NULL) pInParams->Release(); + if (pOutResp != NULL) pOutResp->Release(); +#endif + return(bRet); +} + +#ifndef ALONE +int ipmi_cmd_ms(ushort cmd, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd) +{ + int bRet = -1; + int i; + + fdebugms = fdebugcmd; + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == cmd) break; + } + if (i >= NCMDS) { + printf("ipmi_cmd_ms: Unknown command %04x\n",cmd); + return(-1); + } + if (cmd >= CMDMASK) cmd = cmd & CMDMASK; /* unmask it */ + + bRet = ipmi_cmdraw_ms((uchar)cmd,ipmi_cmds[i].netfn,ipmi_cmds[i].lun, + ipmi_cmds[i].sa, ipmi_cmds[i].bus, + pdata,sdata,presp,sresp,pcc,fdebugcmd); + return (bRet); +} +#endif + +} /* end C */ + +#ifdef TEST_BIN +int main(int argc, char **argv) +{ + uchar rdata[40]; + int i, rv; + int rlen = 0; + uchar cc; + + fdebugms = 1; + rlen = sizeof(rdata); + rv = ipmi_cmdraw_ms(0x01, 0x06, 0, 0x20, 0, /*get_device_id*/ + NULL, 0, rdata, &rlen, &cc, fdebugms); + printf("ipmi_cmdraw_ms ret=%d, cc=%02x\n",rv,cc); + if (rv == 0) { + printf(" ** Return Code: %2.2X\n", cc); + printf(" ** Data[%d]:",rlen); + for (i=0; i < rlen; i++) + printf(" %2.2X", rdata[i]); + printf("\n"); + } + ipmi_close_ms(); + return 0; +} +#endif + + +#endif +/* endif WIN32 */ + +/* end ipmims.cpp */ diff --git a/util/ipmimv.c b/util/ipmimv.c new file mode 100644 index 0000000..06b1baf --- /dev/null +++ b/util/ipmimv.c @@ -0,0 +1,784 @@ +/*M* +// PVCS: +// $Workfile: ipmimv.c $ +// $Revision: 1.1 $ +// $Modtime: 08 Apr 2003 15:31:14 $ +// $Author: arcress at users.sourceforge.net $ +// +// This implements support for the /dev/ipmi0 native interface from +// the MontaVista OpenIPMI Linux driver. +// +// To build this as a standalone test program, do this: +// # gcc -DLINUX -g -O2 -DTEST_BIN -o ipmimv ipmimv.c +// +// 01/29/03 ARC - created, derived from ipmi_test.c and ipmitool_mv.c +// 04/08/03 ARC - don't watch stdin on select, since stdin may not be +// valid if invoked from cron, etc. +// 06/11/03 ARC - ignore EMSGSIZE errno for get_wdt command +// 05/05/04 ARC - only open/close device once per application, +// rely on each app calling ipmi_close, helps performance. +// 08/10/04 ARC - handle alternate device filenames for some 2.6 kernels +// 03/01/05 ARC - fix /dev/ipmi0 IPMB requests (to other than BMC_SA) +// 04/12/07 ARC - check for IPMI_ASYNC_EVENT_RECV_TYPE in ipmicmd_mv + *M*/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2002-2005, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#if defined(LINUX) || defined(BSD) || defined(MACOS) +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <sys/ioctl.h> +#if defined(MACOS) +#include <sys/time.h> +#else +#include <sys/poll.h> +#endif +#ifdef SCO_UW +#include <sys/ioccom.h> +#endif + +#ifdef TEST_BIN +#define ALONE 1 +#endif + +static void dbgmsg(char *pattn, ...); +#ifdef ALONE +#define uchar unsigned char +#define ACCESS_OK 0 +#define GET_SEL_ENTRY 0x43 +static FILE *fperr = NULL; +static FILE *fpdbg = NULL; +void dump_buf(char *tag,uchar *pbuf,int sz, char fshowascii) +{ + if (pbuf == NULL || sz == 0) return; + dbgmsg("%s sz=%d buf: %02x %02x %02x %02x\n",tag,sz, + pbuf[0],pbuf[1], pbuf[2],pbuf[3]); +} +#else +#include "ipmicmd.h" +extern FILE *fperr; /*defined in ipmicmd.c*/ +extern FILE *fpdbg; /*defined in ipmicmd.c*/ +extern ipmi_cmd_t ipmi_cmds[NCMDS]; +#endif + +#define MV_BUFFER_SIZE 300 /*see IPMI_RSPBUF_SIZE also */ +#define IPMI_MAX_ADDR_SIZE 32 +#define IPMI_RESPONSE_RECV_TYPE 1 +#define IPMI_ASYNC_EVENT_RECV_TYPE 2 +#define IPMI_CMD_RECV_TYPE 3 +#define IPMI_RESPONSE_RESPONSE_TYPE 4 + +#ifdef TV_PORT +/* use this to define timeval if it is a portability issue */ +struct timeval { + long int tv_sec; /* (time_t) seconds */ + long int tv_usec; /* (suseconds_t) microseconds */ +}; +#endif + +int ipmi_timeout_mv = 10; /* 10 seconds, was 5 sec */ +#if defined(BSD) || defined(MACOS) +#pragma pack(1) +#endif + +struct ipmi_addr +{ + int adrtype; + short channel; + char data[IPMI_MAX_ADDR_SIZE]; +}; + +struct ipmi_msg +{ + uchar netfn; + uchar cmd; + ushort data_len; + uchar *data; +}; + +struct ipmi_req +{ + unsigned char *addr; /* Address to send the message to. */ + unsigned int addr_len; + long msgid; /* The sequence number for the message. */ + struct ipmi_msg msg; +}; + +struct ipmi_recv +{ + int recv_type; /* Is this a command, response, etc. */ + unsigned char *addr; /* Address the message was from */ + int addr_len; /* The size of the address buffer. */ + long msgid; /* The sequence number from the request */ + struct ipmi_msg msg; /* The data field must point to a buffer. */ +}; + +struct ipmi_cmdspec +{ + unsigned char netfn; + unsigned char cmd; +}; +#if defined(BSD) || defined(MACOS) +#pragma pack() +/* FreeBSD 7.x ipmi ioctls, use _IOW */ +#define IPMI_IOC_MAGIC 'i' +#define IPMICTL_RECEIVE_MSG_TRUNC _IOWR(IPMI_IOC_MAGIC, 11, struct ipmi_recv) +#define IPMICTL_RECEIVE_MSG _IOWR(IPMI_IOC_MAGIC, 12, struct ipmi_recv) +#define IPMICTL_SEND_COMMAND _IOW(IPMI_IOC_MAGIC, 13, struct ipmi_req) +#define IPMICTL_REGISTER_FOR_CMD _IOW(IPMI_IOC_MAGIC, 14, struct ipmi_cmdspec) +#define IPMICTL_UNREGISTER_FOR_CMD _IOW(IPMI_IOC_MAGIC, 15, struct ipmi_cmdspec) +#define IPMICTL_SET_GETS_EVENTS_CMD _IOW(IPMI_IOC_MAGIC, 16, int) +#define IPMICTL_SET_MY_ADDRESS_CMD _IOW(IPMI_IOC_MAGIC, 17, unsigned int) +#define IPMICTL_GET_MY_ADDRESS_CMD _IOW(IPMI_IOC_MAGIC, 18, unsigned int) + +#else +/* Linux ipmi ioctls */ +#define IPMI_IOC_MAGIC 'i' +#define IPMICTL_RECEIVE_MSG_TRUNC _IOWR(IPMI_IOC_MAGIC, 11, struct ipmi_recv) +#define IPMICTL_RECEIVE_MSG _IOWR(IPMI_IOC_MAGIC, 12, struct ipmi_recv) +#define IPMICTL_SEND_COMMAND _IOR(IPMI_IOC_MAGIC, 13, struct ipmi_req) +#define IPMICTL_REGISTER_FOR_CMD _IOR(IPMI_IOC_MAGIC, 14,struct ipmi_cmdspec) +#define IPMICTL_UNREGISTER_FOR_CMD _IOR(IPMI_IOC_MAGIC, 15,struct ipmi_cmdspec) +#define IPMICTL_SET_GETS_EVENTS_CMD _IOR(IPMI_IOC_MAGIC, 16, int) +#define IPMICTL_SET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 17, unsigned int) +#define IPMICTL_GET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 18, unsigned int) +#endif + +/* MAINT ioctls used below, but only valid for Linux */ +#define IPMICTL_GET_MAINTENANCE_MODE_CMD _IOR(IPMI_IOC_MAGIC, 30, int) +#define IPMICTL_SET_MAINTENANCE_MODE_CMD _IOW(IPMI_IOC_MAGIC, 31, int) +#define IPMICTL_GETMAINT 0x8004691e /*only valid if OpenIPMI >=v39.1 */ +#define IPMICTL_SETMAINT 0x4004691f /*only valid if OpenIPMI >=v39.1 */ + +#define BMC_SA 0x20 +#define IPMI_BMC_CHANNEL 0xf +#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE 0x0c +#define IPMI_IPMB_ADDR_TYPE 0x01 +#define IPMI_IPMB_BROADCAST_ADDR_TYPE 0x41 +/* Broadcast get device id is used as described in IPMI 1.5 section 17.9. */ +#define IPMI_LAN_ADDR_TYPE 0x04 + +struct ipmi_system_interface_addr +{ + int adrtype; + short channel; + unsigned char lun; +}; + +struct ipmi_ipmb_addr +{ + int adrtype; + short channel; + uchar slave_addr; + uchar lun; +}; + +struct ipmi_lan_addr +{ + int adrtype; + short channel; + unsigned char privilege; + unsigned char session_handle; + unsigned char remote_SWID; + unsigned char local_SWID; + unsigned char lun; +}; + +static int ipmi_fd = -1; +static int curr_seq = 0; +static int fdebugmv = 0; +static struct ipmi_addr rsp_addr; /*used in getevent_mv, ipmi_rsp_mv*/ +static int rsp_addrlen = 0; /*used in getevent_mv, ipmi_rsp_mv*/ + +void ipmi_get_mymc(uchar *bus, uchar *sa, uchar *lun, uchar *type); + +static void dbgmsg(char *pattn, ...) +{ + va_list arglist; + + if (fpdbg == NULL) return; + // if (fdebugmv == 0) return; + va_start( arglist, pattn ); + vfprintf( fpdbg, pattn, arglist ); + va_end( arglist ); + fflush( fpdbg ); +} + +int ipmi_open_mv(char fdebugcmd) +{ + char *pdev; + uchar bus, sa, lun; + +#ifdef ALONE + fperr = stderr; + fpdbg = stdout; +#endif + + if (ipmi_fd != -1) return(0); /*already open*/ + fdebugmv = fdebugcmd; + pdev = "/dev/ipmi/0"; + ipmi_fd = open("/dev/ipmi/0", O_RDWR); + if (ipmi_fd == -1) { + if (fdebugcmd) dbgmsg("ipmi_open_mv: cannot open %s\n",pdev); + pdev = "/dev/ipmi0"; + ipmi_fd = open(pdev, O_RDWR); + } + if (ipmi_fd == -1) { + if (fdebugcmd) dbgmsg("ipmi_open_mv: cannot open %s\n",pdev); + pdev = "/dev/ipmidev0"; + ipmi_fd = open(pdev, O_RDWR); + } + if (ipmi_fd == -1) { + if (fdebugcmd) dbgmsg("ipmi_open_mv: cannot open %s\n",pdev); + pdev = "/dev/ipmidev/0"; + ipmi_fd = open(pdev, O_RDWR); + } + if (ipmi_fd == -1) { + if (fdebugcmd) dbgmsg("ipmi_open_mv: cannot open %s\n",pdev); + return(-1); + } + ipmi_get_mymc(&bus,&sa,&lun,NULL); + if (sa != BMC_SA) { /* user specified my slave address*/ + int a, rv; + a = sa; + rv = ioctl(ipmi_fd, IPMICTL_SET_MY_ADDRESS_CMD, &a); + if (fdebugcmd) dbgmsg("ipmi_open_mv: set_my_address(%x) rv=%d\n",sa,rv); + if (rv < 0) { + return(rv); + } + } + + if (fdebugcmd) { + dbgmsg("ipmi_open_mv: successfully opened %s, fd=%d\n",pdev,ipmi_fd); + } + return(0); +} + +int ipmi_close_mv(void) +{ + int rc = 0; + if (ipmi_fd != -1) { + rc = close(ipmi_fd); + ipmi_fd = -1; + } + return(rc); +} + +int ipmi_rsp_mv(uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *pdata, int sdata, char fdebugcmd) +{ + struct ipmi_req req; + // struct ipmi_recv rsp; + struct ipmi_lan_addr lan_addr; + // int i, done; + int rv; + + rv = ipmi_open_mv(fdebugcmd); + if (rv != 0) return(rv); + + if (rsp_addrlen > 0) { + /* rsp_addr was previously saved in getevent_mv */ + req.addr = (char *)&rsp_addr; + req.addr_len = rsp_addrlen; + } else { /* try some defaults */ + lan_addr.adrtype = IPMI_LAN_ADDR_TYPE; + lan_addr.channel = bus; /* usu lan_ch == 1 */ + lan_addr.privilege = 0x04; /*admin*/ + lan_addr.session_handle = 0x01; /*may vary*/ + lan_addr.remote_SWID = sa; /*usu 0x81*/ + lan_addr.local_SWID = 0x81; + lan_addr.lun = lun; + req.addr = (char *) &lan_addr; + req.addr_len = sizeof(lan_addr); + } + req.msg.cmd = cmd; + req.msg.netfn = (netfn | 0x01); + req.msgid = curr_seq; + req.msg.data = pdata; + req.msg.data_len = sdata; + rv = ioctl(ipmi_fd, IPMICTL_SEND_COMMAND, &req); + curr_seq++; + if (rv == -1) { + if (fdebugcmd) dbgmsg("mv IPMICTL_SEND_COMMAND errno %d\n",errno); + rv = errno; + } + return(rv); +} + +int ipmicmd_mv(uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *pdata, int sdata, uchar *presp, int sresp, int *rlen) +{ + fd_set readfds; + struct timeval tv; + struct ipmi_req req; + struct ipmi_recv rsp; + struct ipmi_addr addr; + struct ipmi_ipmb_addr ipmb_addr; + struct ipmi_system_interface_addr bmc_addr; + static int need_set_events = 1; + int i, done; + int rv; + + rv = ipmi_open_mv(fdebugmv); + if (rv != 0) return(rv); + + if (need_set_events) { + i = 1; + rv = ioctl(ipmi_fd, IPMICTL_SET_GETS_EVENTS_CMD, &i); + if (fdebugmv) + dbgmsg("getevent_mv: set_gets_events rv=%d errno=%d, n=%d\n", + rv,errno,i); + if (rv) { return(errno); } + need_set_events = 0; + } + + FD_ZERO(&readfds); + // FD_SET(0, &readfds); /* dont watch stdin */ + FD_SET(ipmi_fd, &readfds); /* only watch ipmi_fd for input */ + + /* Special handling for ReadEventMsgBuffer, etc. */ +#ifdef TEST_MSG + recv.msg.data = data; + recv.msg.data_len = sizeof(data); + recv.addr = (unsigned char *) &addr; + recv.addr_len = sizeof(addr); + rv = ioctl(fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv); + if (rv == -1) { + if (errno == EMSGSIZE) { + /* The message was truncated, handle it as such. */ + data[0] = IPMI_REQUESTED_DATA_LENGTH_EXCEEDED_CC; + rv = 0; + } else + goto out; + } +#endif + + /* Send the IPMI command */ + if (sa == BMC_SA) { + i = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + bmc_addr.adrtype = i; + bmc_addr.channel = IPMI_BMC_CHANNEL; + bmc_addr.lun = lun; /* usu BMC_LUN = 0 */ + req.addr = (char *) &bmc_addr; + req.addr_len = sizeof(bmc_addr); + } else { + i = IPMI_IPMB_ADDR_TYPE; + ipmb_addr.adrtype = i; + ipmb_addr.channel = bus; /* usu PUBLIC_BUS = 0 */ + ipmb_addr.slave_addr = sa; + ipmb_addr.lun = lun; + req.addr = (char *) &ipmb_addr; + req.addr_len = sizeof(ipmb_addr); + } + if (fdebugmv) + dbgmsg("mv cmd=%02x netfn=%02x mc=%02x;%02x;%02x adrtype=%x\n", + cmd,netfn,bus,sa,lun,i); + req.msg.cmd = cmd; + req.msg.netfn = netfn; + req.msgid = curr_seq; + req.msg.data = pdata; + req.msg.data_len = sdata; + rv = ioctl(ipmi_fd, IPMICTL_SEND_COMMAND, &req); + curr_seq++; + if (rv == -1) { + if (fdebugmv) dbgmsg("mv IPMICTL_SEND_COMMAND errno %d\n",errno); + rv = errno; + } + + if (netfn & 0x01) done = 1; /*sending response only*/ + else done = 0; /*normal request/response*/ + + if (rv == 0) while (!done) { + done = 1; + tv.tv_sec=ipmi_timeout_mv; + tv.tv_usec=0; + rv = select(ipmi_fd+1, &readfds, NULL, NULL, &tv); + /* expect select rv = 1 here */ + if (rv <= 0) { /* no data within 5 seconds */ + if (fdebugmv) + fprintf(fperr,"mv select timeout, fd = %d, isset = %d, rv = %d, errno = %d\n", + ipmi_fd,FD_ISSET(ipmi_fd, &readfds),rv,errno); + if (rv == 0) rv = -3; + else rv = errno; + } else { + /* receive the IPMI response */ + rsp.addr = (char *) &addr; + rsp.addr_len = sizeof(addr); + rsp.msg.data = presp; + rsp.msg.data_len = sresp; + rv = ioctl(ipmi_fd, IPMICTL_RECEIVE_MSG_TRUNC, &rsp); + if (rv == -1) { + if ((errno == EMSGSIZE) && (rsp.msg.data_len == sresp)) + rv = 0; /* errno 90 is ok */ + else { + rv = errno; + fprintf(fperr,"mv rcv_trunc errno = %d, len = %d\n", + errno, rsp.msg.data_len); + } + } else rv = 0; + /* Driver should ensure matching req.msgid and rsp.msgid */ + /* Skip & retry if async events, only listen for those in + * getevent_mv() below. */ + // if (rsp.recv_type == IPMI_ASYNC_EVENT_RECV_TYPE) + if (rsp.recv_type != IPMI_RESPONSE_RECV_TYPE) { + if (fdebugmv) + dbgmsg("mv cmd=%02x netfn=%02x, got recv_type %d\n", + cmd,netfn,rsp.recv_type); + done = 0; + } + *rlen = rsp.msg.data_len; + } + } /*endif send ok, while select/recv*/ + + /* ipmi_close_mv(); * rely on the app calling ipmi_close */ + return(rv); +} + +int ipmi_cmdraw_mv(uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *pdata, int sdata, uchar *presp, int *sresp, + uchar *pcc, char fdebugcmd) +{ + uchar buf[MV_BUFFER_SIZE]; + int rc, szbuf; + int rlen = 0; + uchar cc; + + if (fdebugcmd) { + dbgmsg("mv cmd=%02x netfn=%02x lun=%02x sdata=%d sresp=%d\n", + cmd,netfn,lun,sdata,*sresp); + dump_buf("mv cmd data",pdata,sdata,0); + } + szbuf = sizeof(buf); + if (*sresp < 2) ; /*just completion code*/ + else if (*sresp < szbuf) szbuf = *sresp + 1; + else if (fdebugcmd) + dbgmsg("mv sresp %d >= szbuf %d, truncated\n",*sresp,szbuf); + rc = ipmicmd_mv(cmd,netfn,lun,sa, bus, pdata,sdata, buf,szbuf,&rlen); + cc = buf[0]; + if (fdebugcmd) { + dbgmsg("ipmi_cmdraw_mv: status=%d ccode=%x rlen=%d\n", + (uint)rc,cc,rlen); + if (rc == 0) dump_buf("mv rsp data",buf,rlen,0); + } + if (rlen > 0) { /* copy data, except first byte */ + rlen -= 1; + if (rlen > *sresp) rlen = *sresp; + memcpy(presp,&buf[1],rlen); + } + *pcc = cc; + *sresp = rlen; + return(rc); +} + +#ifdef ALONE +void ipmi_get_mymc(uchar *bus, uchar *sa, uchar *lun, uchar *type) +{ + if (bus != NULL) *bus = 0; //PUBLIC_BUS; + if (sa != NULL) *sa = BMC_SA; + if (lun != NULL) *lun = 0; //BMC_LUN; + if (type != NULL) *type = 1; //ADDR_SMI; +} +#else +int ipmi_cmd_mv(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + uchar buf[MV_BUFFER_SIZE]; + int rc, i, szbuf; + uchar cc; + int rlen = 0; + int xlen, j; + uchar sa, lun, bus, mtype; + + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == cmd) break; + } + if (i >= NCMDS) { + fprintf(fperr, "ipmi_cmd_mv: Unknown command %x\n",cmd); + return(-1); + } + if (cmd >= CMDMASK) cmd = cmd & CMDMASK; /* unmask it */ + + if (fdebugcmd) { + dbgmsg( "mv cmd=%02x netfn=%02x lun=%02x sdata=%d sresp=%d\n", + cmd,ipmi_cmds[i].netfn,ipmi_cmds[i].lun,sdata, *sresp); + dump_buf("mv cmd data",pdata,sdata,0); + } + szbuf = sizeof(buf); + if (*sresp < szbuf && *sresp >= 2) szbuf = *sresp + 1; + else if (fdebugcmd) + dbgmsg("mv sresp %d >= szbuf %d, truncated\n",*sresp,szbuf); + // ipmi_cmds[i].lun, ipmi_cmds[i].sa, ipmi_cmds[i].bus, + ipmi_get_mc(&bus, &sa, &lun, &mtype); + rc = ipmicmd_mv(cmd,ipmi_cmds[i].netfn, lun, sa, bus, + pdata,sdata,buf,szbuf,&rlen); + // if (rc == -1) dbgmsg("ipmi_cmd_mv: cannot open /dev/ipmi0\n"); + cc = buf[0]; + if (fdebugcmd) { + dbgmsg("ipmi_cmd_mv: ipmicmd_mv status=%x, ccode=%x\n", + (uint)rc, cc); + if (rc == ACCESS_OK) { + uchar * pc; int sz; + sz = rlen; + pc = (uchar *)buf; + dbgmsg("ipmi_cmd_mv: response (len=%d): ",sz); + for (j = 0; j < sz; j++) dbgmsg("%02x ",pc[j]); + dbgmsg("\n"); + } + } + xlen = ipmi_cmds[i].rslen + 1; + if ((ipmi_cmds[i].cmdtyp == GET_SEL_ENTRY) && + (rlen < xlen) && (rc == 0) && (cc != 0) && + (i > 0) && (rlen > 1)) /*not temp slot, have data*/ + { + /* Detect/Handle MV driver SEL bug returning missing bytes */ + if (fdebugcmd) { + dbgmsg("ipmi_cmd_mv[%d] BUG: returned %d, expected %d\n", + i,rlen,xlen); + } + cc = 0x80; /*flag as busy, retry*/ + j = xlen - rlen; + j--; /* omit cc */ + for (i = 0; i < j; i++) presp[i] = 0xff; + if ((rlen+j) > *sresp) rlen = *sresp - j; + memcpy(&presp[j],&buf[0],rlen); + rlen += j; + } + if (rlen > 0) { + /* copy data, except first byte */ + rlen -= 1; + if (rlen > *sresp) rlen = *sresp; + memcpy(presp,&buf[1],rlen); + } + *pcc = cc; + *sresp = rlen; + + return(rc); +} /*end ipmi_cmd_mv*/ +#endif + +int setmaint_mv(uchar mode, uchar *cc) +{ + int data[2]; + int rv; + /* + * Normally OpenIPMI driver issues ReadEventMessageBuffer cmds + * every 1 second. Maint mode disables that polling in + * driver v39.1 and greater. + * maintenance mode values: + * 2 = turn on maint mode + * 1 = turn off maint mode + * 0 = automatic maint mode (on for 30 sec if reset or fw request) + */ + + /* should have called ipmi_open_mv in a previous call */ + rv = ioctl(ipmi_fd, IPMICTL_GETMAINT, &data); + if (rv == -1) { + if (errno != 0) *cc = errno; + } else *cc = 0; + if (fdebugmv) dbgmsg("getmaint: rv=%d mode=%d\n",rv,data[0]); + + data[0] = mode; + rv = ioctl(ipmi_fd, IPMICTL_SETMAINT, &data); + if (rv == -1) { + if (errno != 0) *cc = errno; + } else *cc = 0; + return(rv); +} + +int register_async_mv(uchar cmd, uchar netfn) +{ + uchar data[2]; + int rv; + + data[0] = netfn; + data[1] = cmd; + rv = ioctl(ipmi_fd, IPMICTL_REGISTER_FOR_CMD, &data); + if (fdebugmv) dbgmsg("register_async_mv(%x,%x) rv=%d\n",cmd,netfn,rv); + return(rv); +} + +int unregister_async_mv(uchar cmd, uchar netfn) +{ + uchar data[2]; + int rv; + + data[0] = netfn; + data[1] = cmd; + rv = ioctl(ipmi_fd, IPMICTL_UNREGISTER_FOR_CMD, &data); + if (fdebugmv) dbgmsg("unregister_async_mv(%x,%x) rv=%d\n",cmd,netfn,rv); + return(rv); +} + +int getevent_mv(uchar *evt_data, int *evt_len, uchar *cc, int timeout) +{ + struct ipmi_recv rsp; + uchar data[36]; /* #define MAX_IPMI_DATA_SIZE 36 */ + struct ipmi_addr addr; + static int need_set_events = 1; + int rv = 0; + int n; + + if (need_set_events) { + n = 1; + rv = ioctl(ipmi_fd, IPMICTL_SET_GETS_EVENTS_CMD, &n); + if (fdebugmv) + dbgmsg("getevent_mv: set_gets_events rv=%d errno=%d, n=%d\n", + rv,errno,n); + need_set_events = 0; + } + + /* wait for the mv openipmi driver to provide input to fd */ + if (timeout == 0) + { /*do poll*/ +#if defined(MACOS) + /* there is no poll function in MACOS, so skip this. */ +#else + struct pollfd myfd; + myfd.fd = ipmi_fd; + myfd.events = POLLIN; + myfd.revents = 0; + rv = poll(&myfd,1,-1); + if (rv <= 0) { + if (fdebugmv) dbgmsg("getevent_mv poll rv=%d\n",rv); + return(rv); + } + /* else have input ready to read (myfd.revents & POLLIN)*/ + if (fdebugmv) dbgmsg("getevent_mv poll revents %x\n",myfd.revents); +#endif + } + + /* read the message from the ipmi_fd */ + rsp.msg.data = data; + rsp.msg.data_len = sizeof(data); + rsp.addr = (unsigned char *) &addr; + rsp.addr_len = sizeof(addr); + rv = ioctl(ipmi_fd, IPMICTL_RECEIVE_MSG_TRUNC, &rsp); + if (rv < 0) { + if (fdebugmv) dbgmsg("getevent_mv rv=%d, errno=%d\n",rv,errno); + if (errno == EMSGSIZE) { /* The message was truncated */ + *cc = 0xC8; /*IPMI_REQUESTED_DATA_LENGTH_EXCEEDED_CC;*/ + rsp.msg.data_len = sizeof(data); + rv = 0; + } + else if (errno == EINTR) { return(EINTR); } + } else *cc = 0; + if (rv == 0) { + n = rsp.msg.data_len; + if (fdebugmv) { + dbgmsg("getevent_mv: recv_type=%x cmd=%x data_len=%d\n", + rsp.recv_type,rsp.msg.cmd,n); + // if (n > 0) dump_buf("mv rsp.msg.data",rsp.msg.data, n, 0); + // dump_buf("mv rsp.addr",rsp.addr,rsp.addr_len,0); + } + if (rsp.recv_type == IPMI_CMD_RECV_TYPE) { + evt_data[0] = rsp.recv_type; + evt_data[1] = rsp.msg.netfn; + evt_data[2] = rsp.msg.cmd; + if (n > 0) + memcpy(&evt_data[3],&data[0],n); + n += 3; + /* save the response address */ + memcpy(&rsp_addr,rsp.addr,rsp.addr_len); + rsp_addrlen = rsp.addr_len; + } else if (rsp.recv_type == IPMI_RESPONSE_RESPONSE_TYPE) { + evt_data[0] = rsp.recv_type; + evt_data[1] = rsp.msg.netfn; + evt_data[2] = rsp.msg.cmd; + evt_data[3] = data[0]; + n += 3; + } else { /* rsp.recv_type == IPMI_ASYNC_EVENT_RECV_TYPE */ + if (n > 0) + memcpy(evt_data,&data[0],n); + } + *evt_len = n; + } else if (rv == -1 || rv == -11) { + rv = 0x80; /* -EAGAIN, no data, try again */ + } + return(rv); +} + +#ifdef TEST_BIN +int main(int argc, char *argv[]) +{ + fd_set readfds; + struct timeval tv; + uchar data[40]; + int i, j; + int err, rv; + int rlen = 0; + uchar cc; + + fperr = stderr; + fpdbg = stdout; + fdebugmv = 1; + rlen = sizeof(data); + err = ipmi_cmdraw_mv(0x01, 0x06, 0, 0x20, 0, /*get_device_id*/ + NULL, 0, data, &rlen, &cc, fdebugmv); + dbgmsg("ipmi_cmdraw_mv ret=%d, cc=%02x\n",err,cc); + rv = err; + if (err == 0) { + rv = cc; + dbgmsg(" ** Return Code: %2.2X\n", cc); + dbgmsg(" ** Data[%d]:",rlen); + for (i=0; i < rlen; i++) + dbgmsg(" %2.2X", (uchar)data[i]); + dbgmsg("\n"); + } + + err = setmaint_mv(2,&cc); + dbgmsg("setmaint_mv(2) err=%d cc=%d\n",err,cc); + err = setmaint_mv(1,&cc); + dbgmsg("setmaint_mv(1) err=%d cc=%d\n",err,cc); + err = setmaint_mv(0,&cc); + dbgmsg("setmaint_mv(0) err=%d cc=%d\n",err,cc); + + err = register_async_mv(0x10,0x06); + dbgmsg("register_async_mv(10,6) rv=%d\n",err); + err = register_async_mv(0x01,0x06); + dbgmsg("register_async_mv(01,6) rv=%d\n",err); + err = unregister_async_mv(0x01,0x06); + dbgmsg("unregister_async_mv(01,6) rv=%d\n",err); + err = unregister_async_mv(0x10,0x06); + dbgmsg("unregister_async_mv(10,6) rv=%d\n",err); + + dbgmsg("\n"); + ipmi_close_mv(); + return rv; +} +#endif + +#endif diff --git a/util/ipmiutil.c b/util/ipmiutil.c new file mode 100644 index 0000000..4094cab --- /dev/null +++ b/util/ipmiutil.c @@ -0,0 +1,229 @@ +/*********************************************** + * ipmiutil.c + * + * This is a meta-command utility to invoke each of the + * other sub-commands in a consolidated interface. + * To build this, compile with -DMETACOMMAND. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2006-2007 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 01/03/07 ARCress - created + * 01/05/07 ARCress - version 1.0 + * 01/10/07 ARCress - version 1.1 + * 02/07/07 ARCress - version 1.3 adding isolconsole + * 02/26/07 ARCress - updated sub-command names + * 08/31/07 ARCress - added "leds" subcommand + * + ***********************************************/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2007, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> + +#include "ipmicmd.h" +#include "ipmiutil.h" + +static char *progname = "ipmiutil"; +static char *progver = "2.93"; +// static char fdebug = 0; +/*int ipmiutil(int argc, char **argv); */ + +#define NSUBCMDS 28 +static struct { + int idx; + char tag[16]; + int (*rtn)(int argc, char **argv); + char desc[64]; + } subcmds[NSUBCMDS] = { + { 0, "alarms", i_alarms, "show/set the front panel alarm LEDs and relays" }, + { 1, "leds", i_alarms, "show/set the front panel alarm LEDs and relays" }, + { 2, "discover", i_discover, "discover all IPMI servers on this LAN" }, + { 3, "cmd", i_cmd , "send a specified raw IPMI command to the BMC" }, + { 4, "config", i_config, "list/save/restore BMC configuration parameters" }, + { 26, "dcmi", i_dcmi, "get/set DCMI parameters" }, + { 5, "ekanalyzer", i_ekanalyzer, "run EKeying analyzer on FRU files (deprecated, see fru)" }, + { 6, "events", i_events, "decode IPMI events and display them" }, + { 7, "firewall", i_firewall, "show/set firmware firewall functions" }, + { 8, "fru", i_fru, "show decoded FRU inventory data, write asset tag"}, + { 9, "fwum", i_fwum, "OEM firmware update manager extensions" }, + { 10, "getevt", i_getevt, "get IPMI events and display them, event daemon" }, + { 11, "getevent", i_getevt, "get IPMI events and display them, event daemon" }, + { 12, "health", i_health, "check and show the basic health of the IPMI BMC"}, + { 13, "hpm", i_hpm, "HPM firmware update manager extensions" }, + { 14, "lan", i_lan, "show/set IPMI LAN parameters and PEF table"}, + { 15, "picmg", i_picmg, "show/set picmg extended functions" }, + { 25, "power", i_reset, "issue IPMI reset or power control to the system"}, + { 16, "reset", i_reset, "issue IPMI reset or power control to the system"}, + { 17, "sel", i_sel, "show/clear firmware System Event Log records" }, + { 18, "sensor", i_sensor, "show Sensor Data Records, readings, thresholds" }, + { 19, "serial", i_serial, "show/set IPMI Serial & Terminal Mode parameters"}, + { 20, "sol", i_sol, "start/stop an SOL console session" }, + { 21, "smcoem", i_smcoem, "SuperMicro OEM functions" }, + { 22, "sunoem", i_sunoem, "Sun OEM functions" }, + { 23, "delloem",i_delloem, "Dell OEM functions" }, + { 24, "tsol", i_tsol, "Tyan SOL console start/stop session" }, + { 27, "wdt", i_wdt, "show/set/reset the watchdog timer" } + }; + +static char usagemsg[] = "Usage: ipmiutil <command> [other options]\n" + " where <command> is one of the following:\n"; +static char helpmsg[] = "For help on each command (e.g. 'sel'), enter:\n" + " ipmiutil sel -?\n"; + +static void show_usage() +{ + int i; + printf("%s", usagemsg); + for (i=0; i<NSUBCMDS; i++) + printf("\t%s\t%s\n",subcmds[i].tag,subcmds[i].desc); + printf(" common IPMI LAN options:\n"); + print_lan_opt_usage(); + printf("%s", helpmsg); +} + +#ifdef DOS +int i_discover(int argc, char **argv) +{ + printf("The discover function is not supported in DOS.\n"); + return(1); +} +#endif + +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +{ + int ret = 1; + int i; + char *psubcmd = ""; + + printf("%s ver %s\n", progname,progver); + if (argc < 2) { + show_usage(); + ret = ERR_USAGE; + goto do_exit; + } +#ifdef TEST_LOOP + /* special subcommand processing loop for testing */ +#ifdef WIN32 + while ( !(( _kbhit() ) && (_getch() == 'q')) ) +#else + while ( 1 ) +#endif + { + for (i = 0; i < NSUBCMDS; i++) + { + if (strcmp(argv[1],subcmds[i].tag) == 0) { + psubcmd = argv[1]; + argc--; + argv++; + ret = subcmds[i].rtn(argc,argv); + + argc++; argv--; /*requeue the same subcmd*/ + os_usleep( 1, 0 ); /*sleep 1 sec*/ + break; + } + } + } +#else + for (i = 0; i < NSUBCMDS; i++) + { + if (strcmp(argv[1],subcmds[i].tag) == 0) { + psubcmd = argv[1]; + argc--; + argv++; + ret = subcmds[i].rtn(argc,argv); + break; + } + } +#endif + if (i >= NSUBCMDS) { +#ifdef LINUX + if ((strcmp(argv[1],"svc") == 0) && (argc >= 3)) { + char mycmd[80]; + char *pfunc; + char *psvc; + char fchkok; + /* undocumented: start a given service, only works locally */ + psvc = "ipmi_port"; + if (argc > 2) pfunc = argv[2]; + else pfunc = "on"; + ret = system("ls /sbin/chkconfig >/dev/null 2>&1"); + if (ret == 0) fchkok = 1; + else fchkok = 0; + if (strcmp(pfunc,"off") == 0) { + sprintf(mycmd,"service %s stop\n",psvc); + printf("%s\n",mycmd); + ret = system(mycmd); + if (fchkok) { + sprintf(mycmd,"/sbin/chkconfig --del %s\n",psvc); + printf("%s\n",mycmd); + ret = system(mycmd); + } + } else { + if (fchkok) { + sprintf(mycmd,"/sbin/chkconfig --add %s\n",psvc); + printf("%s\n",mycmd); + ret = system(mycmd); + sprintf(mycmd,"/sbin/chkconfig --level 345 %s on\n",psvc); + // printf("%s\n",mycmd); + ret = system(mycmd); + } + sprintf(mycmd,"service %s start\n",psvc); + printf("%s\n",mycmd); + ret = system(mycmd); + } + } else +#endif + { + show_usage(); + ret = ERR_USAGE; + } + } + +do_exit: + { + char tag[30]; + sprintf(tag,"%s %s",progname,psubcmd); + show_outcome(tag,ret); + } + return(ret); +} + +/*end ipmiutil.c*/ diff --git a/util/ipmiutil.h b/util/ipmiutil.h new file mode 100644 index 0000000..39b5ecb --- /dev/null +++ b/util/ipmiutil.h @@ -0,0 +1,66 @@ +/*********************************************** + * ipmiutil.h + * + * Definitions for ipmiutil.c + * + ***********************************************/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2006, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ +#ifndef IPMIUTIL_H_ +#define IPMIUTIL_H_ + +int i_alarms(int argc, char **argv); +int i_health(int argc, char **argv); +int i_fru(int argc, char **argv); +int i_getevt(int argc, char **argv); +int i_reset(int argc, char **argv); +int i_cmd(int argc, char **argv); +int i_lan(int argc, char **argv); +int i_serial(int argc, char **argv); +int i_sensor(int argc, char **argv); +int i_sel(int argc, char **argv); +int i_wdt(int argc, char **argv); +int i_sol(int argc, char **argv); +int i_discover(int argc, char **argv); +int i_config(int argc, char **argv); +int i_events(int argc, char **argv); +int i_picmg(int argc, char **argv); +int i_firewall(int argc, char **argv); +int i_fwum(int argc, char **argv); +int i_hpm(int argc, char **argv); +int i_sunoem(int argc, char **argv); +int i_delloem(int argc, char **argv); +int i_ekanalyzer(int argc, char **argv); +int i_tsol(int argc, char **argv); +int i_dcmi(int argc, char **argv); +int i_smcoem(int argc, char **argv); + +#endif // IPMIUTIL_H_ diff --git a/util/ipmiutil.mak b/util/ipmiutil.mak new file mode 100644 index 0000000..83a23c1 --- /dev/null +++ b/util/ipmiutil.mak @@ -0,0 +1,424 @@ +# This makefile will build the ipmiutil util directory
+#
+# First download getopt.c getopt.h
+# Then download and build openssl for Windows
+#
+LIBC_RT=libcmt.lib /NODEFAULTLIB:"msvcirt.lib"
+# LIBC_RT=msvcrt.lib /NODEFAULTLIB:"msvcirt.lib"
+
+#MARCH=X64
+MARCH=IX86
+# The ipmiutil directory
+SRC_D=.
+LIB_D=..\lib
+L2_D=$(LIB_D)\lanplus
+L3_D=$(LIB_D)\lanplus\inc
+INSTALLTOP=install
+TMP_D=tmp
+INC=/I$(SRC_D) /I$(L2_D) /I$(L3_D)
+CMD_OBJ = getopt.obj ipmicmd.obj imbapi.obj md5.obj md2.obj \
+ ipmilan.obj ipmims.obj subs.obj
+CMD_OBJ = $(CMD_OBJ) ipmilanplus.obj
+# To remove lanplus support use the empty LANPLUS variables
+# L2_OBJ=
+# LF_LANPLUS=
+# CF_LANPLUS=
+L2_OBJ = $(L2_D)\helper.obj $(L2_D)\ipmi_strings.obj $(L2_D)\lanplus.obj \
+ $(L2_D)\lanplus_crypt_impl.obj $(L2_D)\lanplus_dump.obj \
+ $(L2_D)\lanplus_strings.obj $(L2_D)\lanplus_crypt.obj
+LF_LANPLUS=/LIBPATH:$(LIB_D) $(L2_OBJ) ssleay32.lib libeay32.lib
+CF_LANPLUS=/D HAVE_LANPLUS
+
+# Set your compiler options
+# To remove any GPL dependencies, use the CF_EX line with NON_GPL
+# CFLAGS_O=/W3 /O2 /Zi /MD /GF /Gy /nologo
+# CFLAGS_O=/W3 /O2 /Zi /MD /nologo
+# CFLAGS_O=/W3 /O2 /Zi /MT /nologo
+CFLAGS_O=/W3 /O2 /Zi /MT /nologo
+CF_EX=/DWIN32 $(CF_LANPLUS) $(INC) /D_CONSOLE /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DHAVE_STRING_H
+CF_SAM=/DWIN32 $(INC) /D_CONSOLE /D_CRT_SECURE_NO_DEPRECATE /DHAVE_STRING_H
+CFLAGS=$(CFLAGS_O) $(CF_EX) /DSKIP_MD2
+CFLAGS_M=$(CFLAGS_O) $(CF_EX) /DSKIP_MD2 /DMETACOMMAND
+CFLAGS_SAM=$(CFLAGS_O) $(CF_SAM)
+LFLAGS=/nologo /subsystem:console /machine:$(MARCH) /opt:ref
+#LFLAGS=/nologo /subsystem:console /machine:IX86 /opt:ref
+#LFLAGS=/nologo /subsystem:console /machine:IX86 /opt:ref /debug
+# LFLAGS_D=/nologo /subsystem:console /machine:I386 /opt:ref /dll
+
+# CFLAGS_W=/O2 /D_CONSOLE /D_MBCS /EHsc /ML /W3 /Zi /TP
+CFLAGS_W=/TP /EHsc $(CFLAGS)
+LFLAGS_W=/nologo /subsystem:console /machine:$(MARCH) /opt:ref
+LIBS_W=comsuppw.lib wbemuuid.lib
+# gdi32.lib comdlg32.lib shell32.lib uuid.lib
+
+CC=cl
+LINK=link
+MKDIR=-mkdir
+MKLIB=lib
+RM=del
+CP=copy
+
+LIBS_EX = advapi32.lib kernel32.lib wsock32.lib $(LIBS_W) $(LIBC_RT)
+LIBS_PEF = /LIBPATH:$(LIB_D) iphlpapi.lib
+# LIBS_EX+=wsock32.lib user32.lib gdi32.lib
+
+HEADER=ipmicmd.h imb_api.h ipmilan.h ipmidir.h ipmilanplus.h \
+ ipmiutil.h
+
+SHOWSEL = showsel
+TARG_EXE=ievents.exe $(SHOWSEL)msg.dll ipmi_sample.exe ipmi_sample_evt.exe $(SAMP_DLL)
+# alarms.exe ihealth.exe $(SHOWSEL).exe $(SHOWSEL)msg.dll \
+# ireset.exe ifru.exe ilan.exe iserial.exe wdt.exe \
+# getevent.exe sensor.exe icmd.exe isolconsole.exe idiscover.exe \
+# ievents.exe
+SAMP_LIB = ipmiutil.lib
+SAMP_DLL = ipmiutillib.dll
+
+E_EXE=ipmiutil.exe
+E_OBJ=$(TMP_D)\ipmiutil.obj \
+ $(TMP_D)\ialarms.obj $(TMP_D)\ihealth.obj $(TMP_D)\iwdt.obj \
+ $(TMP_D)\ireset.obj $(TMP_D)\ifru.obj $(TMP_D)\ilan.obj \
+ $(TMP_D)\iserial.obj $(TMP_D)\icmd.obj $(TMP_D)\isol.obj \
+ $(TMP_D)\isolwin.obj $(TMP_D)\AnsiTerm.obj $(TMP_D)\idiscover.obj \
+ $(TMP_D)\iconfig.obj $(TMP_D)\igetevent.obj $(TMP_D)\isensor.obj \
+ $(TMP_D)\isel.obj $(TMP_D)\ievents.obj \
+ $(TMP_D)\ipicmg.obj $(TMP_D)\ifirewall.obj \
+ $(TMP_D)\iekanalyzer.obj $(TMP_D)\ifru_picmg.obj \
+ $(TMP_D)\oem_kontron.obj $(TMP_D)\ihpm.obj $(TMP_D)\ifwum.obj \
+ $(TMP_D)\oem_fujitsu.obj $(TMP_D)\oem_intel.obj \
+ $(TMP_D)\oem_sun.obj $(TMP_D)\oem_dell.obj $(TMP_D)\oem_hp.obj \
+ $(TMP_D)\oem_supermicro.obj $(TMP_D)\itsol.obj $(TMP_D)\idcmi.obj \
+ $(TMP_D)\oem_quanta.obj $(TMP_D)\oem_newisys.obj $(CMD_OBJ) mem_if.obj
+
+###################################################################
+all: banner $(TMP_D) exe
+
+banner:
+ @echo Building ipmiutil
+
+$(TMP_D):
+ $(MKDIR) $(TMP_D)
+ @echo created $(TMP_D)
+
+lib: $(L2_OBJ)
+ cd $(LIB_D)
+ nmake /nologo -f ipmilib.mak
+ cd ../util
+
+exe: $(E_EXE) $(TARG_EXE)
+
+install:
+ $(MKDIR) $(INSTALLTOP)
+ $(MKDIR) $(INSTALLTOP)\bin
+ $(CP) $(E_EXE) $(INSTALLTOP)\bin
+ xcopy $(TARG_EXE) $(INSTALLTOP)\bin
+ xcopy *.dll $(INSTALLTOP)\bin
+
+clean:
+ $(RM) *.obj 2>NUL
+ $(RM) $(TARG_EXE) 2>NUL
+ $(RM) *.exe 2>NUL
+ -$(RM) $(TMP_D)\*.obj 2>NUL
+
+distclean:
+ $(RM) *.obj 2>NUL
+ $(RM) $(TARG_EXE) 2>NUL
+ $(RM) *.exe 2>NUL
+ -$(RM) $(TMP_D)\*.* 2>NUL
+ rmdir $(TMP_D) 2>NUL
+ $(RM) *.rc 2>NUL
+ $(RM) *.bin 2>NUL
+ $(RM) *.RES 2>NUL
+ $(RM) getopt.* 2>NUL
+
+getopt.obj: getopt.c
+ $(CC) /c $(CFLAGS) getopt.c
+
+imbapi.obj: imbapi.c
+ $(CC) /c $(CFLAGS_M) imbapi.c
+
+ipmicmd.obj: ipmicmd.c
+ $(CC) /c $(CFLAGS) ipmicmd.c
+
+ipmilan.obj: ipmilan.c
+ $(CC) /c $(CFLAGS) ipmilan.c
+
+ipmilanplus.obj: ipmilanplus.c
+ $(CC) /c $(CFLAGS_M) ipmilanplus.c
+
+md5.obj: md5.c
+ $(CC) /c $(CFLAGS) md5.c
+
+md2.obj: md2.c
+ $(CC) /c $(CFLAGS) md2.c
+
+ievents.obj: ievents.c
+ $(CC) /c $(CFLAGS) ievents.c
+
+ialarms.obj: ialarms.c
+ $(CC) /c $(CFLAGS) ialarms.c
+
+ihealth.obj: ihealth.c
+ $(CC) /c $(CFLAGS) ihealth.c
+
+igetevent.obj: igetevent.c
+ $(CC) /c $(CFLAGS) igetevent.c
+
+mem_if.obj: mem_if.c
+ $(CC) /c $(CFLAGS_W) mem_if.c
+
+ipmims.obj: ipmims.cpp
+ $(CC) /c $(CFLAGS_W) ipmims.cpp
+
+isel.obj: isel.c
+ $(CC) /c $(CFLAGS) isel.c
+
+ireset.obj: ireset.c
+ $(CC) /c $(CFLAGS) ireset.c
+
+ireset.exe: ireset.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ireset.exe ireset.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ifru.obj: ifru.c
+ $(CC) /c $(CFLAGS) ifru.c
+
+ifru.exe: ifru.obj mem_if.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ifru.exe ifru.obj mem_if.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ilan.obj: ilan.c
+ $(CC) /c $(CFLAGS) ilan.c
+
+ilan.exe: ilan.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ilan.exe ilan.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_PEF) $(LIBS_EX)
+
+iserial.obj: iserial.c
+ $(CC) /c $(CFLAGS) iserial.c
+
+iserial.exe: iserial.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:iserial.exe iserial.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+isensor.obj: isensor.c
+ $(CC) /c $(CFLAGS) isensor.c
+
+isensor.exe: isensor.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isensor.exe isensor.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+iwdt.obj: iwdt.c
+ $(CC) /c $(CFLAGS) iwdt.c
+
+iwdt.exe: iwdt.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:iwdt.exe iwdt.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+isol.obj: isol.c
+ $(CC) /c $(CFLAGS) isol.c
+
+isolwin.obj: isolwin.c
+ $(CC) /c $(CFLAGS) isolwin.c
+
+isol.exe: isol.obj isolwin.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isol.exe isol.obj isolwin.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+icmd.obj: icmd.c
+ $(CC) /c $(CFLAGS) icmd.c
+
+icmd.exe: icmd.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:icmd.exe icmd.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+idiscover.obj: idiscover.c
+ $(CC) /c $(CFLAGS) idiscover.c
+
+idiscover.exe: idiscover.obj getopt.obj
+ $(LINK) $(LFLAGS) /OUT:idiscover.exe idiscover.obj getopt.obj \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ialarms.exe: ialarms.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ialarms.exe ialarms.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ihealth.exe: ihealth.obj mem_if.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ihealth.exe ihealth.obj mem_if.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+igetevent.exe: igetevent.obj ievents.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:igetevent.exe igetevent.obj ievents.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+isel.exe: isel.obj ievents.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isel.exe isel.obj ievents.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+$(SHOWSEL).mc:
+ $(CP) ..\scripts\$(SHOWSEL).mc .
+
+$(SHOWSEL)msg.dll: $(SHOWSEL).mc
+ mc -U $(SHOWSEL).mc
+ rc -r $(SHOWSEL).rc
+ $(LINK) /machine:$(MARCH) -dll -noentry -out:$(SHOWSEL)msg.dll $(SHOWSEL).res
+
+mem_if.exe: $(TMP_D)\mem_if.obj
+ $(LINK) $(LFLAGS_W) /OUT:mem_if.exe $(TMP_D)\mem_if.obj $(LIBS_EX)
+
+$(TMP_D)\mem_if.obj: mem_if.c
+ $(CC) /c $(CFLAGS_W) /DCOMP_BIN /Fo$(TMP_D)\mem_if.obj mem_if.c
+
+ievents.exe: ievents.c
+ $(CC) /c $(CFLAGS) /DALONE ievents.c
+ $(LINK) $(LFLAGS) /OUT:ievents.exe ievents.obj $(LIBS_EX)
+ $(RM) ievents.obj
+
+ipmims.exe: ipmims.cpp
+ $(CC) /c $(CFLAGS_W) /DALONE /DTEST_BIN ipmims.cpp
+ $(LINK) $(LFLAGS_W) /OUT:ipmims.exe ipmims.obj $(LIBS_EX)
+ $(RM) ipmims.obj
+
+$(TMP_D)\ievents.obj: ievents.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ievents.obj ievents.c
+
+$(TMP_D)\ipmiutil.obj: ipmiutil.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ipmiutil.obj ipmiutil.c
+
+$(TMP_D)\ialarms.obj: ialarms.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ialarms.obj ialarms.c
+
+$(TMP_D)\ihealth.obj: ihealth.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ihealth.obj ihealth.c
+
+$(TMP_D)\iconfig.obj: iconfig.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iconfig.obj iconfig.c
+
+$(TMP_D)\ipicmg.obj: ipicmg.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ipicmg.obj ipicmg.c
+
+$(TMP_D)\ifirewall.obj: ifirewall.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifirewall.obj ifirewall.c
+
+$(TMP_D)\ifwum.obj: ifwum.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifwum.obj ifwum.c
+
+$(TMP_D)\ihpm.obj: ihpm.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ihpm.obj ihpm.c
+
+$(TMP_D)\idcmi.obj: idcmi.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\idcmi.obj idcmi.c
+
+$(TMP_D)\oem_fujitsu.obj: oem_fujitsu.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_fujitsu.obj oem_fujitsu.c
+
+$(TMP_D)\oem_kontron.obj: oem_kontron.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_kontron.obj oem_kontron.c
+
+$(TMP_D)\oem_intel.obj: oem_intel.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_intel.obj oem_intel.c
+
+$(TMP_D)\oem_sun.obj: oem_sun.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_sun.obj oem_sun.c
+
+$(TMP_D)\oem_dell.obj: oem_dell.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_dell.obj oem_dell.c
+
+$(TMP_D)\oem_hp.obj: oem_hp.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_hp.obj oem_hp.c
+
+$(TMP_D)\oem_supermicro.obj: oem_supermicro.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_supermicro.obj oem_supermicro.c
+
+$(TMP_D)\oem_quanta.obj: oem_quanta.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_quanta.obj oem_quanta.c
+
+$(TMP_D)\oem_newisys.obj: oem_newisys.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_newisys.obj oem_newisys.c
+
+$(TMP_D)\iekanalyzer.obj: iekanalyzer.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iekanalyzer.obj iekanalyzer.c
+
+$(TMP_D)\ifru_picmg.obj: ifru_picmg.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifru_picmg.obj ifru_picmg.c
+
+$(TMP_D)\ifru.obj: ifru.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifru.obj ifru.c
+
+$(TMP_D)\ireset.obj: ireset.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ireset.obj ireset.c
+
+$(TMP_D)\ilan.obj: ilan.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ilan.obj ilan.c
+
+$(TMP_D)\iserial.obj: iserial.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iserial.obj iserial.c
+
+$(TMP_D)\isensor.obj: isensor.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isensor.obj isensor.c
+
+$(TMP_D)\icmd.obj: icmd.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\icmd.obj icmd.c
+
+$(TMP_D)\igetevent.obj: igetevent.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\igetevent.obj igetevent.c
+
+$(TMP_D)\isel.obj: isel.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isel.obj isel.c
+
+$(TMP_D)\isol.obj: isol.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isol.obj isol.c
+
+$(TMP_D)\isolwin.obj: isolwin.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isolwin.obj isolwin.c
+
+$(TMP_D)\itsol.obj: itsol.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\itsol.obj itsol.c
+
+$(TMP_D)\AnsiTerm.obj: AnsiTerm.cpp
+ $(CC) /c $(CFLAGS_W) /Fo$(TMP_D)\AnsiTerm.obj AnsiTerm.cpp
+
+$(TMP_D)\idiscover.obj: idiscover.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\idiscover.obj idiscover.c
+
+$(TMP_D)\iwdt.obj: iwdt.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iwdt.obj iwdt.c
+
+$(E_EXE): $(E_OBJ)
+ $(LINK) $(LFLAGS) /OUT:$(E_EXE) $(E_OBJ) $(LF_LANPLUS) $(LIBS_PEF) $(LIBS_EX)
+
+ipmi_sample.obj: ipmi_sample.c
+ $(CC) /c $(CFLAGS_SAM) ipmi_sample.c
+
+$(SAMP_LIB): $(CMD_OBJ) mem_if.obj
+ $(CC) /c $(CFLAGS_SAM) ipmilanplus.c
+ $(MKLIB) /OUT:$(SAMP_LIB) /nologo $(CMD_OBJ) mem_if.obj
+ del ipmilanplus.obj
+
+$(SAMP_DLL): $(CMD_OBJ) mem_if.obj
+ $(CC) /D_WINDLL /D_USRDLL /c $(CFLAGS_SAM) ipmilanplus.c
+ $(LINK) /DLL $(LFLAGS) /OUT:$(SAMP_DLL) /def:ipmiutillib.def $(CMD_OBJ) mem_if.obj $(LIBS_PEF) $(LIBS_EX)
+ del ipmilanplus.obj
+
+ipmi_sample.exe: $(SAMP_LIB) ipmi_sample.c
+ $(CC) /c $(CFLAGS_SAM) ipmi_sample.c
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample.exe ipmi_sample.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
+
+ipmi_sample2.exe: $(SAMP_LIB) ipmi_sample.c isensor.c ievents.c
+ $(CC) /c $(CFLAGS_SAM) /DGET_SENSORS ipmi_sample.c
+ $(CC) /c $(CFLAGS_SAM) isensor.c
+ $(CC) /c $(CFLAGS_SAM) ievents.c
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample2.exe ipmi_sample.obj isensor.obj ievents.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
+ del isensor.obj ievents.obj
+
+ipmi_sample_evt.obj: ipmi_sample_evt.c $(HEADER)
+ $(CC) /c $(CFLAGS_SAM) ipmi_sample_evt.c
+
+isensor2.obj: isensor.c isensor.h $(HEADER)
+ $(CC) /c /Foisensor2.obj $(CFLAGS_SAM) isensor.c
+
+ievents2.obj: ievents.c ievents.h $(HEADER)
+ $(CC) /c /Foievents2.obj $(CFLAGS_SAM) /DSENSORS_OK ievents.c
+
+ipmi_sample_evt.exe: $(SAMP_LIB) ipmi_sample_evt.obj ievents2.obj isensor2.obj
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample_evt.exe ipmi_sample_evt.obj ievents2.obj isensor2.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
diff --git a/util/ipmiutil2-64.mak b/util/ipmiutil2-64.mak new file mode 100644 index 0000000..6289e06 --- /dev/null +++ b/util/ipmiutil2-64.mak @@ -0,0 +1,425 @@ +# This makefile will build the ipmiutil util directory (x64 without lanplus)
+#
+# First download getopt.c getopt.h
+# Then download and build openssl for Windows
+#
+LIBC_RT=libcmt.lib /NODEFAULTLIB:"msvcirt.lib"
+# LIBC_RT=msvcrt.lib /NODEFAULTLIB:"msvcirt.lib"
+
+MARCH=X64
+#MARCH=IX86
+# The ipmiutil directory
+SRC_D=.
+LIB_D=..\lib
+L2_D=$(LIB_D)\lanplus
+L3_D=$(LIB_D)\lanplus\inc
+INSTALLTOP=install
+TMP_D=tmp
+INC=/I$(SRC_D) /I$(L2_D) /I$(L3_D)
+CMD_OBJ = getopt.obj ipmicmd.obj imbapi.obj md5.obj md2.obj \
+ ipmilan.obj ipmims.obj subs.obj
+CMD_OBJ = $(CMD_OBJ) ipmilanplus.obj
+# To remove lanplus support use the empty LANPLUS variables
+L2_OBJ=
+L2_LIB=
+LF_LANPLUS=
+CF_LANPLUS=
+#L2_OBJ = $(L2_D)\helper.obj $(L2_D)\ipmi_strings.obj $(L2_D)\lanplus.obj \
+# $(L2_D)\lanplus_crypt_impl.obj $(L2_D)\lanplus_dump.obj \
+# $(L2_D)\lanplus_strings.obj $(L2_D)\lanplus_crypt.obj
+#L2_LIB=lanplus.lib
+#LF_LANPLUS=/LIBPATH:$(LIB_D) $(L2_OBJ) ssleay32.lib libeay32.lib
+#CF_LANPLUS=/D HAVE_LANPLUS
+
+# Set your compiler options
+# To remove any GPL dependencies, use the CF_EX line with NON_GPL
+# CFLAGS_O=/W3 /O2 /Zi /MD /GF /Gy /nologo
+# CFLAGS_O=/W3 /O2 /Zi /MD /nologo
+# CFLAGS_O=/W3 /O2 /Zi /MT /nologo
+CFLAGS_O=/W3 /O2 /Zi /MT /nologo
+CF_EX=/DWIN32 $(CF_LANPLUS) $(INC) /D_CONSOLE /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DHAVE_STRING_H
+CF_SAM=/DWIN32 $(INC) /D_CONSOLE /D_CRT_SECURE_NO_DEPRECATE /DHAVE_STRING_H
+CFLAGS=$(CFLAGS_O) $(CF_EX) /DSKIP_MD2
+CFLAGS_M=$(CFLAGS_O) $(CF_EX) /DSKIP_MD2 /DMETACOMMAND
+CFLAGS_SAM=$(CFLAGS_O) $(CF_SAM)
+LFLAGS=/nologo /subsystem:console /machine:$(MARCH) /opt:ref
+#LFLAGS=/nologo /subsystem:console /machine:IX86 /opt:ref
+#LFLAGS=/nologo /subsystem:console /machine:IX86 /opt:ref /debug
+# LFLAGS_D=/nologo /subsystem:console /machine:I386 /opt:ref /dll
+
+# CFLAGS_W=/O2 /D_CONSOLE /D_MBCS /EHsc /ML /W3 /Zi /TP
+CFLAGS_W=/TP /EHsc $(CFLAGS)
+LFLAGS_W=/nologo /subsystem:console /machine:$(MARCH) /opt:ref
+LIBS_W=comsuppw.lib wbemuuid.lib
+# gdi32.lib comdlg32.lib shell32.lib uuid.lib
+
+CC=cl
+LINK=link
+MKDIR=-mkdir
+MKLIB=lib
+RM=del
+CP=copy
+
+LIBS_EX = advapi32.lib kernel32.lib wsock32.lib ws2_32.lib $(LIBS_W) $(LIBC_RT)
+LIBS_PEF = /LIBPATH:$(LIB_D) iphlpapi.lib
+# LIBS_EX+=wsock32.lib user32.lib gdi32.lib
+
+HEADER=ipmicmd.h imb_api.h ipmilan.h ipmidir.h ipmilanplus.h \
+ ipmiutil.h
+
+SHOWSEL = showsel
+TARG_EXE=ievents.exe $(SHOWSEL)msg.dll ipmi_sample.exe ipmi_sample_evt.exe $(SAMP_DLL)
+# alarms.exe ihealth.exe $(SHOWSEL).exe $(SHOWSEL)msg.dll \
+# ireset.exe ifru.exe ilan.exe iserial.exe wdt.exe \
+# getevent.exe sensor.exe icmd.exe isolconsole.exe idiscover.exe \
+# ievents.exe
+SAMP_LIB = ipmiutil.lib
+SAMP_DLL = ipmiutillib.dll
+
+E_EXE=ipmiutil.exe
+E_OBJ=$(TMP_D)\ipmiutil.obj \
+ $(TMP_D)\ialarms.obj $(TMP_D)\ihealth.obj $(TMP_D)\iwdt.obj \
+ $(TMP_D)\ireset.obj $(TMP_D)\ifru.obj $(TMP_D)\ilan.obj \
+ $(TMP_D)\iserial.obj $(TMP_D)\icmd.obj $(TMP_D)\isol.obj \
+ $(TMP_D)\isolwin.obj $(TMP_D)\AnsiTerm.obj $(TMP_D)\idiscover.obj \
+ $(TMP_D)\iconfig.obj $(TMP_D)\igetevent.obj $(TMP_D)\isensor.obj \
+ $(TMP_D)\isel.obj $(TMP_D)\ievents.obj \
+ $(TMP_D)\ipicmg.obj $(TMP_D)\ifirewall.obj \
+ $(TMP_D)\iekanalyzer.obj $(TMP_D)\ifru_picmg.obj \
+ $(TMP_D)\oem_kontron.obj $(TMP_D)\ihpm.obj $(TMP_D)\ifwum.obj \
+ $(TMP_D)\oem_fujitsu.obj $(TMP_D)\oem_intel.obj \
+ $(TMP_D)\oem_sun.obj $(TMP_D)\oem_dell.obj $(TMP_D)\oem_hp.obj \
+ $(TMP_D)\oem_supermicro.obj $(TMP_D)\itsol.obj $(TMP_D)\idcmi.obj \
+ $(TMP_D)\oem_quanta.obj $(TMP_D)\oem_newisys.obj $(CMD_OBJ) mem_if.obj
+
+###################################################################
+all: banner $(TMP_D) exe
+
+banner:
+ @echo Building ipmiutil
+
+$(TMP_D):
+ $(MKDIR) $(TMP_D)
+ @echo created $(TMP_D)
+
+lib: $(L2_OBJ)
+ cd $(LIB_D)
+ nmake /nologo -f ipmilib.mak
+ cd ../util
+
+exe: $(E_EXE) $(TARG_EXE)
+
+install:
+ $(MKDIR) $(INSTALLTOP)
+ $(MKDIR) $(INSTALLTOP)\bin
+ $(CP) $(E_EXE) $(INSTALLTOP)\bin
+ xcopy $(TARG_EXE) $(INSTALLTOP)\bin
+ xcopy *.dll $(INSTALLTOP)\bin
+
+clean:
+ $(RM) *.obj 2>NUL
+ $(RM) $(TARG_EXE) 2>NUL
+ $(RM) *.exe 2>NUL
+ $(RM) $(TMP_D)\*.obj 2>NUL
+
+distclean:
+ $(RM) *.obj 2>NUL
+ $(RM) $(TARG_EXE) 2>NUL
+ $(RM) *.exe 2>NUL
+ $(RM) $(TMP_D)\*.* 2>NUL
+ rmdir $(TMP_D) 2>NUL
+ $(RM) *.rc 2>NUL
+ $(RM) *.bin 2>NUL
+ $(RM) *.RES 2>NUL
+ $(RM) getopt.* 2>NUL
+
+getopt.obj: getopt.c
+ $(CC) /c $(CFLAGS) getopt.c
+
+imbapi.obj: imbapi.c
+ $(CC) /c $(CFLAGS_M) imbapi.c
+
+ipmicmd.obj: ipmicmd.c
+ $(CC) /c $(CFLAGS) ipmicmd.c
+
+ipmilan.obj: ipmilan.c
+ $(CC) /c $(CFLAGS) ipmilan.c
+
+ipmilanplus.obj: ipmilanplus.c
+ $(CC) /c $(CFLAGS_M) ipmilanplus.c
+
+md5.obj: md5.c
+ $(CC) /c $(CFLAGS) md5.c
+
+md2.obj: md2.c
+ $(CC) /c $(CFLAGS) md2.c
+
+ievents.obj: ievents.c
+ $(CC) /c $(CFLAGS) ievents.c
+
+ialarms.obj: ialarms.c
+ $(CC) /c $(CFLAGS) ialarms.c
+
+ihealth.obj: ihealth.c
+ $(CC) /c $(CFLAGS) ihealth.c
+
+igetevent.obj: igetevent.c
+ $(CC) /c $(CFLAGS) igetevent.c
+
+mem_if.obj: mem_if.c
+ $(CC) /c $(CFLAGS_W) mem_if.c
+
+ipmims.obj: ipmims.cpp
+ $(CC) /c $(CFLAGS_W) ipmims.cpp
+
+isel.obj: isel.c
+ $(CC) /c $(CFLAGS) isel.c
+
+ireset.obj: ireset.c
+ $(CC) /c $(CFLAGS) ireset.c
+
+ireset.exe: ireset.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ireset.exe ireset.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ifru.obj: ifru.c
+ $(CC) /c $(CFLAGS) ifru.c
+
+ifru.exe: ifru.obj mem_if.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ifru.exe ifru.obj mem_if.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ilan.obj: ilan.c
+ $(CC) /c $(CFLAGS) ilan.c
+
+ilan.exe: ilan.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ilan.exe ilan.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_PEF) $(LIBS_EX)
+
+iserial.obj: iserial.c
+ $(CC) /c $(CFLAGS) iserial.c
+
+iserial.exe: iserial.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:iserial.exe iserial.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+isensor.obj: isensor.c
+ $(CC) /c $(CFLAGS) isensor.c
+
+isensor.exe: isensor.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isensor.exe isensor.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+iwdt.obj: iwdt.c
+ $(CC) /c $(CFLAGS) iwdt.c
+
+iwdt.exe: iwdt.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:iwdt.exe iwdt.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+isol.obj: isol.c
+ $(CC) /c $(CFLAGS) isol.c
+
+isolwin.obj: isolwin.c
+ $(CC) /c $(CFLAGS) isolwin.c
+
+isol.exe: isol.obj isolwin.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isol.exe isol.obj isolwin.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+icmd.obj: icmd.c
+ $(CC) /c $(CFLAGS) icmd.c
+
+icmd.exe: icmd.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:icmd.exe icmd.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+idiscover.obj: idiscover.c
+ $(CC) /c $(CFLAGS) idiscover.c
+
+idiscover.exe: idiscover.obj getopt.obj
+ $(LINK) $(LFLAGS) /OUT:idiscover.exe idiscover.obj getopt.obj \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ialarms.exe: ialarms.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ialarms.exe ialarms.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ihealth.exe: ihealth.obj mem_if.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ihealth.exe ihealth.obj mem_if.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+igetevent.exe: igetevent.obj ievents.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:igetevent.exe igetevent.obj ievents.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+isel.exe: isel.obj ievents.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isel.exe isel.obj ievents.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+$(SHOWSEL).mc:
+ $(CP) ..\scripts\$(SHOWSEL).mc .
+
+$(SHOWSEL)msg.dll: $(SHOWSEL).mc
+ mc -U $(SHOWSEL).mc
+ rc -r $(SHOWSEL).rc
+ $(LINK) /machine:$(MARCH) -dll -noentry -out:$(SHOWSEL)msg.dll $(SHOWSEL).res
+
+mem_if.exe: $(TMP_D)\mem_if.obj
+ $(LINK) $(LFLAGS_W) /OUT:mem_if.exe $(TMP_D)\mem_if.obj $(LIBS_EX)
+
+$(TMP_D)\mem_if.obj: mem_if.c
+ $(CC) /c $(CFLAGS_W) /DCOMP_BIN /Fo$(TMP_D)\mem_if.obj mem_if.c
+
+ievents.exe: ievents.c
+ $(CC) /c $(CFLAGS) /DALONE ievents.c
+ $(LINK) $(LFLAGS) /OUT:ievents.exe ievents.obj $(LIBS_EX)
+ $(RM) ievents.obj
+
+ipmims.exe: ipmims.cpp
+ $(CC) /c $(CFLAGS_W) /DALONE /DTEST_BIN ipmims.cpp
+ $(LINK) $(LFLAGS_W) /OUT:ipmims.exe ipmims.obj $(LIBS_EX)
+ $(RM) ipmims.obj
+
+$(TMP_D)\ievents.obj: ievents.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ievents.obj ievents.c
+
+$(TMP_D)\ipmiutil.obj: ipmiutil.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ipmiutil.obj ipmiutil.c
+
+$(TMP_D)\ialarms.obj: ialarms.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ialarms.obj ialarms.c
+
+$(TMP_D)\ihealth.obj: ihealth.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ihealth.obj ihealth.c
+
+$(TMP_D)\iconfig.obj: iconfig.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iconfig.obj iconfig.c
+
+$(TMP_D)\ipicmg.obj: ipicmg.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ipicmg.obj ipicmg.c
+
+$(TMP_D)\ifirewall.obj: ifirewall.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifirewall.obj ifirewall.c
+
+$(TMP_D)\ifwum.obj: ifwum.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifwum.obj ifwum.c
+
+$(TMP_D)\ihpm.obj: ihpm.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ihpm.obj ihpm.c
+
+$(TMP_D)\idcmi.obj: idcmi.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\idcmi.obj idcmi.c
+
+$(TMP_D)\oem_fujitsu.obj: oem_fujitsu.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_fujitsu.obj oem_fujitsu.c
+
+$(TMP_D)\oem_kontron.obj: oem_kontron.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_kontron.obj oem_kontron.c
+
+$(TMP_D)\oem_intel.obj: oem_intel.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_intel.obj oem_intel.c
+
+$(TMP_D)\oem_sun.obj: oem_sun.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_sun.obj oem_sun.c
+
+$(TMP_D)\oem_dell.obj: oem_dell.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_dell.obj oem_dell.c
+
+$(TMP_D)\oem_hp.obj: oem_hp.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_hp.obj oem_hp.c
+
+$(TMP_D)\oem_supermicro.obj: oem_supermicro.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_supermicro.obj oem_supermicro.c
+
+$(TMP_D)\oem_quanta.obj: oem_quanta.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_quanta.obj oem_quanta.c
+
+$(TMP_D)\oem_newisys.obj: oem_newisys.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_newisys.obj oem_newisys.c
+
+$(TMP_D)\iekanalyzer.obj: iekanalyzer.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iekanalyzer.obj iekanalyzer.c
+
+$(TMP_D)\ifru_picmg.obj: ifru_picmg.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifru_picmg.obj ifru_picmg.c
+
+$(TMP_D)\ifru.obj: ifru.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifru.obj ifru.c
+
+$(TMP_D)\ireset.obj: ireset.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ireset.obj ireset.c
+
+$(TMP_D)\ilan.obj: ilan.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ilan.obj ilan.c
+
+$(TMP_D)\iserial.obj: iserial.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iserial.obj iserial.c
+
+$(TMP_D)\isensor.obj: isensor.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isensor.obj isensor.c
+
+$(TMP_D)\icmd.obj: icmd.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\icmd.obj icmd.c
+
+$(TMP_D)\igetevent.obj: igetevent.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\igetevent.obj igetevent.c
+
+$(TMP_D)\isel.obj: isel.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isel.obj isel.c
+
+$(TMP_D)\isol.obj: isol.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isol.obj isol.c
+
+$(TMP_D)\isolwin.obj: isolwin.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isolwin.obj isolwin.c
+
+$(TMP_D)\itsol.obj: itsol.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\itsol.obj itsol.c
+
+$(TMP_D)\AnsiTerm.obj: AnsiTerm.cpp
+ $(CC) /c $(CFLAGS_W) /Fo$(TMP_D)\AnsiTerm.obj AnsiTerm.cpp
+
+$(TMP_D)\idiscover.obj: idiscover.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\idiscover.obj idiscover.c
+
+$(TMP_D)\iwdt.obj: iwdt.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iwdt.obj iwdt.c
+
+$(E_EXE): $(E_OBJ)
+ $(LINK) $(LFLAGS) /OUT:$(E_EXE) $(E_OBJ) $(LF_LANPLUS) $(LIBS_PEF) $(LIBS_EX)
+
+ipmi_sample.obj: ipmi_sample.c
+ $(CC) /c $(CFLAGS_SAM) ipmi_sample.c
+
+$(SAMP_LIB): $(CMD_OBJ) mem_if.obj
+ $(CC) /c $(CFLAGS_SAM) ipmilanplus.c
+ $(MKLIB) /OUT:$(SAMP_LIB) /nologo $(CMD_OBJ) mem_if.obj
+ del ipmilanplus.obj
+
+$(SAMP_DLL): $(CMD_OBJ) mem_if.obj
+ $(CC) /D_WINDLL /D_USRDLL /c $(CFLAGS_SAM) ipmilanplus.c
+ $(LINK) /DLL $(LFLAGS) /OUT:$(SAMP_DLL) /def:ipmiutillib.def $(CMD_OBJ) mem_if.obj $(LIBS_PEF) $(LIBS_EX)
+ del ipmilanplus.obj
+
+ipmi_sample.exe: $(SAMP_LIB) ipmi_sample.obj
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample.exe ipmi_sample.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
+
+ipmi_sample2.exe: $(SAMP_LIB) ipmi_sample.c isensor.c ievents.c
+ $(CC) /c $(CFLAGS_SAM) /DGET_SENSORS ipmi_sample.c
+ $(CC) /c $(CFLAGS_SAM) isensor.c
+ $(CC) /c $(CFLAGS_SAM) ievents.c
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample2.exe ipmi_sample.obj isensor.obj ievents.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
+ del isensor.obj ievents.obj
+
+ipmi_sample_evt.obj: ipmi_sample_evt.c $(HEADER)
+ $(CC) /c $(CFLAGS_SAM) ipmi_sample_evt.c
+
+isensor2.obj: isensor.c isensor.h $(HEADER)
+ $(CC) /c /Foisensor2.obj $(CFLAGS_SAM) isensor.c
+
+ievents2.obj: ievents.c ievents.h $(HEADER)
+ $(CC) /c /Foievents2.obj $(CFLAGS_SAM) /DSENSORS_OK ievents.c
+
+ipmi_sample_evt.exe: $(SAMP_LIB) ipmi_sample_evt.obj ievents2.obj isensor2.obj
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample_evt.exe ipmi_sample_evt.obj ievents2.obj isensor2.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
diff --git a/util/ipmiutil2.mak b/util/ipmiutil2.mak new file mode 100644 index 0000000..8ed0155 --- /dev/null +++ b/util/ipmiutil2.mak @@ -0,0 +1,425 @@ +# This makefile will build the ipmiutil util directory (without lanplus)
+#
+# First download getopt.c getopt.h
+# Then download and build openssl for Windows
+#
+LIBC_RT=libcmt.lib /NODEFAULTLIB:"msvcirt.lib"
+# LIBC_RT=msvcrt.lib /NODEFAULTLIB:"msvcirt.lib"
+
+MARCH=IX86
+#MARCH=IX86
+# The ipmiutil directory
+SRC_D=.
+LIB_D=..\lib
+L2_D=$(LIB_D)\lanplus
+L3_D=$(LIB_D)\lanplus\inc
+INSTALLTOP=install
+TMP_D=tmp
+INC=/I$(SRC_D) /I$(L2_D) /I$(L3_D)
+CMD_OBJ = getopt.obj ipmicmd.obj imbapi.obj md5.obj md2.obj \
+ ipmilan.obj ipmims.obj subs.obj
+CMD_OBJ = $(CMD_OBJ) ipmilanplus.obj
+# To remove lanplus support use the empty LANPLUS variables
+L2_OBJ=
+L2_LIB=
+LF_LANPLUS=
+CF_LANPLUS=
+#L2_OBJ = $(L2_D)\helper.obj $(L2_D)\ipmi_strings.obj $(L2_D)\lanplus.obj \
+# $(L2_D)\lanplus_crypt_impl.obj $(L2_D)\lanplus_dump.obj \
+# $(L2_D)\lanplus_strings.obj $(L2_D)\lanplus_crypt.obj
+#L2_LIB=lanplus.lib
+#LF_LANPLUS=/LIBPATH:$(LIB_D) $(L2_OBJ) ssleay32.lib libeay32.lib
+#CF_LANPLUS=/D HAVE_LANPLUS
+
+# Set your compiler options
+# To remove any GPL dependencies, use the CF_EX line with NON_GPL
+# CFLAGS_O=/W3 /O2 /Zi /MD /GF /Gy /nologo
+# CFLAGS_O=/W3 /O2 /Zi /MD /nologo
+# CFLAGS_O=/W3 /O2 /Zi /MT /nologo
+CFLAGS_O=/W3 /O2 /Zi /MT /nologo
+CF_EX=/DWIN32 $(CF_LANPLUS) $(INC) /D_CONSOLE /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DHAVE_STRING_H
+CF_SAM=/DWIN32 $(INC) /D_CONSOLE /D_CRT_SECURE_NO_DEPRECATE /DHAVE_STRING_H
+CFLAGS=$(CFLAGS_O) $(CF_EX) /DSKIP_MD2
+CFLAGS_M=$(CFLAGS_O) $(CF_EX) /DSKIP_MD2 /DMETACOMMAND
+CFLAGS_SAM=$(CFLAGS_O) $(CF_SAM)
+LFLAGS=/nologo /subsystem:console /machine:$(MARCH) /opt:ref
+#LFLAGS=/nologo /subsystem:console /machine:IX86 /opt:ref
+#LFLAGS=/nologo /subsystem:console /machine:IX86 /opt:ref /debug
+# LFLAGS_D=/nologo /subsystem:console /machine:I386 /opt:ref /dll
+
+# CFLAGS_W=/O2 /D_CONSOLE /D_MBCS /EHsc /ML /W3 /Zi /TP
+CFLAGS_W=/TP /EHsc $(CFLAGS)
+LFLAGS_W=/nologo /subsystem:console /machine:$(MARCH) /opt:ref
+LIBS_W=comsuppw.lib wbemuuid.lib
+# gdi32.lib comdlg32.lib shell32.lib uuid.lib
+
+CC=cl
+LINK=link
+MKDIR=-mkdir
+MKLIB=lib
+RM=del
+CP=copy
+
+LIBS_EX = advapi32.lib kernel32.lib wsock32.lib ws2_32.lib $(LIBS_W) $(LIBC_RT)
+LIBS_PEF = /LIBPATH:$(LIB_D) iphlpapi.lib
+# LIBS_EX+=wsock32.lib user32.lib gdi32.lib
+
+HEADER=ipmicmd.h imb_api.h ipmilan.h ipmidir.h ipmilanplus.h \
+ ipmiutil.h
+
+SHOWSEL = showsel
+TARG_EXE=ievents.exe $(SHOWSEL)msg.dll ipmi_sample.exe ipmi_sample_evt.exe $(SAMP_DLL)
+# alarms.exe ihealth.exe $(SHOWSEL).exe $(SHOWSEL)msg.dll \
+# ireset.exe ifru.exe ilan.exe iserial.exe wdt.exe \
+# getevent.exe sensor.exe icmd.exe isolconsole.exe idiscover.exe \
+# ievents.exe
+SAMP_LIB = ipmiutil.lib
+SAMP_DLL = ipmiutillib.dll
+
+E_EXE=ipmiutil.exe
+E_OBJ=$(TMP_D)\ipmiutil.obj \
+ $(TMP_D)\ialarms.obj $(TMP_D)\ihealth.obj $(TMP_D)\iwdt.obj \
+ $(TMP_D)\ireset.obj $(TMP_D)\ifru.obj $(TMP_D)\ilan.obj \
+ $(TMP_D)\iserial.obj $(TMP_D)\icmd.obj $(TMP_D)\isol.obj \
+ $(TMP_D)\isolwin.obj $(TMP_D)\AnsiTerm.obj $(TMP_D)\idiscover.obj \
+ $(TMP_D)\iconfig.obj $(TMP_D)\igetevent.obj $(TMP_D)\isensor.obj \
+ $(TMP_D)\isel.obj $(TMP_D)\ievents.obj \
+ $(TMP_D)\ipicmg.obj $(TMP_D)\ifirewall.obj \
+ $(TMP_D)\iekanalyzer.obj $(TMP_D)\ifru_picmg.obj \
+ $(TMP_D)\oem_kontron.obj $(TMP_D)\ihpm.obj $(TMP_D)\ifwum.obj \
+ $(TMP_D)\oem_fujitsu.obj $(TMP_D)\oem_intel.obj \
+ $(TMP_D)\oem_sun.obj $(TMP_D)\oem_dell.obj $(TMP_D)\oem_hp.obj \
+ $(TMP_D)\oem_supermicro.obj $(TMP_D)\itsol.obj $(TMP_D)\idcmi.obj \
+ $(TMP_D)\oem_quanta.obj $(TMP_D)\oem_newisys.obj $(CMD_OBJ) mem_if.obj
+
+###################################################################
+all: banner $(TMP_D) exe
+
+banner:
+ @echo Building ipmiutil
+
+$(TMP_D):
+ $(MKDIR) $(TMP_D)
+ @echo created $(TMP_D)
+
+lib: $(L2_OBJ)
+ cd $(LIB_D)
+ nmake /nologo -f ipmilib.mak
+ cd ../util
+
+exe: $(E_EXE) $(TARG_EXE)
+
+install:
+ $(MKDIR) $(INSTALLTOP)
+ $(MKDIR) $(INSTALLTOP)\bin
+ $(CP) $(E_EXE) $(INSTALLTOP)\bin
+ xcopy $(TARG_EXE) $(INSTALLTOP)\bin
+ xcopy *.dll $(INSTALLTOP)\bin
+
+clean:
+ $(RM) *.obj 2>NUL
+ $(RM) $(TARG_EXE) 2>NUL
+ $(RM) *.exe 2>NUL
+ $(RM) $(TMP_D)\*.obj 2>NUL
+
+distclean:
+ $(RM) *.obj 2>NUL
+ $(RM) $(TARG_EXE) 2>NUL
+ $(RM) *.exe 2>NUL
+ $(RM) $(TMP_D)\*.* 2>NUL
+ rmdir $(TMP_D) 2>NUL
+ $(RM) *.rc 2>NUL
+ $(RM) *.bin 2>NUL
+ $(RM) *.RES 2>NUL
+ $(RM) getopt.* 2>NUL
+
+getopt.obj: getopt.c
+ $(CC) /c $(CFLAGS) getopt.c
+
+imbapi.obj: imbapi.c
+ $(CC) /c $(CFLAGS_M) imbapi.c
+
+ipmicmd.obj: ipmicmd.c
+ $(CC) /c $(CFLAGS) ipmicmd.c
+
+ipmilan.obj: ipmilan.c
+ $(CC) /c $(CFLAGS) ipmilan.c
+
+ipmilanplus.obj: ipmilanplus.c
+ $(CC) /c $(CFLAGS_M) ipmilanplus.c
+
+md5.obj: md5.c
+ $(CC) /c $(CFLAGS) md5.c
+
+md2.obj: md2.c
+ $(CC) /c $(CFLAGS) md2.c
+
+ievents.obj: ievents.c
+ $(CC) /c $(CFLAGS) ievents.c
+
+ialarms.obj: ialarms.c
+ $(CC) /c $(CFLAGS) ialarms.c
+
+ihealth.obj: ihealth.c
+ $(CC) /c $(CFLAGS) ihealth.c
+
+igetevent.obj: igetevent.c
+ $(CC) /c $(CFLAGS) igetevent.c
+
+mem_if.obj: mem_if.c
+ $(CC) /c $(CFLAGS_W) mem_if.c
+
+ipmims.obj: ipmims.cpp
+ $(CC) /c $(CFLAGS_W) ipmims.cpp
+
+isel.obj: isel.c
+ $(CC) /c $(CFLAGS) isel.c
+
+ireset.obj: ireset.c
+ $(CC) /c $(CFLAGS) ireset.c
+
+ireset.exe: ireset.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ireset.exe ireset.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ifru.obj: ifru.c
+ $(CC) /c $(CFLAGS) ifru.c
+
+ifru.exe: ifru.obj mem_if.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ifru.exe ifru.obj mem_if.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ilan.obj: ilan.c
+ $(CC) /c $(CFLAGS) ilan.c
+
+ilan.exe: ilan.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ilan.exe ilan.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_PEF) $(LIBS_EX)
+
+iserial.obj: iserial.c
+ $(CC) /c $(CFLAGS) iserial.c
+
+iserial.exe: iserial.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:iserial.exe iserial.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+isensor.obj: isensor.c
+ $(CC) /c $(CFLAGS) isensor.c
+
+isensor.exe: isensor.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isensor.exe isensor.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+iwdt.obj: iwdt.c
+ $(CC) /c $(CFLAGS) iwdt.c
+
+iwdt.exe: iwdt.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:iwdt.exe iwdt.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+isol.obj: isol.c
+ $(CC) /c $(CFLAGS) isol.c
+
+isolwin.obj: isolwin.c
+ $(CC) /c $(CFLAGS) isolwin.c
+
+isol.exe: isol.obj isolwin.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isol.exe isol.obj isolwin.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+icmd.obj: icmd.c
+ $(CC) /c $(CFLAGS) icmd.c
+
+icmd.exe: icmd.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:icmd.exe icmd.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+idiscover.obj: idiscover.c
+ $(CC) /c $(CFLAGS) idiscover.c
+
+idiscover.exe: idiscover.obj getopt.obj
+ $(LINK) $(LFLAGS) /OUT:idiscover.exe idiscover.obj getopt.obj \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ialarms.exe: ialarms.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ialarms.exe ialarms.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ihealth.exe: ihealth.obj mem_if.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ihealth.exe ihealth.obj mem_if.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+igetevent.exe: igetevent.obj ievents.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:igetevent.exe igetevent.obj ievents.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+isel.exe: isel.obj ievents.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isel.exe isel.obj ievents.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+$(SHOWSEL).mc:
+ $(CP) ..\scripts\$(SHOWSEL).mc .
+
+$(SHOWSEL)msg.dll: $(SHOWSEL).mc
+ mc -U $(SHOWSEL).mc
+ rc -r $(SHOWSEL).rc
+ $(LINK) /machine:$(MARCH) -dll -noentry -out:$(SHOWSEL)msg.dll $(SHOWSEL).res
+
+mem_if.exe: $(TMP_D)\mem_if.obj
+ $(LINK) $(LFLAGS_W) /OUT:mem_if.exe $(TMP_D)\mem_if.obj $(LIBS_EX)
+
+$(TMP_D)\mem_if.obj: mem_if.c
+ $(CC) /c $(CFLAGS_W) /DCOMP_BIN /Fo$(TMP_D)\mem_if.obj mem_if.c
+
+ievents.exe: ievents.c
+ $(CC) /c $(CFLAGS) /DALONE ievents.c
+ $(LINK) $(LFLAGS) /OUT:ievents.exe ievents.obj $(LIBS_EX)
+ $(RM) ievents.obj
+
+ipmims.exe: ipmims.cpp
+ $(CC) /c $(CFLAGS_W) /DALONE /DTEST_BIN ipmims.cpp
+ $(LINK) $(LFLAGS_W) /OUT:ipmims.exe ipmims.obj $(LIBS_EX)
+ $(RM) ipmims.obj
+
+$(TMP_D)\ievents.obj: ievents.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ievents.obj ievents.c
+
+$(TMP_D)\ipmiutil.obj: ipmiutil.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ipmiutil.obj ipmiutil.c
+
+$(TMP_D)\ialarms.obj: ialarms.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ialarms.obj ialarms.c
+
+$(TMP_D)\ihealth.obj: ihealth.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ihealth.obj ihealth.c
+
+$(TMP_D)\iconfig.obj: iconfig.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iconfig.obj iconfig.c
+
+$(TMP_D)\ipicmg.obj: ipicmg.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ipicmg.obj ipicmg.c
+
+$(TMP_D)\ifirewall.obj: ifirewall.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifirewall.obj ifirewall.c
+
+$(TMP_D)\ifwum.obj: ifwum.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifwum.obj ifwum.c
+
+$(TMP_D)\ihpm.obj: ihpm.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ihpm.obj ihpm.c
+
+$(TMP_D)\idcmi.obj: idcmi.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\idcmi.obj idcmi.c
+
+$(TMP_D)\oem_fujitsu.obj: oem_fujitsu.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_fujitsu.obj oem_fujitsu.c
+
+$(TMP_D)\oem_kontron.obj: oem_kontron.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_kontron.obj oem_kontron.c
+
+$(TMP_D)\oem_intel.obj: oem_intel.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_intel.obj oem_intel.c
+
+$(TMP_D)\oem_sun.obj: oem_sun.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_sun.obj oem_sun.c
+
+$(TMP_D)\oem_dell.obj: oem_dell.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_dell.obj oem_dell.c
+
+$(TMP_D)\oem_hp.obj: oem_hp.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_hp.obj oem_hp.c
+
+$(TMP_D)\oem_supermicro.obj: oem_supermicro.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_supermicro.obj oem_supermicro.c
+
+$(TMP_D)\oem_quanta.obj: oem_quanta.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_quanta.obj oem_quanta.c
+
+$(TMP_D)\oem_newisys.obj: oem_newisys.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_newisys.obj oem_newisys.c
+
+$(TMP_D)\iekanalyzer.obj: iekanalyzer.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iekanalyzer.obj iekanalyzer.c
+
+$(TMP_D)\ifru_picmg.obj: ifru_picmg.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifru_picmg.obj ifru_picmg.c
+
+$(TMP_D)\ifru.obj: ifru.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifru.obj ifru.c
+
+$(TMP_D)\ireset.obj: ireset.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ireset.obj ireset.c
+
+$(TMP_D)\ilan.obj: ilan.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ilan.obj ilan.c
+
+$(TMP_D)\iserial.obj: iserial.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iserial.obj iserial.c
+
+$(TMP_D)\isensor.obj: isensor.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isensor.obj isensor.c
+
+$(TMP_D)\icmd.obj: icmd.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\icmd.obj icmd.c
+
+$(TMP_D)\igetevent.obj: igetevent.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\igetevent.obj igetevent.c
+
+$(TMP_D)\isel.obj: isel.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isel.obj isel.c
+
+$(TMP_D)\isol.obj: isol.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isol.obj isol.c
+
+$(TMP_D)\isolwin.obj: isolwin.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isolwin.obj isolwin.c
+
+$(TMP_D)\itsol.obj: itsol.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\itsol.obj itsol.c
+
+$(TMP_D)\AnsiTerm.obj: AnsiTerm.cpp
+ $(CC) /c $(CFLAGS_W) /Fo$(TMP_D)\AnsiTerm.obj AnsiTerm.cpp
+
+$(TMP_D)\idiscover.obj: idiscover.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\idiscover.obj idiscover.c
+
+$(TMP_D)\iwdt.obj: iwdt.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iwdt.obj iwdt.c
+
+$(E_EXE): $(E_OBJ)
+ $(LINK) $(LFLAGS) /OUT:$(E_EXE) $(E_OBJ) $(LF_LANPLUS) $(LIBS_PEF) $(LIBS_EX)
+
+ipmi_sample.obj: ipmi_sample.c
+ $(CC) /c $(CFLAGS_SAM) ipmi_sample.c
+
+$(SAMP_LIB): $(CMD_OBJ) mem_if.obj
+ $(CC) /c $(CFLAGS_SAM) ipmilanplus.c
+ $(MKLIB) /OUT:$(SAMP_LIB) /nologo $(CMD_OBJ) mem_if.obj
+ del ipmilanplus.obj
+
+$(SAMP_DLL): $(CMD_OBJ) mem_if.obj
+ $(CC) /D_WINDLL /D_USRDLL /c $(CFLAGS_SAM) ipmilanplus.c
+ $(LINK) /DLL $(LFLAGS) /OUT:$(SAMP_DLL) /def:ipmiutillib.def $(CMD_OBJ) mem_if.obj $(LIBS_PEF) $(LIBS_EX)
+ del ipmilanplus.obj
+
+ipmi_sample.exe: $(SAMP_LIB) ipmi_sample.obj
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample.exe ipmi_sample.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
+
+ipmi_sample2.exe: $(SAMP_LIB) ipmi_sample.c isensor.c ievents.c
+ $(CC) /c $(CFLAGS_SAM) /DGET_SENSORS ipmi_sample.c
+ $(CC) /c $(CFLAGS_SAM) isensor.c
+ $(CC) /c $(CFLAGS_SAM) ievents.c
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample2.exe ipmi_sample.obj isensor.obj ievents.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
+ del isensor.obj ievents.obj
+
+ipmi_sample_evt.obj: ipmi_sample_evt.c $(HEADER)
+ $(CC) /c $(CFLAGS_SAM) ipmi_sample_evt.c
+
+isensor2.obj: isensor.c isensor.h $(HEADER)
+ $(CC) /c /Foisensor2.obj $(CFLAGS_SAM) isensor.c
+
+ievents2.obj: ievents.c ievents.h $(HEADER)
+ $(CC) /c /Foievents2.obj $(CFLAGS_SAM) /DSENSORS_OK ievents.c
+
+ipmi_sample_evt.exe: $(SAMP_LIB) ipmi_sample_evt.obj ievents2.obj isensor2.obj
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample_evt.exe ipmi_sample_evt.obj ievents2.obj isensor2.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
diff --git a/util/ipmiutil64.mak b/util/ipmiutil64.mak new file mode 100644 index 0000000..4c7b315 --- /dev/null +++ b/util/ipmiutil64.mak @@ -0,0 +1,423 @@ +# This makefile will build the ipmiutil util directory (x64)
+#
+# First download getopt.c getopt.h
+# Then download and build openssl for Windows
+#
+LIBC_RT=libcmt.lib /NODEFAULTLIB:"msvcirt.lib"
+# LIBC_RT=msvcrt.lib /NODEFAULTLIB:"msvcirt.lib"
+
+#MARCH=IX86
+MARCH=X64
+# The ipmiutil directory
+SRC_D=.
+LIB_D=..\lib
+L2_D=$(LIB_D)\lanplus
+L3_D=$(LIB_D)\lanplus\inc
+INSTALLTOP=install
+TMP_D=tmp
+INC=/I$(SRC_D) /I$(L2_D) /I$(L3_D)
+CMD_OBJ = getopt.obj ipmicmd.obj imbapi.obj md5.obj md2.obj \
+ ipmilan.obj ipmims.obj subs.obj
+CMD_OBJ = $(CMD_OBJ) ipmilanplus.obj
+# To remove lanplus support use the empty LANPLUS variables
+# L2_OBJ=
+# LF_LANPLUS=
+# CF_LANPLUS=
+L2_OBJ = $(L2_D)\helper.obj $(L2_D)\ipmi_strings.obj $(L2_D)\lanplus.obj \
+ $(L2_D)\lanplus_crypt_impl.obj $(L2_D)\lanplus_dump.obj \
+ $(L2_D)\lanplus_strings.obj $(L2_D)\lanplus_crypt.obj
+LF_LANPLUS=/LIBPATH:$(LIB_D) $(L2_OBJ) ssleay32.lib libeay32.lib
+CF_LANPLUS=/D HAVE_LANPLUS
+
+# Set your compiler options
+# To remove any GPL dependencies, use the CF_EX line with NON_GPL
+# CFLAGS_O=/W3 /O2 /Zi /MD /GF /Gy /nologo
+# CFLAGS_O=/W3 /O2 /Zi /MD /nologo
+# CFLAGS_O=/W3 /O2 /Zi /MT /nologo
+CFLAGS_O=/W3 /O2 /Zi /MT /nologo
+CF_EX=/DWIN32 $(CF_LANPLUS) $(INC) /D_CONSOLE /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DHAVE_STRING_H
+CF_SAM=/DWIN32 $(INC) /D_CONSOLE /D_CRT_SECURE_NO_DEPRECATE /DHAVE_STRING_H
+CFLAGS=$(CFLAGS_O) $(CF_EX) /DSKIP_MD2
+CFLAGS_M=$(CFLAGS_O) $(CF_EX) /DSKIP_MD2 /DMETACOMMAND
+CFLAGS_SAM=$(CFLAGS_O) $(CF_SAM)
+LFLAGS=/nologo /subsystem:console /machine:$(MARCH) /opt:ref
+#LFLAGS=/nologo /subsystem:console /machine:IX86 /opt:ref
+#LFLAGS=/nologo /subsystem:console /machine:IX86 /opt:ref /debug
+# LFLAGS_D=/nologo /subsystem:console /machine:I386 /opt:ref /dll
+
+# CFLAGS_W=/O2 /D_CONSOLE /D_MBCS /EHsc /ML /W3 /Zi /TP
+CFLAGS_W=/TP /EHsc $(CFLAGS)
+LFLAGS_W=/nologo /subsystem:console /machine:$(MARCH) /opt:ref
+LIBS_W=comsuppw.lib wbemuuid.lib
+# gdi32.lib comdlg32.lib shell32.lib uuid.lib
+
+CC=cl
+LINK=link
+MKDIR=-mkdir
+MKLIB=lib
+RM=del
+CP=copy
+
+LIBS_EX = advapi32.lib kernel32.lib wsock32.lib ws2_32.lib $(LIBS_W) $(LIBC_RT)
+LIBS_PEF = /LIBPATH:$(LIB_D) iphlpapi.lib
+# LIBS_EX+=wsock32.lib user32.lib gdi32.lib
+
+HEADER=ipmicmd.h imb_api.h ipmilan.h ipmidir.h ipmilanplus.h \
+ ipmiutil.h
+
+SHOWSEL = showsel
+TARG_EXE=ievents.exe $(SHOWSEL)msg.dll ipmi_sample.exe ipmi_sample2.exe ipmi_sample_evt.exe $(SAMP_DLL)
+# alarms.exe ihealth.exe $(SHOWSEL).exe $(SHOWSEL)msg.dll \
+# ireset.exe ifru.exe ilan.exe iserial.exe wdt.exe \
+# getevent.exe sensor.exe icmd.exe isolconsole.exe idiscover.exe \
+# ievents.exe
+SAMP_LIB = ipmiutil.lib
+SAMP_DLL = ipmiutillib.dll
+
+E_EXE=ipmiutil.exe
+E_OBJ=$(TMP_D)\ipmiutil.obj \
+ $(TMP_D)\ialarms.obj $(TMP_D)\ihealth.obj $(TMP_D)\iwdt.obj \
+ $(TMP_D)\ireset.obj $(TMP_D)\ifru.obj $(TMP_D)\ilan.obj \
+ $(TMP_D)\iserial.obj $(TMP_D)\icmd.obj $(TMP_D)\isol.obj \
+ $(TMP_D)\isolwin.obj $(TMP_D)\AnsiTerm.obj $(TMP_D)\idiscover.obj \
+ $(TMP_D)\iconfig.obj $(TMP_D)\igetevent.obj $(TMP_D)\isensor.obj \
+ $(TMP_D)\isel.obj $(TMP_D)\ievents.obj \
+ $(TMP_D)\ipicmg.obj $(TMP_D)\ifirewall.obj \
+ $(TMP_D)\iekanalyzer.obj $(TMP_D)\ifru_picmg.obj \
+ $(TMP_D)\oem_kontron.obj $(TMP_D)\ihpm.obj $(TMP_D)\ifwum.obj \
+ $(TMP_D)\oem_fujitsu.obj $(TMP_D)\oem_intel.obj \
+ $(TMP_D)\oem_sun.obj $(TMP_D)\oem_dell.obj $(TMP_D)\oem_hp.obj \
+ $(TMP_D)\oem_supermicro.obj $(TMP_D)\itsol.obj $(TMP_D)\idcmi.obj \
+ $(TMP_D)\oem_quanta.obj $(TMP_D)\oem_newisys.obj $(CMD_OBJ) mem_if.obj
+
+###################################################################
+all: banner $(TMP_D) exe
+
+banner:
+ @echo Building ipmiutil
+
+$(TMP_D):
+ $(MKDIR) $(TMP_D)
+ @echo created $(TMP_D)
+
+lib: $(L2_OBJ)
+ cd $(LIB_D)
+ nmake /nologo -f ipmilib.mak
+ cd ../util
+
+exe: $(E_EXE) $(TARG_EXE)
+
+install:
+ $(MKDIR) $(INSTALLTOP)
+ $(MKDIR) $(INSTALLTOP)\bin
+ $(CP) $(E_EXE) $(INSTALLTOP)\bin
+ xcopy $(TARG_EXE) $(INSTALLTOP)\bin
+ xcopy *.dll $(INSTALLTOP)\bin
+
+clean:
+ $(RM) *.obj 2>NUL
+ $(RM) $(TARG_EXE) 2>NUL
+ $(RM) *.exe 2>NUL
+ -$(RM) $(TMP_D)\*.obj 2>NUL
+
+distclean:
+ $(RM) *.obj 2>NUL
+ $(RM) $(TARG_EXE) 2>NUL
+ $(RM) *.exe 2>NUL
+ -$(RM) $(TMP_D)\*.* 2>NUL
+ rmdir $(TMP_D) 2>NUL
+ $(RM) *.rc 2>NUL
+ $(RM) *.bin 2>NUL
+ $(RM) *.RES 2>NUL
+ $(RM) getopt.* 2>NUL
+
+getopt.obj: getopt.c
+ $(CC) /c $(CFLAGS) getopt.c
+
+imbapi.obj: imbapi.c
+ $(CC) /c $(CFLAGS_M) imbapi.c
+
+ipmicmd.obj: ipmicmd.c
+ $(CC) /c $(CFLAGS) ipmicmd.c
+
+ipmilan.obj: ipmilan.c
+ $(CC) /c $(CFLAGS) ipmilan.c
+
+ipmilanplus.obj: ipmilanplus.c
+ $(CC) /c $(CFLAGS_M) ipmilanplus.c
+
+md5.obj: md5.c
+ $(CC) /c $(CFLAGS) md5.c
+
+md2.obj: md2.c
+ $(CC) /c $(CFLAGS) md2.c
+
+ievents.obj: ievents.c
+ $(CC) /c $(CFLAGS) ievents.c
+
+ialarms.obj: ialarms.c
+ $(CC) /c $(CFLAGS) ialarms.c
+
+ihealth.obj: ihealth.c
+ $(CC) /c $(CFLAGS) ihealth.c
+
+igetevent.obj: igetevent.c
+ $(CC) /c $(CFLAGS) igetevent.c
+
+mem_if.obj: mem_if.c
+ $(CC) /c $(CFLAGS_W) mem_if.c
+
+ipmims.obj: ipmims.cpp
+ $(CC) /c $(CFLAGS_W) ipmims.cpp
+
+isel.obj: isel.c
+ $(CC) /c $(CFLAGS) isel.c
+
+ireset.obj: ireset.c
+ $(CC) /c $(CFLAGS) ireset.c
+
+ireset.exe: ireset.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ireset.exe ireset.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ifru.obj: ifru.c
+ $(CC) /c $(CFLAGS) ifru.c
+
+ifru.exe: ifru.obj mem_if.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ifru.exe ifru.obj mem_if.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ilan.obj: ilan.c
+ $(CC) /c $(CFLAGS) ilan.c
+
+ilan.exe: ilan.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ilan.exe ilan.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_PEF) $(LIBS_EX)
+
+iserial.obj: iserial.c
+ $(CC) /c $(CFLAGS) iserial.c
+
+iserial.exe: iserial.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:iserial.exe iserial.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+isensor.obj: isensor.c
+ $(CC) /c $(CFLAGS) isensor.c
+
+isensor.exe: isensor.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isensor.exe isensor.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+iwdt.obj: iwdt.c
+ $(CC) /c $(CFLAGS) iwdt.c
+
+iwdt.exe: iwdt.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:iwdt.exe iwdt.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+isol.obj: isol.c
+ $(CC) /c $(CFLAGS) isol.c
+
+isolwin.obj: isolwin.c
+ $(CC) /c $(CFLAGS) isolwin.c
+
+isol.exe: isol.obj isolwin.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isol.exe isol.obj isolwin.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+icmd.obj: icmd.c
+ $(CC) /c $(CFLAGS) icmd.c
+
+icmd.exe: icmd.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:icmd.exe icmd.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+idiscover.obj: idiscover.c
+ $(CC) /c $(CFLAGS) idiscover.c
+
+idiscover.exe: idiscover.obj getopt.obj
+ $(LINK) $(LFLAGS) /OUT:idiscover.exe idiscover.obj getopt.obj \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ialarms.exe: ialarms.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ialarms.exe ialarms.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+ihealth.exe: ihealth.obj mem_if.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:ihealth.exe ihealth.obj mem_if.obj $(CMD_OBJ) \
+ $(LF_LANPLUS) $(LIBS_EX)
+
+igetevent.exe: igetevent.obj ievents.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:igetevent.exe igetevent.obj ievents.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+isel.exe: isel.obj ievents.obj $(CMD_OBJ)
+ $(LINK) $(LFLAGS) /OUT:isel.exe isel.obj ievents.obj \
+ $(CMD_OBJ) $(LF_LANPLUS) $(LIBS_EX)
+
+$(SHOWSEL).mc:
+ $(CP) ..\scripts\$(SHOWSEL).mc .
+
+$(SHOWSEL)msg.dll: $(SHOWSEL).mc
+ mc -U $(SHOWSEL).mc
+ rc -r $(SHOWSEL).rc
+ $(LINK) /machine:$(MARCH) -dll -noentry -out:$(SHOWSEL)msg.dll $(SHOWSEL).res
+
+mem_if.exe: $(TMP_D)\mem_if.obj
+ $(LINK) $(LFLAGS_W) /OUT:mem_if.exe $(TMP_D)\mem_if.obj $(LIBS_EX)
+
+$(TMP_D)\mem_if.obj: mem_if.c
+ $(CC) /c $(CFLAGS_W) /DCOMP_BIN /Fo$(TMP_D)\mem_if.obj mem_if.c
+
+ievents.exe: ievents.c
+ $(CC) /c $(CFLAGS) /DALONE ievents.c
+ $(LINK) $(LFLAGS) /OUT:ievents.exe ievents.obj $(LIBS_EX)
+ $(RM) ievents.obj
+
+ipmims.exe: ipmims.cpp
+ $(CC) /c $(CFLAGS_W) /DALONE /DTEST_BIN ipmims.cpp
+ $(LINK) $(LFLAGS_W) /OUT:ipmims.exe ipmims.obj $(LIBS_EX)
+ $(RM) ipmims.obj
+
+$(TMP_D)\ievents.obj: ievents.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ievents.obj ievents.c
+
+$(TMP_D)\ipmiutil.obj: ipmiutil.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ipmiutil.obj ipmiutil.c
+
+$(TMP_D)\ialarms.obj: ialarms.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ialarms.obj ialarms.c
+
+$(TMP_D)\ihealth.obj: ihealth.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ihealth.obj ihealth.c
+
+$(TMP_D)\iconfig.obj: iconfig.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iconfig.obj iconfig.c
+
+$(TMP_D)\ipicmg.obj: ipicmg.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ipicmg.obj ipicmg.c
+
+$(TMP_D)\ifirewall.obj: ifirewall.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifirewall.obj ifirewall.c
+
+$(TMP_D)\ifwum.obj: ifwum.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifwum.obj ifwum.c
+
+$(TMP_D)\ihpm.obj: ihpm.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ihpm.obj ihpm.c
+
+$(TMP_D)\idcmi.obj: idcmi.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\idcmi.obj idcmi.c
+
+$(TMP_D)\oem_fujitsu.obj: oem_fujitsu.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_fujitsu.obj oem_fujitsu.c
+
+$(TMP_D)\oem_kontron.obj: oem_kontron.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_kontron.obj oem_kontron.c
+
+$(TMP_D)\oem_intel.obj: oem_intel.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_intel.obj oem_intel.c
+
+$(TMP_D)\oem_sun.obj: oem_sun.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_sun.obj oem_sun.c
+
+$(TMP_D)\oem_dell.obj: oem_dell.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_dell.obj oem_dell.c
+
+$(TMP_D)\oem_hp.obj: oem_hp.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_hp.obj oem_hp.c
+
+$(TMP_D)\oem_supermicro.obj: oem_supermicro.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_supermicro.obj oem_supermicro.c
+
+$(TMP_D)\oem_quanta.obj: oem_quanta.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_quanta.obj oem_quanta.c
+
+$(TMP_D)\oem_newisys.obj: oem_newisys.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\oem_newisys.obj oem_newisys.c
+
+$(TMP_D)\iekanalyzer.obj: iekanalyzer.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iekanalyzer.obj iekanalyzer.c
+
+$(TMP_D)\ifru_picmg.obj: ifru_picmg.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifru_picmg.obj ifru_picmg.c
+
+$(TMP_D)\ifru.obj: ifru.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ifru.obj ifru.c
+
+$(TMP_D)\ireset.obj: ireset.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ireset.obj ireset.c
+
+$(TMP_D)\ilan.obj: ilan.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\ilan.obj ilan.c
+
+$(TMP_D)\iserial.obj: iserial.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iserial.obj iserial.c
+
+$(TMP_D)\isensor.obj: isensor.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isensor.obj isensor.c
+
+$(TMP_D)\icmd.obj: icmd.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\icmd.obj icmd.c
+
+$(TMP_D)\igetevent.obj: igetevent.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\igetevent.obj igetevent.c
+
+$(TMP_D)\isel.obj: isel.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isel.obj isel.c
+
+$(TMP_D)\isol.obj: isol.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isol.obj isol.c
+
+$(TMP_D)\isolwin.obj: isolwin.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\isolwin.obj isolwin.c
+
+$(TMP_D)\itsol.obj: itsol.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\itsol.obj itsol.c
+
+$(TMP_D)\AnsiTerm.obj: AnsiTerm.cpp
+ $(CC) /c $(CFLAGS_W) /Fo$(TMP_D)\AnsiTerm.obj AnsiTerm.cpp
+
+$(TMP_D)\idiscover.obj: idiscover.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\idiscover.obj idiscover.c
+
+$(TMP_D)\iwdt.obj: iwdt.c
+ $(CC) /c $(CFLAGS_M) /Fo$(TMP_D)\iwdt.obj iwdt.c
+
+$(E_EXE): $(E_OBJ)
+ $(LINK) $(LFLAGS) /OUT:$(E_EXE) $(E_OBJ) $(LF_LANPLUS) $(LIBS_PEF) $(LIBS_EX)
+
+ipmi_sample.obj: ipmi_sample.c
+ $(CC) /c $(CFLAGS_SAM) ipmi_sample.c
+
+$(SAMP_LIB): $(CMD_OBJ) mem_if.obj
+ $(CC) /c $(CFLAGS_SAM) ipmilanplus.c
+ $(MKLIB) /OUT:$(SAMP_LIB) /nologo $(CMD_OBJ) mem_if.obj
+ del ipmilanplus.obj
+
+$(SAMP_DLL): $(CMD_OBJ) mem_if.obj
+ $(CC) /D_WINDLL /D_USRDLL /c $(CFLAGS_SAM) ipmilanplus.c
+ $(LINK) /DLL $(LFLAGS) /OUT:$(SAMP_DLL) /def:ipmiutillib.def $(CMD_OBJ) mem_if.obj $(LIBS_PEF) $(LIBS_EX)
+ del ipmilanplus.obj
+
+ipmi_sample.exe: $(SAMP_LIB) ipmi_sample.obj
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample.exe ipmi_sample.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
+
+ipmi_sample2.exe: $(SAMP_LIB) ipmi_sample.c isensor.c ievents.c
+ $(CC) /c $(CFLAGS_SAM) /DGET_SENSORS ipmi_sample.c
+ $(CC) /c $(CFLAGS_SAM) isensor.c
+ $(CC) /c $(CFLAGS_SAM) ievents.c
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample2.exe ipmi_sample.obj isensor.obj ievents.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
+ del isensor.obj ievents.obj
+
+ipmi_sample_evt.obj: ipmi_sample_evt.c $(HEADER)
+ $(CC) /c $(CFLAGS_SAM) ipmi_sample_evt.c
+
+isensor2.obj: isensor.c isensor.h $(HEADER)
+ $(CC) /c /Foisensor2.obj $(CFLAGS_SAM) isensor.c
+
+ievents2.obj: ievents.c ievents.h $(HEADER)
+ $(CC) /c /Foievents2.obj $(CFLAGS_SAM) /DSENSORS_OK ievents.c
+
+ipmi_sample_evt.exe: $(SAMP_LIB) ipmi_sample_evt.obj ievents2.obj isensor2.obj
+ $(LINK) $(LFLAGS) /OUT:ipmi_sample_evt.exe ipmi_sample_evt.obj ievents2.obj isensor2.obj $(SAMP_LIB) $(LIBS_PEF) $(LIBS_EX)
diff --git a/util/ipmiutillib.def b/util/ipmiutillib.def new file mode 100644 index 0000000..57f3dc1 --- /dev/null +++ b/util/ipmiutillib.def @@ -0,0 +1,31 @@ +LIBRARY ipmiutillib
+EXPORTS
+ ipmi_cmd
+ ipmi_cmdraw
+ ipmi_close_
+ ipmi_set_mc
+ ipmi_get_mc
+ ipmi_restore_mc
+ ipmi_cmd_mc
+ ipmi_cmdraw_mc
+ parse_lan_options
+ print_lan_opt_usage
+ set_lan_options
+ get_lan_options
+ set_max_kcs_loops
+ get_driver_type
+ set_driver_type
+ get_nodename
+ nodeislocal
+ is_remote
+ ipmi_getdeviceid
+ show_devid
+ show_outcome
+ dump_buf
+ decode_rv
+ decode_cc
+ str_icmp
+ strdup_
+ htoi
+ os_usleep
+ write_syslog
diff --git a/util/ireset.c b/util/ireset.c new file mode 100644 index 0000000..8116b7d --- /dev/null +++ b/util/ireset.c @@ -0,0 +1,751 @@ +/* + * ireset.c (was hwreset.c) + * + * This tool power cycles (or powers off) the IPMI system. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2009 Kontron America, Inc. + * Copyright (c) 2002-2008 Intel Corporation + * + * 01/08/02 Andy Cress - created + * 01/31/02 Andy Cress - converted to use ipmi_cmd_ia, + * added more user options + * 02/06/02 Andy Cress - added ipmi_cmd_va + * 02/22/02 Andy Cress - added -s to reboot to service partition + * 07/02/02 Andy Cress v1.3 added more Usage text + * 08/02/02 Andy Cress v1.4 moved common ipmi_cmd() code to ipmicmd.c + * 09/24/02 Andy Cress - stubbed in OS shutdown option + * 01/29/03 Andy Cress v1.5 added MV OpenIPMI support + * 04/08/03 Andy Cress v1.6 added OS shutdown option (-o) + * 05/02/03 Andy Cress v1.7 leave console redir alone in SET_BOOT_OPTIONS + * 05/05/04 Andy Cress v1.8 call ipmi_close before exit, did WIN32 port. + * 08/09/04 Andy Cress v1.9 make sure to show error if ccode != 0, and + * detect Langley platforms to do special + * watchdog method for -o option. + * 11/01/04 Andy Cress 1.10 add -N / -R for remote nodes + * 11/16/04 Andy Cress 1.11 add -U for remote username + * 11/30/04 Andy Cress 1.12 fix bug 1075550 with -o -N, skip -o if not local. + * 03/28/05 Andy Cress 1.13 add netapp_reset commands for platforms that + * use this instead of chassis_reset. + * 05/16/05 Andy Cress 1.14 add -u option for power up + * 03/31/06 Andy Cress 1.15 add -e -p -m options + * 09/18/06 Andy Cress 1.20 allow more platforms to do soft reset, and + * if Tyan, ignore set boot options errors. + * 01/10/07 Andy Cress 1.25 added reset_str(), modify initchar (6) if -o. + */ +/*M* +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include "getopt.h" +#elif defined(EFI) + // EFI: defined (EFI32) || defined (EFI64) || defined(EFIX64) + // also would define ALONE (not METACOMMAND) to minimize externals + #ifndef NULL + #define NULL 0 + #endif + #include <types.h> + #include <libdbg.h> + #include <unistd.h> +#elif defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <stdlib.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include <string.h> +#include "ipmicmd.h" +#include "oem_intel.h" /* for is_romley*/ + +#define platIntel 1 /*Intel Sahalee servers, use alt soft-shutdown.*/ +#define platMBMC 2 /*mini-BMC platforms */ +#define platS5500 3 /*Intel S5500 platforms */ +#define platOther 4 /*Other platforms */ +#define GET_POWER_STATE 0x07 +#define INIT_VAL 0xff + +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "ireset"; +static uchar ipmi_maj; +static uchar ipmi_min; +static uchar sms_sa = 0x81; +static char fdebug = 0; +static char fipmilan = 0; +static char fignore_opterr = 0; +static char fwait = 0; +static char fpersist = 0; +static char platform = 0; /* platform type: MBMC or TSR */ +static int shuttime = 60; /* shutdown timeout in seconds */ +#define MAX_INIT 77 /* 80 minus 3 for IANA */ +static char * initstr = NULL; /* boot initiator mailbox string */ +static uchar iana[3] = { 0x00, 0x00, 0x00 }; /*default to devid, see -j */ +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static uchar gbootparm = 0x48; //verbose disply, bypass pswd, same console redir + +#if defined(EFI) +int getopt(int argc, char **argv, const char *opts) +{ /*very simple getopt */ + int c = EOF; + static int iopt = 0; + iopt++; + if ((argc <= iopt) || (argv[iopt] == NULL)) return c; + if (argv[iopt][0] == '-') c = argv[iopt][1]; + return(c); +} +#endif +#if defined(ALONE) +int is_romley(int vend, int prod) +{ + int ret = 0; + if (vend != VENDOR_INTEL) return(ret); + if (prod >= 0x0048 && prod <= 0x005e) ret = 1; + return(ret); +} +int write_syslog(char *msg) { return(0); } /*stub*/ +#else +/*extern*/ int write_syslog(char *msg); /*from showsel.c*/ +#endif + +static void show_error(char *tag, int rv, uchar cc) +{ + if (rv > 0 && cc == 0) cc = (uchar)rv; + printf("%s: error %d ccode = %x %s\n", + tag,rv,cc,decode_cc((ushort)0,cc)); + return; +} + +static int set_wdt(uchar val, uchar act) +{ + uchar idata[6]; + uchar rdata[16]; + int rlen = 8; + uchar ccode; + int ret, t; + + t = val * 10; /* val is in sec, make timeout in 100msec */ + if ((ipmi_maj > 1) || /* IPMI 1.5 or greater */ + (ipmi_maj == 1 && ipmi_min >= 5)) + idata[0] = 0x44; /* DontLog=0, DontStop=1 & use SMS/OS */ + else idata[0] = 0x04; /* IPMI 1.0 or less */ + idata[1] = act; + /* 0x01; * action: no pretimeout, hard reset action */ + /* 0x02; * action value for power down instead */ + idata[2] = 0; /* pretimeout: 30 sec (but disabled) */ + idata[3] = 0x10; /* clear SMS/OS when done */ + idata[4] = t & 0x00ff; /*timeout in 100msec: 0x4B0 = 1200. */ + idata[5] = (t & 0xff00) >> 8; + ret = ipmi_cmd_mc(WATCHDOG_SET, idata, 6, rdata, &rlen, &ccode, fdebug); + if (fdebug) printf("set_wdt: wd set(%d,%d) rv=%d cc=%x\n", + val,act,ret,ccode); + if (ret == 0 && ccode != 0) ret = ccode; + + if (ret == 0) { /* Start the timer by issuing a watchdog reset */ + ret = ipmi_cmd_mc(WATCHDOG_RESET,idata,0,rdata,&rlen, &ccode,fdebug); + if (fdebug) printf("set_wdt: wd reset rv=%d cc=%x\n",ret,ccode); + if (ret == 0 && ccode != 0) ret = ccode; + } + return(ret); +} /*end set_wdt()*/ + +char *reset_str(uchar breset, uchar bopt) +{ + char *str; + switch(breset) { + case 0: str = "powering down"; break; + case 1: str = "powering up"; break; + case 2: str = "power cycling"; break; + case 3: str = "resetting"; break; /* -r, etc.*/ + case 4: str = "sending NMI"; break; + case 5: str = "shutdown/reset"; break; + case 6: str = "shutdown/power_off"; break; /*via agent*/ + case 7: str = "cold reset"; break; + default: str = "resetting"; break; + } + if (bopt > 0) + switch(bopt) { + case 1: str = "resetting to Svc partition"; break; + case 2: str = "resetting to EFI"; break; + case 3: str = "resetting to PXE"; break; + case 4: str = "resetting to CDROM"; break; + case 5: str = "resetting to hard disk"; break; + case 6: str = "resetting to BIOS Setup"; break; + case 7: str = "resetting to floppy"; break; + default: str = "resetting"; break; + } + return(str); +} + +int set_boot_init_string(char *istr) +{ + int rv = 0; + uchar idata[20]; /*need 17 bytes*/ + uchar rdata[MAX_BUFFER_SIZE]; + uchar cc; + int i, n, len, rlen; + + /* set param 7 for boot initiator mailbox */ + len = (int)strlen(istr); + n = 0; + for (i = 0; n < len; i++) + { + memset(idata,0,18); + idata[0] = 0x07; /* param, 7 = boot init mailbox */ + idata[1] = i; /* set selector */ + if (i == 0) { /* insert IANA */ + idata[2] = iana[0]; + idata[3] = iana[1]; + idata[4] = iana[2]; + strncpy(&idata[5],&istr[n],13); + n += 13; + } else { + strncpy(&idata[2],&istr[n],16); + n += 16; + } + rlen = MAX_BUFFER_SIZE; + rv = ipmi_cmd_mc(SET_BOOT_OPTIONS, idata, 18, rdata, &rlen, &cc, fdebug); + if (rv == 0 && cc != 0) rv = cc; + if (rv != 0) break; + } + return(rv); +} + +static int IPMI_Reset(uchar bpower, uchar bootopt) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar completionCode; + uchar inputData[20]; + char initmsg[80]; + int status = 0; + uchar cmd; + + /* May want to GetSystemBootOptions first to show existing. */ + + /* if (bootopt != 0) then set param 3 to not clear boot valid flag */ + if (bootopt != 0) + { + inputData[0] = 0x03; // param, 3 = boot clear + if (fpersist) + inputData[1] = 0x1F; // persist all available conditions + else inputData[1] = 0x00; // clear after next boot + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmd_mc(SET_BOOT_OPTIONS, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + if (status == 0) status = completionCode; + if (status != 0) { + if (fdebug || !fignore_opterr) + printf("set_boot_options ccode %x, resp[0] = %x, resp[1] = %x\n", + completionCode, responseData[0], responseData[1]); + if (!fignore_opterr) + return(status); /* abort if the boot options can't be set */ + } + + inputData[0] = 0x05; // param, 5 = boot flags + if (fpersist) + inputData[1] = 0xC0; // valid flags, persistent + else inputData[1] = 0x80; // valid flags, next boot only + if (bootopt == 2) inputData[1] |= 0x20; // add boot to EFI + if (bootopt == 1) inputData[2] = 0x10; // boot to svc partition + else if (bootopt == 3) inputData[2] = 0x04; // boot to PXE + else if (bootopt == 4) inputData[2] = 0x14; // boot to CDROM + else if (bootopt == 5) inputData[2] = 0x08; // boot to Hard Disk + else if (bootopt == 6) inputData[2] = 0x18; // boot to BIOS Setup + else if (bootopt == 7) inputData[2] = 0x3C; // boot to Floppy/Remov + else if (bootopt == 8) inputData[2] = 0x0C; // boot to HardDisk/Safe + else inputData[2] = 0x00; // normal boot + inputData[3] = gbootparm; + inputData[4] = 0x00; //no overrides + inputData[5] = 0x00; // + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmd_mc(SET_BOOT_OPTIONS, inputData, 6, responseData, + &responseLength, &completionCode, fdebug); + if (status == 0) status = completionCode; + if (status != 0) { + if (fdebug || !fignore_opterr) + printf("set_boot_options ccode %x, resp[0] = %x, resp[1] = %x\n", + completionCode, responseData[0], responseData[1]); + if (!fignore_opterr) + return(status); /* abort if the boot options can't be set */ + } + if (initstr != NULL) { + status = set_boot_init_string(initstr); + if (fdebug) printf("set_boot_init_string(%s) status = %d\n", + initstr,status); + if (status != 0) { + if (!fignore_opterr) return(status); + else status = 0; + } + } + } + + /* + * fshutdown (bpower >= 5) for Intel: + * Since we are in user mode, we can't wait for it to fully + * shut down and then issue the IPMI Chassis Reset. + * IPMI can trigger this by emulating an overtemp event. + * There is also a watchdog/init0 method used by platIntel. + * bpower was set by caller to 5 or 6 + */ + if ((bpower >= 5) && (platform == platIntel)) + { /*Intel os shutdown requested*/ + if (fipmilan) { +#ifdef EXPERIMENTAL + int rv; + /*Try remote shutdown via Bridged SMS */ + inputData[0] = 5; /* chassis ctl soft shutdown option */ + responseLength = MAX_BUFFER_SIZE; + rv = ipmi_cmdraw( CHASSIS_CTL, + NETFN_APP,BMC_SA,PUBLIC_BUS, SMS_LUN, + inputData,1,responseData,&responseLength, + &completionCode, fdebug); + printf("Remote soft shutdown initiated (%d,%d).\n",status,rv); +#else + /* abort if call this with fipmi_lan, platIntel. */ + /* should have invoked remote agent method before this. */ + return(LAN_ERR_NOTSUPPORT); +#endif + } else { /* do local shutdown with wdt*/ + uchar action; + char initcmd[16]; + char initchar, shutchar; + + /* + * Special OS shutdown method for CG Servers + * Set up a watchdog event to do reset after timeout. + * Valid on other platforms too if they support watchdog. + * Note that the "init 0" only makes sense if local. + */ + if (bpower == 6) { action = 0x02; /*do power_down*/ + initchar = '0'; + shutchar = 's'; + } else { action = 0x01; /*do hard_reset*/ + initchar = '6'; + shutchar = 'r'; + } + status = set_wdt((uchar)shuttime, action); + if (status == 0) + { /*local shutdown */ + sprintf(initmsg,"%s: soft shutdown -%c initiated\n",progname,shutchar); + write_syslog(initmsg); +#ifdef WIN32 + sprintf(initcmd,"shutdown -%c -c %s",shutchar,progname); + status = system(initcmd); /* do the OS shutdown */ + printf("Windows soft shutdown initiated (%s).\n",initcmd); +#else + sprintf(initcmd,"init %c",initchar); + status = system(initcmd); /* do the OS shutdown */ + printf("Linux soft shutdown initiated (%s).\n",initcmd); +#endif + } + /* + * Note that this can generate a Watchdog 2 event in the SEL. + * If the init 0/6 is successful within the 60 second timeout, + * BIOS will stop the watchdog. + */ + return(status); + } /*endif local*/ + } /*endif Intel os shutdown*/ + + /* 0 = power down, 1 = power up, 2 = power cycle, 3 = hard reset */ + /* 4 = NMI interrupt, 5 = soft shutdown OS via ACPI */ + if (bpower > 5) bpower = 5; /* if invalid, try shutdown */ + if (!fipmilan) { /*only write to syslog if local*/ + sprintf(initmsg,"%s: chassis %s\n",progname,reset_str(bpower,bootopt)); + write_syslog(initmsg); + } + inputData[0] = bpower; // chassis control reset + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmd_mc(CHASSIS_CTL, inputData, 1, responseData, + &responseLength, &completionCode, fdebug); + if (fdebug) { + printf("Chassis_Ctl(%x) ccode=%x, resp[0]=%x, resp[1]=%x\n", + bpower, completionCode, + responseData[0], responseData[1]); + } + if (status == ACCESS_OK && completionCode == 0) { + printf("chassis_reset ok\n"); + //successful, done + return(0); + } else if (fipmilan && (status < 0)) { + /* Remote IPMI LAN reset could not connect, + * no point in continuing. */ + return(status); + } else { + if (bpower == 5 && completionCode == 0xcc) { + /* See IPMI spec 22.3 Chassis Control, Table 22-4 */ + printf("Optional soft-shutdown mode not supported\n"); + /* If get here, need to use method like platIntel above. */ + } else { + show_error("chassis_reset",status,completionCode); + // status = -1; + + /* Try net_app warm/cold reset commands instead */ + if (bpower == 2) cmd = 2; /* cold reset */ + else cmd = 3; /* warm reset */ + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmdraw( cmd,NETFN_APP, g_sa, g_bus, g_lun, + inputData,0,responseData,&responseLength, + &completionCode, fdebug); + if (status == ACCESS_OK && completionCode == 0) { + printf("netapp_reset ok\n"); + } else { + show_error("netapp_reset",status,completionCode); + if (status == 0) status = completionCode; + } + } + } /*end else*/ + return(status); +} /*end IPMI_Reset()*/ + +static void wait_ready(void) +{ + int i, c; + uchar devrec[16]; + /* wait for BMC ready again */ + os_usleep(1,0); /*delay 1 sec*/ + for (i = 0; i < 15; i++) { + os_usleep(1,0); /*delay 1 sec*/ + c = ipmi_getdeviceid(devrec,16,fdebug); + if (c == 0) break; + else { /* expect LAN_ERR_RECV_FAIL if BMC not ready */ + if (fdebug) printf("after reset, try%d ret = %d\n",i,c); + if (c != LAN_ERR_RECV_FAIL) break; + } + } /*end-for*/ +} + +static void show_usage(void) +{ + printf("Usage: %s [-bcdDefhkmnoprsuwxy -N node -U user -P/-R pswd -EFTVY]\n", + progname); + printf(" where -c power Cycles the system\n"); + printf(" -d powers Down the system\n"); + printf(" -D soft-shutdown OS and power down\n"); + printf(" -k do Cold Reset of the BMC firmware\n"); + printf(" -i<str> set boot Initiator mailbox string\n"); + printf(" -j<num> set IANA number for boot Initiator\n"); + printf(" -n sends NMI to the system\n"); + printf(" -o soft-shutdown OS and reset\n"); + printf(" -r hard Resets the system\n"); + printf(" -u powers Up the system\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -b reboots to BIOS Setup\n"); + printf(" -e reboots to EFI\n"); + printf(" -f reboots to Floppy/Removable\n"); + printf(" -h reboots to Hard Disk\n"); + printf(" -p reboots to PXE via network\n"); + printf(" -s reboots to Service Partition\n"); + printf(" -v reboots to DVD/CDROM Media\n"); + printf(" -w Wait for BMC ready after reset\n"); + printf(" -x show eXtra debug messages\n"); + printf(" -y Yes, persist boot options [-befhpms]\n"); + print_lan_opt_usage(); +} + +#ifdef METACOMMAND +int i_reset(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret; + int c; + uchar breset; + uchar bopt; + uchar fshutdown = 0; + uchar devrec[16]; + int rlen; + uchar rqdata[10]; + uchar rsdata[32]; + int rslen; + int mfg = 0; + uchar cc; + char *s1; + +#if defined (EFI) + InitializeLib(_LIBC_EFIImageHandle, _LIBC_EFISystemTable); +#endif + // progname = argv[0]; + printf("%s ver %s\n", progname,progver); + breset = INIT_VAL; /* invalid as default, require an option */ + bopt = 0; /* Boot Options default */ + /* Request admin privilege by default, since power control requires it. */ + parse_lan_options('V',"4",0); + + while ((c = getopt(argc,argv,"bcdDefhi:j:km:noprsuvwyT:V:J:YEF:N:P:R:U:Z:x?")) != EOF) + switch(c) { + case 'd': breset = 0; break; /* power down */ + case 'u': breset = 1; break; /* power up */ + case 'c': breset = 2; break; /* power cycle */ + case 'o': breset = 5; fshutdown = 1; break; /*soft shutdown,reset*/ + case 'D': breset = 6; fshutdown = 1; break; /*soft shutdown,pwrdown*/ + case 'n': breset = 4; break; /* interrupt (NMI) */ + case 'r': breset = 3; break; /* hard reset */ + case 's': breset = 3; bopt = 1; break; /* hard reset to svc part */ + case 'e': breset = 3; bopt = 2; break; /* hard reset to EFI */ + case 'p': breset = 3; bopt = 3; break; /* hard reset to PXE */ + case 'v': breset = 3; bopt = 4; break; /* hard reset to DVD/CD Media*/ + case 'h': breset = 3; bopt = 5; break; /* hard reset to Hard Disk */ + case 'b': breset = 3; bopt = 6; break; /* hard reset to BIOS Setup */ + case 'f': breset = 3; bopt = 7; break; /* hard reset to floppy/remov*/ + case 'i': if (strlen(optarg) < MAX_INIT) initstr = optarg; break; + case 'j': mfg = atoi(optarg); /*IANA number*/ + iana[0] = ((mfg & 0xFF0000) >> 16); + iana[1] = ((mfg & 0x00FF00) >> 8); + iana[2] = (mfg & 0x0000FF); + break; + case 'k': breset = 7; break; /* cold reset */ + case 'w': fwait = 1; break; /* wait for ready */ + case 'y': fpersist = 1; break; /* yes, persist boot options */ + case 'm': /* specific MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("set MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case 'x': fdebug = 1; break; /* debug messages */ + default: + show_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + if (breset == INIT_VAL) { + show_usage(); + printf("An option is required\n"); + ret = ERR_BAD_PARAM; + goto do_exit; + } + + fipmilan = is_remote(); + /* + * Check the Device ID to determine the platform type. + */ + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + ipmi_close_(); + goto do_exit; + } else { + char *pstr; + int vendid; + ushort prodid; + uchar j; + + if (fdebug) { + printf("devid: "); + for (j = 0; j < 16; j++) printf("%02x ",devrec[j]); + printf("\n"); + } + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + vendid = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + if (mfg == 0) memcpy(iana,&devrec[6],3); /*not set, use default*/ + prodid = devrec[9] + (devrec[10] << 8); + pstr = "BMC"; + if (fdebug) printf("vendor = %06x, product_id = %04x\n",vendid,prodid); + if (vendid == VENDOR_NSC) { /* NSC mBMC */ + pstr = "mBMC"; + platform = platMBMC; + } else if (vendid == VENDOR_HP) { /* HP */ + platform = platOther; /* other platform types */ + gbootparm = 0x00; + fignore_opterr = 1; /* ignore boot options errors */ + } else if (vendid == VENDOR_TYAN) { /* Tyan */ + platform = platOther; /* other platform types */ + fignore_opterr = 1; /* ignore boot options errors */ + } else if (vendid == VENDOR_INTEL) { /* Intel */ + if (prodid != 0x0100) /* ia64 Itanium2 is different */ + platform = platIntel; /* else handle as Intel Sahalee */ + if (is_romley(vendid,prodid) || (prodid == 0x003E)) { + /* Romley or Thurley/S5520UR */ + platform = platS5500; /* not like Intel Sahalee */ + set_max_kcs_loops(URNLOOPS); /*longer KCS timeout*/ + } + } else if (vendid == VENDOR_KONTRON) { /* Kontron */ + fignore_opterr = 1; /* ignore boot options errors */ + /* supports Chassis Soft Power command 0x05, so not platIntel */ + platform = platOther; /* handle like other platforms */ + } else { /* other vendors */ + platform = platOther; /* other platform types */ + } + printf("-- %s version %x.%x, IPMI version %d.%d \n", + pstr, devrec[2], devrec[3], ipmi_maj, ipmi_min); + } + + { /* show current power state */ + char *pstr; + uchar pstate; + rlen = sizeof(devrec); + ret = ipmi_cmdraw( GET_POWER_STATE, NETFN_APP, + g_sa, g_bus, g_lun, + NULL,0, devrec,&rlen,&cc, fdebug); + if (ret == 0) { + pstate = devrec[0] & 0x7f; + switch(pstate) { + case 0x00: pstr = "S0: working"; break; + case 0x01: pstr = "S1: clock stopped, context ok"; break; + case 0x02: pstr = "S2: clock stopped, context lost"; break; + case 0x03: pstr = "S3: suspend-to-RAM"; break; + case 0x04: pstr = "S4: suspend-to-Disk"; break; + case 0x05: pstr = "S5: soft off"; break; + case 0x06: pstr = "S4/S5: soft off, either S4 or S5"; break; + case 0x07: pstr = "G3: mechanical off"; break; + case 0x08: pstr = "S1-S3: sleeping"; break; + case 0x09: pstr = "S1-S4: sleeping"; break; + case 0x0A: pstr = "S5/o: soft off by override"; break; + case 0x20: pstr = "legacy on"; break; + case 0x21: pstr = "legacy soft-off"; break; + default: pstr = "unknown"; break; + } + if (cc == 0) + printf("Power State = %02x (%s)\n",pstate,pstr); + } + } + + if (breset == 7) { /*do Cold Reset */ + printf("%s: %s ...\n",progname,reset_str(breset,bopt)); + rslen = sizeof(rsdata); + ret = ipmi_cmdraw( 0x02, NETFN_APP, g_sa, g_bus, g_lun, + rqdata,0, rsdata, &rslen, &cc, fdebug); + if (fdebug) + printf("cold_reset(%02x) ret=%d cc=%x, rslen=%d\n",g_sa,ret,cc,rslen); + if (ret == 0) ret = cc; + if (ret == 0) + printf("%s: Cold_Reset ok\n",progname); + else + printf("%s: Cold_Reset error %d\n",progname,ret); + ipmi_close_(); + + } else if (fshutdown && fipmilan && (platform == platIntel)) { /*soft reset*/ + int fdaemonok = 0; + /* Either do special remote soft-shutdown, or + * handle it within IPMI_Reset. */ + /* Special remote soft-shutdown, requires a service to + * be running on the target node. + * GET_SOFTWARE_ID == 0x00 + * SMS_OS_REQUEST == 0x10 : (down=0, reset=1) + * BRIDGE_REQUEST == 0x20 : (down=0, reset=1) + * SMS_SA == 0x81 + */ + rslen = sizeof(rsdata); + ret = ipmi_cmdraw( 0x00, NETFN_APP,sms_sa,PUBLIC_BUS, SMS_LUN, + rqdata,0, rsdata, &rslen, &cc, fdebug); + if (fdebug) + printf("ipmilan getswid ret=%d cc=%x, rslen=%d\n",ret,cc,rslen); + if (ret == 0 && cc == 0) { + ushort v,x; + v = (rsdata[6] << 16) + (rsdata[7] << 8) + rsdata[8]; + x = (rsdata[9] << 8) + rsdata[10]; + if (fdebug) printf("swid v: %06x x: %04x\n",v,x); + if (v == 0x000157 && x == 0x0001) fdaemonok = 1; + } + if (fdaemonok) { + /* os_usleep(0,50000); *delay 50 ms, not needed*/ + if (breset == 0 || breset == 6) + rqdata[0] = 0x01; /* shutdown & power down */ + else rqdata[0] = 0x02; /* shutdown & reset */ + if (fdebug) printf("ipmilan shutdown action=%x\n",rqdata[0]); + rslen = sizeof(rsdata); + ret = ipmi_cmdraw( SMS_OS_REQUEST, NETFN_APP,sms_sa,PUBLIC_BUS,SMS_LUN, + rqdata,1, rsdata, &rslen, &cc, fdebug); + printf("ipmilan shutdown request: ret = %d, cc = %x\n", ret,cc); + if (fipmilan && fwait) { + ipmi_close_(); /* to try new connection */ + wait_ready(); + } + } + else printf("ipmilan async bridge agent not present\n"); + ipmi_close_(); + } else { + printf("%s: %s ...\n",progname,reset_str(breset,bopt)); + ret = IPMI_Reset(breset,bopt); + if (ret == 0) { /* if ok */ + printf("%s: IPMI_Reset ok\n",progname); + /* It starts resetting by this point, so do not close. */ + if (breset == 4) ipmi_close_(); /*NMI, so close*/ + if (fipmilan && fwait) { + ipmi_close_(); /* to try new connection */ + wait_ready(); + ipmi_close_(); + } + } else { + printf("%s: IPMI_Reset error %d\n",progname,ret); + ipmi_close_(); + } + } +do_exit: + // show_outcome(progname,ret); + return(ret); +} /* end main()*/ + +/* end ireset.c */ diff --git a/util/isel.c b/util/isel.c new file mode 100644 index 0000000..c974b24 --- /dev/null +++ b/util/isel.c @@ -0,0 +1,884 @@ +/* + * isel.c (was showsel.c) + * + * This tool reads the firmware System Event Log records via IPMI commands. + * It can use either the Intel /dev/imb driver or VALinux /dev/ipmikcs. + * + * Author: Andy Cress arcress at users.sourceforge.net + * + * Copyright (c) 2001-2005 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * Copyright (c) 2013 Andy Cress <arcress at users.sourceforge.net> + * + * 10/16/01 Andy Cress - created + * 10/19/01 Andy Cress - added text for Sensor Types from Table 36-3 + * 10/24/01 Andy Cress - added panic string display for OS Crit Stop + * 11/01/01 Andy Cress - added logic to write SEL records to syslog + * 11/15/01 Andy Cress - added logic for more description strings + * 01/31/02 Andy Cress - isolated dependencies on /dev/imb to ipmi_cmd_ia(), + * added ipmi_cmd_va() for va ipmi driver also, + * added posterrs array for more descriptions. + * 02/06/02 Andy Cress - fixed bug 279 (extra debug msg at EOF). + * 03/25/02 Andy Cress - show free space, add -c to clear SEL. + * 04/11/02 Andy Cress - decode timestamp into readable form + * 06/14/02 Andy Cress - also show status error in ClearSEL + * 07/02/02 Andy Cress v1.3 add more Usage text + * 08/02/02 Andy Cress v1.4 moved common ipmi_cmd() code to ipmicmd.c + * 10/07/02 Andy Cress v1.5 added -v option with BMC version too + * 01/16/03 Andy Cress v1.6 Handle new OS crit stop format with die code + * 01/29/03 Andy Cress v1.7 added MV OpenIPMI support + * 02/05/03 Andy Cress v1.8 show better message if empty SEL (cc=0xCB), + * show an additional warning if free space is low. + * 02/18/03 Andy Cress v1.9 trim out some fields so it fits on 1 line, + * decode Boot Event subcodes + * 02/27/03 Andy Cress v1.10 change OS Crit Stop decoding to handle new types + * 03/20/03 Andy Cress v1.11 for -w, save id also, so we don't have to start + * over at the beginning each time. + * 04/30/03 Andy Cress v1.12 changed display ordering. + * 06/23/03 Andy Cress v1.13 fix -w if log gets cleared + * 08/19/03 Andy Cress v1.14 handle OEM/other record types + * 09/16/03 Andy Cress v1.15 added more sens_desc strings + * 10/03/03 Andy Cress v1.16 added more sens_desc strings (for boot) + * 01/19/04 Andy Cress v1.17 added more sens_desc for Fans + * 01/30/04 Andy Cress v1.18 added WIN32 flags, and sens_desc for Voltage + * 03/12/04 Andy Cress v1.19 ClockSync description changed + * 03/29/04 Andy Cress v1.20 change pattern matching for thresholds, + * added sens_desc for ID Button + * check either time or record_id if fwritesel + * show warning if <20% free also + * added sens_desc for System Events, HSC, Power, Int + * 04/13/04 Andy Cress v1.21 added threshold OK descriptions, + * change header (time is local, not GMT) + * 05/05/04 Andy Cress v1.22 call ipmi_close before exit, + * include ReportEvent code for WIN32 + * 06/10/04 Andy Cress v1.23 use gmtime instead of localtime for WIN32 + * 08/16/04 Andy Cress v1.24 added more decoding for Power events + * 09/20/04 Andy Cress v1.25 added 2 event descriptors for ia64 platforms + * 11/01/04 Andy Cress v1.26 add -N / -R for remote nodes + * 11/16/04 Andy Cress v1.27 add -U for username, + * added more decoding for mBMC watchdog events + * 11/19/04 Andy Cress v1.28 added more decoding for crit_int, slots, etc. + * changed firmware error decoding. + * 02/17/05 Andy Cress v1.29 made decode_sel_entry() a subroutine, + * added logic for OEM 0xc0 record types. + * 05/24/05 Andy Cress v1.30 fixed SegFault with StartWriting/fscanf + * 05/26/05 Andy Cress v1.31 moved decode_sel_entry to events.c + * 08/01/05 Andy Cress v1.32 updated events.c for PowerUnit & Battery + * 09/12/05 Andy Cress v1.33 dont check superuser for fipmi_lan + * 06/29/06 Andy Cress v1.34 added -l option + * 02/06/08 Andy Cress v2.8 make sure savid for -w is unsigned + */ +/*M* +Copyright (c) 2002-2005, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#include <stdio.h> +#ifdef WIN32 +#include <windows.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#else +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <syslog.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include <time.h> + +#include "ipmicmd.h" + +#define SELprintf printf +#define ETYPE_CRITSTOP 0x20 +#define RTYPE_OEM2 0xe0 /* 2nd OEM type (range) */ + +#pragma pack(1) +typedef struct +{ + ushort record_id; + uchar record_type; + uint timestamp; + ushort generator_id; /*slave_addr/channel*/ + uchar evm_rev; //event message revision + uchar sensor_type; + uchar sensor_number; + uchar event_trigger; + uchar event_data1; + uchar event_data2; + uchar event_data3; +} SEL_RECORD; +#pragma pack() + +#define MIN_FREE 128 /*=8*16, minimal bytes of free SEL space */ +#define REC_SIZE 16 /*SEL Record Size, see IPMI 1.5 Table 26-1 */ +#define RECORD_BASE 2 //base value to the SEL record in IMB resp data +#define RID_OFFSET 0 //byte offset to the record id +#define RTYPE_OFFSET 2 //byte offset to the record type +#define RTS_OFFSET 3 //byte offset to the record timestamp +#define RGID_OFFSET 7 //byte offset to the record generator id +#define REREV_OFFSET 9 //byte offset to the record event message rev +#define RSTYPE_OFFSET 10 //byte offset to the record sensor type +#define RSN_OFFSET 11 //byte offset to the record sensor number +#define RET_OFFSET 12 //byte offset to the record event trigger +#define RDATA_OFFSET 13 //byte offset to the record event data + +static char *progname = "isel"; +static char *progver = "2.93"; +#ifdef WIN32 +#define IDXFILE "sel.idx" +static char idxfile[80] = IDXFILE; +static char idxfile2[80] = "%ipmiutildir%\\sel.idx"; +#else +static char idxfile[80] = "/var/lib/ipmiutil/sel.idx"; +static char idxfile2[80] = "/usr/share/ipmiutil/sel.idx"; /*old location*/ +#endif +static char fdebug = 0; +static char fall = 1; +static char futc = 0; +static char fwritesel = 0; +static char fshowraw = 0; +static char fdecoderaw = 0; +static char fdecodebin = 0; +static char fclearsel = 0; +static char faddsel = 0; +static char fonlyver = 0; +static char flastrecs = 0; +static char fremote = 0; +static char fsensdesc = 0; +static char fcanonical = 0; +static char fset_mc = 0; +static uchar min_sev = 0; /*only show sev >= this value [0,1,2,3]*/ +static char *addstr = NULL; +static char *addhex = NULL; +static uint savtime = 0; +static ushort savid = 0; +static int nlast = 20; +static ushort idinc = REC_SIZE; +static char *rawfile = NULL; +static int vend_id, prod_id; +static uchar *sdrs = NULL; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + +/*------------------------------------------------------------------------ + * decode_sel_entry + * Parse and decode the SEL record into readable format. + * See ievents.c + *------------------------------------------------------------------------*/ +extern char *evt_hdr; +extern char *evt_hdr2; +extern int decode_sel_entry( uchar *psel, char *outbuf, int sz); +extern int decode_raw_sel( char *raw_file, int mode); +extern void set_sel_opts(int sensdsc, int canon, void *sdrs, char fdbg, char u); +extern int get_sdr_cache( uchar **sdrs); +extern void free_sdr_cache( uchar *sdrs); +extern uchar find_msg_sev(char *msgbuf); /* subs.c*/ +extern int OpenSyslog(char *tag); /*see subs.c*/ +extern void CloseSyslog(void); /*see subs.c*/ +extern void WriteSyslog(char *msgbuf); /*see subs.c*/ +extern int write_syslog(char *msg); /*see subs.c*/ + +/*F* +//////////////////////////////////////////////////////////////////////////////// +// GetSelEntry +//////////////////////////////////////////////////////////////////////////////// +// Name : GetSelEntry +// +// Purpose : This routine gets the next SEL record +// +// Parameters : +// pRecordID : input/output pointer to next Record ID +// selRecord : output pointer to the sel record +// +// Returns : 0 if success +// -1 if last record. +// -2 if completion code error. +// -3 if null buffer on input. +// -4 if record id mismatch. +// +// Notes : uses ipmi_cmd() +// +*F*/ +int GetSelEntry(ushort *pRecordID, SEL_RECORD *selRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[6]; + uchar completionCode; + char* cpRecordID; //for next record id + ushort inRecordID; //save the input record id + + inRecordID = *pRecordID; + if (!selRecord) + { + if (fdebug) + SELprintf("GetSelEntry: error, output buffer is NULL\n"); + return -3; + } + + //set the reservation id to zero + inputData[0] = 0; + inputData[1] = 0; + + //set the record id to get + cpRecordID = (char*) pRecordID; + inputData[2] = cpRecordID[0]; + inputData[3] = cpRecordID[1]; + + //set the offset to the record to value zero + inputData[4] = 0; + + //set the number of byte to read. 0xFF means read the entire record + inputData[5] = (char) 0xFF; + + status = ipmi_cmd(GET_SEL_ENTRY, inputData, 6, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (completionCode == 0xCB && inRecordID == 0) + SELprintf("Firmware Log (SEL) is empty\n"); + else + SELprintf("GetSelEntry[%x]: completion code=%x\n", + inRecordID,completionCode); // responseData[0]); + } else { + //successful, done + + //save the next SEL record id + cpRecordID[0] = responseData[0]; + cpRecordID[1] = responseData[1]; + + //save the SEL record content + //(note that selRecord structure must be pragma_pack'd) + memcpy(selRecord,&responseData[RECORD_BASE],16); + + if (inRecordID == 0 || inRecordID == selRecord->record_id) + { + /* We return success if the input record is + begin-of-SEL (value 0), or + input and output record id matches. + */ + return 0; + } + else + { + /* If last record, inRecordID will be -1 from + response data, so return -1 as normal EOF. + (fix to bug 279) + */ + if (inRecordID == 0xFFFF) return(-1); + /* If not last record, this is an error. */ + if (fdebug) + SELprintf("GetSelEntry: input id %d != output id %d \n", inRecordID, selRecord->record_id); + *pRecordID = inRecordID; //restore the input record id + return -4; + } + } + } + + // we are here because after the retry, completionCode is not COMPLETION_CODE_OK + + if (fdebug) + SELprintf("GetSelEntry: ipmi_cmd error %d completion code, code=%d\n", status,completionCode); + return -2; + +} /* end GetSelEntry() */ + +int AddSelEntry(uchar *selrec, int ilen) +{ + uchar rdata[MAX_BUFFER_SIZE]; + int rlen = MAX_BUFFER_SIZE; + uchar idata[16]; + uchar ccode; + int rv; + + /* Do not use AddSelEntry unless there is a legitimate + hardware-related event. */ + memset(idata,0,16); + if (ilen > 16) ilen = 16; + memcpy(idata,selrec,ilen); + rv = ipmi_cmdraw(0x44, NETFN_STOR, g_sa, g_bus, g_lun, + idata, 16, rdata, &rlen, &ccode, fdebug); + return (rv); +} + +int get_sel_time_utc_offset(short *offset) +{ + uchar rdata[MAX_BUFFER_SIZE]; + int rlen = MAX_BUFFER_SIZE; + uchar idata[16]; + uchar ccode; + int rv; + + if (offset == NULL) return(-1); + *offset = 0; + rv = ipmi_cmdraw(0x5C, NETFN_STOR, g_sa, g_bus, g_lun, + idata, 0, rdata, &rlen, &ccode, fdebug); + if (rv == 0) rv = ccode; + if (rv == 0) *offset = rdata[0] + (rdata[1] << 8); + return (rv); +} + +void StartWriting(uint *plasttime, ushort *plastid) +{ + FILE *fd; + uint lasttime; + uint lastid; + int ret = -1; + + lasttime = 0; + lastid = 0; + // Open the index file + fd = fopen(idxfile,"r"); + if (fd == NULL) fd = fopen(idxfile2,"r"); + if (fd != NULL) { + // Read the file, get savtime & savid + ret = fscanf(fd,"%x %x",&lasttime,&lastid); + fclose(fd); + } + else printf("StartWriting: cannot open %s\n",idxfile); + if (fdebug) printf("StartWriting: idx fd=%p, savtime=%x, savid=%x\n", + fd,lasttime,(ushort)lastid); + *plasttime = lasttime; + *plastid = (ushort)lastid; + + ret = OpenSyslog("SEL"); + if (fdebug) printf("StartWriting: ret = %d\n",ret); + return; +} + +void StopWriting(uint lasttime, ushort lastid) +{ + FILE *fd; + // Rewrite the saved time & record id + fd = fopen(idxfile,"w"); + if (fd != NULL) { + fprintf(fd,"%x %x\n",lasttime,lastid); + fclose(fd); + } + else printf("StopWriting: cannot open %s\n",idxfile); + CloseSyslog(); + return; +} + +int ClearSEL(void) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[6]; + uchar completionCode; + ushort cmd; + + cmd = RESERVE_SEL; /*0x0A42*/ + status = ipmi_cmd(cmd, inputData, 0, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK && completionCode == 0) { + cmd = CLEAR_SEL; /*0x0A47*/ + inputData[0] = responseData[0]; /*Reservation ID [0]*/ + inputData[1] = responseData[1]; /*Reservation ID [1]*/ + inputData[2] = 'C'; + inputData[3] = 'L'; + inputData[4] = 'R'; + inputData[5] = 0xAA; /* initiate erase */ + status = ipmi_cmd(cmd, inputData, 6, responseData, + &responseLength, &completionCode, fdebug); + /* The reservation is cancelled by the CLEAR_SEL cmd */ + } + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("ClearSEL: cmd = %x, completion code=%x\n", + cmd,completionCode); + status = completionCode; + } else { + /* Successful, done. */ + SELprintf("ClearSEL: Log Cleared successfully\n"); + } + } else { + SELprintf("ClearSEL: cmd = %x, error status = %d\n", + cmd,status); + } + if (fwritesel) { /* this won't always be enough, but try */ + StartWriting(&savtime,&savid); + savid = 0; + StopWriting(savtime,savid); + } + return(status); +} /* ClearSEL()*/ + + +void ReadSEL(uchar mytype, char fwriteit) +{ + ushort RecordID = 0; /* 0 = first record, 0xFFFF = end */ + SEL_RECORD selRecord; + SEL_RECORD *pSelRecord = &selRecord; + char output[160]; + int rc = 0; + int ilast = 0; + short recid0; + uchar *bsel; + uchar sev; + char fskipit = 0; + + if (fwriteit) { + StartWriting(&savtime,&savid); + RecordID = savid; + } + memset(pSelRecord, 0, sizeof(SEL_RECORD)); + if (flastrecs) { + /* read the first two records to get the record id increment */ + RecordID = 0; + rc = GetSelEntry( &RecordID, pSelRecord); + recid0 = pSelRecord->record_id; + rc = GetSelEntry( &RecordID, pSelRecord); + if (rc == 0) idinc = pSelRecord->record_id - recid0; + else { idinc = recid0; rc = 0; } + RecordID = 0xFFFF; /* -1=0xFFFF; * get last record */ + if (fdebug) printf("recid inc = 0x%02x (%x - %x)\n",idinc, + pSelRecord->record_id,recid0); + } + set_sel_opts(fsensdesc, fcanonical, sdrs, fdebug,futc); + if (futc) { /*Try to get the UTC offset*/ + short utc_off; + printf("Showing SEL Time as UTC\n"); + rc = get_sel_time_utc_offset(&utc_off); + if (rc == 0) { + printf("SEL Time UTC Offset = %d\n",utc_off); + } else rc = 0; /*may fail if not supported, but ok*/ + } + /* show header for the SEL records */ + if (fcanonical) + printf("%s",evt_hdr2); /*RecId | Date/Time */ + else printf("%s",evt_hdr); /*RecId Date/Time_______ */ + while( rc == 0 ) { + rc = GetSelEntry( &RecordID, pSelRecord); + if (fwriteit && (rc != 0) && (RecordID == savid)) { + /* If here, log was probably cleared, so try + * again from the log start. */ + RecordID = 0; + rc = GetSelEntry( &RecordID, pSelRecord); + } + if (fdebug) printf("rc = %d, recid = %04x, next = %04x\n", + rc, pSelRecord->record_id, RecordID); + if (flastrecs && (ilast == 0) && (rc == -1)) rc = 0; + if (rc != 0) { /* EOF or error */ break; } + + if (fshowraw) { + bsel = (uchar *)&selRecord; + sprintf(output,"%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + bsel[0], bsel[1], bsel[2], bsel[3], + bsel[4], bsel[5], bsel[6], bsel[7], + bsel[8], bsel[9], bsel[10], bsel[11], + bsel[12], bsel[13], bsel[14], bsel[15]); + printf("%s", output); + } else { + if (mytype == 0xff || pSelRecord->sensor_type == mytype) { + /* show all records, or type matches */ + decode_sel_entry((uchar *)pSelRecord,output, sizeof(output)); + fskipit = 0; + if (min_sev > 0) { + sev = find_msg_sev(output); + if (fdebug) printf("min_sev=%d, sev=%d\n",min_sev,sev); + if (sev < min_sev) fskipit = 1; + } + if (!fskipit) printf("%s", output); + } else if ((mytype == ETYPE_CRITSTOP) && + (pSelRecord->record_type >= RTYPE_OEM2)) { + /* if showing panics only, also show its oem records */ + decode_sel_entry((uchar *)pSelRecord,output,sizeof(output)); + printf("%s", output); + } else { + if (fdebug) printf("decoding error, mytype = %d\n",mytype); + output[0] = 0; + } + } + + if (fwriteit) { + /* Only write newer records to syslog */ + if (pSelRecord->record_type == 0x02) { + if ((pSelRecord->timestamp > savtime) || + (pSelRecord->record_id > savid)) { + WriteSyslog(output); + savid = pSelRecord->record_id; + savtime = pSelRecord->timestamp; + } + } else { /* no timestamp */ + if (pSelRecord->record_id > savid) { + WriteSyslog(output); + savid = pSelRecord->record_id; + } + } + } /*endif writeit*/ + if( pSelRecord->record_id == 0xFFFF ) + break; + if( RecordID == pSelRecord->record_id ) + break; + if (flastrecs) { + ++ilast; + if (fdebug) printf("ilast = %d, next = %x, id = %x\n", + ilast,RecordID,pSelRecord->record_id); + if (ilast >= nlast) break; + RecordID = pSelRecord->record_id - idinc; + if (RecordID > pSelRecord->record_id) break; + if (RecordID == 0) break; + } + memset(pSelRecord, 0, sizeof(SEL_RECORD)); + } /*endwhile*/ + if (fwriteit) StopWriting(savtime,savid); +} /* end ReadSEL()*/ + +static uint vfree = 0; +static uint vused = 0; +static uint vtotal = 0; +static uint vsize = REC_SIZE; + +static int ReadSELinfo() +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar completionCode; + uchar inputData[6]; + uchar b; + char *strb; + + status = ipmi_cmd(GET_SEL_INFO, inputData, 0, responseData, + &responseLength, &completionCode, fdebug); + if (fdebug) printf("GetSelInfo status = %x, cc = %x\n", + status,completionCode); + + if ((status == ACCESS_OK) && (completionCode == 0)) { + vfree = responseData[3] + (responseData[4] << 8); // in Bytes + vused = responseData[1] + (responseData[2] << 8); // in Entries/Allocation Units + vtotal = vused + (vfree/vsize); // vsize from AllocationInfo + b = responseData[13]; + if (b & 0x80) strb = " overflow"; /*SEL overflow occurred*/ + else strb = ""; + if (b & 0x1) { // Get SEL Allocation Info supported + status = ipmi_cmd(GET_SEL_ALLOCATION_INFO, inputData, 0, + responseData, &responseLength, + &completionCode, fdebug); + if (fdebug) printf("GetSelInfo status = %x, cc = %x\n", + status,completionCode); + if ((status == ACCESS_OK) && (completionCode == 0)) { + vsize = responseData[2] + (responseData[3] << 8); + if (vsize == 0) vsize = REC_SIZE; + vtotal = responseData[0] + (responseData[1] << 8); + } + } + + if (fcanonical) + SELprintf("SEL %s Size = %d records (Used=%d, Free=%d)\n", + strb, vtotal, vused, vfree/vsize ); + else + SELprintf("SEL Ver %x Support %02x%s, Size = %d records (Used=%d, Free=%d)\n", + responseData[0], + b, strb, + vtotal, + vused, + vfree/vsize ); + //successful, done + return(0); + } else { + vfree = MIN_FREE * 2; /*sane values to avoid SEL full warning*/ + vused = 0; + vtotal = vused + (vfree/vsize); + return(1); + } + +} /*end ReadSELinfo()*/ + + +#ifdef ALONE +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#else +/* METACOMMAND */ +int i_sel(int argc, char **argv) +#endif +{ + int ret = -1; + char DevRecord[16]; + int c; + char *s1; + + printf("%s: version %s\n",progname,progver); + while ((c = getopt(argc,argv,"a:b:cdef:h:l:m:nprs:uwvx:T:V:J:EYF:P:N:U:R:Z:?")) != EOF) + switch(c) { + case 'a': faddsel = 1; /*undocumented option, to prevent misuse*/ + addstr = optarg; /*text string, max 13 bytes*/ + break; + case 'h': faddsel = 1; /*undocumented option, to prevent misuse*/ + addhex = optarg; /*string of 16 hex characters, no spaces*/ + break; + case 'b': fdecodebin = 1; + rawfile = optarg; + break; + case 'd': fclearsel = 1; break; /*delete/clear SEL*/ + case 'e': fsensdesc = 1; break; /*extended sensor descriptions*/ + case 'f': fdecoderaw = 1; + rawfile = optarg; + break; + case 'l': flastrecs = 1; + nlast = atoi(optarg); + break; + case 'm': /* specific MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + printf("set MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'c': + case 'n': fcanonical = 1; /*parse easier, canonical*/ + fsensdesc = 1; /*extended sensor descriptions*/ + /* Note that this option does not show event data bytes */ + break; + case 'p': fall = 0; break; /*crit stop (panic) only*/ + case 'r': fshowraw = 1; break; + case 's': min_sev = atob(optarg); break; /*show sev >= value*/ + case 'u': futc = 1; break; + case 'v': fonlyver = 1; break; + case 'w': fwritesel = 1; break; + case 'x': fdebug = 1; break; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-bcdefmnprsuvwx] [-l 5] [-NUPREFTVY]\n", + progname); + printf(" -b interpret Binary file with raw SEL data\n"); + printf(" -c Show canonical output with delimiters\n"); + printf(" -d Delete, Clears all SEL records\n"); + printf(" -e shows Extended sensor description if run locally\n"); + printf(" -f interpret File with ascii hex SEL data\n"); + printf(" -l5 Show last 5 SEL records (reverse order)\n"); + printf(" -r Show uninterpreted raw SEL records in ascii hex\n"); + printf(" -n Show nominal/canonical output (same as -c)\n"); + printf(" -p Show only Panic/Critical Stop records\n"); + printf(" -s1 Show only Severity >= value (0,1,2,3)\n"); + printf(" -u use raw UTC time\n"); + printf(" -v Only show version information\n"); + printf(" -w Writes new SEL records to syslog\n"); + printf(" -x Display extra debug messages\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + if (fwritesel && flastrecs) { + printf("Error: Options -l and -w are incompatible\n"); + ret = ERR_BAD_PARAM; + goto do_exit; + } + + /* Handle simple decoding options -f, -b */ + if (fdecoderaw) { /* -f */ + ret = decode_raw_sel(rawfile,1); + goto do_exit; + } else if (fdecodebin) { /* -b */ + ret = decode_raw_sel(rawfile,2); + goto do_exit; + } + + // if (fwrite) fall = 1; // would we ever set fwrite without fall?? +#ifdef WIN32 + fremote = is_remote(); + if (fwritesel) { /*resolve path of idxfile*/ + char *ipath; + ipath = getenv("ipmiutildir"); /*ipmiutil directory path*/ + if (ipath != NULL) { + if (strlen(ipath)+8 < sizeof(idxfile)) { + sprintf(idxfile,"%s\\%s",ipath,"\\",IDXFILE); + } + } + } +#elif defined(DOS) + fremote = 0; +#else + /* Linux, BSD, Solaris */ + fremote = is_remote(); + if (fremote == 0) { + //uchar guid[16]; + //char gstr[36]; + /* only run this as superuser */ + ret = geteuid(); + if (ret > 1) { + printf("Not superuser (%d)\n", ret); + ret = ERR_NOT_ALLOWED; + goto do_exit; + } + } +#endif + if (fremote) { /*remote, ipmi lan, any OS*/ + char *node; + node = get_nodename(); + strcat(idxfile,"-"); + strcat(idxfile,node); + strcat(idxfile2,"-"); + strcat(idxfile2,node); + } +#ifdef REMOVABLE + else { + // if removable media, may need to add uniqueness to local file. + ret = get_SystemGuid(guid); + if (ret == 0) { + sprintf(gstr,"%02X%02X%02X%02X%02X%02X%02X%02X", + guid[8], guid[9], guid[10], guid[11], + guid[12], guid[13], guid[14], guid[15]); + strcat(idxfile,"-"); + strcat(idxfile,gstr); + strcat(idxfile2,"-"); + strcat(idxfile2,gstr); + } + } +#endif + if (fremote) { + if (faddsel || fclearsel) + parse_lan_options('V',"4",0); /*admin priv to clear*/ + } + + if (faddsel) { /* -a, Add a custom SEL record */ + /* use this sparingly, only for hardware-related events. */ + char buf[16]; + int i, len = 0; + buf[0] = 0; + buf[1] = 0; + if (addstr != NULL) { /*ASCII text string*/ + buf[2] = 0xf1; /*use SEL type OEM 0xF1*/ + len = strlen_(addstr); + if (len > 13) len = 13; + if (len <= 0) ret = LAN_ERR_TOO_SHORT; + else memcpy(&buf[3],addstr,len); + len += 3; + } + if (addhex != NULL) { /*string of hex characters, no spaces*/ + len = strlen_(addhex); + if (len < 32) ret = LAN_ERR_TOO_SHORT; + else { + for (i=2; i<16; i++) + buf[i] = htoi(&addhex[i*2]); + } + len = 16; + } + if (fdebug) { + printf("Ready to AddSelEntry: "); + for (i=0; i<16; i++) printf("%02x ",buf[i]); + printf("\n"); + } + if (ret == 0) + ret = AddSelEntry(buf, len); + printf("AddSelEntry ret = %d\n",ret); + goto do_exit; + } + + ret = ipmi_getdeviceid( DevRecord, sizeof(DevRecord),fdebug); + if (ret == 0) { + uchar ipmi_maj, ipmi_min; + ipmi_maj = DevRecord[4] & 0x0f; + ipmi_min = DevRecord[4] >> 4; + show_devid( DevRecord[2], DevRecord[3], ipmi_maj, ipmi_min); + prod_id = DevRecord[9] + (DevRecord[10] << 8); + vend_id = DevRecord[6] + (DevRecord[7] << 8) + (DevRecord[8] << 16); + if (vend_id == VENDOR_INTEL) { + if (prod_id == 0x003E) /*Urbanna NSN2U or CG2100*/ + set_max_kcs_loops(URNLOOPS); /*longer KCS timeout*/ + } + } else { + goto do_exit; + } + + ret = ReadSELinfo(); + if (ret == 0 && !fonlyver) { + if (fclearsel) { + ret = ClearSEL(); + } else { + if (fsensdesc) { + if (fdebug) printf("%s: fetching SDRs ...\n",progname); + ret = get_sdr_cache(&sdrs); + if (fdebug) printf("%s: get_sdr_cache ret = %d\n",progname,ret); + ret = 0; /*if error, keep going anyway*/ + } + if (fdebug) printf("%s: starting ReadSEL ...\n",progname); + if (fall) ReadSEL(0xff,fwritesel); /* show all SEL records */ + else ReadSEL(ETYPE_CRITSTOP,fwritesel); /* only show OS Crit Stops*/ + /* PEF alerts and other log messages fail if low free space, + so show a warning. */ + if (vfree < MIN_FREE) { + printf("WARNING: free space is very low (=%d), need to clear with -c\n", + vfree); + } else if ((vfree/vsize) < ((vtotal * 20)/100)) { + printf("WARNING: free space is low (=%d), need to clear with -c\n", + vfree); + } + } + } +do_exit: + free_sdr_cache(sdrs); + ipmi_close_(); + // show_outcome(progname,ret); + return(ret); +} + +/* end isel.c */ diff --git a/util/iseltime.c b/util/iseltime.c new file mode 100644 index 0000000..2562202 --- /dev/null +++ b/util/iseltime.c @@ -0,0 +1,260 @@ +/* + * iseltime.c + * + * Author: Andy Cress arcress at users.sourceforge.net + * + * 05/11/09 Andy Cress v1.0 - created + * 07/23/10 Andy Cress v1.1 - always show System time also + * 08/20/10 Andy Cress v1.2 - show/set RTC time also if Linux + */ +/*M* +Copyright (c) 2013, Andy Cress +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include "getopt.h" +#elif defined(EFI) + // EFI: defined (EFI32) || defined (EFI64) || defined(EFIX64) + #ifndef NULL + #define NULL 0 + #endif + #include <types.h> + #include <libdbg.h> + #include <unistd.h> + #include <errno.h> +#elif defined(DOS) + #include <dos.h> + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include "getopt.h" +#else +/* Linux, Solaris, BSD */ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include <time.h> +#include <string.h> +#include "ipmicmd.h" + +#define GET_SELTIME 0x48 +#define SET_SELTIME 0x49 +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "iseltime"; +static char fdebug = 0; +static char fset = 0; +static uchar ipmi_maj = 0; +static uchar ipmi_min = 0; + +static int get_sel_time(uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + ret = ipmi_cmdraw(GET_SELTIME, NETFN_STOR, BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, 0, rdata, &rlen, &ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_sel_time()*/ + +static int set_sel_time(time_t newtime) +{ + uchar idata[4]; + uchar rdata[16]; + int rlen = 8; + int ret; + uchar ccode; + + idata[0] = (uchar)(newtime & 0x00ff); + idata[1] = (uchar)((newtime >> 8) & 0x00ff); + idata[2] = (uchar)((newtime >> 16) & 0x00ff); + idata[3] = (uchar)((newtime >> 24) & 0x00ff); + ret = ipmi_cmdraw(SET_SELTIME, NETFN_STOR, BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, 4, rdata, &rlen, &ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end set_sel_time()*/ + +time_t utc2local(time_t t) +{ + struct tm * tm_tmp; + int gt_year,gt_yday,gt_hour,lt_year,lt_yday,lt_hour; + int delta_hour; + time_t lt; + + //modify UTC time to local time expressed in number of seconds from 1/1/70 0:0:0 1970 GMT + // check for dst? + tm_tmp=gmtime(&t); + gt_year=tm_tmp->tm_year; + gt_yday=tm_tmp->tm_yday; + gt_hour=tm_tmp->tm_hour; + tm_tmp=localtime(&t); + lt_year=tm_tmp->tm_year; + lt_yday=tm_tmp->tm_yday; + lt_hour=tm_tmp->tm_hour; + delta_hour=lt_hour - gt_hour; + if ( (lt_year > gt_year) || ((lt_year == gt_year) && (lt_yday > gt_yday)) ) + delta_hour += 24; + if ( (lt_year < gt_year) || ((lt_year == gt_year) && (lt_yday < gt_yday)) ) + delta_hour -= 24; + if (fdebug) printf("utc2local: delta_hour = %d\n",delta_hour); + lt = t + (delta_hour * 60 * 60); + return(lt); +} + +#define TIMESTR_SZ 30 +void show_time(time_t etime) +{ + char buf[TIMESTR_SZ]; + int bufsz = TIMESTR_SZ; + time_t t; + + strcpy(buf,"00/00/00 00:00:00"); + t = utc2local(etime); + strftime(buf,bufsz, "%x %H:%M:%S", gmtime(&t)); /*or "%x %T"*/ + printf("%s\n",buf); + return; +} + +#ifdef METACOMMAND +int i_iseltime(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int rv = 0; + uchar devrec[20]; + uchar timebuf[4]; + time_t ltime1, ltime2, ltime3; + int c; + +#if defined (EFI) + InitializeLib(_LIBC_EFIImageHandle, _LIBC_EFISystemTable); +#else + printf("%s ver %s\n", progname,progver); +#endif + + while ( (c = getopt( argc, argv,"sT:V:J:EYF:P:N:R:U:x?")) != EOF ) + switch(c) { + case 's': fset = 1; break; /* read only */ + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-sx -NUPRETVF]\n", progname); + printf(" where -s Set SEL time (usually once a day)\n"); + printf(" -x show eXtra debug messages\n"); + print_lan_opt_usage(); + exit(1); + } + + rv = ipmi_getdeviceid(devrec,16,fdebug); + if (rv != 0) { + show_outcome(progname,rv); + ipmi_close_(); + exit(rv); + } else { + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; +#ifndef EFI + printf("-- BMC version %x.%x, IPMI version %d.%d \n", + devrec[2], devrec[3], ipmi_maj, ipmi_min); +#endif + } + + rv = get_sel_time(&timebuf[0],4); + if (rv != 0) { + printf("get_sel_time error: ret = %x\n",rv); + ipmi_close_(); + exit(1); + } + time(<ime2); + printf("Current System time: "); show_time(ltime2); + ltime1 = timebuf[0] + (timebuf[1] << 8) + (timebuf[2] << 16) + + (timebuf[3] << 24); + printf("Current SEL time: "); show_time(ltime1); + + // if (fdebug) ltime3 = utc2local(ltime1); + + if (fset == 1) { + /* get current time */ + time(<ime2); + rv = set_sel_time(ltime2); + printf("Setting SEL time to System Time: ret = %x\n",rv); + if (rv != 0) printf("set_sel_time error: ret = %x\n",rv); + else { /*successful*/ + rv = get_sel_time(timebuf,8); + if (rv != 0) printf("get_sel_time error: ret = %x\n",rv); + else { + ltime3 = timebuf[0] + (timebuf[1] << 8) + (timebuf[2] << 16) + + (timebuf[3] << 24); + printf("New SEL time: "); show_time(ltime3); + } + } + } +#ifdef LINUX + if (is_remote() == 0) { + c = system("echo \"Current RTC time: `hwclock`\""); + if (fset == 1) { + c = system("hwclock --systohc"); + printf("Copying System Time to RTC: ret = %d\n",c); + } + } +#endif + ipmi_close_(); + show_outcome(progname,rv); + exit (rv); +} /* end main()*/ + +/* end iseltime.c */ diff --git a/util/isensor.c b/util/isensor.c new file mode 100644 index 0000000..ac93411 --- /dev/null +++ b/util/isensor.c @@ -0,0 +1,3680 @@ +/* + * isensor.c + * + * This tool reads the SDR records to return sensor information. + * It can use either the Intel /dev/imb driver or VALinux /dev/ipmikcs. + * + * Author: arcress at users.sourceforge.net + * Copyright (c) 2002-2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 07/25/02 Andy Cress created + * 10/09/02 Andy Cress v1.1 added decodeValue(RawToFloat) routine + * 10/11/02 Andy Cress v1.2 added expon routine + * 10/30/02 Andy Cress v1.3 added SDR types 08 & 14 + * 12/04/02 Andy Cress v1.4 changed dstatus descriptions + * 01/29/03 Andy Cress v1.5 added MV OpenIPMI driver support + * Hannes Schulz <schulz@schwaar.com> + * 1) correct raw readings to floatval + * 2) allow extra SDR bytes returned from HP netserver 1000r + * Guo Min <guo.min@intel.com> + * add -l option for simpler list display + * 02/25/03 Andy Cress v1.6 misc cleanup + * 05/02/03 Andy Cress v1.7 add PowerOnHours + * 07/28/03 Andy Cress v1.8 added -t option for threshold values, + * added sample Discovery routine (unfinished), + * added ipmi_getdeviceid for completeness. + * 09/05/03 Andy Cress v1.9 show SDR OEM subtypes, + * fix GetSDR multi-part get for OEM SDRs + * stop if SDR Repository is empty + * 09/23/03 Andy Cress v1.10 Add options to set thresholds + * 10/14/03 Andy Cress v1.11 Fixed sdr offset for ShowThreshold values + * 01/15/04 Andy Cress v1.12 Fixed SetThreshold to set hysteresis, + * Fixed sens_cap testing in ShowThresh(Full) + * 01/30/04 Andy Cress v1.13 Changed field display order, added header, + * check for sdr sz below min, added WIN32. + * 02/19/04 Andy Cress v1.14 Added SDR type 3 parsing for mBMC + * 02/27/04 Andy Cress v1.15 Added check for superuser, more mBMC logic + * 03/11/04 Andy Cress v1.16 Added & removed private mBMC code for set + * thresholds due to licensing issues + * 04/13/04 Andy Cress v1.17 Added -r to show raw SDRs also + * 05/05/04 Andy Cress v1.18 call ipmi_close before exit, + * fix sresp in GetSDR for WIN32. + * 07/07/04 Andy Cress v1.19 Added -a to reArm sensor, + * show debug raw reading values only in hex + * 08/18/04 Andy Cress v1.20 Added decoding for DIMM status + * 11/01/04 Andy Cress v1.21 add -N / -R for remote nodes, + * added -U for remote username + * 11/19/04 Andy Cress v1.22 added more decoding for compact reading types, + * added -w option to wrap thresholds + * 11/24/04 ARCress v1.23 added sens_type to display output + * 12/10/04 ARCress v1.24 added support for device sdrs also, + * fixed sens_cap byte, + * 01/10/05 ARCress v1.25 change ShowThresh order, highest to lowest, + * change signed exponent type in RawToFloat + * 01/13/05 ARCress v1.26 added time display if fwrap + * 01/28/05 ARCress v1.27 mod for Power Redundancy SDR status + * 02/15/05 ARCress v1.28 added FloatToRaw for -h/-l threshold set funcs, + * always take -n sensor_num as hex (like displayed) + * 03/07/05 ARCress v1.29 added "LAN Leash Lost" decoding in decode_comp_ + * added -v to show max/min & hysteresis. + * 03/22/05 ARCress v1.30 added OEM subtype 0x60 for BMC TAM + * 03/26/05 ARCress v1.31 added battery type to decode_comp_reading + * 04/21/05 ARCress v1.32 added error message if -n sensor_num not found, + * added more decoding for Power Redund sensor + * 06/20/05 ARCress v1.33 if GetSDRRepository cc=0xc1 switch fdevsdrs mode, + * also detect fdevsdrs better for ATCA. + * 07/28/05 ARCress v1.34 check for Reading init state, + * add extra byte to decode_comp_reading() + * 09/12/05 ARCress v1.35 don't check superuser for fipmi_lan + * 01/26/06 ARCress v1.36 added -i option to only show one sensor index + * 03/14/06 ARCress v1.37 added -p option to save persistent thresholds + * 04/06/06 ARCress v1.38 show auto/manual rearm + * 07/17/06 ARCress v1.39 add -V, add -L, handle RepInfo rc=0xc1 + * 11/28/06 ARCress v1.46 added -c -m for ATCA child MCs + * 08/15/07 ARCress v1.58 filter display if -n sensor_num + * 08/29/07 ARCress v1.59 fixed Battery sensor interpretation + * 10/31/07 ARCress v2.3 retry GetSDR if cc=0xC5 (lost reservationID) + * 01/14/08 ARCress v2.6 add -u param for setting unique thresholds, + * always show float when setting thresholds, + * fixup in decoding Proc,PS Comp readings + * 01/25/08 ARCress v2.7 allow float input with -u thresholds, + * add -p persist logic for -u thresholds. + */ +/*M* +Copyright (c) 2002-2006 Intel Corporation. +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#include <stdio.h> +#include <stdlib.h> +#include <math.h> // for: double pow(double x, double y); +#include <string.h> +#include <time.h> +#ifdef WIN32 +#include <windows.h> +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include "getopt.h" +#else +#include <sys/stat.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#if defined(LINUX) +#include <unistd.h> +#include <sys/types.h> +#endif +#include "ipmicmd.h" +#include "isensor.h" + +#define PICMG_CHILD 1 /* show child MCs if -b */ +#define MIN_SDR_SZ 8 +#define SZCHUNK 16 /* SDR chunksize was 8, now 16 */ +#define INIT_SNUM 0xff +#define N_SGRP 16 +#define THR_EMPTY 999 + +extern int get_LastError( void ); /* ipmilan.c */ +extern int use_devsdrs(int picmg); /* ipmicmd.c */ +extern int get_MemDesc(int array, int dimm, char *desc, int *psz); /*mem_if.c*/ +extern char *get_sensor_type_desc(uchar stype); /*ievents.c*/ +#ifdef METACOMMAND +#include "oem_intel.h" +/* void show_oemsdr_intel(uchar *sdr); in oem_intel.h */ +/* int decode_sensor_intel(); in oem_intel.h */ +/* int is_romley(int vend, int prod); in oem_intel.h */ +extern int decode_sensor_kontron(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_kontron.c*/ +extern int decode_sensor_fujitsu(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_fujitsu.c*/ +extern int decode_sensor_sun(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_sun.c*/ +extern int decode_sensor_supermicro(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_supermicro.c*/ +extern int decode_sensor_quanta(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_quanta.c*/ +extern int decode_sensor_hp(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_hp.c*/ +extern int decode_sensor_dell(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_dell.c*/ +extern void show_oemsdr_hp(uchar *sdr); +#else +int is_romley(int vend, int prod) { + if ((vend == VENDOR_INTEL) && ((prod >= 0x0048) && (prod <= 0x005e))) + return(1); + return(0); +} +int is_thurley(int vend, int prod) { + if ((vend == VENDOR_INTEL) && ((prod >= 0x003A) && (prod <= 0x0040))) + return(1); + return(0); +} +#endif +#ifdef ALONE +#define NENTID 53 +static char *entity_id_str[NENTID] = { +/* 00 */ "unspecified", +/* 01 */ "other", +/* 02 */ "unknown", +/* 03 */ "processor", +/* 04 */ "disk", +/* 05 */ "peripheral bay", +/* 06 */ "management module", +/* 07 */ "system board", +/* 08 */ "memory module", +/* 09 */ "processor module", +/* 10 */ "power supply", +/* 11 */ "add-in card", +/* 12 */ "front panel bd", +/* 13 */ "back panel board", +/* 14 */ "power system bd", +/* 15 */ "drive backplane", +/* 16 */ "expansion board", +/* 17 */ "Other system board", +/* 18 */ "processor board", +/* 19 */ "power unit", +/* 20 */ "power module", +/* 21 */ "power distr board", +/* 22 */ "chassis back panel bd", +/* 23 */ "system chassis", +/* 24 */ "sub-chassis", +/* 25 */ "Other chassis board", +/* 26 */ "Disk Drive Bay", +/* 27 */ "Peripheral Bay", +/* 28 */ "Device Bay", +/* 29 */ "fan", +/* 30 */ "cooling unit", +/* 31 */ "cable/interconnect", +/* 32 */ "memory device ", +/* 33 */ "System Mgt Software", +/* 34 */ "BIOS", +/* 35 */ "Operating System", +/* 36 */ "system bus", +/* 37 */ "Group", +/* 38 */ "Remote Mgt Comm Device", +/* 39 */ "External Environment", +/* 40 */ "battery", +/* 41 */ "Processing blade", +/* 43 */ "Processor/memory module", +/* 44 */ "I/O module", +/* 45 */ "Processor/IO module", +/* 46 */ "Mgt Controller Firmware", +/* 47 */ "IPMI Channel", +/* 48 */ "PCI Bus", +/* 49 */ "PCI Express Bus", +/* 50 */ "SCSI Bus", +/* 51 */ "SATA/SAS bus", +/* 52 */ "Processor FSB" +}; +char *decode_entity_id(int id) { + if (id < NENTID) return (""); + else return(entity_id_str[id]); } +#else +/* char *decode_entity_id(int id); *isensor.h, from ievents.c*/ +#endif +/************************ + * Global Data + ************************/ +static char *progname = "isensor"; +static char *progver = "2.93"; +#ifdef WIN32 +static char savefile[] = "%ipmiutildir%\\thresholds.cmd"; +#else +static char savefile[] = "/var/lib/ipmiutil/thresholds.sh"; +// static char savefile[] = "/usr/share/ipmiutil/thresholds.sh"; +#endif +extern char fdebug; /*from ipmicmd.c*/ +int sens_verbose = 0; /* =1 show max/min & hysteresis also */ +static int fdevsdrs = 0; +static int fReserveOK = 1; +static int fDoReserve = 1; +static int fsimple = 0; /*=1 simple, canonical output*/ +static int fshowthr = 0; /* =1 show thresholds, =2 show thr in ::: fmt */ +static int fwrap = 0; +static int frawsdr = 0; +static int frearm = 0; +static int fshowidx = 0; /* only show a specific SDR index/range */ +static int fshowgrp = 0; /* =1 show group of sensors by sensor type */ +static int fdoloop = 0; /* =1 if user specified number of loops */ +static int fpicmg = 0; +static int fchild = 0; /* =1 show child SDRs */ +static int fset_mc = 0; /* =1 -m to set_mc */ +static int fdump = 0; +static int frestore = 0; +static int fjumpstart = 0; +static int fgetmem = 0; +static int fprivset = 0; +static char fremote = 0; +static int nloops = 1; /* num times to show repeated sensor readings */ +static char bdelim = BDELIM; /* delimiter for canonical output */ +static char tmpstr[20]; /* temp string */ +static char *binfile = NULL; +static int fsetthresh = 0; +static int fsavethresh = 0; +static uchar sensor_grps[N_SGRP] = {0, 0}; /*sensor type groups*/ +static ushort sensor_idx1 = 0xffff; +static ushort sensor_idxN = 0xffff; +static uchar sensor_num = INIT_SNUM; +static uchar sensor_hi = 0xff; +static uchar sensor_lo = 0xff; +static uchar sensor_thr[6] = {0,0,0,0,0,0}; +static double sensor_thrf[6] = {0,0,0,0,0,0}; +static double sensor_hi_f = 0; +static double sensor_lo_f = 0; +static int fmBMC = 0; +static int fRomley = 0; +static char chEol = '\n'; /* newline by default, space if option -w */ +static uchar resid[2] = {0,0}; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = 0; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static int vend_id = 0; +static int prod_id; + +/* sensor_dstatus + * This is used to decode the sensor reading types and meanings. + * Use IPMI Table 36-1 and 36-2 for this. + */ +#define N_DSTATUS 82 +#define STR_CUSTOM 58 +#define STR_OEM 71 +#define STR_AC_LOST 76 +#define STR_PS_FAIL 77 +#define STR_PS_CONFIG 78 +#define STR_HSC_OFF 79 +#define STR_REBUILDING 80 +#define STR_OTHER 81 +static char oem_string[50] = "OEM"; +static char *sensor_dstatus[N_DSTATUS] = { +/* 0 00h */ "OK ", +/* Threshold event states */ +/* 1 01h */ "Warn-lo", // "Warning-lo", +/* 2 02h */ "Crit-lo", // "Critical-lo", +/* 3 04h */ "BelowCrit", // "BelowCrit-lo", +/* 4 08h */ "Warn-hi", // "Warning-hi", +/* 5 10h */ "Crit-hi", // "Critical-hi", +/* 6 20h */ "AboveCrit", // "AboveCrit-hi", +/* 7 40h */ "Init ", /*in init state, no reading*/ +/* 8 80h */ "OK* ", +/* Hotswap Controller event states, also Availability */ +/* 9 HSC */ "Present", /*present,inserted*/ +/*10 HSC */ "Absent", /*absent,removed,empty,missing*/ +/*11 HSC */ "Ready", +/*12 HSC */ "Faulty", +/* Digital/Discrete event states */ +/*13 D-D */ "Asserted", +/*14 D-D */ "Deassert", +/*15 D-D */ "Predict ", +/* Availability event states */ +/*16 Avl */ "Disabled", +/*17 Avl */ "Enabled ", +/*18 Avl */ "Redundant", +/*19 Avl */ "RedunLost", +/*20 Avl */ "RedunDegr", +/* ACPI Device Power States */ +/*21 ACPI*/ "Off ", +/*22 ACPI*/ "Working", +/*23 ACPI*/ "Sleeping", /*D2/S2*/ +/*24 ACPI*/ "On", +/* Critical Interrupt event states */ +/*25 CrI */ "FP_NMI ", +/*26 CrI */ "Bus_TimOut", +/*27 CrI */ "IOch_NMI", +/*28 CrI */ "SW_NMI ", +/*29 CrI */ "PCI_PERR", +/*30 CrI */ "PCI_SERR", +/*31 CrI */ "EISA_TimOut", +/*32 CrI */ "Bus_Warn ", /*Correctable*/ +/*33 CrI */ "Bus_Error", /*Uncorrectable*/ +/*34 CrI */ "Fatal_NMI", +/*35 CrI */ "Bus_Fatal", /*0x0A*/ +/*36 CrI */ "Bus_Degraded", /*0x0B*/ +/* Physical Security event states */ +/*37 Phys*/ "LanLeashLost", +/*38 Phys*/ "ChassisIntrus", +/* Memory states */ +/*39 Mem */ "ECCerror", +/*40 Mem */ "ParityErr", +/* Discrete sensor invalid readings (error or init state) */ +/*41 D-D */ "Unknown", +/*42 D-D */ "NotAvailable", +/* Discrete sensor OEM reading states */ +/*43 OEM */ "Enabled ", +/*44 OEM */ "Disabled", +/* Session Audit states */ +/*45 OEM */ "Activated ", +/*46 OEM */ "Deactivated", +/*47 HSC */ "Unused ", +/* Processor event states */ +/*48 Proc*/ "IERR", +/*49 Proc*/ "ThermalTrip", +/*50 Proc*/ "FRB1Failure", +/*51 Proc*/ "FRB2Failure", +/*52 Proc*/ "FRB3Failure", +/*53 Proc*/ "ConfigError", +/*54 Proc*/ "SMBIOSError", +/*55 Proc*/ "ProcPresent", +/*56 Proc*/ "ProcDisabled", +/*57 Proc*/ "TermPresent", +/* Custom data string, 15 bytes */ +/*58 Custom*/ "CustomData12345", +/* Event Log */ +/*59 EvLog*/ "MemLogDisab", +/*60 EvLog*/ "TypLogDisab", +/*61 EvLog*/ "LogCleared", +/*62 EvLog*/ "AllLogDisab", +/*63 EvLog*/ "SelFull", +/*64 EvLog*/ "SelNearFull", +/* more Digital Discrete */ +/*65 D-D */ "Exceeded", +/*66 Alert*/ "AlertPage", +/*67 Alert*/ "AlertLAN", +/*68 Alert*/ "AlertPET", +/*69 Alert*/ "AlertSNMP", +/*70 Alert*/ "None", +/*71 OEM str*/ &oem_string[0], +/* Version Change */ +/*72 Change*/ "HW Changed", +/*73 Change*/ "SW Changed", +/*74 Change*/ "HW incompatibility", +/*75 Change*/ "Change Error", +/* Power Supply event states */ +/*76 PS */ "AC_Lost ", +/*77 PS */ "PS_Failed", +/* Power Supply event states */ +/*78 PS */ "Config_Err", +/*79 HSC */ "Offline", +/*80 HSC */ "Rebuilding", +/*81 other*/ " _ " +}; + +static char *raid_states[9] = { /*for sensor type 0x0d drive status */ + "Faulty", + "Rebuilding", + "InFailedArray", + "InCriticalArray", + "ParityCheck", + "PredictedFault", + "Un-configured", + "HotSpare", + "NoRaid" }; + +#define NSENSTYPES 0x2a +#ifdef OLD +/* see ievents.c */ +static const char *sensor_types[NSENSTYPES] = { /*IPMI 2.0 Table 42-3*/ +/* 00h */ "reserved", +/* 01h */ "Temperature", +/* 02h */ "Voltage", +/* 03h */ "Current", +/* 04h */ "Fan", +/* 05h */ "Platform Chassis Intrusion", +/* 06h */ "Platform Security Violation", +/* 07h */ "Processor", +/* 08h */ "Power Supply", +/* 09h */ "Power Unit", +/* 0Ah */ "Cooling Device", +/* 0Bh */ "FRU Sensor", +/* 0Ch */ "Memory", +/* 0Dh */ "Drive Slot", +/* 0Eh */ "POST Memory Resize", +/* 0Fh */ "System Firmware", +/* 10h */ "SEL Disabled", +/* 11h */ "Watchdog 1", +/* 12h */ "System Event", /* offset 0,1,2 */ +/* 13h */ "Critical Interrupt", /* offset 0,1,2 */ +/* 14h */ "Button", /* offset 0,1,2 */ +/* 15h */ "Board", +/* 16h */ "Microcontroller", +/* 17h */ "Add-in Card", +/* 18h */ "Chassis", +/* 19h */ "Chip Set", +/* 1Ah */ "Other FRU", +/* 1Bh */ "Cable / Interconnect", +/* 1Ch */ "Terminator", +/* 1Dh */ "System Boot Initiated", +/* 1Eh */ "Boot Error", +/* 1Fh */ "OS Boot", +/* 20h */ "OS Critical Stop", +/* 21h */ "Slot / Connector", +/* 22h */ "ACPI Power State", +/* 23h */ "Watchdog 2", +/* 24h */ "Platform Alert", +/* 25h */ "Entity Presence", +/* 26h */ "Monitor ASIC", +/* 27h */ "LAN", +/* 28h */ "Management Subsystem Health", +/* 29h */ "Battery", +}; +#endif + +#define NUNITS 30 +static char *unit_types[] = { +/* 00 */ "unspecified", +/* 01 */ "degrees C", +/* 02 */ "degrees F", +/* 03 */ "degrees K", +/* 04 */ "Volts", +/* 05 */ "Amps", +/* 06 */ "Watts", +/* 07 */ "Joules", +/* 08 */ "Coulombs", +/* 09 */ "VA", +/* 10 */ "Nits", +/* 11 */ "lumen", +/* 12 */ "lux", +/* 13 */ "Candela", +/* 14 */ "kPa", +/* 15 */ "PSI", +/* 16 */ "Newton", +/* 17 */ "CFM", +/* 18 */ "RPM", +/* 19 */ "Hz", +/* 20 */ "microseconds", +/* 21 */ "milliseconds", +/* 22 */ "seconds", +/* 23 */ "minutes", +/* 24 */ "hours", +/* 25 */ "days", +/* 26 */ "weeks", +/* 27 */ "mil", +/* 28 */ "inches", +/* 29 */ "feet", +/* 42 */ "cycles" +}; +/* 68 * "megabit", */ +/* 72 * "megabyte", */ +/* 90 * "uncorrectable error" (last defined)*/ +static char *unit_types_short[] = { +/* 00 */ "?", /*unknown, not specified*/ +/* 01 */ "C", +/* 02 */ "F", +/* 03 */ "K", +/* 04 */ "V", +/* 05 */ "A", +/* 06 */ "W", +/* 07 */ "J", +/* 08 */ "Coul", +/* 09 */ "VA", +/* 10 */ "Nits", +/* 11 */ "lumen", +/* 12 */ "lux", +/* 13 */ "Cand", +/* 14 */ "kPa", +/* 15 */ "PSI", +/* 16 */ "Newton", +/* 17 */ "CFM", +/* 18 */ "RPM", +/* 19 */ "Hz", +/* 20 */ "usec", +/* 21 */ "msec", +/* 22 */ "sec", +/* 23 */ "min", +/* 24 */ "hrs", +/* 25 */ "days", +/* 26 */ "wks", +/* 27 */ "mil", +/* 28 */ "in", +/* 29 */ "ft", +/* 42 */ "cyc" +}; + +ushort parse_idx(char *str) +{ + int i, n; + char istr[5]; + if (strncmp(str,"0x",2) == 0) str += 2; + n = strlen_(str); + if (n == 4) { + i = (htoi(str) << 8) + htoi(&str[2]); + } else if (n == 3) { + istr[0] = '0'; + memcpy(&istr[1],str,3); + i = (htoi(istr) << 8) + htoi(&istr[2]); + } else i = htoi(str); /*was atoi()*/ + printf("idx = 0x%x\n",i); + return((ushort)i); +} + +int get_idx_range(char *str) +{ + // int i = 0; + char *p; + p = strchr(str,'-'); + if (p == NULL) p = strchr(str,','); + if (p != NULL) { + *p = 0; + p++; + sensor_idx1 = parse_idx(str); + sensor_idxN = parse_idx(p); + } else { + sensor_idx1 = parse_idx(str); + sensor_idxN = sensor_idx1; + } + return(0); +} + +char *get_unit_type(int iunits, int ibase, int imod, int fshort) +{ + char *pstr = NULL; + char **punittypes; + static char unitstr[32]; + int jbase, jmod; + uchar umod; + + punittypes = unit_types; + if (fshort) punittypes = unit_types_short; + if (fdebug) printf("get_unit_type(%x,%d,%d,%d)\n",iunits,ibase,imod,fshort); + umod = (iunits & 0x06) >> 1; + if (ibase < NUNITS) jbase = ibase; + else { + if (fdebug) printf("units base %02x > %d\n",ibase,NUNITS); + if (ibase == 42) jbase = NUNITS; /*"cycles"*/ + else jbase = 0; + } + if (imod < NUNITS) jmod = imod; + else { + if (fdebug) printf("units mod %02x > %d\n",imod,NUNITS); + jmod = 0; + } + switch (umod) { + case 2: + snprintf(unitstr,sizeof(unitstr),"%s * %s", + punittypes[jbase],punittypes[jmod]); + pstr = unitstr; + break; + case 1: + snprintf(unitstr,sizeof(unitstr),"%s/%s", + punittypes[jbase],punittypes[jmod]); + pstr = unitstr; + break; + case 0: + default: + pstr = punittypes[jbase]; + break; + } + if ((umod == 0) && (iunits > 0)) { + /* special cases for other SensorUnits1 bits */ + if ((iunits & 0x01) != 0) { /*percentage*/ + if (fshort) pstr = "%"; + else pstr = "percent"; + } else if (iunits == 0xC0) { /*no analog reading*/ + pstr = "na"; + } else if (iunits == 0x18) { + /* For Tyan fans: base=42, units=24.(0x18) -> cycles/hour */ + snprintf(unitstr,sizeof(unitstr),"%s/hour",punittypes[jbase]); + pstr = unitstr; + } + } + return(pstr); +} + +char *decode_capab(uchar c) +{ + static char cstr[50]; + char *arm; + char *thr; + char *evt; + // char *hys; + uchar b; + /* decode sens_capab bits */ + if ((c & 0x40) == 0) arm = "man"; /*manual rearm*/ + else arm = "auto"; /*automatic rearm*/ + /* skip hysteresis bits (0x30) */ + b = ((c & 0x0c) >> 2); + switch(b) { + case 0x00: thr = "none"; break; /*no thresholds*/ + case 0x01: thr = "read"; break; + case 0x02: thr = "write"; break; /*read & write*/ + case 0x03: + default: thr = "fixed"; break; + } + b = (c & 0x03) ; + switch(b) { + case 0x00: evt = "state"; break; /*threshold or discrete state*/ + case 0x01: evt = "entire"; break; /*entire sensor only*/ + case 0x02: evt = "disab"; break; /*global disable only*/ + case 0x03: + default: evt = "none"; break; /*no events*/ + } + sprintf(cstr,"arm=%s thr=%s evts=%s",arm,thr,evt); + return(cstr); +} + + +int get_group_id(char *pstr) +{ + int i, j, n, sz, len; + char *p; + int rv = -1; + + sz = strlen_(pstr); + p = &pstr[0]; + n = 0; + for (i = 0; i <= sz; i++) { + if (n >= N_SGRP) break; + switch(pstr[i]) { + case ',': /*delimiter*/ + case '\n': + case '\0': + pstr[i] = 0; /*stringify this word*/ + len = strlen_(p); + for (j = 0; j < NSENSTYPES; j++) { + if (strncasecmp(get_sensor_type_desc(j),p,len) == 0) { + sensor_grps[n++] = (uchar)j; + rv = 0; + break; + } + } /*endfor(j)*/ + if (i+1 < sz) p = &pstr[i+1]; /*set p for next word*/ + if (j >= NSENSTYPES) { /* sensor type not found */ + rv = -1; + i = sz; /*exit loop*/ + } + break; + default: + break; + } /*end switch*/ + } /*end for(i)*/ + if (rv == 0) rv = n; + else rv = -1; + return(rv); +} + +static int validate_thresholds(void *pthrs, char flag, uchar *sdr) +{ + double *thrf; + uchar *thr; + int rv = 0; + uchar bits; + + if (sdr == NULL) bits = 0xff; /*assume all are used*/ + else bits = sdr[18]; /*18=indicates which are readable/used */ + + if (bits == 0) { + printf("No threshold values can be set for this sensor.\n"); + return(3); + } + if (flag == 1) { /*float*/ + thrf = (double *)pthrs; + if (fdebug) + printf("validate_thresh: bits=%02x, values: %f>=%f>=%f, %f<=%f<=%f\n", + bits, thrf[0],thrf[1],thrf[2], thrf[3],thrf[4],thrf[5]); + if ((bits & 0x02) != 0) { /*thrf[1] lo-crit is valid*/ + if ((thrf[1] > thrf[0]) && ((bits & 0x01) != 0)) rv = 1; + if ((thrf[2] > thrf[1]) && ((bits & 0x04) != 0)) rv = 1; /*lo is wrong*/ + } + if ((bits & 0x10) != 0) { /*thrf[4] hi-crit is valid*/ + if ((thrf[4] < thrf[3]) && ((bits & 0x08) != 0)) rv = 2; + if ((thrf[5] < thrf[4]) && ((bits & 0x20) != 0)) rv = 2; /*hi is wrong*/ + } + if (rv != 0) { + printf("Threshold values: %f>=%f>=%f, %f<=%f<=%f\n", + thrf[0], thrf[1], thrf[2], thrf[3], thrf[4], thrf[5]); + printf("Invalid threshold order in %s range.\n", + ((rv == 1)? "lo": "hi")); + } + } else { + thr = (uchar *)pthrs; + if ((bits & 0x02) != 0) { /*thr[1] lo-crit is valid*/ + if ((thr[1] > thr[0]) && ((bits & 0x01) != 0)) rv = 1; + if ((thr[2] > thr[1]) && ((bits & 0x04) != 0)) rv = 1; /*lo is wrong*/ + } + if ((bits & 0x10) != 0) { /*thr[4] hi-crit is valid*/ + if ((thr[4] < thr[3]) && ((bits & 0x08) != 0)) rv = 2; + if ((thr[5] < thr[4]) && ((bits & 0x20) != 0)) rv = 2; /*hi is wrong*/ + } + if (rv != 0) { + printf("Threshold values: %02x>=%02x>=%02x %02x<=%02x<=%02x\n", + thr[0], thr[1], thr[2], thr[3], thr[4], thr[5]); + printf("Invalid threshold order within -u (%s)\n", + ((rv == 1)? "lo": "hi")); + } + } + return(rv); +} + +int +GetSDRRepositoryInfo(int *nret, int *fdev) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + int rc; + int nSDR; + int freespace; + ushort cmd; + uchar cc = 0; + int i; + + memset(resp,0,6); /* init first part of buffer */ + if (nret != NULL) *nret = 0; + if (fdev != NULL) fdevsdrs = *fdev; + if (fdevsdrs) cmd = GET_DEVSDR_INFO; + else cmd = GET_SDR_REPINFO; + rc = ipmi_cmd_mc(cmd, NULL, 0, resp,&sresp, &cc, fdebug); + if (fdebug) printf("ipmi_cmd[%04x] repinf(%d) status=%d cc=%x\n", + cmd, fdevsdrs,rc,cc); + /* some drivers return cc in rc */ + if ((rc == 0xc1) || (rc == 0xd4)) cc = rc; + else if (rc != 0) return(rc); + if (cc != 0) { + if ((cc == 0xc1) || /*0xC1 (193.) means unsupported command */ + (cc == 0xd4)) /*0xD4 means insufficient privilege (Sun/HP)*/ + { + /* Must be reporting wrong bit for fdevsdrs, + * so switch & retry */ + if (fdevsdrs) { + fdevsdrs = 0; + cmd = GET_SDR_REPINFO; + } else { + fdevsdrs = 1; + cmd = GET_DEVSDR_INFO; + } + sresp = MAX_BUFFER_SIZE; + rc = ipmi_cmd_mc(cmd, NULL, 0, resp,&sresp, &cc, fdebug); + if (fdebug) + printf("ipmi_cmd[%04x] repinf status=%d cc=%x\n",cmd,rc,cc); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + } else return(cc); + } + + if (fdevsdrs) { + nSDR = resp[0]; + freespace = 1; + fReserveOK = 1; + } else { + nSDR = resp[1] + (resp[2] << 8); + freespace = resp[3] + (resp[4] << 8); + if ((resp[13] & 0x02) == 0) fReserveOK = 0; + else fReserveOK = 1; + } + if (nret != NULL) *nret = nSDR; + if (fdev != NULL) *fdev = fdevsdrs; + if (fdebug) { + //successful, show data + printf("SDR Repository (len=%d): ",sresp); + for (i = 0; i < sresp; i++) printf("%02x ",resp[i]); + printf("\n"); + printf("SDR Info: fdevsdrs=%d nSDRs=%d free space = %x ReserveOK=%d\n", + fdevsdrs,nSDR,freespace,fReserveOK); + } + + return(0); +} /*end GetSDRRepositoryInfo()*/ + + +int +GetSensorThresholds(uchar sens_num, uchar *thr_data) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[6]; + int rc; + uchar cc = 0; + + inputData[0] = sens_num; + rc = ipmi_cmd_mc(GET_SENSOR_THRESHOLD, inputData,1, resp,&sresp, &cc,fdebug); + if (fdebug) + printf("GetSensorThreshold[%02x] rc = %d, resp(%d) %02x %02x %02x %02x %02x %02x %02x\n", + sens_num,rc, sresp,resp[0],resp[1],resp[2],resp[3], + resp[4],resp[5],resp[6]); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + if (sresp == 0) return(-2); + memcpy(thr_data,resp,sresp); + return(0); +} + +int +RearmSensor(uchar sens_num) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[8]; + int rc; + uchar cc = 0; + + memset(inputData,0,6); + memset(resp,0,6); + inputData[0] = sens_num; + rc = ipmi_cmd_mc(GET_SEVT_ENABLE, inputData, 1, resp,&sresp, &cc, fdebug); + if (rc == 0 && cc != 0) rc = cc; + if (rc != 0 || fdebug) + printf("GetSensorEventEnable(%02x) rc = %d, cc = %x %02x %02x %02x\n", + sens_num,rc,cc,resp[0],resp[1],resp[3]); + if (rc == 0 && resp[0] != 0xc0) { + printf("EventEnable(%02x) = %02x, is not 0xc0\n", + sens_num,resp[0]); + memset(inputData,0,6); + inputData[0] = sens_num; + inputData[1] = resp[0] | 0xc0; + inputData[2] = resp[1]; + inputData[3] = resp[2]; + inputData[4] = resp[3]; + inputData[5] = resp[4]; + rc = ipmi_cmd_mc(SET_SEVT_ENABLE, inputData, 6, resp,&sresp, + &cc, fdebug); + if (rc == 0 && cc != 0) rc = cc; + if (rc != 0 || fdebug) + printf("SetSensorEventEnable(%02x) rc = %d, cc = %x\n", + sens_num,rc,cc); + } + + memset(inputData,0,6); + inputData[0] = sens_num; + inputData[1] = 0; /* rearm all events for this sensor */ + rc = ipmi_cmd_mc(REARM_SENSOR, inputData, 6, resp,&sresp, &cc, fdebug); + if (fdebug) + printf("RearmSensor(%02x) rc = %d, cc = %x %02x %02x\n", + sens_num,rc,cc,resp[0],resp[1]); + if (rc == 0 && cc != 0) rc = cc; + + /* Could also do a global rearm via SetEventReceiver. */ + + return(rc); +} /*end RearmSensor*/ + +int +SetSensorThresholds(uchar sens_num, uchar hi, uchar lo, + uchar *thr_data, uchar *thr_set) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[8]; + int rc; + uchar cc = 0; + uchar sets = 0; + int i; + + /* + * Set the sensor Hysteresis before setting the threshold. + */ + memset(inputData,0,8); + inputData[0] = sens_num; + inputData[1] = 0xff; + rc = ipmi_cmd_mc(GET_SENSOR_HYSTERESIS,inputData,2, resp,&sresp, &cc,fdebug); + if (fdebug) + printf("GetSensorHysteresis(%02x) rc = %d, cc = %x %02x %02x\n", + sens_num,rc,cc,resp[0],resp[1]); + if (rc != ACCESS_OK) return(rc); + inputData[0] = sens_num; + inputData[1] = 0xff; + inputData[2] = resp[0]; + inputData[3] = resp[1]; + rc = ipmi_cmd_mc(SET_SENSOR_HYSTERESIS,inputData,4, resp,&sresp, &cc,fdebug); + if (fdebug) + printf("SetSensorHysteresis(%02x) rc = %d, cc = %x\n", + sens_num,rc,cc); + if (rc != ACCESS_OK) return(rc); + + /* + * The application should validate that values are ordered, + * e.g. upper critical should be greater than upper + * non-critical. + * Due to the limited command line parameter interface, + * use the hi & lo values to set each of the thresholds. + * For a full implemenation, these thresholds should be set + * individually. + */ + memset(inputData,0,8); + inputData[0] = sens_num; + sets = thr_data[0]; + if (thr_set != NULL) { /* use specific thr_set values */ + memcpy(&inputData[2],thr_set,6); + } else { /*default, use hi/lo params */ + if (lo == 0xff) sets &= 0x38; /* don't set lowers */ + else { + inputData[2] = lo; /* lower non-crit (& 0x01) */ + inputData[3] = lo - 1; /* lower critical (& 0x02) */ + inputData[4] = lo - 2; /* lower non-recov (& 0x04) */ + } + if (hi == 0xff) sets &= 0x07; /* don't set uppers */ + else { + inputData[5] = hi; /* upper non-crit (& 0x08) */ + inputData[6] = hi + 1; /* upper critical (& 0x10) */ + inputData[7] = hi + 2; /* upper non-recov (& 0x20) */ + } + } + inputData[1] = sets; /* which ones to set */ + { /* show from/to changes */ + printf("GetThreshold[%02x]: %02x ",sens_num,sens_num); + for (i = 0; i < 7; i++) printf("%02x ",thr_data[i]); + printf("\n"); + printf("SetThreshold[%02x]: ",sens_num); + for (i = 0; i < 8; i++) printf("%02x ",inputData[i]); + printf("\n"); + } + rc = ipmi_cmd_mc(SET_SENSOR_THRESHOLD, inputData, 8, resp,&sresp, &cc, fdebug); + if (fdebug) + printf("SetSensorThreshold(%02x) rc = %d, cc = %x\n", + sens_num,rc,cc); + if (rc == 0 && cc != 0) rc = cc; + /* mBMC gets cc = 0xD5 (213.) here, setting thresholds disabled. */ + return(rc); +} + +int +GetSensorReading(uchar sens_num, void *psdr, uchar *sens_data) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[6]; + SDR02REC *sdr = NULL; + int mc; + int rc; + uchar cc = 0; + uchar lun = 0; + uchar chan = 0; + + if (psdr != NULL) { + sdr = (SDR02REC *)psdr; + mc = sdr->sens_ownid; + if (mc != BMC_SA) { /* not BMC, e.g. HSC or ME sensor */ + uchar a = ADDR_IPMB; + if (mc == HSC_SA) a = ADDR_SMI; + chan = (sdr->sens_ownlun & 0xf0) >> 4; + lun = (sdr->sens_ownlun & 0x03); + ipmi_set_mc(chan,(uchar)mc, lun,a); + } + } else mc = BMC_SA; + inputData[0] = sens_num; + rc = ipmi_cmd_mc(GET_SENSOR_READING,inputData,1, resp,&sresp,&cc,fdebug); + if (fdebug) + printf("GetSensorReading mc=%x,%x,%x status=%d cc=%x sz=%d resp: %02x %02x %02x %02x\n", + chan,mc,lun,rc,cc,sresp,resp[0],resp[1],resp[2],resp[3]); + if (mc != BMC_SA) ipmi_restore_mc(); + if ((rc == 0) && (cc != 0)) { + if (fdebug) printf("GetSensorReading error %x %s\n",cc, + decode_cc((ushort)0,(uchar)cc)); + rc = cc; + } + if (rc != 0) return(rc); + + if (resp[1] & 0x20) { /* init state, reading invalid */ + if (fdebug) + printf("sensor[%x] in init state, no reading\n", sens_num); + sens_data[1] = resp[1]; + sens_data[2] = 0x40; /*set bit num for init state*/ + } else { /*valid reading, copy it*/ + /* only returns 4 bytes, no matter what type */ + memcpy(sens_data,resp,4); + } + return(0); +} /*end GetSensorReading()*/ + +int +GetSensorReadingFactors(uchar snum, uchar raw, int *m, int *b, int * b_exp, + int *r, int *a) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[6]; + int rc; + uchar cc = 0; + int toler, a_exp; + + inputData[0] = snum; + inputData[1] = raw; + rc = ipmi_cmd_mc(GET_SENSOR_READING_FACTORS, inputData, 2, + resp,&sresp, &cc, fdebug); + if (fdebug) printf("GetSensorReadingFactors status = %d\n",rc); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + + /* successful, copy values */ + *m = resp[1] + ((resp[2] & 0xc0) << 2); + toler = resp[2] & 0x3f; + *b = resp[3] + ((resp[4] & 0xc0) << 2); + *a = (resp[4] & 0x3f) + ((resp[5] & 0xf0) << 4); + a_exp = (resp[5] & 0xc0) >> 2; + *r = (resp[6] &0xf0) >> 4; + *b_exp = resp[6] & 0x0f; + if (fdebug) { + printf("factors: next=%x m=%d b=%d b_exp=%d a=%d a_exp=%d r=%d\n", + resp[0],*m,*b,*b_exp,*a,a_exp,*r); + } + return(0); +} + +int GetSensorType(uchar snum, uchar *stype, uchar *rtype) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[6]; + int rc; + uchar cc = 0; + + inputData[0] = snum; + rc = ipmi_cmd_mc(GET_SENSOR_TYPE, inputData, 1, + resp,&sresp, &cc, fdebug); + if (fdebug) printf("GetSensorType: ipmi_cmd rv = %d, cc = %x\n",rc,cc); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + /* successful, copy values */ + if (stype != NULL) *stype = resp[0]; + if (rtype != NULL) *rtype = resp[1] & 0x7f; + return(rc); +} + +void set_reserve(int val) +{ + fDoReserve = val; +} + +int sdr_get_reservation(uchar *res_id, int fdev) +{ + int sresp; + uchar resp[MAX_BUFFER_SIZE]; + uchar cc = 0; + ushort cmd; + int rc = -1; + + if (fDoReserve == 1) { + fDoReserve = 0; /* only reserve SDR the first time */ + sresp = sizeof(resp);; + if (fdev) cmd = RESERVE_DEVSDR_REP; + else cmd = RESERVE_SDR_REP; + rc = ipmi_cmd_mc(cmd, NULL, 0, resp, &sresp, &cc, fdebug); + if (rc == 0 && cc != 0) rc = cc; + if (rc == 0) { /* ok, so set the reservation id */ + resid[0] = resp[0]; + resid[1] = resp[1]; + } + /* A reservation is cancelled by the next reserve request. */ + if (fdebug) + printf("ipmi_cmd RESERVE status=%d cc=%x id=%02x%02x\n", + rc,cc,resid[0],resid[1]); + } else rc = 0; + /* if not first time, or if error, return existing resid. */ + res_id[0] = resid[0]; + res_id[1] = resid[1]; + return(rc); +} /*end sdr_get_reservation*/ + +int sdr_clear_repo(int fdev) +{ + int sresp; + uchar resp[MAX_BUFFER_SIZE]; + uchar inputData[6]; + uchar cc = 0; + int rc = -1; + ushort cmd; + uchar resv[2] = {0,0}; + + if (fReserveOK) + rc = sdr_get_reservation(resv,fdev); + + cmd = 0x27 + (NETFN_STOR << 8); /*Clear SDR Repository*/ + inputData[0] = resv[0]; /*res id LSB*/ + inputData[1] = resv[1]; /*res id MSB*/ + inputData[2] = 'C'; + inputData[3] = 'L'; + inputData[4] = 'R'; + inputData[5] = 0xAA; + sresp = sizeof(resp);; + rc = ipmi_cmd_mc(cmd, inputData, 6, resp, &sresp,&cc, fdebug); + if (fdebug) printf("sdr_clear_repo: rc = %d, cc = %x, sz=%d\n",rc,cc,sresp); + if (rc == 0 && cc != 0) rc = cc; + + if (rc == 0 && (resp[0] & 1) != 1) { + if (fdebug) printf("Wait for sdr_clear_repo to complete\n"); + os_usleep(1,0); + } + return(rc); +} + +int sdr_add_record(uchar *sdr, int fdev) +{ + int sresp; + uchar resp[MAX_BUFFER_SIZE]; + uchar inputData[6+SZCHUNK]; + uchar cc = 0; + int rc = -1; + ushort cmd; + uchar resv[2] = {0,0}; + int reclen, len, i; + int recid, chunksz; + uchar prog; + + reclen = sdr[4] + 5; + recid = sdr[0] + (sdr[1] << 8); + /* OEM SDRs can be min 8 bytes, less is an error. */ + if (reclen < 8) return(LAN_ERR_BADLENGTH); + if (fReserveOK) + rc = sdr_get_reservation(resv,fdev); + if (fdebug) printf("sdr_add_record[%x]: reclen = %d, reserve rc = %d\n", + recid,reclen,rc); + + cmd = 0x25 + (NETFN_STOR << 8); /*PartialAddSdr*/ + recid = 0; /*first chunk must be added as 0000*/ + chunksz = SZCHUNK; + for (i = 0; i < reclen; ) + { + prog = 0; + len = chunksz; + if ((i+chunksz) >= reclen) { /*last record*/ + len = reclen - i; + prog = 1; + } + inputData[0] = resv[0]; /*res id LSB*/ + inputData[1] = resv[1]; /*res id MSB*/ + inputData[2] = recid & 0x00ff; /*record id LSB*/ + inputData[3] = (recid >> 8) & 0x00ff; /*record id MSB*/ + inputData[4] = (uchar)i; /*offset */ + inputData[5] = prog; /*progress: 1=last record*/ + memcpy(&inputData[6],&sdr[i],len); + sresp = sizeof(resp); + rc = ipmi_cmd_mc(cmd, inputData, 6+len, resp, &sresp,&cc, fdebug); + if (fdebug) + printf("sdr_add_record[%x,%x]: rc = %d, cc = %x, sz=%d\n", + recid,i,rc,cc,sresp); + if (rc == 0 && cc != 0) rc = cc; + if (rc != 0) break; + if (recid == 0 && rc == 0) /*first time, so set recid*/ + recid = resp[0] + (resp[1] << 8); + i += len; + } + return(rc); +} + +int GetSDR(int r_id, int *r_next, uchar *recdata, int srecdata, int *rlen) +{ + int sresp; + uchar resp[MAX_BUFFER_SIZE+SZCHUNK]; + uchar respchunk[SZCHUNK+10]; + uchar inputData[6]; + uchar cc = 0; + int rc = -1; + int i, chunksz, thislen, off; + int reclen; + ushort cmd; + uchar resv[2] = {0,0}; + + chunksz = SZCHUNK; + reclen = srecdata; /*max size of SDR record*/ + off = 0; + *rlen = 0; + *r_next = 0xffff; /*default*/ + if (fReserveOK) + rc = sdr_get_reservation(resv,fdevsdrs); + if (fdevsdrs) cmd = GET_DEVICE_SDR; + else cmd = GET_SDR; + if (reclen == 0xFFFF) { /* get it all in one call */ + inputData[0] = resv[0]; /*res id LSB*/ + inputData[1] = resv[1]; /*res id MSB*/ + inputData[2] = r_id & 0x00ff; /*record id LSB*/ + inputData[3] = (r_id & 0xff00) >> 8; /*record id MSB*/ + inputData[4] = 0; /*offset */ + inputData[5] = 0xFF; /*bytes to read, ff=all*/ + sresp = sizeof(resp);; + if (fdebug) printf("ipmi_cmd SDR id=%d read_all, len=%d\n", + r_id,sresp); + rc = ipmi_cmd_mc(cmd, inputData, 6, recdata, &sresp,&cc, fdebug); + /* This will usually return cc = 0xCA (invalid length). */ + if (fdebug) printf("ipmi_cmd SDR data status = %d, cc = %x, sz=%d\n", + rc,cc,sresp); + reclen = sresp; + *r_next = recdata[0] + (recdata[1] << 8); + } else /* if (reclen > chunksz) do multi-part chunks */ + for (off = 0; off < reclen; ) + { + thislen = chunksz; + if ((off+chunksz) > reclen) thislen = reclen - off; + inputData[0] = resv[0]; /*res id LSB*/ + inputData[1] = resv[1]; /*res id MSB*/ + inputData[2] = r_id & 0x00ff; /*record id LSB*/ + inputData[3] = (r_id & 0xff00) >> 8; /*record id MSB*/ + inputData[4] = (uchar)off; /*offset */ + inputData[5] = (uchar)thislen; /*bytes to read, ff=all*/ + sresp = sizeof(respchunk); + rc = ipmi_cmd_mc(cmd, inputData, 6, respchunk, &sresp,&cc, fdebug); + if (fdebug) + printf("ipmi_cmd SDR[%x] off=%d ilen=%d status=%d cc=%x sz=%d\n", + r_id,off,thislen,rc,cc,sresp); + if (off == 0 && cc == 0xCA && thislen == SZCHUNK) { + /* maybe shorter than SZCHUNK, try again */ + chunksz = 0x06; + if (fdebug) printf("sdr[%x] try again with chunksz=%d\n", + r_id,chunksz); + continue; + } + if (off > chunksz) { + /* already have first part of the SDR, ok to truncate */ + if (rc == -3) { /* if LAN_ERR_RECV_FAIL */ + if (fdebug) printf("sdr[%x] error rc=%d len=%d truncated\n", + r_id,rc,sresp); + sresp = 0; + rc = 0; + } + if (cc == 0xC8 || cc == 0xCA) { /* length errors */ + /* handle certain MCs that report wrong length, + * at least use what we already have (sresp==0) */ + if (fdebug) printf("sdr[%x] error cc=%02x len=%d truncated\n", + r_id,cc,sresp); + cc = 0; + } + } + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + /* if here, successful, chunk was read */ + if (sresp < (thislen+2)) { + /* There are some SDRs that may report the wrong length, and + * return less bytes than they reported, so just truncate. */ + if (fdebug) printf("sdr[%x] off=%d, expected %d, got %d\n", + r_id,off,thislen+2,sresp); + if (sresp >= 2) thislen = sresp - 2; + else thislen = 0; + reclen = off + thislen; /* truncate, stop reading */ + } + /* successful */ + memcpy(&resp[off],&respchunk[2],thislen); + if (off == 0 && sresp >= 5) { + *r_next = respchunk[0] + (respchunk[1] << 8); + reclen = respchunk[6] + 5; /*get actual record size*/ + if (reclen > srecdata) { + if (fdebug) printf("sdr[%x] chunk0, reclen=%d srecdata=%d\n", + r_id, reclen, srecdata); + reclen = srecdata; /*truncate*/ + } + } + off += thislen; + *rlen = off; + } + if (fdebug) { + printf("GetSDR[%04x] next=%x (len=%d): ",r_id,*r_next,reclen); + for (i = 0; i < reclen; i++) printf("%02x ",resp[i]); + printf("\n"); + } + memcpy(recdata,&resp[0],reclen); + *rlen = reclen; + return(rc); +} /*end GetSDR*/ + +static int nsdrs = 0; /*number of sdrs*/ +static int sz_sdrs = 0; /*actual size used with sdrs*/ +static uchar *psdrcache = NULL; + +void free_sdr_cache(uchar *ptr) +{ + if (ptr != NULL) free(ptr); + if ((ptr != psdrcache) && (psdrcache != NULL)) + free(psdrcache); + psdrcache = NULL; +} + +int get_sdr_file(char *sdrfile, uchar **sdrlist) +{ + int rv = -1; + FILE *fp = NULL; + int i, n, num, nsdr, isdr, len; + uchar *sdrbuf; + uchar buff[255]; + uchar hbuf[85]; + char fvalid; + + fp = fopen(sdrfile,"r"); + if (fp == NULL) { + printf("Cannot open file %s\n",sdrfile); + return(ERR_FILE_OPEN); + } + /* determine number of SDRs by number of lines in the file */ + num = 0; + while (fgets(buff, 255, fp)) { num++; } + if (fdebug) printf("Reading %d SDRs from file %s\n",num,sdrfile); + sdrbuf = malloc(num * SDR_SZ); + if (sdrbuf == NULL) { + fclose(fp); + return(rv); + } + fseek(fp, 0L, SEEK_SET); + *sdrlist = sdrbuf; + psdrcache = sdrbuf; + nsdrs = num; + isdr = 0; + nsdr = 0; + while (fgets(buff, 255, fp)) { + len = strlen_(buff); + fvalid = 0; + if (buff[0] >= '0' && (buff[0] <= '9')) fvalid = 1; + else if (buff[0] >= 'a' && (buff[0] <= 'f')) fvalid = 1; + else if (buff[0] >= 'A' && (buff[0] <= 'F')) fvalid = 1; + if (fvalid == 0) continue; + i = 0; + for (n = 0; n < len; ) { + if (buff[n] < 0x20) break; /* '\n', etc. */ + hbuf[i++] = htoi(&buff[n]); + n += 3; + } + memcpy(&sdrbuf[isdr],hbuf,i); + isdr += i; + nsdr++; + } /*end while*/ + if (fdebug) printf("Read %d SDRs, %d bytes\n",nsdr,isdr); + fclose(fp); + rv = 0; + return(rv); +} + +int get_sdr_cache(uchar **pret) +{ + int rv = -1; + int i, n, sz, len, asz; + int recid, recnext; + uchar *pcache; + uchar *psdr; + + if (pret == NULL) return(rv); + fdevsdrs = use_devsdrs(fpicmg); + + if ((psdrcache != NULL) && (nsdrs > 0)) { /*already have sdrcache*/ + *pret = psdrcache; + if (fdebug) printf("get_sdr_cache: already have cache (%p)\n",*pret); + return(0); + } + + rv = GetSDRRepositoryInfo(&n,&fdevsdrs); + if (rv != 0) return(rv); + if (n == 0) { + /* this is an error, probably because fdevsdrs is wrong.*/ + if (fdebug) printf("get_sdr_cache: nsdrs=0, retrying\n"); + fdevsdrs = (fdevsdrs ^ 1); + n = 150; /*try some default num SDRs*/ + } + + sz = n * SDR_SZ; /*estimate max size for n sdrs*/ + pcache = malloc(sz); + if (pcache == NULL) return(rv); + psdrcache = pcache; + *pret = pcache; + memset(pcache,0,sz); + recid = 0; + asz = 0; + for (i = 0; i <= n; i++) + { + if (recid == 0xffff) break; + // psdr = &pcache[i * SDR_SZ]; + psdr = &pcache[asz]; + rv = GetSDR(recid,&recnext,psdr,SDR_SZ,&len); + if (fdebug) + printf("GetSDR[%x] rv = %d len=%d next=%x\n",recid,rv,len,recnext); + if (rv != 0) { + if (rv == 0xC5) { set_reserve(1); i--; } /*retry*/ + else break; + } else { /*success*/ + asz += len; + if (recnext == recid) recid = 0xffff; + else recid = recnext; + } + } + nsdrs = n; + sz_sdrs = asz; /* save the size for later*/ + if (fdebug) { + printf("get_sdr_cache, n=%d sz=%d asz=%d\n",n,sz,asz); + if (i < n) printf("get_sdr_cache error, i=%d < n=%d, rv=%d\n",i,n,rv); + } + return(rv); +} + +int find_nsdrs(uchar *pcache) +{ + int num = 0; + int asz = 0; + int i, len; + uchar *sdr; + ushort recid; + + if (pcache == NULL) return(num); + for (i = 0; asz < sz_sdrs; i++) + { + sdr = &pcache[asz]; + len = sdr[4] + 5; + recid = sdr[0] + (sdr[1] << 8); + asz += len; + if (fdebug) printf("SDR[%x] len=%d i=%d\n", recid,len,i); + } + num = i; + return(num); +} + +int find_sdr_by_snum(uchar *psdr, uchar *pcache, uchar snum, uchar sa) +{ + int rv = -1; + uchar *sdr; + int i, k, len; + int asz = 0; + if (psdr == NULL) return(rv); + if (pcache == NULL) return(rv); + for (i = 0; i <= nsdrs; i++) + { + // sdr = &pcache[i * SDR_SZ]; + sdr = &pcache[asz]; + len = sdr[4] + 5; + asz += len; + switch(sdr[3]) { + case 0x01: k = 7; break; /*full sensor*/ + case 0x02: k = 7; break; /*compact sensor*/ + case 0x03: k = 7; break;/*compact sensor*/ + default: k = 0; break; + } + if (k == 0) continue; + else { + if ((sdr[5] == sa) && (sdr[k] == snum)) { + memcpy(psdr,sdr,len); + return(0); + } + } + } + return(rv); +} + +int find_sdr_by_tag(uchar *psdr, uchar *pcache, char *tag, uchar dbg) +{ + int rv = -1; + uchar *sdr; + int i, k, n, len; + int asz = 0; + if (psdr == NULL) return(rv); + if (pcache == NULL) return(rv); + if (tag == NULL) return(rv); + if (dbg) fdebug = 1; + n = strlen_(tag); + if (fdebug) printf("find_sdr_by_tag(%s) nsdrs=%d\n",tag,nsdrs); + for (i = 0; i <= nsdrs; i++) + { + // sdr = &pcache[i * SDR_SZ]; + sdr = &pcache[asz]; + len = sdr[4] + 5; + asz += len; + switch(sdr[3]) { /* set tag offset by SDR type */ + case 0x01: k = 48; break; /*full SDR*/ + case 0x02: k = 32; break; /*compact SDR*/ + case 0x03: k = 17; break; /*event-only SDR*/ + case 0x10: k = 16; break; /*device locator SDR*/ + case 0x11: k = 16; break; /*FRU device locator SDR*/ + case 0x12: k = 16; break; /*IPMB device locator SDR*/ + default: k = 0; break; /*else do not have an ID string/tag*/ + } + if (k == 0) { + if (fdebug) printf("sdr[%d] idx=%02x%02x num=%x type=%x skip\n", + i,sdr[1],sdr[0],sdr[7],sdr[3]); + continue; + } else { + if (len > SDR_SZ) len = SDR_SZ; + if (fdebug) { + char tmp[17]; + memset(tmp,0,sizeof(tmp)); + memcpy(tmp,&sdr[k],(len - k)); + tmp[16] = 0; /*force stringify*/ + printf("sdr[%d] idx=%02x%02x num=%x tag: %s\n",i,sdr[1],sdr[0], + sdr[7],tmp); + } + if (strncmp(tag,&sdr[k],n) == 0) { + memcpy(psdr,sdr,len); + return(0); + } + } + } + return(rv); +} + + +int find_sdr_next(uchar *psdr, uchar *pcache, ushort id) +{ + int rv = -1; + uchar *sdr; + int i, imatch, len; + ushort recid; + int asz = 0; + if (psdr == NULL) return(rv); + if (pcache == NULL) return(rv); + imatch = nsdrs; + for (i = 0; i < nsdrs; i++) + { + // sdr = &pcache[i * SDR_SZ]; + sdr = &pcache[asz]; + len = sdr[4] + 5; + recid = sdr[0] + (sdr[1] << 8); + asz += len; + // if (fdebug) printf("SDR[%x] len=%d id=%x i=%d imatch=%d\n", + // recid,len,id,i,imatch); + if (recid == id) imatch = i + 1; /*matches prev, return next one*/ + if (id == 0) { rv = 0; break; } + if (i == imatch) { rv = 0; break; } + } + if (rv == 0) memcpy(psdr,sdr,len); + return(rv); +} + +int find_sdr_by_id(uchar *psdr, uchar *pcache, ushort id) +{ + int rv = -1; + uchar *sdr; + int i, imatch, len; + ushort recid; + int asz = 0; + if (psdr == NULL) return(rv); + if (pcache == NULL) return(rv); + imatch = nsdrs; + for (i = 0; i < nsdrs; i++) + { + sdr = &pcache[asz]; + len = sdr[4] + 5; + recid = sdr[0] + (sdr[1] << 8); + asz += len; + if (recid == id) { rv = 0; break; } + } + if (rv == 0) memcpy(psdr,sdr,len); + return(rv); +} + +uchar +bitnum(ushort value) +{ + uchar ret = 0; + int i; + /* returns the highest bit number number set in this word. */ + /* Bit numbers are 1-based in this routine, 0 means no bits set. */ + /* scan 15 bits (0x7FFF). */ + for (i = 0; i < 15; i++) { + if (value & 0x01) ret = i+1; /*was ret++;*/ + value = (value >> 1); + } + return(ret); +} + +static double +expon(int x, int y) +{ + double res; + int i; + /* compute exponent: x to the power y */ + res = 1; + if (y > 0) { + for (i = 0; i < y; i++) res = res * x; + } else if (y < 0) { + for (i = 0; i > y; i--) res = res / x; + } /* else if if (y == 0) do nothing, res=1 */ + return(res); +} + +double +RawToFloat(uchar raw, uchar *psdr) +{ + double floatval; + int m, b, a; + uchar ax; + int rx, b_exp; + SDR01REC *sdr; + int signval; + + sdr = (SDR01REC *)psdr; + floatval = (double)raw; /*default*/ + + // if (raw == 0xff) floatval = 0; else + if (sdr->rectype == 0x01) { /* SDR rectype == full */ + if (fdebug) + printf("units=%x base=%d mod=%d (raw=%x, nom_rd=%x)\n", + sdr->sens_units,sdr->sens_base,sdr->sens_mod, + raw, sdr->nom_reading); + m = sdr->m + ((sdr->m_t & 0xc0) << 2); + b = sdr->b + ((sdr->b_a & 0xc0) << 2); + if (b & 0x0200) b = (b - 0x0400); /*negative*/ + if (m & 0x0200) m = (m - 0x0400); /*negative*/ + rx = (sdr->rx_bx & 0xf0) >> 4; + if (rx & 0x08) rx = (rx - 0x10); /*negative, fix sign w ARM compilers*/ + a = (sdr->b_a & 0x3f) + ((sdr->a_ax & 0xf0) << 2); + ax = (sdr->a_ax & 0x0c) >> 2; + b_exp = (sdr->rx_bx & 0x0f); + if (b_exp & 0x08) b_exp = (b_exp - 0x10); /*negative*/ + //b_exp |= 0xf0; /* negative 8-bit */ + if ((sdr->sens_units & 0xc0) == 0) { /*unsigned*/ + floatval = (double)raw; + } else { /*signed*/ + if (raw & 0x80) signval = (raw - 0x100); + else signval = raw; + floatval = (double)signval; + } + floatval *= (double) m; +#ifdef MATH_OK + floatval += (b * pow (10,b_exp)); + floatval *= pow (10,rx); +#else + floatval += (b * expon (10,b_exp)); + floatval *= expon (10,rx); +#endif + if (fdebug) + printf("decode1: m=%d b=%d b_exp=%x rx=%d, a=%d ax=%d l=%x, floatval=%f\n", + m,b,b_exp,rx,a,ax,sdr->linear,floatval); + switch(sdr->linear) { + case 0: /*linear*/ + break; + case 7: /*invert 1/x*/ + /* skip if zero to avoid dividing by zero */ + if (raw != 0) floatval = 1 / floatval; + break; + case 1: /*ln*/ + case 2: /*log10, log2, e, exp10, exp2, */ + case 3: /*log2*/ + case 4: /*e*/ + case 5: /*exp10*/ + case 6: /*exp2*/ + case 8: /*sqr(x)*/ + case 9: /*cube(x)*/ + case 10: /*sqrt(x)*/ + case 11: /*cube-1(x)*/ + default: + if (fdebug) printf("linear mode %x not implemented\n",sdr->linear); + break; + } /*end-switch linear*/ + } + +#ifdef NOT_LINEAR + /* else if (sdr->linear != 7) */ + { + double be, re; + rc = GetSensorType(sdr->sens_num,&stype,&rtype); + if (fdebug) + printf("decode: rc=%x, stype=%x, rtype=%x\n",rc,stype,rtype); + if (rc != 0) return(floatval); + + /* GetSensorReadingFactors */ + rc = GetSensorReadingFactors(sdr->sens_num,raw,&m,&b,&b_exp,&r,&a); + if (rc == 0) { + // floatval = ((m * raw) + (b * be)) * re; + } + if (fdebug) printf("decode: rc=%x, floatval=%f\n",rc,floatval); + } +#endif + + return(floatval); +} + +#define IpmiAnalogDataFormatUnsigned 0 +#define IpmiAnalogDataFormat1Compl 1 +#define IpmiAnalogDataFormat2Compl 2 + +uchar +FloatToRaw(double val, uchar *psdr, int rounding) +{ + double cval; + int lowraw, highraw, raw, maxraw, minraw, next_raw; + int analog_dfmt; + + analog_dfmt = (psdr[20] >> 6) & 0x03; + switch( analog_dfmt ) + { + case IpmiAnalogDataFormat1Compl: + lowraw = -127; + highraw = 127; + minraw = -127; + maxraw = 127; + next_raw = 0; + break; + case IpmiAnalogDataFormat2Compl: + lowraw = -128; + highraw = 127; + minraw = -128; + maxraw = 127; + next_raw = 0; + break; + case IpmiAnalogDataFormatUnsigned: + default: + lowraw = 0; + highraw = 255; + minraw = 0; + maxraw = 255; + next_raw = 128; + break; + } + + /* do a binary search for the right nth root value */ + do { + raw = next_raw; + cval = RawToFloat( (uchar)raw, psdr ); + if ( cval < val ) { + next_raw = ((highraw - raw) / 2) + raw; + lowraw = raw; + } else { + next_raw = ((raw - lowraw) / 2) + lowraw; + highraw = raw; + } + } while ( raw != next_raw ); + + /* Do rounding to get the final value */ + switch( rounding ) { + case 0: /* Round Normal = Round to nearest value */ + if ( val > cval ) { + if ( raw < maxraw ) { + double nval; + nval = RawToFloat((uchar)(raw+1),psdr); + nval = cval + ((nval - cval) / 2.0); + if ( val >= nval ) raw++; + } + } else { + if ( raw > minraw ) { + double pval; + pval = RawToFloat((uchar)(raw-1),psdr); + pval = pval + ((cval - pval) / 2.0); + if ( val < pval ) raw--; + } + } + break; + case 1: /*Round Down*/ + if ((val < cval) && (raw > minraw )) raw--; + break; + case 2: /*Round Up*/ + if ((val > cval) && (raw < maxraw)) raw++; + break; + } + if ( analog_dfmt == IpmiAnalogDataFormat1Compl ) + if ( raw < 0 ) raw -= 1; + return((uchar)raw); +} /*end FloatToRaw()*/ + +static int fill_thresholds(double *thrf, uchar *sdr) +{ + int rv = 0; + uchar *vals; + uchar bits; + + // snum = sdr[7]; + bits = sdr[19]; /*which are settable*/ + vals = &sdr[36]; + if (fdebug) + printf("fill_thresholds: bits=%02x, values: %f>=%f>=%f, %f<=%f<=%f\n", + bits, thrf[0],thrf[1],thrf[2], thrf[3],thrf[4],thrf[5]); + if (thrf[0] == THR_EMPTY) { + if ((bits & 0x01) != 0) { /*lo-noncrit*/ + thrf[0] = RawToFloat(vals[5],sdr); + rv++; + } else thrf[0] = 0; + } + if (thrf[1] == THR_EMPTY) { + if ((bits & 0x02) != 0) { /*lo-crit*/ + thrf[1] = RawToFloat(vals[4],sdr); + rv++; + } else thrf[1] = 0; + } + if (thrf[2] == THR_EMPTY) { + if ((bits & 0x04) != 0) { /*lo-unrec*/ + thrf[2] = RawToFloat(vals[3],sdr); + rv++; + } else thrf[2] = 0; + } + if (thrf[3] == THR_EMPTY) { + if ((bits & 0x08) != 0) { /*hi-noncrit*/ + thrf[3] = RawToFloat(vals[2],sdr); + rv++; + } else thrf[3] = 0; + } + if (thrf[4] == THR_EMPTY) { + if ((bits & 0x10) != 0) { /*hi-crit*/ + thrf[4] = RawToFloat(vals[1],sdr); + rv++; + } else thrf[4] = 0; + } + if (thrf[5] == THR_EMPTY) { + if ((bits & 0x20) != 0) { /*hi-unrec*/ + thrf[5] = RawToFloat(vals[0],sdr); + rv++; + } else thrf[5] = 0; + } + if (fdebug) + printf("fill_thresholds: after rv=%d values: %f>=%f>=%f, %f<=%f<=%f\n", + rv,thrf[0],thrf[1],thrf[2], thrf[3],thrf[4],thrf[5]); + return(rv); +} + +char * +decode_itype(uchar itype) +{ + char *retstr; + int i; + /* Decode the Interrupt Type from Entity Assoc records */ + + retstr = tmpstr; + if (itype <= 0x0f) sprintf(retstr,"IRQ_%d",itype); + else if (itype <= 0x13) { + strcpy(retstr,"PCI-A"); + for (i=0x10;i<itype;i++) retstr[4]++; + } + else if (itype == 0x14) strcpy(retstr,"SMI"); + else if (itype == 0x15) strcpy(retstr,"SCI"); + else if (itype >= 0x20 && itype <= 0x5f) + sprintf(retstr,"SysInt_%d",itype-0x20); + else if (itype == 0x60) strcpy(retstr,"ACPI/PnP"); + else if (itype == 0xFF) strcpy(retstr,"NoInt"); + else strcpy(retstr,"Invalid"); + return(retstr); +} + +int decode_oem_sensor(uchar *sdr,uchar *reading,char *pstring,int slen) +{ + int rv = -1; +#ifdef METACOMMAND + switch(vend_id) { + case VENDOR_INTEL: + rv = decode_sensor_intel(sdr, reading, pstring, slen); + break; + case VENDOR_KONTRON: + rv = decode_sensor_kontron(sdr, reading, pstring, slen); + break; + case VENDOR_FUJITSU: + rv = decode_sensor_fujitsu(sdr,reading,pstring,slen); + break; + case VENDOR_SUN: + rv = decode_sensor_sun(sdr, reading, pstring, slen); + break; + case VENDOR_MAGNUM: + case VENDOR_SUPERMICRO: + case VENDOR_SUPERMICROX: + rv = decode_sensor_supermicro(sdr, reading, pstring, slen); + break; + case VENDOR_QUANTA: + rv = decode_sensor_quanta(sdr, reading, pstring, slen); + break; + case VENDOR_HP: + rv = decode_sensor_hp(sdr, reading, pstring, slen); + break; + case VENDOR_DELL: + rv = decode_sensor_dell(sdr, reading, pstring, slen); + break; + default: + break; + } /*end-switch vend_id*/ + if (fdebug && rv == 0) + printf("decode_oem_sensor rv=%d vend=%x string=%s\n",rv,vend_id,pstring); +#endif + return (rv); +} + +int show_oemsdr(int vend, uchar *sdr) +{ + int rv = -1; + int i, len; + +#ifdef METACOMMAND + if (vend == VENDOR_INTEL) { + show_oemsdr_intel(sdr); /*show subtypes for Intel BMC_TAM*/ + rv = 0; + } else if (vend == 4156) { /*special HP/NewAccess OEM SDR*/ + show_oemsdr_hp(sdr); + rv = 0; + } else if (vend == VENDOR_QUANTA) { + printf("Quanta: "); + show_oemsdr_nm(sdr); + rv = 0; + } +#endif + if (rv != 0) { + len = sdr[4] + 5; + if (vend == VENDOR_FUJITSU) printf("Fujitsu: "); + else if (vend == VENDOR_INTEL) printf("Intel: "); + else printf("manuf=%d: ",vend); + for (i = 8; i < len; i++) printf("%02x ",sdr[i]); + printf("\n"); + } + return(rv); +} + +void +ShowThresh(int flg, uchar bits, uchar *vals, uchar *sdr) +{ + char str[128] = ""; + char part[24]; /* ~15 bytes used */ + double ival; + char sep[4]; + char *tag; + tag = ""; + if (fsimple) { + sprintf(sep,"%c ",bdelim); + tag = "Thresholds"; + } else sep[0] = 0; /*null string*/ + if (fshowthr == 2) { + double i0, i1, i2, i3, i4, i5; + i0 = RawToFloat(vals[0],sdr); + i1 = RawToFloat(vals[1],sdr); + i2 = RawToFloat(vals[2],sdr); + i3 = RawToFloat(vals[3],sdr); + i4 = RawToFloat(vals[4],sdr); + i5 = RawToFloat(vals[5],sdr); + sprintf(str,"%.2f:%.2f:%.2f:%.2f:%.2f:%.2f",i0,i1,i2,i3,i4,i5); + printf("\t%s%s%s%c",sep,"Thresh ",str,chEol); + } else if (flg != 0) { /* Compact, did GetThresholds, reverse order */ + if (bits & 0x20) { + ival = RawToFloat(vals[5],sdr); + sprintf(part,"%shi-unrec %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x10) { + ival = RawToFloat(vals[4],sdr); + sprintf(part,"%shi-crit %.2f ", sep,ival); + strcat(str,part); + } + if (bits & 0x08) { + ival = RawToFloat(vals[3],sdr); + sprintf(part,"%shi-noncr %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x01) { + ival = RawToFloat(vals[0],sdr); + sprintf(part,"%slo-noncr %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x02) { + ival = RawToFloat(vals[1],sdr); + sprintf(part,"%slo-crit %.2f ", sep,ival); + strcat(str,part); + } + if (bits & 0x04) { + ival = RawToFloat(vals[2],sdr); + sprintf(part,"%slo-unrec %.2f ",sep,ival); + strcat(str,part); + } + if (flg == 2) { + if (sens_verbose) tag = "Volatile "; + printf("\t%s%s%s%c",sep,tag,str,chEol); + } else + printf("\t%s%s%s%c",sep,tag,str,chEol); + } else { /*Full SDR*/ + if (fdebug) printf("ShowThresh[%x]: bits=%02x, sdr18=%02x %02x\n", + sdr[7],bits,sdr[18],sdr[19]); + if (bits & 0x20) { + ival = RawToFloat(vals[0],sdr); + sprintf(part,"%shi-unrec %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x10) { + ival = RawToFloat(vals[1],sdr); + sprintf(part,"%shi-crit %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x08) { + ival = RawToFloat(vals[2],sdr); + sprintf(part,"%shi-noncr %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x01) { + ival = RawToFloat(vals[5],sdr); + sprintf(part,"%slo-noncr %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x02) { + ival = RawToFloat(vals[4],sdr); + sprintf(part,"%slo-crit %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x04) { + ival = RawToFloat(vals[3],sdr); + sprintf(part,"%slo-unrec %.2f ",sep,ival); + strcat(str,part); + } + if (sens_verbose) tag = "SdrThres "; + printf("\t%s%s%s%c",sep,tag,str,chEol); + if (sens_verbose) + { /* show max/min & hysteresis from full sdr */ + str[0] = 0; + ival = RawToFloat(sdr[31],sdr); + sprintf(part,"%snom %.2f ",sep,ival); + strcat(str,part); + ival = RawToFloat(sdr[32],sdr); + sprintf(part,"%snmax %.2f ",sep,ival); + strcat(str,part); + ival = RawToFloat(sdr[33],sdr); + sprintf(part,"%snmin %.2f ",sep,ival); + strcat(str,part); + + ival = RawToFloat(sdr[34],sdr); + sprintf(part,"%ssmax %.2f ",sep,ival); + strcat(str,part); + + ival = RawToFloat(sdr[35],sdr); + sprintf(part,"%ssmin %.2f ",sep,ival); + strcat(str,part); + +#ifdef OLD + ival = RawToFloat(sdr[42],sdr); + sprintf(part,"%s+hyst %.2f ",sep,ival); + strcat(str,part); + + ival = RawToFloat(sdr[43],sdr); + sprintf(part,"%s-hyst %.2f ",sep,ival); + strcat(str,part); +#endif + + printf("\t%s%c",str,chEol); + } + } /*endif full sdr*/ +} + +/* + * decode_comp_reading + * + * Decodes the readings from compact SDR sensors. + * Use sensor_dstatus array for sensor reading types and meaning strings. + * Refer to IPMI Table 36-1 and 36-2 for this. + * + * Note that decoding should be based on sensor type and ev_type only, + * except for end cases. + * + * Note reading1 = sens_reading[2], reading2 = sens_reading[3] + */ +int +decode_comp_reading(uchar type, uchar evtype, uchar num, + uchar reading1, uchar reading2) +{ + int istr = 0; /*string index into sensor_dstatus[] */ + uchar b; + ushort reading; + static char customstr[35]; + + /* usually reading2 has h.o. bit set (0x80). */ + reading = reading1 | ((reading2 & 0x7f) << 8); + + switch(type) + { + case 0x01: /*Discrete Thermal, Temperature*/ + if (fdebug) + printf("Discrete Thermal snum %x evtype=%x reading=%x\n", + num,evtype,reading); + if (evtype == 0x07) { + b = bitnum(reading); + if (b == 0) istr = 8; /*no bits set, "OK*"*/ + else if (b < 3) istr = 0; /*bits 1,2 "OK"*/ + else istr = 65; /*transition to error, Limit Exceeded*/ + } else if (evtype == 0x05) { + /* see CPU1 VRD Temp on S5000, snum 0xc0 thru 0xcf */ + if (reading & 0x01) istr = 65; /* Limit Exceeded*/ + else istr = 0; /* "OK" LimitNotExceeded*/ + } else if (evtype == 0x03) { + if (reading & 0x01) istr = 13; /* Asserted */ + else istr = 0; /* "OK" Deasserted */ + } else { /* evtype == other 0x05 */ + if (reading & 0x01) istr = 0; /* 8="OK*", 0="OK" */ + else istr = 5; /*state asserted, Crit-hi */ + } + break; + case 0x02: /*Discrete Voltage*/ + { /* evtype == 0x05 for VBat, 0x03 for VR Watchdog */ + if (reading & 0x01) istr = 65; /*LimitExceeded, was Crit-hi*/ + else istr = 0; /* "OK" LimitNotExceeded*/ + } + break; + case 0x04: /*Fan*/ + if (evtype == 0x0b) { /*redundancy*/ + b = reading & 0x3f; + if (b == 0x00) istr = 16; /*sensor disabled*/ + else if (b == 0x01) istr = 18; /*fully redundant*/ + else if (b == 0x02) istr = 19; /*redundancy lost*/ + else if (b == 0x0b) istr = STR_AC_LOST; /*ac lost*/ + else istr = 20; /*redundancy degraded*/ + } else if (evtype == 0x08) { /*presence*/ + if (reading & 0x02) istr = 9; /*Present/Inserted*/ + else if (reading & 0x01) istr = 10; /*Absent/Removed*/ + else /*reading==00*/ istr = 47; /*Unused*/ + } else if (evtype == 0x03) { /*PS Fan Fail*/ + if (reading == 0) istr = 0; /*OK*/ + else istr = 12; /*faulty*/ + } else { /*other evtype*/ + b = reading & 0x0f; + if (b == 0) istr = 12; /*faulty*/ + else if (b & 0x01) istr = 11; /*ready*/ + else istr = 41; /*Unknown*/ + } + break; + case 0x05: /*Physical Security, Chassis */ + if (reading == 0) istr = 0; /*OK*/ + else if (reading & 0x01) istr = 38; /*chassis intrusion*/ + /* 0x02 Drive bay intrusion */ + /* 0x04 IO area intrusion */ + /* 0x08 Processor area intrusion */ + else if (reading & 0x10) istr = 37; /*lan leash lost*/ + /* 0x20 Dock/Undock */ + /* 0x40 Fan area intrusion */ + else istr = 41; /* Unknown, was bitnum(reading); */ + break; + case 0x07: /*Processor Status - 0x80 is OK/Present */ + b = bitnum(reading); + if (evtype == 0x03) { + if (b <= 1) istr = 0; /*bit1 Deasserted, OK* */ + else istr = 13; /*bit2 Asserted*/ + } else { /*usu 0x6f*/ + if (b > 10) istr = 41; /*Unknown*/ + else if (b == 0) istr = 0; /*OK*/ + else istr = 47 + b; /*Proc strings 48 thru 57*/ + } + break; + case 0x08: /*Power Supply*/ + b = reading & 0x7f; + if (b == 0) istr = 10; /*absent*/ + else if (b & 0x40) istr = STR_PS_CONFIG; /*Config Err*/ + else if (b & 0x08) istr = STR_AC_LOST; /*AC Lost*/ + else if (b & 0x04) istr = 15; /*Predictive Fail*/ + else if (b & 0x02) istr = STR_PS_FAIL; /*PS Fail*/ + else if (b & 0x01) istr = 9; /*present*/ + break; + case 0x09: /*Power Unit*/ + b = reading & 0x3f; + if (evtype == 0x0b) { /*Power Redundancy*/ + if (b == 0x00) istr = 16; /*sensor disabled*/ + else if (b == 0x01) istr = 18; /*fully redundant*/ + else if (b == 0x02) istr = 19; /*redundancy lost*/ + else if (b == 0x0b) istr = STR_AC_LOST; /*ac lost*/ + else istr = 20; /*redundancy degraded*/ + } else { /* Power Unit (evtype==0x6f or 0xef) */ + if (b == 0) istr = 17; /*enabled*/ + else if ((b & 0x01) == 1) istr = 16; /*disabled*/ + } + break; + case 0x0C: /* Memory */ + b = reading & 0x3f; + if (b == 0) istr = 0; /*OK*/ + else if (b & 0x01) istr = 8; /*Correctable ECC (OK*)*/ + else if ((b & 0x02) || (b & 0x20)) istr = 39; /*ECC Error*/ + else if (b & 0x04) istr = 40; /*Parity Error*/ + else istr = bitnum(b); /* ECC or other error */ + break; + case 0x0D: /* drive slot - usually HSC sens_ownid == 0xc0 */ + if (fRomley) { /* evtype==0x6f, has both status and presence */ + if (reading & 0x02) istr = 12; /*Faulty*/ + else if (reading & 0x80) istr = STR_REBUILDING; /*Rebuilding*/ + else if (reading & 0x01) istr = 9; /*Present (OK)*/ + else istr = 10; /*Absent*/ + } else { + if (evtype == 8) { /* HSC slot presence sensors (num > 8)*/ + if (reading1 & 0x02) istr = 9; /*Present/Inserted*/ + else if (reading1 & 0x01) istr = 10; /*Absent/Removed*/ + else /*reading1==00*/ istr = 47; /*Unused*/ + } else { /* HSC slot status sensors (evtype==0x6f) */ + /* usually reading2 == 0x82 or 0x8E if healthy */ + if (reading2 & 0x01) istr = 12; /*state8=Rebuild stopped*/ + else if (reading2 & 0x02) istr = 11; /*state9=Inserted/Ready */ + else if (reading2 & 0x04) istr = 11; /*state10=Safe_to_Remove*/ + else if (reading2 & 0x08) istr = 11; /*state11=Ready */ + else if (reading2 == 0x80) istr = 47; /*no states, Unused*/ + else istr = 12; /*faulty*/ + b = 8; /*if no bits set, no raid state */ + if (reading1 & 0x01) { b = 0; } /*state0=Faulty*/ + else if (reading1 & 0x02) b = 1; /*state1=Rebuilding*/ + else if (reading1 & 0x04) b = 2; /*state2=InFailedArray*/ + else if (reading1 & 0x08) b = 3; /*state3=InCriticalArray*/ + else if (reading1 & 0x10) b = 4; /*state4=ParityCheck*/ + else if (reading1 & 0x20) b = 5; /*state5=PredictedFault*/ + else if (reading1 & 0x40) b = 6; /*state6=Un-configured*/ + else if (reading1 & 0x80) b = 7; /*state7=HotSpare*/ + if (b < 8) { + /* also include a raid_state, via custom string */ + sprintf(customstr,"%s %s", + sensor_dstatus[istr], raid_states[b]); + istr = STR_CUSTOM; + sensor_dstatus[istr] = customstr; + if (fdebug) printf("dstatus=%s\n",sensor_dstatus[istr]); + } + } /*end-else HSC slot status*/ + } + break; + case 0x10: /*Event Logging*/ + /* usu evtype==0x6f*/ + b = bitnum(reading & 0x3f); + switch (b) { + case 0x00: istr = 0; break; /*OK*/ + case 0x01: istr = 59; break; /*MemLogDisabled*/ + case 0x02: istr = 60; break; /*TypLogDisabled*/ + case 0x03: istr = 61; break; /*LogCleared*/ + case 0x04: istr = 62; break; /*AllLogDisabled*/ + case 0x05: istr = 63; break; /*SelFull*/ + case 0x06: istr = 64; break; /*SelNearFull*/ + default: istr = 41; break; /*Unknown*/ + } + break; + case 0x12: /*System Event*/ + if (reading == 0) istr = 0; + else istr = 13; /*Asserted*/ + break; + case 0x13: /*Critical Interrupt*/ + /* valid bits: 0x03FF */ + if (reading == 0) istr = 0; /*OK*/ + else { + b = bitnum(reading); /* ECC or other error */ + if (b > 10) b = 10; + istr = 24 + b; + } + break; + case 0x14: /*Button*/ + if (reading == 0) istr = 0; /*OK*/ + else istr = 13; /*Asserted*/ + break; + case 0x15: /*Module/ Board */ + if (evtype == 0x08) { /*presence*/ + if (reading & 0x02) istr = 9; /*Present/Inserted*/ + else if (reading & 0x01) istr = 10; /*Absent/Removed*/ + else /*reading==00*/ istr = 47; /*Unused*/ + } + break; + case 0x16: /* HSBP Status (esp. Romley) */ + if (reading & 0x010) istr = STR_HSC_OFF; /*Offline*/ + else istr = 0; /*OK*/ + break; + case 0x17: /* ATCA CDM, Air Filter, Filter Tray */ + if (reading == 0) istr = 0; /*OK*/ + else if (reading & 0x01) istr = 10; /*Absent*/ + else istr = bitnum(reading); /* other error, TODO: fix this */ + break; + case 0x1C: /*Terminator (usu SCSI)*/ + if (reading & 0x01) istr = 9; /*present*/ + else istr = 10; /*missing,absent*/ + break; + case 0x21: /*DIMM memory slot*/ + if ((reading & 0x04) != 0) istr = 9; /*present*/ + else istr = 10; /*absent*/ + sprintf(customstr,"%s", sensor_dstatus[istr]); + if ((reading & 0x01) != 0) strcat(customstr,",Fault"); + if ((reading & 0x0100) != 0) strcat(customstr,",Disabled"); + istr = 58; /*use a custom string*/ + sensor_dstatus[istr] = customstr; + if (fdebug) printf("dstatus=%s\n",sensor_dstatus[istr]); + break; + case 0x22: /*ACPI Power State*/ + b = bitnum(reading); + switch(b) { + case 0: istr = 0; break; /*OK*/ + case 1: istr = 22; break; /*Working*/ + case 2: + case 3: + case 4: + case 5: + case 9: + case 10: istr = 23; break; /*Sleeping*/ + case 6: + case 7: + case 8: + case 11: + case 13: istr = 21; break; /*Off*/ + case 12: istr = 24; break; /*On*/ + default: istr = 41; /*unknown*/ + } + break; + case 0x23: /*Watchdog*/ + if (reading == 0) istr = 0; + else istr = 13; /*Asserted*/ + break; + case 0x24: /*Platform Alert*/ + b = bitnum(reading); + switch(b) { + case 0: istr = 0; break; /*OK, no bits set*/ + case 1: istr = 66; break; /*Page, bit 0 set*/ + case 2: istr = 67; break; /*LAN, bit 1 set*/ + case 3: istr = 68; break; /*PET*/ + case 4: istr = 69; break; /*SNMP OEM*/ + default: istr = 70; /*None*/ + } + break; + case 0x25: /* Entity Presence */ + if (reading & 0x01) istr = 8; /*Present*/ + else if (reading & 0x02) istr = 9; /*Absent*/ + else if (reading & 0x04) istr = 16; /*Disabled*/ + else istr = 42; /* NotAvailable */ + break; + case 0x28: /* BMC FW Health */ + if (reading == 0) istr = 0; /*OK*/ + else istr = 12; /*Faulty*/ + break; + case 0x29: /* Battery */ + switch(reading & 0x7f) { + case 0x00: istr = 0; break; /*OK*/ + case 0x01: istr = 15; break; /*Predict Fail*/ + case 0x04: istr = 9; break; /*Present*/ + case 0x02: + default: istr = 12; break; /*Failed/Faulty*/ + } + break; + case 0x2A: /* Session Audit (IPMI 2.0) */ + if (reading == 0x00) istr = 45; /*Activated*/ + else istr = 46; /*Deactivated*/ + break; + case 0x2B: /* Version Change */ + b = bitnum(reading1); + switch(b) { + case 0: istr = 0; break; /*OK, no bits set*/ + case 1: istr = 72; break; /*HW Changed, bit 0 set*/ + case 2: istr = 73; break; /*SW Changed, bit 1 set*/ + case 3: istr = 74; break; /*HW incompatibility*/ + default: istr = 75; break; /*Change error*/ + } + break; + case 0x60: /* SCSI 1 Term Flt */ + case 0x61: /* SCSI 2 Term Flt */ + break; + /* sensor types 0xC0 - 0xFF are OEM RESERVED */ + case 0xF1: /* ATCA IPMB-0 Sensor */ + if ((reading & 0x7fff) == 0x0008) istr = 0; /*OK*/ + else istr = bitnum(reading1); /* other error, TODO: refine this */ + break; + case 0xC0: /* SMI State, NMI State */ + case 0xD8: /* BIST */ + case 0xF0: /* ATCA FRU HotSwap, TODO: refine this */ + case 0xF2: /* ATCA Module HotSwap, TODO: refine this */ + case 0xF3: /* SMI Timeout, etc. */ + if (reading & 0x01) istr = 13; /* Asserted */ + else istr = 0; /* "OK", Deasserted */ + break; + default: + if (fdebug) + printf("sensor[%x] type %02x not decoded, reading = %04x\n", + num,type,reading); + istr = STR_OTHER; /* other " - " */ + } + return(istr); +} /* end decode_comp_reading */ + +#define STYPSZ 15 +static char *get_stype_str(uchar stype) +{ /*return sensor type string, with fixed length */ + static char stype_str[STYPSZ+1]; + char *tmpstr; + int i, n; + tmpstr = get_sensor_type_desc(stype); + n = strlen_(tmpstr); + if (n > STYPSZ) n = STYPSZ; + strncpy(stype_str,tmpstr,n); + for (i = n; i < STYPSZ; i++) stype_str[i] = ' '; + stype_str[i] = 0; + tmpstr = stype_str; + return(tmpstr); +} + +void +ShowSDR(char *tag, uchar *sdr) +{ + SDR01REC *sdr01; + SDR02REC *sdr02; + SDR08REC *sdr08; + SDR11REC *sdr11; + SDR12REC *sdr12; + SDR14REC *sdr14; + SDRc0REC *sdrc0; + char idstr[32]; + char *typestr = NULL; + int vend; + int len, ilen, i, j; + int ioff; + uchar sens[4]; + uchar sens_cap; + uchar shar_cnt; + int rc; + double val; + char brearm; + uchar sep[4]; + char rdgstr[50]; + + len = sdr[4] + 5; + sens_cap = 0x80; /*ignore*/ + if (fdebug) printf("ShowSDR: len=%d, type=%x\n",len,sdr[3]); + memset(sens,0,4); + if (frawsdr || fdebug) { + printf("raw SDR: "); + for (i = 0; i < len; i++) + printf("%02x ",sdr[i]); + printf("\n"); + } + switch(sdr[3]) + { + case 0x01: /* Full sensor record */ + sdr01 = (SDR01REC *)sdr; + ioff = 48; + if (ioff > len) { + if (fdebug) printf("bad length: type=%x, len=%d, ioff=%d\n", + sdr[3],len,ioff); + printf("Bad SDR Length, please apply the correct FRU/SDR diskette\n"); + return; + } + sens_cap = sdr[11]; /*sdr01->sens_capab*/ + ilen = len - ioff; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[ioff],ilen); + for (i=ilen; i<16; i++) { idstr[i] = ' '; ilen++; } + idstr[ilen] = 0; /* stringify */ + if ((sdr01->sens_capab & 0x40) == 0) brearm = 'm'; /*manual rearm*/ + else brearm = 'a'; /*automatic rearm*/ + if (fdebug) printf("entity %d.%d, idlen=%d sizeof=%d idstr0=%c s0=%x\n", + sdr01->entity_id, sdr01->entity_inst, + ilen,sizeof(SDR01REC),idstr[0],sdr[ioff]); + rc = GetSensorReading(sdr01->sens_num,sdr01,sens); + if (rc != 0) { /* if rc != 0, leave sens values zero */ + i = 41; /* Unknown */ + val = 0; + if (rc == 0xCB) { /*sensor not present*/ + i = 10; /* Absent */ + typestr = "na"; + } else typestr = decode_rv(rc); + } else { + j = (sens[2] & 0x3f); /*sensor reading state*/ + i = bitnum((ushort)j); /*sensor_dstatus index*/ + if (fdebug) + printf("bitnum(%02x)=%d raw=%02x init=%x base/units=%x/%x\n", + sens[2],i,sens[0],sens[1],sdr01->sens_base, + sdr01->sens_units); + if ((sens[1] & 0x20) != 0) { i = 7; val = 0; } /* Init state */ + else val = RawToFloat(sens[0],sdr); + typestr = get_unit_type(sdr01->sens_units, sdr01->sens_base, + sdr01->sens_mod, fsimple); +#ifdef WRONG + if (is_romley(vend_id,prod_id) && + (sdr01->sens_type == 0x0C) && (sdr01->sens_units & 0x01)) + { /* Intel Memory Thermal Throttling %, raw 0x01 == 0.5 % */ + val = (val / 2); /* handle MTT SDR errata */ + } /*correct solution is to fix the SDR m-value instead */ +#endif + } + rc = decode_oem_sensor(sdr,sens,oem_string,sizeof(oem_string)); + if (rc == 0) { + strncpy(rdgstr,oem_string,sizeof(rdgstr)); + } else { + if (fsimple) + snprintf(rdgstr,sizeof(rdgstr),"%s %c %.2f %s", + sensor_dstatus[i],bdelim,val,typestr); + else + snprintf(rdgstr,sizeof(rdgstr),"%02x %s %.2f %s", + sens[0], sensor_dstatus[i],val,typestr); + } + sep[0] = 0; /*null string*/ + printf("%s", tag); + if (fsimple) { + sprintf(sep,"%c ",bdelim); + printf("%04x %c Full %c %s %c %02x %c %s %c %s%c", + sdr01->recid, bdelim, bdelim, + get_stype_str(sdr01->sens_type), + bdelim, sdr01->sens_num,bdelim, idstr, + bdelim,rdgstr,chEol); + } else + printf("%04x SDR Full %02x %02x %02x %c %02x snum %02x %s = %s%c", + sdr01->recid, sdr01->rectype, sdr01->ev_type, + sdr01->sens_ownid, brearm, sdr01->sens_type, sdr01->sens_num, + idstr, rdgstr, chEol); + if (fdebug && fshowthr) + printf("cap=%02x settable=%02x, readable=%02x\n", + sens_cap,sdr[19],sdr[18]); + if (sens_verbose) /* if -v, also show Entity ID */ + printf("\t%sEntity ID %d.%d (%s), Capab: %s%c", + sep, sdr01->entity_id, sdr01->entity_inst, + decode_entity_id(sdr01->entity_id), // sens_cap, + decode_capab(sens_cap),chEol); + if (fshowthr && (sens_cap & 0x0f) != 0x03) { + uchar thresh[7]; + /* Thresholds, so show them */ + /* Use settable bits to show thresholds, since the + * readable values will be off for Full SDRs. + * If cant set any thresholds, only show SDR thresholds */ + if (sdr[19] == 0) rc = 1; + else { + /* Show volatile thresholds. */ + rc = GetSensorThresholds(sdr01->sens_num,&thresh[0]); + if (rc == 0) ShowThresh(2,thresh[0],&thresh[1],sdr); + } + /* Show SDR non-volatile thresholds. */ + if (sens_verbose || rc !=0) ShowThresh(0,sdr[18],&sdr[36],sdr); + // ShowThresh(0,0x3f,&sdr[36],sdr); /* to show all %%%% */ + } + if (fwrap) { /* (chEol != '\n') include time */ + time_t ltime; + time(<ime); + if (fsimple) + printf("%c %s",bdelim,ctime(<ime)); /*ctime has '\n' */ + else + printf("at %s",ctime(<ime)); /*ctime has '\n' */ + } + break; + case 0x02: /* Compact sensor record */ + sdr02 = (SDR02REC *)sdr; + ioff = 32; + if (ioff > len) { + if (fdebug) printf("bad length: type=%x, len=%d, ioff=%d\n", + sdr[3],len,ioff); + printf("Bad SDR Length, please apply the correct FRU/SDR diskette\n"); + return; + } + sens_cap = sdr[11]; /*sdr02->sens_capab*/ + shar_cnt = sdr02->shar_cnt & 0x0f; /*sdr[23]*/ + ilen = len - ioff; + if ((ilen+1) >= sizeof(idstr)) ilen = sizeof(idstr) - 2; + memcpy(idstr,&sdr[ioff],ilen); + if ((shar_cnt > 1) && (sdr02->shar_off & 0x80) != 0) { /*do shared SDR*/ + j = (sdr02->shar_off & 0x7f); /*sdr[24] = modifier offset*/ + if (fdebug) printf("share count = %d, mod_offset = %d\n",shar_cnt,j); + if ((sdr02->shar_cnt & 0x10) != 0) { /*alpha*/ + idstr[ilen++] = 0x40 + j; /* j=1 -> 'A' */ + idstr[ilen] = 0; /* stringify */ + } else { /*numeric*/ + sprintf(&idstr[ilen],"%d",j); + ilen = strlen_(idstr); + } + } /* else normal idstr */ + for (i=ilen; i<16; i++) { idstr[i] = ' '; ilen++; } + idstr[ilen] = 0; /* stringify */ + if ((sdr02->sens_capab & 0x40) == 0) brearm = 'm'; /*manual rearm*/ + else brearm = 'a'; /*automatic rearm*/ + if (fdebug) printf("ilen=%d, istr0=%c, sizeof=%d, s0=%x\n", + ilen,idstr[0],sizeof(SDR02REC),sdr[ioff]); + memset(sens,0,sizeof(sens)); + rc = GetSensorReading(sdr02->sens_num,sdr02,sens); + if (rc != 0) { /* if rc != 0, leave sens values zero */ + i = 41; /* Unknown */ + val = 0; + if (rc == 0xCB) { /*sensor not present*/ + i = 10; /* Absent */ + typestr = "na"; + } else typestr = decode_rv(rc); + } else { + if ((sens[1] & 0x20) != 0) i = 42; /*init state, NotAvailable*/ + else { + rc = decode_oem_sensor(sdr,sens,oem_string,sizeof(oem_string)); + if (rc == 0) i = STR_OEM; + else i = decode_comp_reading(sdr02->sens_type,sdr02->ev_type, + sdr02->sens_num,sens[2],sens[3]); + } + } + if (fdebug) + printf("snum %x type %x evt %x reading %02x%02x i=%d rc=%d %s\n", + sdr02->sens_num,sdr02->sens_type,sdr02->ev_type, + sens[3],sens[2],i,rc, decode_rv(rc)); + j = sens[2] | ((sens[3] & 0x7f) << 8); /*full reading, less h.o. bit*/ + sep[0] = 0; /*null string*/ + printf("%s", tag); + if (fsimple) { + sprintf(sep,"%c ",bdelim); + printf("%04x %c Compact %c %s %c %02x %c %s %c %s %c%c", + sdr02->recid, bdelim, bdelim, + get_stype_str(sdr02->sens_type), + bdelim, sdr02->sens_num, bdelim, idstr, + bdelim, sensor_dstatus[i],bdelim,chEol); + } else if (i == STR_OEM) { + // idstr[ilen] = 0; /*cut out padding in idstr*/ + printf("%04x SDR Comp %02x %02x %02x %c %02x snum %02x %s = %04x %s%c", + sdr02->recid, sdr02->rectype, sdr02->ev_type, + sdr02->sens_ownid, brearm, sdr02->sens_type, sdr02->sens_num, + idstr, j, sensor_dstatus[i],chEol); + // sensor_dstatus[i] == oem_string + } else { + printf("%04x SDR Comp %02x %02x %02x %c %02x snum %02x %s = %04x %s%c", + sdr02->recid, sdr02->rectype, sdr02->ev_type, + sdr02->sens_ownid, brearm, sdr02->sens_type, sdr02->sens_num, + idstr, j, sensor_dstatus[i],chEol); + /* idstr, sens[0], sens[1], sens[2], sens[3], */ + } + if (fdebug && fshowthr) + printf("cap=%02x settable=%02x, readable=%02x\n", + sens_cap,sdr[19],sdr[18]); + if (fshowthr) /*also show Entity ID */ + printf("\t%sEntity ID %d.%d (%s), Capab: %s%c", + sep, sdr02->entity_id, sdr02->entity_inst, + decode_entity_id(sdr02->entity_id), // sens_cap, + decode_capab(sens_cap),chEol); + if (fshowthr && + ((sens_cap & 0x80) == 0) && (sens_cap & 0x0C) != 0) { + uchar thresh[7]; + /* Thresholds, show them */ + /* Use readable bits to get & show thresholds */ + if (sdr[20] != 0) { + rc = GetSensorThresholds(sdr02->sens_num,&thresh[0]); + if (rc == 0) ShowThresh(1,thresh[0],&thresh[1],sdr); + } + } + if (fwrap) { /*include time and \n */ + time_t ltime; + time(<ime); + if (fsimple) + printf("%c %s",bdelim,ctime(<ime)); /*ctime has '\n' */ + else + printf("at %s",ctime(<ime)); /*ctime has '\n' */ + } + break; + case 0x03: /* Event-only sensor record, treat like Compact SDR */ + sdr02 = (SDR02REC *)sdr; + ioff = 17; + if (ioff > len) { + printf("Bad SDR %x Length %d. Please apply the correct FRU/SDR diskette\n", + sdr02->recid, len); + return; + } + if (!fsimple) + { + ilen = len - ioff; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[ioff],ilen); + for (i=ilen; i<16; i++) { idstr[i] = ' '; ilen++; } + idstr[ilen] = 0; /* stringify */ + sens_cap = sdr[11]; + memset(sens,0,sizeof(sens)); + if ((sdr02->sens_capab & 0x40) == 0) brearm = 'm'; /*manual rearm*/ + else brearm = 'a'; /*automatic rearm*/ + // rc = GetSensorReading(sdr02->sens_num,sdr02,sens); + /* EvtOnly SDRs do not support readings. + * GetSensorReading would return ccode=0xCB (not present), + * but this skips error msg */ + rc = 0xCB; + i = bitnum((ushort)sens[2]); + j = sens[2] | ((sens[3] & 0x7f) << 8); + printf("%s",tag); + printf("%04x SDR EvtO %02x %02x %02x %c %02x snum %02x %s = %04x %s\n", + sdr02->recid, sdr02->rectype, sdr02->reclen, + sdr02->sens_ownid, 'a', sdr[10], sdr02->sens_num, + idstr, j, sensor_dstatus[i]); + // sens[0], sens[1], sens[2], sens[3], sensor_dstatus[i] + } + break; + case 0x08: /* Entity Association record */ + sdr08 = (SDR08REC *)sdr; + if (!fsimple) + { + printf("%s",tag); + printf("%04x SDR EntA %02x %02x %02x %02x %02x: ", + sdr08->recid, sdr08->rectype, sdr08->reclen, + sdr08->contid, sdr08->continst, sdr08->flags); + for (i = 0; i < 8; i++) printf("%02x ",sdr08->edata[i]); + printf("\n"); + } + break; + case 0x09: /* Device-relative Entity Association record */ + sdr08 = (SDR08REC *)sdr; /*but SDR09 is 26 bytes*/ + if (!fsimple) + { + printf("%s",tag); + printf("%04x SDR DEnt %02x %02x %02x %02x %02x %02x %02x: ", + sdr08->recid, sdr08->rectype, sdr08->reclen, + sdr08->contid, sdr08->continst, sdr08->flags, + sdr08->edata[0], sdr08->edata[1]); + /*display 2 of 4 contained entity devices edata[2-10] */ + for (i = 2; i < 8; i++) printf("%02x ",sdr08->edata[i]); + printf("\n"); + } + break; + case 0x10: /* Generic Device Locator record */ + sdr11 = (SDR11REC *)sdr; + ioff = 16; + if (ioff > len) { + if (fdebug) printf("SDR %x bad length: type=%x, len=%d, ioff=%d\n", + sdr11->recid, sdr[3],len,ioff); + return; + } + if (!fsimple) + { + ilen = len - ioff; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[ioff],ilen); + idstr[ilen] = 0; /* stringify */ + printf("%s", tag); + if (fsimple) + printf("DevLocator record[%x]%c device %02x %c %s\n", + sdr11->recid, bdelim,sdr11->dev_slave_adr,bdelim,idstr); + else + printf("%04x SDR DLoc %02x %02x dev: %02x %02x %02x %02x %02x %02x %s\n", + sdr11->recid, sdr11->rectype, sdr11->reclen, + sdr11->dev_access_adr, sdr11->dev_slave_adr, + sdr11->access_lun, sdr[8], sdr[10], sdr[11], + idstr); + } + break; + case 0x11: /* FRU record */ + sdr11 = (SDR11REC *)sdr; + ioff = 16; + if (ioff > len) { + if (fdebug) printf("SDR %x bad length: type=%x len=%d ioff=%d\n", + sdr11->recid, sdr[3],len,ioff); + printf("Please apply the correct FRU/SDR diskette\n"); + return; + } + if (!fsimple) + { + ilen = len - ioff; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[ioff],ilen); + idstr[ilen] = 0; /* stringify */ + if (fdebug) printf("ilen=%d, istr0=%c, sizeof=%d, s0=%x\n", + ilen,idstr[0],sizeof(SDR11REC),sdr[ioff]); + printf("%s", tag); + if (fsimple) + printf("FRU record[%x]: device %02x : %s\n", + sdr11->recid, sdr11->dev_slave_adr,idstr); + else + printf("%04x SDR FRU %02x %02x dev: %02x %02x %02x %02x %02x %02x %s\n", + sdr11->recid, sdr11->rectype, sdr11->reclen, + sdr11->dev_access_adr, sdr11->dev_slave_adr /*fru_id*/, + sdr11->access_lun, sdr11->chan_num, + sdr11->entity_id, sdr11->entity_inst, + idstr); + } + break; + case 0x12: /* IPMB record */ + sdr12 = (SDR12REC *)sdr; + ioff = 16; + if (ioff > len) { + if (fdebug) printf("bad length: type=%x, len=%d, ioff=%d\n", + sdr[3],len,ioff); + printf("Please apply the correct FRU/SDR diskette\n"); + return; + } + if (!fsimple) + { + ilen = len - ioff; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[ioff],ilen); + idstr[ilen] = 0; /* stringify */ + if (fdebug) printf("ilen=%d, istr0=%c, sizeof=%d, s0=%x\n", + ilen,idstr[0],sizeof(SDR12REC),sdr[ioff]); + printf("%s", tag); + if (fsimple) + printf("IPMB record[%x]%c addr %02x %02x %c %s\n", + sdr12->recid, bdelim,sdr12->dev_slave_adr, + sdr12->chan_num,bdelim,idstr); + else + printf("%04x SDR IPMB %02x %02x dev: %02x %02x %02x %02x %02x %s\n", + sdr12->recid, sdr12->rectype, sdr12->reclen, + sdr12->dev_slave_adr, sdr12->chan_num, sdr12->dev_capab, + sdr12->entity_id, sdr12->entity_inst, + idstr); + } + break; + case 0x14: /* BMC Message Channel Info record */ + sdr14 = (SDR14REC *)sdr; + if(!fsimple){ + printf("%s", tag); + printf("%04x SDR BMsg %02x %02x: ", + sdr14->recid, sdr14->rectype, sdr14->reclen ); + for (i = 0; i < 8; i++) printf("%02x ",sdr14->mdata[i]); + printf("%s %s %02x\n",decode_itype(sdr14->mint), + decode_itype(sdr14->eint), sdr14->rsvd); + } + break; + case 0xc0: /* OEM SDR record (manuf_id 343. = Intel) */ + sdrc0 = (SDRc0REC *)sdr; + if(!fsimple) + { + vend = sdrc0->manuf_id[0] + (sdrc0->manuf_id[1] << 8) + + (sdrc0->manuf_id[2] << 16); + printf("%s",tag); + printf("%04x SDR OEM %02x %02x ", + sdrc0->recid, sdrc0->rectype, sdrc0->reclen); + show_oemsdr(vend,sdr); + } + break; + default: + sdrc0 = (SDRc0REC *)sdr; + /* also saw type = 0x08 & 0x14 on STL2s */ + if (!fsimple){ + printf("%s", tag); + printf("%04x SDR type=%02x ", sdrc0->recid, sdr[3]); + for (i = 0; i < len; i++) printf("%02x ",sdr[i]); + printf("\n"); + } + } + return; +} + +static int +ShowPowerOnHours(void) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar cc; + int rc = -1; + int i; + unsigned int hrs; + + if (fmBMC) return(0); + if (fsimple) return(0); + sresp = MAX_BUFFER_SIZE; + memset(resp,0,6); /* default response size is 5 */ + rc = ipmi_cmd_mc(GET_POWERON_HOURS, NULL, 0, resp, &sresp, &cc, fdebug); + if (rc == 0 && cc == 0) { + /* show the hours (32-bits) */ + hrs = resp[1] | (resp[2] << 8) | (resp[3] << 16) | (resp[4] << 24); + if (resp[0] == 0) /*avoid div-by-zero*/ i = 1; + else if (resp[0] == 60) /*normal*/ i = 1; + else { + i = 60 / resp[0]; + hrs = hrs / i; + } + printf(" SDR IPMI sensor: Power On Hours \t = %d hours\n", + hrs); + } + if (fdebug) { + printf("PowerOnHours (rc=%d cc=%x len=%d): ",rc,cc,sresp); + if (rc == 0) + for (i = 0; i < sresp; i++) printf("%02x ",resp[i]); + printf("\n"); + } + return(rc); +} + +int SaveThreshold(int id, int sensor_num, int sensor_lo, int sensor_hi, + uchar *thr_set) +{ + int rv = 0; + char lostr[20]; + char histr[20]; + FILE *fd; + + /* persist the thresholds by re-applying with ipmiutil sensor commands.*/ + if (thr_set != NULL) { + sprintf(lostr,"-u 0x%02x%02x%02x%02x%02x%02x", + sensor_thr[0], sensor_thr[1], sensor_thr[2], + sensor_thr[3], sensor_thr[4], sensor_thr[5]); + histr[0] = 0; /*empty string*/ + } else { + if (sensor_lo != 0xff) { + sprintf(lostr,"-l 0x%02x",sensor_lo); + } else lostr[0] = 0; + if (sensor_hi != 0xff) { + sprintf(histr,"-h 0x%02x",sensor_hi); + } else histr[0] = 0; + } + fd = fopen(savefile,"a+"); + if (fd == NULL) return(-1); + fprintf(fd, "ipmiutil sensor -i 0x%04x -n 0x%02x %s %s\n", id, sensor_num, + lostr,histr); + fclose(fd); + return(rv); +} + +#ifdef NOT_USED +#define PICMG_GET_ADDR_INFO 0x01 +static int get_picmg_addrinfo(uchar a1, uchar a2, uchar *addrdata) +{ + uchar idata[5]; + uchar rdata[16]; + int rlen; + ushort icmd; + uchar ilen, cc; + int rv; + + idata[0] = 0x00; + idata[1] = 0x00; + idata[2] = 0x03; + idata[3] = a1; /* 01 thru 0f */ + idata[4] = a2; /* 00, 01 thru 09 */ + ilen = 5; + rlen = sizeof(rdata); + icmd = PICMG_GET_ADDR_INFO | (NETFN_PICMG << 8); + rv = ipmi_cmd_mc(icmd, idata, ilen, rdata, &rlen, &cc, fdebug); + if (rv == 0 && cc != 0) rv = cc; + if (rv == 0) { + if (fdebug) { + printf("picmg_addr(%02x,%02x)",a1,a2); + dump_buf("picmg_addr",rdata,rlen,0); + } + memcpy(addrdata,rdata,rlen); + } + return(rv); +} +#endif + +#ifdef WIN32 +static int get_filesize(char *fileName, ulong *psize) +{ + int rv; + WIN32_FILE_ATTRIBUTE_DATA fileInfo; + + if (fileName == NULL) return -1; + if (psize == NULL) return -1; + rv = GetFileAttributesEx(fileName, GetFileExInfoStandard, (void*)&fileInfo); + if (!rv) return -1; + *psize = (long)fileInfo.nFileSizeLow; + return 0; +} +#endif + +int read_sdr_binfile(char *binfile, uchar **pbufret, int *buflen) +{ + uchar *pbuf = NULL; + FILE *fp; + int len; + int ret; +#ifdef WIN32 + { + ulong flen; + ret = get_filesize(binfile, &flen); + if (ret == 0) len = flen; + else { + ret = get_LastError(); + printf("Cannot get file size for %s, error %d\n",binfile,ret); + return(ret); + } + } +#endif + fp = fopen(binfile,"r"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + return(ret); + } +#ifndef WIN32 + { + struct stat st; + /* use fstat to get file size and allocate buffer */ + ret = fstat(fileno(fp), &st); + len = st.st_size; /*file size in bytes*/ + if (ret != 0) { + ret = get_LastError(); + printf("Cannot stat file %s, error %d\n",binfile,ret); + return(ret); + } + } +#endif + // len = nsdrs * SDR_SZ; /*estimate max size for n sdrs*/ + sz_sdrs = len; + pbuf = malloc(len); + if (fdebug) printf("restore: malloc(%d) pbuf=%p\n",len,pbuf); + if (pbuf == NULL) { + ret = -1; + fclose(fp); + return(ret); + } + /*ok, so proceed with restore*/ + ret = 0; + len = (int)fread(pbuf, 1, sz_sdrs, fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d reading file %s\n",ret,binfile); + sz_sdrs = 0; /*for safety*/ + } + fclose(fp); + if (fdebug) { + printf("SDR buffer from file (len=%d,sz=%d)\n",len,sz_sdrs); + dump_buf("SDR buffer",pbuf,len,1); + } + *pbufret = pbuf; + *buflen = len; + return(ret); +} + +#ifdef ALONE +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#else +/* METACOMMAND or libipmiutil */ +int i_sensor(int argc, char **argv) +#endif +{ + int ret, rv; + int c; + int recid, recnext; + uchar sdrdata[MAX_BUFFER_SIZE]; + uchar devrec[16]; + int sz, i, j; + int fsetfound = 0; + int iloop; + int ipass, npass; + uchar *pset; + char *p; + char *s1; + + printf("%s: version %s\n",progname,progver); + + while ( (c = getopt( argc, argv,"a:bcd:ef:g:h:i:j:l:m:n:opqrstu:vwxT:V:J:L:EYF:P:N:R:U:Z:?")) != EOF ) + switch(c) { + case 'a': /* reArm sensor number N */ + if (strncmp(optarg,"0x",2) == 0) frearm = htoi(&optarg[2]); + else frearm = htoi(optarg); /*was atoi()*/ + break; + case 'c': fsimple = 1; break; /* Canonical/simple output*/ + case 'd': fdump = 1; /* Dump SDRs to a file*/ + binfile = optarg; break; + case 'b': fchild = 1; break; /* Bladed, so get child SDRs */ + case 'e': fchild = 1; break; /* Extra bladed child SDRs */ + case 'f': frestore = 1; /* Restore SDRs from a file*/ + binfile = optarg; break; + case 's': fsimple = 1; break; /* Simple/canonical output */ + /*fcanonical==fsimple*/ + case 'g': + rv = get_group_id(optarg); + if (rv < 0) { + printf("Unrecognized sensor type group (%s)\n",optarg); + ret = ERR_BAD_PARAM; + goto do_exit; + } else fshowgrp = rv; + if (fdebug) printf("num sensor type groups = %d\n",fshowgrp); + break; + case 'i': + fshowidx = 1; + get_idx_range(optarg); + break; + case 'j': fjumpstart = 1; /* Load SDR cache from a file*/ + binfile = optarg; break; + case 't': fshowthr = 1; break; + case 'v': fshowthr = 1; sens_verbose = 1; break; + case 'p': fsavethresh = 1; break; + case 'q': fshowthr = 2; fwrap = 1; break; + case 'r': frawsdr = 1; break; + case 'm': /* specific MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + printf("set MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'o': + fgetmem = 1; + break; + case 'n': + if (strncmp(optarg,"0x",2) == 0) i = htoi(&optarg[2]); + else i = htoi(optarg); /*was atoi()*/ + sensor_num = (uchar)i; + printf("sensor_num = 0x%x\n",sensor_num); + break; + case 'h': /* highest threshold */ + if (strncmp(optarg,"0x",2) == 0) { + i = htoi(&optarg[2]); + sensor_hi = (uchar)i; + fsetthresh = 1; + } else { + sensor_hi_f = atof(optarg); + fsetthresh = 2; /*indicates float conversion*/ + } + break; + case 'l': /* lowest threshold */ + if (strncmp(optarg,"0x",2) == 0) { + i = htoi(&optarg[2]); + sensor_lo = (uchar)i; + fsetthresh = 1; + } else { + sensor_lo_f = atof(optarg); + fsetthresh = 2; /*indicates float conversion*/ + } + break; + case 'u': /* specify unique thresholds in hex or float */ + /* raw hex format: 0xLNLCLUHNHCHU, all 6 required */ + if (strncmp(optarg,"0x",2) == 0) { /*raw hex thresholds*/ + sensor_thr[0] = htoi(&optarg[2]); /*lo noncrit*/ + sensor_thr[1] = htoi(&optarg[4]); /*lo crit*/ + sensor_thr[2] = htoi(&optarg[6]); /*lo unrec*/ + sensor_thr[3] = htoi(&optarg[8]); /*hi noncrit*/ + sensor_thr[4] = htoi(&optarg[10]); /*hi crit*/ + sensor_thr[5] = htoi(&optarg[12]); /*hi unrec*/ + /* validate sensor threshold ordering */ + rv = validate_thresholds(&sensor_thr[0],0,NULL); + if (rv == 0) { + sensor_lo = sensor_thr[0]; + sensor_hi = sensor_thr[3]; + fsetthresh = 3; /*indicates unique raw thresholds */ + } else { + ret = ERR_BAD_PARAM; + goto do_exit; + } + } else { + /* assume float input thresholds, with ':' separator*/ + /* format LN:LC:LU:HN:HC:HU */ + sz = strlen_(optarg); + p = &optarg[0]; + for (i = 0; i < 6; i++) sensor_thrf[i] = THR_EMPTY; + j = 0; + for (i = 0; i <= sz; i++) { + if (j >= 6) break; + switch(optarg[i]) { + case ':': + case '\n': + case '\0': + optarg[i] = 0; + if (p[0] == 0) sensor_thrf[j] = THR_EMPTY; + else sensor_thrf[j] = atof(p); + if (i+1 < sz) p = &optarg[i+1]; + j++; + break; + default: + break; + } + } + /* validate sensor threshold ordering later */ + // rv = validate_thresholds(&sensor_thrf[0],1,NULL); + // if (rv == 0) { + sensor_lo_f = sensor_thrf[0]; + sensor_hi_f = sensor_thrf[3]; + fsetthresh = 4; /*indicates unique float thresholds */ + // } else { + // ret = ERR_BAD_PARAM; + // goto do_exit; + // } + } /*end-else -u float thresholds*/ + break; + case 'w': fwrap = 1; break; + case 'x': fdebug = 1; break; + case 'L': /* Loop */ + nloops = atoi(optarg); + fdoloop = 1; + break; + case 'V': /* priv level */ + fprivset = 1; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: /*usage*/ + printf("Usage: %s [-abcdefghijlmnprstuvwxL -NUPREFTVY]\n",progname); + printf("where -x shows eXtra debug messages\n"); + printf(" -a snum reArms the sensor (snum) for events\n"); + printf(" -b show Bladed child MCs for PICMG (same as -e)\n"); + printf(" -c displays a simpler, Canonical output fmt\n"); + printf(" -d file Dump SDRs to a binary file\n"); + printf(" -e show Every bladed child MC for PICMG\n"); + // printf(" -f file Restore SDRs from a binary dump file\n"); + printf(" -g fan show only this sensor type group\n"); + printf(" -h tval specifies the Highest threshold to set\n"); + printf(" -i id only show these sensor ids\n"); + printf(" -j file Jump-start SDR cache from a binary file\n"); + printf(" -l tval specifies the Lowest threshold to set\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -n snum specifies the sensor Number to set hi/lo\n"); + printf(" -o output memory DIMM information\n"); + printf(" -p persist the threshold being set\n"); + printf(" -q shows threshold values in d:d:d format\n"); + printf(" -r show Raw SDR bytes\n"); + printf(" -s displays a Simpler output format\n"); + printf(" -t shows Threshold values in text format\n"); + printf(" -u thr set Unique threshold values (e.g. 3:2:1:48:49:50)\n"); + printf(" -v Verbose: thresholds, max/min, hysteresis\n"); + printf(" -w Wrap thresholds on sensor line\n"); + printf(" -L n Loop n times\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + if (fjumpstart && fchild) { + printf("Cannot use -j jumpstart cache with -c child SDRs\n"); + ret = ERR_BAD_PARAM; + goto do_exit; + } + fremote = is_remote(); +#ifndef WIN32 + if (fremote == 0) { + /* only run this as superuser for accessing IPMI devices. */ + i = geteuid(); + if (i > 1) { + printf("Not superuser (%d)\n", i); + ret = ERR_NOT_ALLOWED; + goto do_exit; + } + } +#endif + if (fremote) { + if (!fprivset) { + /* on many systems, getting the SDR Reservation ID requires admin */ + /* if ((fsetthresh != 0) || (frearm != 0)) also require admin */ + parse_lan_options('V',"4",0); + } + } + + ret = ipmi_getdeviceid(devrec,sizeof(devrec),fdebug); + if (ret == 0) { + uchar ipmi_maj; + uchar ipmi_min; + char *pstr; + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + if ((devrec[1] & 0x80) == 0x80) fdevsdrs = 1; + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + prod_id = devrec[9] + (devrec[10] << 8); + if (vend_id == VENDOR_NSC) { /*NSC mBMC*/ + pstr = "mBMC"; + fmBMC = 1; + fdevsdrs = 0; + } else if (vend_id == VENDOR_INTEL) { /*Intel BMC*/ + /*Intel Sahalee BMC */ + pstr = "BMC"; + fmBMC = 0; + if (is_romley(vend_id,prod_id)) fRomley = 1; + if (prod_id == 0x003E || fRomley) /*Urbanna NSN2U,CG2100*/ + set_max_kcs_loops(URNLOOPS); /*longer KCS timeout*/ + } else { /* Other products */ + pstr = "BMC"; + fmBMC = 0; + if (vend_id == VENDOR_NEC) fdevsdrs = 0; + } + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + // "-- %s version %x.%x, IPMI version %d.%d \n", pstr, + } else { + goto do_exit; + } + + ret = ipmi_getpicmg( devrec, sizeof(devrec),fdebug); + if (ret == 0) fpicmg = 1; + /*if not PICMG, some vendors override to SDR Rep*/ + fdevsdrs = use_devsdrs(fpicmg); + if (fdevsdrs) printf("supports device sdrs\n"); + npass = 1; + if (g_sa != 0) { + /* target a specific MC via IPMB (usu a picmg blade) */ + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + fchild = 0; /* no children, only the specified address */ + } else { +#ifdef PICMG_CHILD + /* fchild set above if -b is specified to get Blade child SDRs */ + /* npass = 2 will get both SdrRep & DevSdr passes on CMM */ + if (fpicmg && fdevsdrs) { + npass = 2; + g_addrtype = ADDR_IPMB; + } +#endif + g_sa = BMC_SA; + } + + if (fgetmem) { + if (fremote) printf("Cannot get memory DIMM information remotely.\n"); + else { + int msz; + char desc[80]; + char szstr[25]; + ret = -1; + for (j = 0; j < 1; j++) { + for (i = 0; i < 16; i++) { + rv = get_MemDesc(j, i, desc,&msz); + if (rv == 0) { + if (msz == 0) strcpy(szstr,"not present"); + else if (msz & 0x8000) + sprintf(szstr,"size=%dKB",(msz & 0x7FFF)); + else sprintf(szstr,"size=%dMB",msz); + printf("Memory Device (%d,%d): %s : %s\n", + j,i,desc,szstr); + ret = 0; + } + } + } + } /*end-else*/ + goto do_exit; + } + + if (fdump) { + uchar *pbuf = NULL; + FILE *fp; + int len; + ret = get_sdr_cache(&pbuf); + if (ret == 0) { + fp = fopen(binfile,"w"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + } else { + printf("Writing SDR size %d to %s ...\n",sz_sdrs,binfile); + len = (int)fwrite(pbuf, 1, sz_sdrs, fp); + fclose(fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d writing file %s\n",ret,binfile); + } else ret = 0; + } + free_sdr_cache(pbuf); + } + goto do_exit; + } /*endif fdump*/ + + if (frestore) { + uchar sdr[MAX_BUFFER_SIZE]; + ushort id; + int slen; + uchar *pbuf = NULL; + + ret = read_sdr_binfile(binfile,&pbuf,&slen); + if (ret == 0) { /*successful, so write SDRs */ + nsdrs = find_nsdrs(pbuf); + printf("Ready to restore %d SDRs\n",nsdrs); + set_reserve(1); + ret = sdr_clear_repo(fdevsdrs); + if (ret != 0) { + printf("SDR Clear Repository error %d\n",ret); + goto do_exit; + } + id = 0; + while(find_sdr_next(sdr,pbuf,id) == 0) { + id = sdr[0] + (sdr[1] << 8); + if (fdebug) printf("adding SDR[%x]\n",id); + set_reserve(1); + ret = sdr_add_record(sdr,fdevsdrs); + if (ret != 0) { + printf("SDR[%x] add error %d\n",id,ret); + break; + } + } /*end while sdr*/ + } + if (ret == 0) printf("Restored %d SDRs successfully.\n",nsdrs); + free_sdr_cache(pbuf); /* does nothing if (pbuf == NULL) */ + goto do_exit; + } /*endif frestore*/ + + if (fjumpstart) { + uchar *pbuf = NULL; + int slen; + ret = read_sdr_binfile(binfile,&pbuf,&slen); + if (ret != 0) fjumpstart = 0; /* use normal method if error*/ + else { /* set this as the SDR cache */ + psdrcache = pbuf; + sz_sdrs = slen; + nsdrs = find_nsdrs(pbuf); + if (fdebug) printf("jumpstart cache: nsdrs=%d size=%d\n",nsdrs,slen); + } + } /*endif fjumpstart*/ + + for (ipass = 0; ipass < npass; ipass++) + { + if (fjumpstart) ; /*already got this above*/ + else { + ret = GetSDRRepositoryInfo(&j,&fdevsdrs); + if (fdebug) printf("GetSDRRepositoryInfo: ret=%x nSDRs=%d\n",ret,j); + if (ret == 0 && j == 0) { + printf("SDR Repository is empty\n"); + goto do_exit; + } + nsdrs = j; + } + + /* show header for SDR records */ + if (fsimple) + printf(" ID | SDRType | Type |SNum| Name |Status| Reading\n"); + else + printf("_ID_ SDR_Type_xx ET Own Typ S_Num Sens_Description Hex & Interp Reading\n"); + + if (fwrap) chEol = ' '; + if (!fdoloop) nloops = 1; + for (iloop = 0; iloop < nloops; iloop++) + { + if (fshowidx) recid = sensor_idx1; + else recid = 0; + while (recid != 0xffff) + { + if (fjumpstart) { + ret = find_sdr_next(sdrdata,psdrcache,recid); + if (ret != 0) { ret = 0; break; } /*end of sdrs*/ + recnext = sdrdata[0] + (sdrdata[1] << 8); /*same as recid*/ + sz = sdrdata[4] + 5; + } else { + ret = GetSDR(recid,&recnext,sdrdata,sizeof(sdrdata),&sz); + if (fdebug) + printf("GetSDR[%04x]: ret = %x, next=%x\n",recid,ret,recnext); + if (ret != 0) { + if (ret > 0) { /* ret is a completion code error */ + printf("%04x GetSDR error 0x%02x %s, rlen=%d\n",recid,ret, + decode_cc((ushort)0,(uchar)ret),sz); + if (ret == 0xC5) { /* lost Reservation ID, retry */ + /* This means that some other IPMI software has + * requested a Reservation before we finished, so + * we need to refresh the Reservation ID * retry. */ + fDoReserve = 1; /* get a new SDR Reservation ID */ + ret = GetSDR(recid,&recnext,sdrdata,sizeof(sdrdata),&sz); + if (fdebug) + printf("GetSDR[%04x]: ret = %x, next=%x\n",recid,ret, + recnext); + } + } else printf("%04x GetSDR error %d, rlen = %d\n", recid,ret,sz); + if (sz < MIN_SDR_SZ) { /* don't have recnext, so abort */ + break; + } /* else fall through & continue */ + } + } /*end-else*/ + if (ret == 0) { /* (ret == 0) OK, got full SDR */ + if (fdebug) { + dump_buf("got SDR",sdrdata,sz,0); + } + if (sz < MIN_SDR_SZ) goto NextSdr; + /* if recid == 0, get real record id */ + if (recid == 0) recid = sdrdata[0] + (sdrdata[1] << 8); + if (fshowgrp > 0) { + for (i = 0; i < fshowgrp; i++) { + uchar styp; + if (sdrdata[3] == 0x03) styp = sdrdata[10]; /*EvtOnly*/ + else styp = sdrdata[12]; + if (fdebug) printf("sdrt=%02x styp=%02x sgrp[%d]=%02x\n", + sdrdata[3],styp,i,sensor_grps[i]); + if (sdrdata[3] == 0xc0) continue; /*skip OEM SDRs*/ + if (styp == sensor_grps[i]) break; + } + if (i >= fshowgrp) goto NextSdr; + } + + if ((sensor_num == INIT_SNUM) || (sdrdata[7] == sensor_num) + || fsetthresh) { + /* if -n not set or if -n matches, parse and show the SDR */ + ShowSDR("",sdrdata); + } /* else filter SDRs if not matching -n sensor_num */ + +#ifdef PICMG_CHILD + /* + * Special logic for blade child MCs in PICMG ATCA systems + * if fchild, try all child MCs within the chassis. + * SDR type 12 capabilities bits (sdrdata[8]): + * 80 = Chassis Device + * 40 = Bridge + * 20 = IPMB Event Generator + * 10 = IPMB Event Receiver + * 08 = FRU Device + * 04 = SEL Device + * 02 = SDR Repository Device + * 01 = Sensor Device + * But all child MCs use Device SDRs anyway. + */ + if (fpicmg && fchild && (sdrdata[3] == 0x12)) { /* PICMG MC DLR */ + int _recid, _recnext, _sz; + uchar _sdrdata[MAX_SDR_SIZE]; + int devsdrs_save; + uchar cc; + + /* save the BMC globals, use IPMB MC */ + devsdrs_save = fdevsdrs; + fdevsdrs = 1; /* use Device SDRs for the children*/ + if (fdebug) + printf(" --- IPMB MC (sa=%02x cap=%02x id=%02x devsdrs=%d):\n", + sdrdata[5],sdrdata[8],sdrdata[12],fdevsdrs); + fDoReserve = 1; /* get a new SDR Reservation ID */ + ipmi_set_mc(PICMG_SLAVE_BUS,sdrdata[5],sdrdata[6],g_addrtype); + + _sz = 16; + ret = ipmi_cmd_mc(GET_DEVICE_ID,NULL,0,_sdrdata,&_sz,&cc,fdebug); + if (ret == 0 && cc == 0) { + /* Get the SDRs from the IPMB MC */ + _recid = 0; + while (_recid != 0xffff) + { + ret = GetSDR(_recid,&_recnext,_sdrdata,sizeof(_sdrdata),&_sz); + if (ret != 0) { + printf("%04x GetSDR error %d, rlen = %d\n",_recid,ret,_sz); + break; + } + else if (_sz >= MIN_SDR_SZ) + ShowSDR(" ",_sdrdata); + + if (_recnext == _recid) _recid = 0xffff; + else _recid = _recnext; + } /*end while*/ + } /*endif ret==0*/ + + /* restore BMC globals */ + fdevsdrs = devsdrs_save; + ipmi_restore_mc(); + fDoReserve = 1; /* get a new SDR Reservation ID */ + } /*endif fpicmg && fchild*/ +#endif + + if (fdebug) printf("fsetthresh=%d snum=%02x(%02x) sa=%02x(%02x)\n", + fsetthresh,sdrdata[7],sensor_num,sdrdata[5],g_sa); + if (fsetthresh && (sdrdata[7] == sensor_num) + && (sdrdata[5] == g_sa)) /*g_sa usu is BMC_SA*/ + { + /* setting threshold, compute threshold raw values */ + if (fsetthresh == 2) { /*set from float*/ + if (fdebug) + printf("lof=%.2f hif=%.2f\n", sensor_lo_f,sensor_hi_f); + if (sensor_lo_f != 0) + sensor_lo = FloatToRaw(sensor_lo_f,sdrdata,0); + if (sensor_hi_f != 0) + sensor_hi = FloatToRaw(sensor_hi_f,sdrdata,0); + } else if (fsetthresh == 1) { /*raw thresholds*/ + if (sensor_hi != 0xff) + sensor_hi_f = RawToFloat(sensor_hi,sdrdata); + if (sensor_lo != 0xff) + sensor_lo_f = RawToFloat(sensor_lo,sdrdata); + } else if (fsetthresh == 3) { /*unique raw thresholds*/ + if (sensor_hi != 0xff) + sensor_hi_f = RawToFloat(sensor_hi,sdrdata); + if (sensor_lo != 0xff) + sensor_lo_f = RawToFloat(sensor_lo,sdrdata); + } else if (fsetthresh == 4) { /*set unique from float*/ + i = fill_thresholds(&sensor_thrf[0], sdrdata); + /* if (i > 0) ; * filled in some thresholds */ + { /* always set lo/hi if any are non-zero */ + for (j = 0; j < 3; j++) { + if (sensor_thrf[j] != 0) { + sensor_lo_f = sensor_thrf[j]; break; } + } + for (j = 3; j < 6; j++) { + if (sensor_thrf[j] != 0) { + sensor_hi_f = sensor_thrf[j]; break; } + } + } + if (fdebug) + printf("lof=%.2f hif=%.2f\n", sensor_lo_f,sensor_hi_f); + /* convert thrf (float) to thr (raw) */ + if (sensor_lo_f != 0) { + sensor_lo = FloatToRaw(sensor_lo_f,sdrdata,0); + sensor_thr[0] = FloatToRaw(sensor_thrf[0],sdrdata,0); + sensor_thr[1] = FloatToRaw(sensor_thrf[1],sdrdata,0); + sensor_thr[2] = FloatToRaw(sensor_thrf[2],sdrdata,0); + } + if (sensor_hi_f != 0) { + sensor_hi = FloatToRaw(sensor_hi_f,sdrdata,0); + sensor_thr[3] = FloatToRaw(sensor_thrf[3],sdrdata,0); + sensor_thr[4] = FloatToRaw(sensor_thrf[4],sdrdata,0); + sensor_thr[5] = FloatToRaw(sensor_thrf[5],sdrdata,0); + } + /* validate threshold ordering */ + if (validate_thresholds(sensor_thrf,1,sdrdata) != 0) { + ret = ERR_BAD_PARAM; + goto do_exit; + } + } + { + printf("\tSetting SDR %04x sensor %02x to lo=%02x hi=%02x\n", + recid,sensor_num,sensor_lo,sensor_hi); + if (recid == 0) fsetfound = 1; + else fsetfound = recid; + } + } /*endif fsetthresh */ + } /*endif ok, got full SDR */ + +NextSdr: + if (fshowidx) { + /* if we have already read the last in the range, done. */ + if (recid >= sensor_idxN) break; // recnext = 0xffff; // break; + } + if (fjumpstart) recid = recnext; + else { + if (recnext == recid) recid = 0xffff; /*break;*/ + else recid = recnext; + } + } /*end while recid*/ + if (fdoloop && (nloops > 1)) { + printf("\n"); /* output an empty separator line */ + os_usleep(1,0); /*delay 1 sec between loops*/ + } + } /*end for nloops*/ + + if (npass > 1) { /* npass==2 for PICMG */ + /* Switch fdevsdrs from Device to Repository */ + if (fdevsdrs == 0) fdevsdrs = 1; + else fdevsdrs = 0; + fDoReserve = 1; /* get a new SDR Reservation ID */ + } + } /*end for npass*/ + + if ((fshowidx == 0) && (fshowgrp == 0)) { + /* use local rv, errors are ignored for POH */ + rv = ShowPowerOnHours(); + } + + if (frearm != 0) { + ret = RearmSensor((uchar)frearm); + printf("RearmSensor(0x%02x) ret = %d\n",frearm,ret); + } + + if (fsetthresh != 0) { + uchar tdata[7]; + if (fsetfound == 0) { + printf("Did not find sensor number %02x.\nPlease enter the sensor number parameter in hex, as it is displayed above.\n",sensor_num); + } + ret = GetSensorThresholds(sensor_num,tdata); + if (ret != 0) goto do_exit; +#ifdef TEST + printf("thresh(%02x): %02x %02x %02x %02x %02x %02x %02x %02x\n", + sensor_num, sensor_num, tdata[0], tdata[1], tdata[2], + tdata[3], tdata[4], tdata[5], tdata[6]); + printf(" set(%02x): %02x %02x \n", + sensor_num,sensor_lo,sensor_hi); +#endif + if (fsetthresh == 3 || fsetthresh == 4) { + /* apply unique sensor thresholds */ + pset = &sensor_thr[0]; + } else pset = NULL; /* use just hi/lo */ + ret = SetSensorThresholds(sensor_num,sensor_hi,sensor_lo,tdata,pset); + printf("SetSensorThreshold[%02x] to lo=%02x(%4.3f) hi=%02x(%4.3f), ret = %d\n", + sensor_num,sensor_lo,sensor_lo_f,sensor_hi,sensor_hi_f,ret); + if (fsavethresh && ret == 0) { + recid = fsetfound; + rv = SaveThreshold(recid,sensor_num,sensor_lo,sensor_hi,pset); + if (rv == 0) + printf("Saved thresholds for sensor %02x\n",sensor_num); + } + fsetthresh = 0; /*only set threshold once*/ + } + +do_exit: + if (fjumpstart) free_sdr_cache(psdrcache); /* does nothing if ==NULL*/ + /* show_outcome(progname,ret); *handled in ipmiutil.c*/ + ipmi_close_(); + return(ret); +} + +/* end isensor.c */ diff --git a/util/isensor.h b/util/isensor.h new file mode 100644 index 0000000..8927b6e --- /dev/null +++ b/util/isensor.h @@ -0,0 +1,176 @@ +/* + * isensor.h + * common routines from isensor.c + */ +#define SDR_SZ 80 /*max SDR size*/ + +typedef struct { + ushort recid; + uchar sdrver; /*usu. 0x51 = v1.5*/ + uchar rectype; /* 01, 02, 11, 12, c0 */ + uchar reclen; + uchar sens_ownid; + uchar sens_ownlun; + uchar sens_num; /*sdr[7]*/ + uchar entity_id; + uchar entity_inst; + uchar sens_init; + uchar sens_capab; + uchar sens_type; + uchar ev_type; + uchar data1[6]; /*masks*/ + uchar sens_units; /*sdr[20]*/ + uchar sens_base; + uchar sens_mod; + uchar linear; + uchar m; + uchar m_t; + uchar b; + uchar b_a; + uchar a_ax; + uchar rx_bx; + uchar flags; + uchar nom_reading; + uchar norm_max; + uchar norm_min; + uchar sens_max_reading; + uchar sens_min_reading; + uchar unr_threshold; + uchar ucr_threshold; + uchar unc_threshold; + uchar lnr_threshold; + uchar lcr_threshold; + uchar lnc_threshold; + uchar pos_hysteresis; + uchar neg_hysteresis; + uchar data3[3]; + uchar id_strlen; + uchar id_string[16]; + } SDR01REC; + +typedef struct { + ushort recid; + uchar sdrver; /*usu. 0x51 = v1.5*/ + uchar rectype; /* 01, 02, 11, 12, c0 */ + uchar reclen; + uchar sens_ownid; + uchar sens_ownlun; + uchar sens_num; + uchar entity_id; + uchar entity_inst; + uchar sens_init; + uchar sens_capab; + uchar sens_type; + uchar ev_type; + uchar data1[6]; + uchar sens_units; + uchar sens_base; + uchar sens_mod; + uchar shar_cnt; + uchar shar_off; + uchar pos_hysteresis; + uchar neg_hysteresis; + uchar data2[4]; + uchar id_strlen; + uchar id_string[16]; + } SDR02REC; + +typedef struct { /* 0x08 = Entity Association record */ + ushort recid; + uchar sdrver; /*usu. 0x51 = v1.5*/ + uchar rectype; /* 01, 02, 11, 12, c0 */ + uchar reclen; + uchar contid; + uchar continst; + uchar flags; + uchar edata[8]; + } SDR08REC; + +typedef struct { /*0x14 = BMC Message Channel Info record */ + ushort recid; + uchar sdrver; /*usu. 0x51 = v1.5*/ + uchar rectype; /* 01, 02, 11, 12, c0 */ + uchar reclen; + uchar mdata[8]; + uchar mint; + uchar eint; + uchar rsvd; + } SDR14REC; + +typedef struct { /*0x11 = FRU Locator*/ + ushort recid; + uchar sdrver; /*usu. 0x51 = v1.5*/ + uchar rectype; /* 01, 02, 11, 12, c0 */ + uchar reclen; + uchar dev_access_adr; /*usu sa*/ + uchar dev_slave_adr; /*usu fru_id*/ + uchar access_lun; + uchar chan_num; + uchar reserved; + uchar dev_type; + uchar dev_typemod; + uchar entity_id; + uchar entity_inst; + uchar oem; + uchar id_strlen; + uchar id_string[16]; + } SDR11REC; + +typedef struct { /*0x12 = IPMB Locator, for MCs*/ + ushort recid; + uchar sdrver; /*usu. 0x51 = v1.5*/ + uchar rectype; /* 01, 02, 11, 12, c0 */ + uchar reclen; + uchar dev_slave_adr; + uchar chan_num; + uchar power_state; + uchar dev_capab; + uchar reserved[3]; + uchar entity_id; + uchar entity_inst; + uchar oem; + uchar id_strlen; + uchar id_string[16]; + } SDR12REC; + +typedef struct { /*0xc0 = OEM Record*/ + ushort recid; + uchar sdrver; /*usu. 0x51 = v1.5*/ + uchar rectype; /* 01, 02, 11, 12, c0 */ + uchar reclen; + uchar manuf_id[3]; /*Intel = 0x57,0x01,0x00 = 343.*/ + uchar oem_data[60]; /* (reclen-3 bytes)*/ + } SDRc0REC; + +int get_sdr_cache(uchar **pcache); +void free_sdr_cache(uchar *pcache); +int get_sdr_file(char *sdrfile, uchar **sdrlist); +int find_nsdrs(uchar *pcache); +int find_sdr_next(uchar *psdr, uchar *pcache, ushort id); +int find_sdr_by_snum(uchar *psdr, uchar *pcache, uchar snum, uchar sa); +int find_sdr_by_tag(uchar *psdr, uchar *pcache, char *tag, uchar dbg); +int find_sdr_by_id(uchar *psdr, uchar *pcache, ushort id); + +void ShowSDR(char *tag, uchar *sdr); +int GetSDRRepositoryInfo(int *nret, int *fdev); +int GetSensorThresholds(uchar sens_num, uchar *data); +int GetSensorReading(uchar sens_num, void *psdr, uchar *sens_data); +double RawToFloat(uchar raw, uchar *psdr); +char *decode_entity_id(int id); +char *get_unit_type(int iunits, int ibase, int imod, int fshort); + +/* + * decode_comp_reading + * + * Decodes the readings from compact SDR sensors. + * Use sensor_dstatus array for sensor reading types and meaning strings. + * Refer to IPMI Table 36-1 and 36-2 for this. + * Note that decoding should be based on sensor type and ev_type only, + * except for end cases. + * + * reading1 = sens_reading[2], reading2 = sens_reading[3] + */ +int decode_comp_reading(uchar type, uchar evtype, uchar num, + uchar reading1, uchar reading2); + +/* end isensor.h */ diff --git a/util/iserial.c b/util/iserial.c new file mode 100644 index 0000000..ce00ed3 --- /dev/null +++ b/util/iserial.c @@ -0,0 +1,1592 @@ +/* + * tmconfig.c + * + * This tool sets up the serial EMP port for the Terminal Mode settings. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2002-2006 Intel Corporation. + * + * Options: + * -b Set serial port up for Basic Mode (fBMode) + * -B Set baud rate for serial port + * -d Disable serial port for IPMI use + * -f Flow Control setting, default=1 (RTS/CTS) + * -r Read-only, view serial port parameters + * -s configure serial port for Shared Basic Mode & Remote Console + * -t Configure serial port for shared Terminal Mode (TMode) & Console + * -u username Set username for EMP TMode login (default is null user 1) + * -p password Set password for EMP TMode login + * -l show LAN parameters also + * -m0 switch MUX to Normal baseboard operation + * -m1 switch MUX to BMC operation (BMode or TMode) + * -x eXtra debug messages + * -f special boot Flags + * + * Change Log: + * 02/12/02 Andy Cress - created from pefconfig.c + * 03/08/02 Andy Cress - added GET_USER_ACCESS to serial parameters shown + * 03/11/02 Andy Cress - changed MUX param 8 value for -b + * 03/13/02 Andy Cress - changed default behavior to be like -r, + * added -c option to configure TMode + * 03/15/02 Andy Cress v1.3 added bootflags + * 04/12/02 Andy Cress v1.4 use always avail instead of shared mode + * also, don't do boot flags if not specified + * 07/02/02 Andy Cress v1.5 add more Usage, add -d option. + * 07/25/02 Andy Cress v1.6 fixed passwd offset for fSetTMode (-c) + * 08/02/02 Andy Cress v1.7 moved common ipmi_cmd() code to ipmicmd.c + * 12/09/02 Andy Cress v1.8 make sure -d sets user1 to admin again, + * combine -n/-t into -m for MUX, + * fix -c to drop thru to SetTMode logic, + * param 8 values changed, + * Dont SetUser for TMode unless -u, + * use DCD & RTS/CTS for TMode. + * 12/12/02 Andy Cress v1.9 change access from 0x23 to 0x2b + * 01/23/03 Andy Cress v1.10 decode UserAccess meanings + * 01/29/03 Andy Cress v1.11 added MV OpenIPMI support + * 07/31/03 Andy Cress v1.12 added -F to try force it + * 09/10/03 Andy Cress v1.13 isolate ser_ch, add -n option to specify chan#, + * abort if no serial channels + * 05/05/04 Andy Cress v1.14 call ipmi_close before exit, added WIN32 + * 06/29/04 Andy Cress v1.15 added fSetPsw even if not fSetUser3 + * 11/01/04 Andy Cress v1.16 add -N / -R for remote nodes + * 11/23/04 Andy Cress v1.17 recompile with ipmignu.c changes + * 01/31/05 Andy Cress v1.18 allow IPMI 2.0 versions + * 03/18/05 Andy Cress v1.19 fix for -n, show the ser_ch it is using. + * 05/19/05 Andy Cress v1.20 show 4 users if IPMI20 + * 06/13/05 Andy Cress v1.21 show multiple alert destinations + * 08/10/05 Andy Cress v1.22 truncate extra string chars + * 05/02/06 Andy Cress v1.23 add -B option for baud rate + * 09/12/06 Andy Cress v1.26 use authmask to set Serial Param(2) + * 09/29/06 Andy Cress v1.27 add -q for user number, add -f for Flow Control, + * adjust Mode if known, clear SerialParam(3) if -d, + * added ShowAccess if -r. + */ +/*M* +Copyright (c) 2002-2006, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#include <string.h> +#endif +#include "ipmicmd.h" + +#define SELprintf printf +#define SER_CH 4 +#define LAN_CH 1 +#define MAXCHAN 16 +#define PSW_LEN 16 /*see also PSW_MAX=20 in ipmicmd.h*/ +/* Note: The optional IPMI 2.0 20-byte passwords are not supported here, + * due to back-compatibility issues. */ + +/* serial channel access values */ +#define ALWAYS_AUTH 0x22 +#define ALWAYS_NOAUTH 0x2A +#define SHARED_AUTH 0x23 +#define SHARED_NOAUTH 0x2B + +typedef struct +{ + unsigned short record_id; + uchar record_type; + int timestamp; + unsigned short generator_id; + uchar evm_rev; //event message revision + uchar sensor_type; + uchar sensor_number; + uchar event_trigger; + uchar event_data1; + uchar event_data2; + uchar event_data3; +} SEL_RECORD; + +typedef struct +{ /* See IPMI Table 19-3 */ + uchar data[30]; +} SER_RECORD; + +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "iserial"; +static int vend_id = 0; +static int prod_id = 0; +static char fdebug = 0; +static char fpicmg = 0; +static char freadonly = 0; +static char fdoanyway = 0; +static char fSetUser3 = 0; /* =1 set User3->admin and User1->user access*/ +static char fSetPsw = 0; /* =1 set Password to user parameter */ +static char fSetTMode = 0; /* =1 configure for TMode */ +static char fBasebdOn = 0; /* =1 only do MUX switch BMC -> Baseboard */ +static char fTModeOn = 0; /* =1 only do MUX switch Baseboard -> BMC */ +static char fBMode = 0; /* =1 do Basic mode config stuff */ +static char fShared = 0; /* =1 shared Basic mode & Remote console */ +static char fDisable = 0; /* =1 to disable serial port IPMI */ +static char fKnownMode = 0; /* =0 if unknown, =1 if TMode, =2 if BMode */ +static char fgetlan = 0; +static char fnotshared = 0; /* =1 if IPMI serial shared with OS/BIOS*/ +static char fconsoleonly = 0; /* =1 BIOS console only, no serial mux */ +static char fIPMI20 = 0; /* =1 IPMI v2.0 or greater */ +static char fcanonical = 0; /* =1 IPMI v2.0 or greater */ +static char fuser1admin = 0; /* =1 if default user 1 should be admin */ +static char bdelim = ':'; +static char bFlow = 1; /* Flow Control: 1=RTS/CTS, 0=none */ +static char inactivity = 0; /* Inactivity Timeout (30 sec increments) */ +static char newbaud = 0x07; /* default = 19.2K */ +static uchar bootflags = 16; /* if < 16 use these bootflags */ +static uchar ser_ch = SER_CH; +static uchar lan_ch = LAN_CH; /* usu LAN 1 = 7 */ +static uchar ser_user = 0x03; /* if -u specified, configure user 3 */ +static uchar ser_access = 0x04; /* user priv 4=Admin, 3=Operator, 2=User */ +static uchar usernum = 0; /* set non-zero to specify user number */ +static uchar useridx = 0; /* user number index for get/show*/ +static uchar max_users = 5; /* set in GetUserAccess() if unum==1 */ +static uchar enabled_users = 0; /* set in GetUserAccess() if unum==1 */ +static uchar show_users = 5; /* set in GetUserAccess() if unum==1 */ +static char rguser[16] = "root"; /* default, settable via user param */ +static char rgpasswd[PSW_LEN+1] = "password"; /* default, set via user param */ + +#define NLAN 27 +static struct { + int cmd; + int sz; + char desc[28]; +} lanparams[NLAN] = { /* see IPMI Table 19-4 */ + /* 0 */ { 0, 1, "Set in progress"}, + /* 1 */ { 1, 1, "Auth type support"}, + /* 2 */ { 2, 5, "Auth type enables"}, + /* 3 */ { 3, 4, "IP address"}, + /* 4 */ { 4, 1, "IP addr src"}, /* (DHCP/Static) */ + /* 5 */ { 5, 6, "MAC addr"}, + /* 6 */ { 6, 4, "Subnet mask"}, + /* 7 */ { 7, 3, "IPv4 header"}, + /* 8 */ { 8, 2, "Prim RMCP port "}, + /* 9 */ { 9, 2, "Sec RMCP port "}, + /* 10 */ {10, 1, "BMC grat ARP "}, + /* 11 */ {11, 1, "grat ARP interval"}, + /* 12 */ {12, 4, "Def gateway IP"}, + /* 13 */ {13, 6, "Def gateway MAC"}, + /* 14 */ {14, 4, "Sec gateway IP"}, + /* 15 */ {15, 6, "Sec gateway MAC"}, + /* 16 */ {16,18, "Community string"}, + /* 17 */ {17, 1, "Num dest"}, + /* 18 */ {18, 5, "Dest type"}, + /* 19 */ {19, 13, "Dest address"}, + /* 20 */ {96, 28, "OEM Alert String"}, + /* 21 */ {97, 1, "Alert Retry Algorithm"}, + /* 22 */ {98, 3, "UTC Offset"}, + /* 23 */ {192, 4, "DHCP Server IP"}, + /* 24 */ {193, 6, "DHCP MAC Address"}, + /* 25 */ {194, 1, "DHCP Enable"}, + /* 26 */ {201, 2, "Channel Access Mode (Lan)"} +}; + +/* Special temp ids for other serial commands that aren't serial params */ +#define CMDID_CA1 201 /*this is the first temp id*/ +#define CMDID_UA1 202 +#define CMDID_UA2 203 +#define CMDID_UA3 204 +#define CMDID_UA4 205 +#define CMDID_MUX 210 +#define CMDID_BOOT 211 +#define NSER 28 /* was 32 */ +static struct { + int cmd; + int sz; + char desc[28]; +} serparams[NSER] = { /* see IPMI Table 20-4 */ + /* 0 */ { 0, 1, "Set in progress"}, + /* 1 */ { 1, 1, "Auth type support"}, + /* 2 */ { 2, 5, "Auth type enables"}, + /* 3 */ { 3, 1, "Connection Mode"}, + /* 4 */ { 4, 1, "Sess Inactiv Timeout"}, + /* 5 */ { 5, 5, "Channel Callback"}, + /* 6 */ { 6, 1, "Session Termination"}, + /* 7 */ { 7, 2, "IPMI Msg Comm"}, + /* 8 */ { 8, 2, "Mux Switch"}, + /* 9 */ { 9, 2, "Modem Ring Time"}, + /* 10 */ {10,17, "Modem Init String"}, + /* 11 */ {11, 5, "Modem Escape Seq"}, + /* 12 */ {12, 8, "Modem Hangup Seq"}, + /* 13 */ {13, 8, "Modem Dial Command"}, + /* 14 */ {14, 1, "Page Blackout Interval"}, + /* 15 */ {15,18, "Community String"}, + /* 16 */ {16, 1, "Num of Alert Dest"}, + /* 17 */ {17, 5, "Destination Info"}, + /* 18 */ {18, 1, "Call Retry Interval"}, + /* 19 */ {19, 3, "Destination Comm Settings"}, + /* 20 */ {20, 1, "Number Dial Strings"}, + /* 21 */ {21,33, "Dest Dial String"}, + /* 22 */ {22, 1, "Number Dest IP Addrs"}, + /* 23 */ {23, 5, "Dest IP Address"}, + /* 24 */ {29, 2, "Terminal Mode Config"}, + /* 25 */ {CMDID_MUX, 1,"Get Serial MUX Status"}, + /* 26 */ {CMDID_BOOT, 3,"Get Boot Options(3)"}, + /* 27 */ {CMDID_CA1, 2,"Channel Access Mode (Ser)"} + /* 28 *% {CMDID_UA1, 4,""}, //"Get User Access (1)", */ + /* 29 *% {CMDID_UA2, 4,""}, //"Get User Access (2)", */ + /* 30 *% {CMDID_UA3, 4,""}, //"Get User Access (3)", */ + /* 31 *% {CMDID_UA4, 4,""} //"Get User Access (4)" */ +}; + +static int GetDeviceID(SER_RECORD *pSerRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (pSerRecord == NULL) return(-1); + + status = ipmi_cmd(GET_DEVICE_ID, inputData, 0, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("GetDeviceID: completion code=%x\n", + completionCode); + } else { + // dont copy first byte (Parameter revision, usu 0x11) + memcpy(pSerRecord,&responseData[0],responseLength); + set_mfgid(&responseData[0],responseLength); + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(-1); +} /*end GetDeviceID() */ + +static int GetChanAcc(uchar chan, uchar parm, SER_RECORD *pSerRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (pSerRecord == NULL) return(-1); + responseLength = 3; + inputData[0] = chan; + inputData[1] = parm; /* 0x80 = active, 0x40 = non-volatile */ + + status = ipmi_cmd(GET_CHANNEL_ACC, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("GetChanAcc: completion code=%x\n", + completionCode); + } else { + memcpy(pSerRecord,&responseData[0],responseLength); + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(-1); +} /*GetChanAcc()*/ + +static int SetChanAcc(uchar chan, uchar parm, uchar val) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + /* parm: 0x80 = active, 0x40 = set non-vol*/ + responseLength = 1; + inputData[0] = chan; /* channel */ + inputData[1] = (parm & 0xc0) | (val & 0x3F); + if (chan == lan_ch) inputData[2] = 0x04; /* LAN, don't set priv level*/ + else inputData[2] = (parm & 0xc0) | 0x04; /* set Admin priv level */ + /* serial defaults to 0x02 = User priv level */ + + status = ipmi_cmd(SET_CHANNEL_ACC, inputData, 3, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("SetChanAcc: completion code=%x\n", + completionCode); + } else { + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(-1); +} /*SetChanAcc()*/ + +static int GetSerEntry(uchar subfunc, uchar bset, SER_RECORD *pSerRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + uchar chan; + + if (pSerRecord == NULL) + { + if (fdebug) + printf("GetSerEntry: error, output buffer is NULL\n"); + return (-1); + } + + chan = ser_ch; /* sample: 0=IPMB, 1=EMP/serial, 6=LAN2, 7=LAN1 */ + + inputData[0] = chan; // flags, channel 3:0 (1=EMP) + inputData[1] = subfunc; // Param selector + inputData[2] = bset; // Set selector + inputData[3] = 0; // Block selector + if (subfunc == 10) { /*modem init string*/ + inputData[3] = 1; /*blocks start with 1*/ + } else if (subfunc == 21) { + inputData[3] = 1; /*blocks start with 1*/ + } + + status = ipmi_cmd(GET_SER_CONFIG, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (completionCode == 0x80) + SELprintf("GetSerEntry(%d): Parameter not supported\n", + subfunc); + else + SELprintf("GetSerEntry(%d): completion code=%x\n", + subfunc,completionCode); // responseData[0]); + } else { + // dont copy first byte (Parameter revision, usu 0x11) + memcpy(pSerRecord,&responseData[1],responseLength-1); + pSerRecord->data[responseLength-1] = 0; + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + printf("GetSerEntry: ipmi_cmd status=%d, completion code=%d\n", + status,completionCode); + return -1; +} + +static int SetSerEntry(uchar subfunc, SER_RECORD *pSerRecord, int reqlen) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + + if (pSerRecord == NULL) + { + if (fdebug) + printf("SetSerEntry(%d): error, input buffer is NULL\n", + subfunc); + return (-1); + } + + inputData[0] = ser_ch; // flags, channel 3:0 (EMP) + inputData[1] = subfunc; // Param selector + memcpy(&inputData[2],pSerRecord,reqlen); + + status = ipmi_cmd(SET_SER_CONFIG, inputData, (uchar)(reqlen+2), + responseData, &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (completionCode == 0x80) + SELprintf("SetSerEntry(%d): Parameter not supported\n", + subfunc); + else + SELprintf("SetSerEntry(%d): completion code=%x\n", + subfunc, completionCode); + } else { + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + printf("SetSerEntry: ipmi_cmd status=%d, completion code=%d\n", + status,completionCode); + return -1; +} /* end SetSerEntry() */ + +#ifdef NEEDED +int SerialIsOptional(uchar bparam) +{ + /* These Serial Parameters are for optional Modem/Callback functions. */ + uchar optvals[9] = { 5, 9, 10, 11, 12, 13, 14, 20, 21 }; + int rv = 0; + int i; + for (i = 0; i < sizeof(optvals); i++) { + if (optvals[i] == bparam) { rv = 1; break; } + } + return(rv); +} +#endif + +int SetMiscEntry(ushort icmd, SER_RECORD *pSerRecord, int reqlen) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + + if (pSerRecord == NULL) { + if (fdebug) printf("SetMiscEntry: error, input buffer is NULL\n"); + return (-1); + } + memcpy(&inputData[0],pSerRecord,reqlen); + + status = ipmi_cmd(icmd, inputData, (uchar)reqlen, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + printf("SetMiscEntry(%04x): completion code=%x\n", + icmd,completionCode); + } else { //successful + if (responseLength > 1) { + // skip first byte (Parameter revision, usu 0x11) + memcpy(pSerRecord,&responseData[1],responseLength-1); + } + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + printf("SetMiscEntry: ipmi_cmd status=%d, completion code=%d\n", + status,completionCode); + return -1; +} /* end SetMiscEntry() */ + +int GetMiscEntry(ushort icmd, SER_RECORD *pSerRecord, int reqlen) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + + if (pSerRecord == NULL) { + if (fdebug) printf("GetMiscEntry: error, output buffer is NULL\n"); + return (-1); + } + + memcpy(&inputData[0],pSerRecord,reqlen); + status = ipmi_cmd(icmd, inputData, (uchar)reqlen, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (completionCode == 0x80) + printf("GetMiscEntry(%d): Parameter not supported\n", + icmd); + else + printf("GetMiscEntry(%d): completion code=%x\n", + icmd,completionCode); + } else { //successful + if (responseLength > 1) + memcpy(pSerRecord,&responseData[0],responseLength); + return(0); + } + } + + if (fdebug) + printf("GetMiscEntry(%d): ipmi_cmd status=%d, completion code=%x\n", + icmd,status,completionCode); + return -1; +} /* end GetMiscEntry() */ + +void ShowUserAccess(uchar unum, uchar c0, uchar c1, uchar c2, uchar c, + char *name) +{ + /* channel is always ser_ch */ + if (unum == 1 && !fcanonical) { + printf("Users: showing %d of max %d users (%d enabled)\n", + show_users,max_users,enabled_users); + } + printf("Get User Access(%d)%c %02x %02x %02x %02x%c ", + unum,bdelim,c0,c1,c2,c,bdelim); + if (c & 0x10) printf("IPMI, "); + c = (c & 0x0f); + switch(c) { + case 1: printf("Callback"); break; + case 2: printf("User "); break; + case 3: printf("Operator"); break; + case 4: printf("Admin"); break; + case 5: printf("OEM "); break; + case 0x0f: printf("No access"); break; + default: printf("Reserved"); + } + printf(" (%s)\n",name); +} + +int GetUserAccess(uchar unum, uchar *rdata, char *name) +{ + int rv; + /* rdata must be at least 2 bytes, and name must be at least 16 bytes */ + rdata[0] = ser_ch; /* channel# */ + rdata[1] = unum; /* user# */ + rv = GetMiscEntry(GET_USER_ACCESS, (SER_RECORD *)rdata, 2); + if (rv == 0 && name != NULL) { + name[0] = unum; /* user# */ + rv = GetMiscEntry(GET_USER_NAME, (SER_RECORD *)name, 1); + if (rv != 0) name[0] = 0; + rv = 0; + } + if (unum == 1) { /*get max_users and enabled_users*/ + max_users = rdata[0] & 0x3f; + enabled_users = rdata[1] & 0x3f; + // if (enabled_users > show_users) show_users = enabled_users; + if (show_users > max_users) show_users = max_users; + } + if (rv == 0) + ShowUserAccess(unum,rdata[0],rdata[1],rdata[2],rdata[3],name); + else printf("Get User Access(%d): error %d\n",unum,rv); + return(rv); +} + +static int GetLanEntry(uchar subfunc, SER_RECORD *pSerRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + uchar chan; uchar bset; + + if (pSerRecord == NULL) + { + if (fdebug) + printf("GetLanEntry: error, output buffer is NULL\n"); + return (-1); + } + + chan = lan_ch; + if (subfunc == 18 || subfunc == 19) bset = 1; /* dest id = 1 */ + else bset = 0; + + inputData[0] = chan; // flags, channel 3:0 (LAN 1) + inputData[1] = subfunc; // Param selector (3 = ip addr) + inputData[2] = bset; // Set selector + inputData[3] = 0; // Block selector + + status = ipmi_cmd(GET_LAN_CONFIG, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("GetLanEntry: completion code=%x\n", + completionCode); // responseData[0]); + } else { + // dont copy first byte (Parameter revision, usu 0x11) + memcpy(pSerRecord,&responseData[1],responseLength-1); + pSerRecord->data[responseLength-1] = 0; + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + printf("GetLanEntry: ipmi_cmd status=%d, completion code=%d\n", + status,completionCode); + return -1; +} /* end GetLanEntry() */ + +#ifdef NOT +static int SetLanEntry(uchar subfunc, SER_RECORD *pSerRecord, int reqlen) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + + if (pSerRecord == NULL) + { + if (fdebug) + printf("SetLanEntry: error, input buffer is NULL\n"); + return (-1); + } + + inputData[0] = lan_ch; // flags, channel 3:0 (LAN 1) + inputData[1] = subfunc; // Param selector (3 = ip addr) + memcpy(&inputData[2],pSerRecord,reqlen); + + status = ipmi_cmd(SET_LAN_CONFIG,inputData,(uchar)(reqlen+2),responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("SetLanEntry: completion code=%x\n", + completionCode); // responseData[0]); + } else { + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + printf("SetLanEntry: ipmi_cmd status=%d, completion code=%d\n", + status,completionCode); + return -1; +} /* end SetLanEntry() */ +#endif + +static int ReadSELinfo() +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar completionCode; + uchar inputData[6]; + int status; + + status = ipmi_cmd(GET_SEL_INFO, inputData, 0, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) + { + if (fdebug) + SELprintf("Code %d SEL Ver %d Support %d\n", + completionCode, + responseData[0], + responseData[13] + ); + //successful, done + return(0); + } + else return(1); + +} /*end ReadSELinfo()*/ + +#define NBAUDS 10 +static struct { + unsigned char val; + char str[8]; + } mapbaud[NBAUDS] = { + { 6, "9600" }, + { 6, "9.6K" }, + { 7, "19.2K" }, + { 7, "19200" }, + { 8, "38.4K" }, + { 8, "38400" }, + { 9, "57.6K" }, + { 9, "57600" }, + { 10, "115.2K" }, + { 10, "115200" } + }; + +static unsigned char Str2Baud(char * str) +{ + unsigned char baud = 0; + int i, n, len; + len = (int)strlen(str); + for (i = 0; i < len; i++) /*toupper*/ + if (str[i] >= 'a' && str[i] <= 'z') str[i] &= 0x5F; + for (i = 0; i < NBAUDS; i++) { + n = (int)strlen(mapbaud[i].str); + if (strncmp(str,mapbaud[i].str,n) == 0) { + baud = mapbaud[i].val; + break; + } + } + if (i == NBAUDS || baud == 0) { + printf("Invalid -B parameter value (%s), using 19.2K.\n",str); + i = 1; /* default is 19.2K */ + baud = mapbaud[i].val; /* =7 */ + } + if (fdebug) printf("new baud = %02x (%s)\n",baud,mapbaud[i].str); + return(baud); +} + +static char *Baud2Str(unsigned char bin) +{ + char *baudstr; + unsigned char b; + b = bin & 0x0f; + switch(b) { + case 6: baudstr = "9600 "; break; + case 7: baudstr = "19.2k"; break; + case 8: baudstr = "38.4k"; break; + case 9: baudstr = "57.6k"; break; + case 10: baudstr = "115.2k"; break; + default: baudstr = "nobaud"; + } + return(baudstr); +} + +void ShowChanAccess(uchar chan, char *tag, uchar access, uchar access2) +{ + printf("Channel Access Mode(%d=%s)%c %02x %02x %c ", + chan,tag,bdelim,access,access2,bdelim); + switch (access & 0x03) { + case 0: printf("Access = Disabled, "); break; + case 1: printf("Access = Pre-Boot, "); break; + case 2: printf("Access = Always Avail, "); break; + case 3: printf("Access = Shared, "); break; + default: break; + } + if (access & 0x20) printf("PEF Alerts Disabled\n"); /*0*/ + else printf("PEF Alerts Enabled\n"); /*1*/ +} + +static int valid_priv(int c) +{ + int rv; + switch(c) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 0x0f: + rv = 1; break; + default: + rv = 0; break; + } + return(rv); +} + +#ifdef METACOMMAND +int i_serial(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret; + SER_RECORD SerRecord; + char uname[16]; + int i, idx; + int c; + int rlen; + uchar iData[2]; + uchar rData[10]; + uchar cc; + int j; + uchar bset; + uchar nalert, ndial, ndest; + uchar ialert, idial, idest; + uchar authmask = 0; + char mystr[80]; + + // progname = argv[0]; + printf("%s ver %s \n",progname,progver); + + if (argc <= 1) freadonly = 1; /* default to readonly if no options */ + + while ( (c = getopt( argc, argv,"abcdef:gi:lm:n:p:#:q:rstu:v:xB:F:T:V:J:EYP:N:R:U:X:Z:?")) != EOF ) + switch(c) { + case 'x': fdebug = 1; break; + case 'r': freadonly = 1; break; + case 'l': fgetlan = 1; break; + case 'd': fDisable = 1; freadonly = 0; break; + case 'a': fcanonical = 1; /* canonical mode with delimeter */ + bdelim = BDELIM; break; + case 'c': /* configure Terminal Mode & Console */ + case 't': fSetTMode = 1; /* set Terminal Mode & Console */ + freadonly = 0; break; + case 'e': fSetTMode = 1; /* set Terminal Mode not shared*/ + fnotshared = 1; /* no BIOS console, not shared */ + freadonly = 0; break; + case 'g': fSetTMode = 1; /* set Terminal Mode, but BCR only */ + fconsoleonly = 1; /* BIOS console only, disable mux */ + freadonly = 0; break; + case 'b': fBMode = 1; /* set Basic Mode only */ + freadonly = 0; break; + case 's': fBMode = 1; /* set Basic Mode & Console */ + fShared = 1; freadonly = 0; + break; + case 'f': i = atoi(optarg); /*flow control*/ + if (i >= 0 && i < 2) bFlow = (uchar)i; + break; + case 'i': i = atoi(optarg); /*inactivity timeout*/ + if (i > 0 && i < 30) inactivity = 1; + else inactivity = i / 30; + break; + case 'B': newbaud = Str2Baud(optarg); break; + case 'm': /* set MUX to specific value */ + i = atoi(optarg); + if (fdebug) printf("MUX Mode %d\n",i); + switch(i) { + case 0: fBasebdOn = 1; break; + case 1: fTModeOn = 1; break; + default: fBasebdOn = 1; + } + break; + case 'u': + strncpy(rguser,optarg,16); + rguser[15] = 0; + /* Use specified user #3, and set user 1 to not admin */ + fSetUser3 = 1; + break; + case 'p': + strncpy(rgpasswd,optarg,PSW_LEN); + rgpasswd[PSW_LEN] = 0; + fSetPsw = 1; + /* Hide password from 'ps' */ + memset(optarg, ' ', strlen(optarg)); + break; + case 'q': + case '#': + usernum = atob(optarg); + if (usernum > 15) usernum = 0; /*MAX_IPMI_USERS = 4*/ + break; + case 'n': + ser_ch = atob(optarg); + if (ser_ch > MAXCHAN) ser_ch = SER_CH; /*default=1*/ + break; + case 'v': /*user privilege level access */ + i = atoi(optarg); + if (valid_priv(i)) ser_access = i & 0x0f; + else printf("Invalid privilege -v %d, using Admin\n",i); + break; + case 'X': + bootflags = atob(optarg); + fdoanyway = 1; /* undocumented, for test only */ + break; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-bcdefglmnq#rstxB -u user -p passwd -NUPREFTVY]\n",progname); + printf(" -b configure serial port for Basic Mode\n"); + printf(" -c Configure serial port for shared Terminal Mode & Console\n"); + printf(" -d Disable serial port for IPMI use.\n"); + printf(" -e configure serial port for Terminal Mode only\n"); + printf(" -f0 Flow control: 0=none, 1=RTS/CTS(default)\n"); + printf(" -g configure serial port for console only, with BMode CTS\n"); + printf(" -s configure serial port for Shared Basic Mode & Remote Console\n"); + printf(" -l show some LAN parameters also\n"); + printf(" -m0 switch MUX to Normal baseboard operation\n"); + printf(" -m1 switch MUX to BMC operation (BMode or TMode)\n"); + printf(" -B bval set Baud to bval for serial port\n"); + printf(" -n ser_chan serial channel Number (default=1)\n"); + printf(" -p password set Password for EMP TMode login\n"); + printf(" -u username set Username for EMP TMode login\n"); + printf(" -q/-# User number of Username for EMP\n"); + printf(" -r Read-only, view serial port parameters (default)\n"); + printf(" -t Configure serial port for shared Terminal Mode & Console (same as -c)\n"); + printf(" -v4 access priVilege: 4=Admin, 3=Operator, 2=User\n"); + printf(" -x eXtra debug messages\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + if (is_remote() && !freadonly) parse_lan_options('V',"4",0); + + ret = GetDeviceID( &SerRecord); + if (ret != 0) { + goto do_exit; + } else { + uchar ipmi_maj, ipmi_min; + uchar *devrec; + + devrec = &SerRecord.data[0]; + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + vend_id = devrec[6] + (devrec[7] << 8) + (int)(devrec[8] << 16); + prod_id = devrec[9] + (devrec[10] << 8); + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + if ((ipmi_maj == 0) || (ipmi_maj == 1 && ipmi_min < 5)) { + /* IPMI 0.9 and 1.0 dont support this. */ + printf("This system does not support EMP Terminal Mode.\n"); + if (!fdoanyway) + ret = LAN_ERR_NOTSUPPORT; + goto do_exit; + } + if (ipmi_maj >= 2) fIPMI20 = 1; + /* Determine if Basic or Terminal Mode is supported by product id */ + if (vend_id == VENDOR_INTEL) { /*Intel*/ + switch(prod_id) { + case 0x4311: fKnownMode = 1; break; /*NSI2U, BMode*/ + case 0x000C: fKnownMode = 1; break; /*TSRLT2, BMode*/ + case 0x0100: fKnownMode = 1; break; /*Tiger2, BMode*/ + case 0x001B: fKnownMode = 2; break; /*TIGPR2U, TMode*/ + case 0x0022: fKnownMode = 2; break; /*TIGI2U, TMode*/ + case 0x0026: fKnownMode = 2; break; /*Alcolu, TMode*/ + case 0x0028: fKnownMode = 2; break; /*Alcolu, TMode*/ + case 0x0811: fKnownMode = 2; break; /*TIGW1U, TMode*/ + case 0x003E: fKnownMode = 2; /*NSN2U/CG2100, TMode*/ + set_max_kcs_loops(URNLOOPS); /*longer KCS timeout*/ + break; + default: break; + } + } else if (vend_id == VENDOR_NSC) { /*NSC*/ + if (prod_id == 0x4311) fKnownMode = 1; /*TIGPT1U, No EMP*/ + } /* else * other vend_id, leave defaults */ + if (fKnownMode > 0) { + /* Adjust if we know that the user set the wrong one. */ + if (fKnownMode == 1 && fSetTMode == 1) { + printf("Adjusting from Terminal Mode to Basic Mode\n"); + fSetTMode = 0; fBMode = 1; fShared = 1; + } else if (fKnownMode == 2 && fBMode == 1) { + printf("Adjusting from Basic Mode to Terminal Mode\n"); + fSetTMode = 1; fBMode = 0; + } + } + } /*end-else have device_id */ + + ret = ipmi_getpicmg( &SerRecord.data[0], 16, fdebug); + if (ret == 0) fpicmg = 1; + + ret = ReadSELinfo(); + if (ret == 0) { /* talking to BMC ok */ + + /* find the first Serial channel via Channel Info */ + for (j = 1; j < MAXCHAN; j++) { + iData[0] = (uchar)j; /*channel #*/ + rlen = sizeof(rData); + ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, 0); + if (ret != 0) break; + if (rData[1] == 4) { /* 4 = LAN type*/ + if (fdebug) printf("chan[%d] = lan\n",j); + lan_ch = (uchar)j; + } else if (rData[1] == 5) { /* 5 = Serial type*/ + if (fdebug) printf("chan[%d] = serial\n",j); + if (ser_ch != SER_CH) { /* user set it */ + if (j == ser_ch) break; + } else { /* find the first serial channel */ + ser_ch = (uchar)j; + break; + } + } else /* 7 = SMBus, 12 = System Interface */ + if (fdebug) printf("chan[%d] = %d\n",j,rData[1]); + } + if (fdebug) printf("ser_ch = %d\n",ser_ch); + if (j >= MAXCHAN) { + printf("No serial channel support found (channel %d)\n",ser_ch); + ret = LAN_ERR_NOTSUPPORT; + goto do_exit; + } + + if (fdebug && fSetUser3 == 1) + printf("user %d/%d: username=%s, password=%p\n", + usernum,ser_user, rguser,rgpasswd); + + if (fgetlan && !fcanonical) { + int ival; + printf("%s, GetLanEntry for channel %d ...\n",progname,lan_ch); + for (idx = 0; idx < NLAN; idx++) + { + ival = lanparams[idx].cmd; + if (ival == 8 || ival == 9) continue; /* not implemented */ + if (ival >= 96 && ival <= 98) continue; /* not implemented */ + if (ival == CMDID_CA1) { + ret = GetChanAcc(lan_ch, 0x40, &SerRecord); + } else { + ret = GetLanEntry((uchar)ival, &SerRecord); + } + if (ret == 0) { // Show the LAN record + uchar * pc; int sz; + pc = (uchar *)&SerRecord; + sz = lanparams[idx].sz; + printf("Lan Param(%d) %s%c ",ival,lanparams[idx].desc,bdelim); + if (ival == 16) { printf("%s \n",pc); /* string */ + } else { /* print results for others */ + for (i = 0; i < sz; i++) { + if (ival == 3 || ival == 6 || ival == 12 || ival == 14 || + ival == 192) + printf("%d ",pc[i]); /* IP addresses in dec */ + else printf("%02x ",pc[i]); /* show in hex */ + } + /* if (ival == 4) { pc[0]: 01 = static, 02 = DHCP } */ + printf("\n"); + } + } else /* ret != 0 */ + printf("GetLanEntry(%d), ret = %d\n",ival,ret); + } /*end for*/ + } + + printf("%s, GetSerEntry for channel %d ...\n",progname,ser_ch); + nalert = 1; ialert = 1; + ndial = 1; idial = 1; + ndest = 1; idest = 1; + for (idx = 0; idx < NSER; idx++) { + int ival; + ival = serparams[idx].cmd; + /* + * ival is either the Serial Param# or a temp id. + * Do the appropriate Get command, based on ival. + */ + if (ival == CMDID_CA1) { + ret = GetChanAcc(ser_ch, 0x40, &SerRecord); + } else if (ival == CMDID_UA1) { + useridx = 1; + ret = GetUserAccess(useridx,(uchar *)&SerRecord,uname); + } else if (ival == CMDID_UA2) { + useridx = 2; + ret = GetUserAccess(useridx,(uchar *)&SerRecord,uname); + } else if (ival == CMDID_UA3) { + useridx = 3; + ret = GetUserAccess(useridx,(uchar *)&SerRecord,uname); + } else if (ival == CMDID_UA4) { + useridx = 4; + if (fIPMI20 == 0) continue; /* IPMI 1.5 only has 3 users */ + ret = GetUserAccess(useridx,(uchar *)&SerRecord,uname); + } else if (ival == CMDID_MUX) { + SerRecord.data[0] = ser_ch; /* channel 1 = EMP */ + SerRecord.data[1] = 0x00; /* just get MUX status */ + ret = SetMiscEntry(SET_SER_MUX, &SerRecord, 2); + } else if (ival == CMDID_BOOT) { + SerRecord.data[0] = 0x03; /* Boot Param 3 */ + SerRecord.data[1] = 0x00; /* Set Selector */ + SerRecord.data[2] = 0x00; /* %%%% */ + ret = GetMiscEntry(GET_BOOT_OPTIONS, &SerRecord, 3); + } else { + if (fcanonical) { + switch(ival) { /*only show certain parameters*/ + case 3: + case 4: + case 6: + case 7: + case 8: + case 29: + break; + default: + continue; break; + } + } + if (vend_id == VENDOR_SUPERMICROX && ival == 8) continue; + if (vend_id == VENDOR_SUPERMICRO && ival == 8) continue; + if (ival == 17 || ival == 19) bset = ialert; + else if (ival == 21) bset = idial; + else if (ival == 23) bset = idest; + else bset = 0; /*default*/ + ret = GetSerEntry((uchar)ival, bset, &SerRecord); + } + /* + * Now the Get command is done, check the status, and + * show the raw output. + */ + if (ret == 0) { // Show the SER record + uchar * pc; int sz; + pc = (uchar *)&SerRecord; + sz = serparams[idx].sz; + /* save some input data for later reuse */ + if (ival == 16) nalert = pc[0]; + else if (ival == 20) ndial = pc[0]; + else if (ival == 22) ndest = pc[0]; + if (ival == CMDID_CA1) ; + else if (ival > CMDID_CA1) + printf("%s%c ",serparams[idx].desc,bdelim); + else + printf("Serial Param(%d) %s%c ",ival,serparams[idx].desc,bdelim); + if (ival == 1) { /* Auth Type support*/ + authmask = pc[0]; /* auth type support mask */ + mystr[0] = 0; + if (authmask & 0x01) strcat(mystr,"None "); + if (authmask & 0x02) strcat(mystr,"MD2 "); + if (authmask & 0x04) strcat(mystr,"MD5 "); + if (authmask & 0x10) strcat(mystr,"Pswd "); + if (authmask & 0x20) strcat(mystr,"OEM "); + printf("%02x %c %s\n",authmask,bdelim,mystr); + } + else if (ival == 10) { /* modem init string */ + pc[sz] = 0; + printf("%02x %s\n",pc[0],&pc[1]); + } + else if (ival == 21) { /* modem dial string */ + pc[sz] = 0; + printf("%02x %02x %s\n",pc[0],pc[1],&pc[2]); + } + else if ((ival >= 11 && ival <= 13) || ival == 15) { /* strings */ + pc[sz] = 0; + printf("%s\n",pc); + } + else if (ival == 23) { /* Dest IP Address */ + printf("%02x %d %d %d %d\n", pc[0], /*dest index*/ + pc[1],pc[2],pc[3],pc[4]); + } + else if (ival == CMDID_CA1) { /* Channel Access */ + ShowChanAccess(ser_ch,"Ser",pc[0],pc[1]); + } + else if (ival == CMDID_UA1 || ival == CMDID_UA2 || + ival == CMDID_UA3 || ival == CMDID_UA4) { + // ShowUserAccess(useridx,pc[0],pc[1],pc[2],pc[3],uname); + } /*endif UA*/ + else /* hex data */ + { + for (i = 0; i < sz; i++) { + printf("%02x ",pc[i]); /* show in hex */ + } + /* + * Raw hex data display is complete, now do post-processing. + * Interpret some hex data. + */ + if (ival == 4) { /* Session Inactivity Timeout */ + c = pc[0]; + if (c == 0) strcpy(mystr,"infinite"); + else sprintf(mystr,"%d sec",(c * 30)); + printf(" %c %s",bdelim,mystr); + } + else if (ival == 7) { /*IPMI Msg Comm*/ + uchar v; + char *flow; char *dtr; char *baud; + v = pc[0] & 0xc0; + switch(v) { + case 0x40: flow = "RTS/CTS"; break; + case 0x80: flow = "XON/XOFF"; break; + case 0x00: + default: flow = "no_flow"; + } + if ((pc[0] & 0x20) == 0) dtr="no_DTR"; + else dtr = "DTR"; + baud = Baud2Str(pc[1]); + printf("%c %s, %s, %s",bdelim,flow,dtr,baud); + } + else if (ival == 19) { /*Dest Comm Settings*/ + uchar v; + char *flow; char *baud; + uchar chsz,parity,stopb; + v = pc[1] & 0xc0; + switch(v) { + case 0x40: flow = "RTS/CTS"; break; + case 0x80: flow = "XON/XOFF"; break; + case 0x00: + default: flow = "no_flow"; + } + if ((pc[1] & 0x10) == 0) stopb = 1; + else stopb = 2; + if ((pc[1] & 0x08) == 0) chsz = 8; + else chsz = 7; + v = pc[1] & 0x07; + switch(v) { + case 1: parity = 'O'; break; + case 2: parity = 'E'; break; + case 0: + default: parity = 'N'; + } + baud = Baud2Str(pc[2]); + printf("%c %s, %d%c%d, %s",bdelim,flow,chsz,parity,stopb,baud); + } +#ifdef TEST + /* This MUX reading is volatile and may not be accurate */ + else if (ival == CMDID_MUX) { + /* Apparently this always shows 0x01 even if System. */ + if (pc[0] & 0x01 == 1) printf("%c BMC",bdelim); + else printf("%c System",bdelim); /*BIOS*/ + } +#endif + printf("\n"); + } /*end else hex*/ + } /*endif show*/ + if (ival == 17 || ival == 19) { /* alert params */ + if (ialert < nalert) { + ialert++; + idx--; /* repeat this param*/ + } else ialert = 1; + } + if (ival == 21) { /* dial param */ + if (idial < ndial) { + idial++; + idx--; /* repeat this param*/ + } else idial = 1; + } + if (ival == 23) { /* dest param */ + if (idest < ndest) { + idest++; + idx--; /* repeat this param*/ + } else idest = 1; + } + } /*end for(idx) serial params*/ + + for (i = 1; i <= show_users; i++) + ret = GetUserAccess((uchar)i,(uchar *)&SerRecord,uname); + + if (!freadonly) { /* set serial channel parameters */ + uchar access; + if (fBasebdOn) { /* -m0 */ + SerRecord.data[0] = ser_ch; /* channel 1 = EMP */ + SerRecord.data[1] = 0x03; /* force switch to Baseboard */ + ret = SetMiscEntry(SET_SER_MUX, &SerRecord, 2); + printf("SetSerialMux(System), ret = %d, value = %02x\n", + ret,SerRecord.data[0]); + } else if (fTModeOn) { /* -m1 */ + SerRecord.data[0] = ser_ch; /* channel 1 = EMP */ + SerRecord.data[1] = 0x04; /* force switch to BMC for TMode */ + ret = SetMiscEntry(SET_SER_MUX, &SerRecord, 2); + printf("SetSerialMux(BMC), ret = %d, value = %02x\n", + ret,SerRecord.data[0]); + + } else if (fDisable) { /* -d */ + /* + * DISABLE SERIAL CHANNEL ACCESS + */ + if (vend_id == VENDOR_INTEL && fuser1admin) { + /* First, make sure null user (1) has admin privileges again */ + SerRecord.data[0] = 0x90 | ser_ch; /*0x91*/ + SerRecord.data[1] = 0x01; /*user 1*/ + SerRecord.data[2] = ser_access; /* usu 0x04 admin access*/ + SerRecord.data[3] = 0x00; + ret = SetMiscEntry(SET_USER_ACCESS, &SerRecord, 4); + printf("SetUserAccess(1/%02x), ret = %d\n",ser_access,ret); + } + if (usernum != 0) { /*disable usernum if specified*/ + SerRecord.data[0] = 0x80 | ser_ch; /*0x81*/ + SerRecord.data[1] = usernum; + SerRecord.data[2] = 0x0F; /*No access*/ + SerRecord.data[3] = 0x00; + ret = SetMiscEntry(SET_USER_ACCESS, &SerRecord, 4); + printf("SetUserAccess(%d/none), ret = %d\n",usernum,ret); + } + ret = SetChanAcc(ser_ch, 0x80, 0x20); /*vol access=disabled*/ + if (fdebug) printf("SetChanAcc(ser/disable), ret = %d\n",ret); + ret = SetChanAcc(ser_ch, 0x40, 0x20); /*nvol access=disabled*/ + printf("SetChanAcc(ser/disable), ret = %d\n",ret); + ret = GetChanAcc(ser_ch, 0x40, &SerRecord); + access = SerRecord.data[0]; + printf("GetChanAcc(ser/disable), ret = %d, new value = %02x\n", + ret,access); + if ((vend_id != VENDOR_SUPERMICROX) && + (vend_id != VENDOR_SUPERMICRO)) { + /* Also disable the Serial Parameter 3: Connection Mode */ + SerRecord.data[0] = 0x00; /* Connection Mode = none */ + ret = SetSerEntry(3, &SerRecord,1); + printf("SetSerEntry(3/disable), ret = %d\n",ret); + } + + } else if (fSetTMode || fBMode) { + /* + * ENABLE SERIAL CHANNEL ACCESS + * Enable: configure everything for TMode and/or BMode + * + * Set Serial/EMP Channel Access + * Use serial channel in shared mode + * 0x20 means alerting=off, disabled (system only) + * 0x22 means alerting=off, always avail + * which would only show BMC messages, not OS messages + * 0x23 means alerting=off, always avail + shared + user-auth on + * 0x2A means alerting=off, always avail + user-auth off + * 0x2B means alerting=off, always avail + shared + user-auth off + * 0x0B means alerting=on, always avail + shared + user-auth off + * SSU won't set 0x2B, but we need shared access mode. + */ + if (fconsoleonly) { + access = ALWAYS_NOAUTH; /*0x2A*/ + } else if (fnotshared) { /* serial IPMI, but no console (-e only) */ + if (fSetTMode) access = ALWAYS_NOAUTH; /*0x2A*/ + else access = ALWAYS_AUTH; /*0x22*/ + } else { /* shared with BIOS console, normal */ + if (fSetTMode) access = SHARED_NOAUTH; /*0x2B*/ + else access = SHARED_AUTH; /*0x23*/ + } + ret = SetChanAcc(ser_ch, 0x80, access); + if (fdebug) printf("SetChanAcc(ser/active), ret = %d\n",ret); + ret = SetChanAcc(ser_ch, 0x40, access); + printf("SetChanAcc(ser), ret = %d\n",ret); + ret = GetChanAcc(ser_ch, 0x80, &SerRecord); + if (fdebug) { + access = SerRecord.data[0]; + printf("GetChanAcc(ser/active), ret = %d, new value = %02x\n", + ret,access); + } + ret = GetChanAcc(ser_ch, 0x40, &SerRecord); + access = SerRecord.data[0]; + printf("GetChanAcc(ser), ret = %d, new value = %02x\n", + ret,access); + ShowChanAccess(ser_ch,"ser",access,SerRecord.data[1]); + + /* Needed if (fSetTMode), otherwise extra. */ + { + /* auth types: pswd, MD5, MD2, none */ + if (authmask == 0) authmask = 0x17; + SerRecord.data[0] = (0x16 & authmask); /*Callback level*/ + SerRecord.data[1] = (0x16 & authmask); /*User level */ + SerRecord.data[2] = (0x16 & authmask); /*Operator level*/ + SerRecord.data[3] = (0x16 & authmask); /*Admin level */ + SerRecord.data[4] = 0x00; /*OEM level*/ + ret = SetSerEntry(2, &SerRecord,5); + printf("SetSerEntry(2), ret = %d\n",ret); + } + if (fconsoleonly) SerRecord.data[0] = 0x81; /*direct, Basic only */ + else if (fBMode) SerRecord.data[0] = 0x83; /*direct; PPP & Basic */ + else SerRecord.data[0] = 0x87; /*direct; TMode, PPP, Basic*/ + if ((vend_id != VENDOR_SUPERMICROX) && + (vend_id != VENDOR_SUPERMICRO)) { + ret = SetSerEntry(3, &SerRecord,1); + printf("SetSerEntry(3), ret = %d\n",ret); + } + /* + * BMode inactivity timeout = 2 (* 30 sec = 60 sec) + * TMode inactivity timeout = 0 (infinite) + */ + if (fBMode) SerRecord.data[0] = 0x02; + else SerRecord.data[0] = inactivity; /*usu 0, infinite*/ + ret = SetSerEntry(4, &SerRecord,1); + printf("SetSerEntry(4), ret = %d\n",ret); + if ((vend_id != VENDOR_SUPERMICROX) && + (vend_id != VENDOR_SUPERMICRO)) { + // SerRecord.data[0] = 0x02; /* enable inactivity, ignore DCD */ + SerRecord.data[0] = 0x03; /* enable inactivity, enable DCD */ + ret = SetSerEntry(6, &SerRecord,1); + printf("SetSerEntry(6), ret = %d\n",ret); + /* flow control: 60=RTS/CTS+DTR, 20=none+DTR */ + SerRecord.data[0] = (bFlow << 6) | 0x20; + SerRecord.data[1] = newbaud; /* baud default = 19.2K bps */ + ret = SetSerEntry(7, &SerRecord,2); + printf("SetSerEntry(7) baud %s, ret = %d\n",Baud2Str(newbaud),ret); + if (fBMode) { + SerRecord.data[0] = 0x1e; /* mux 2way control, GetChanAuth, PPP */ + } else { /*TMode*/ + // SerRecord.data[0] = 0x1e; /* mux 2way control,GetChanAuth,PPP */ + SerRecord.data[0] = 0x16; /* mux 2way control, GetChanAuth,no PPP*/ + /* 2way: <ESC>( and <ESC>Q */ + } + if (fconsoleonly) + SerRecord.data[1] = 0x09; /* enable serial port sharing, hb=not */ + else if (fBMode && !fShared) /* Basic Mode and NOT shared */ + SerRecord.data[1] = 0x0a; /* enable serial port sharing,heartbeat*/ + else + SerRecord.data[1] = 0x08; /* enable serial port sharing, hb=off */ + ret = SetSerEntry(8, &SerRecord,2); + printf("SetSerEntry(8), ret = %d\n",ret); + } + + if (fSetUser3) { + if (usernum == 0) usernum = ser_user; /* user 3 */ + /* + * Set up admin user for Serial User (usu User# 3) + * Username: root + * Password: password + * + * cmdtool 20 18 45 3 72 6F 6F 74 0 0 0 0 0 0 0 0 0 0 0 0 + * cmdtool 20 18 47 3 2 70 61 73 73 77 6F 72 64 0 0 0 0 0 0 0 0 + * cmdtool 20 18 47 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + */ + SerRecord.data[0] = usernum; /* user 3 */ + memset(&SerRecord.data[1],0,16); + memcpy(&SerRecord.data[1],rguser,strlen(rguser)); + ret = SetMiscEntry(SET_USER_NAME, &SerRecord, 17); + printf("SetUserName(%d), ret = %d\n",usernum,ret); + /* set password for user 3 */ + SerRecord.data[0] = usernum; + SerRecord.data[1] = 0x02; + memset(&SerRecord.data[2],0,PSW_LEN); + memcpy(&SerRecord.data[2],rgpasswd,strlen(rgpasswd)); + ret = SetMiscEntry(SET_USER_PASSWORD, &SerRecord, 2+PSW_LEN); + printf("SetUserPassword(%d,2), ret = %d\n",usernum,ret); + /* enable user 3 */ + SerRecord.data[0] = usernum; + SerRecord.data[1] = 0x01; + memset(&SerRecord.data[2],0,PSW_LEN); + ret = SetMiscEntry(SET_USER_PASSWORD, &SerRecord, 2+PSW_LEN); + printf("SetUserPassword(%d,1), ret = %d\n",usernum,ret); + + /* Testing User #3 password */ + // cmdtool 20 18 47 3 3 70 61 73 73 77 6F 72 64 0 0 0 0 0 0 0 0 + SerRecord.data[0] = usernum; + SerRecord.data[1] = 0x03; + memset(&SerRecord.data[2],0,PSW_LEN); + memcpy(&SerRecord.data[2],rgpasswd,strlen(rgpasswd)); + ret = SetMiscEntry(SET_USER_PASSWORD, &SerRecord, 2+PSW_LEN); + printf("SetUserPassword(%d,3), ret = %d\n",usernum,ret); + + /* Set User #3 access up w/ ADMIN privilege for serial channel */ + // cmdtool 20 18 43 91 3 4 0 + SerRecord.data[0] = 0x90 | ser_ch; /*0x91*/ + SerRecord.data[1] = usernum; /* user 3 */ + SerRecord.data[2] = ser_access; /*usu 0x04; Admin*/ + SerRecord.data[3] = 0x00; + ret = SetMiscEntry(SET_USER_ACCESS, &SerRecord, 4); + printf("SetUserAccess(%d/%02x), ret = %d\n",usernum,ser_access,ret); + + if (ipmi_reserved_user(vend_id,0x01) == 0) { + /* Set NULL user access up w/ USER privilege for serial channel */ + // cmdtool 20 18 43 91 1 2 0 + SerRecord.data[0] = 0x90 | ser_ch; /*0x91*/ + SerRecord.data[1] = 0x01; /* user 1 (default) */ + SerRecord.data[2] = 0x02; /* user privilege */ + SerRecord.data[3] = 0x00; + ret = SetMiscEntry(SET_USER_ACCESS, &SerRecord, 4); + printf("SetUserAccess(1/user), ret = %d\n",ret); + } + } else { + /* No username specified, use NULL user 1 for Serial */ + if (ipmi_reserved_user(vend_id,0x01) == 0) { + /* Set NULL user password, if specified */ + if (fSetPsw) { + SerRecord.data[0] = 0x01; /*user 1*/ + SerRecord.data[1] = 0x02; + memset(&SerRecord.data[2],0,PSW_LEN); + memcpy(&SerRecord.data[2],rgpasswd,strlen(rgpasswd)); + ret = SetMiscEntry(SET_USER_PASSWORD, &SerRecord, 2+PSW_LEN); + printf("SetUserPassword(1,2), ret = %d\n",ret); + /* make sure user 1 is enabled */ + SerRecord.data[0] = 0x01; + SerRecord.data[1] = 0x01; + memset(&SerRecord.data[2],0,PSW_LEN); + ret = SetMiscEntry(SET_USER_PASSWORD, &SerRecord, 2+PSW_LEN); + printf("SetUserPassword(1,1), ret = %d\n",ret); + } + /* Set NULL user access up w/ ADMIN privilege for serial channel */ + // cmdtool 20 18 43 91 1 4 0 + SerRecord.data[0] = 0x90 | ser_ch; /*0x91*/ + SerRecord.data[1] = 0x01; /* user 1 */ + SerRecord.data[2] = ser_access; /* admin */ + SerRecord.data[3] = 0x00; + ret = SetMiscEntry(SET_USER_ACCESS, &SerRecord, 4); + printf("SetUserAccess(1/%02x), ret = %d\n",ser_access,ret); + } + } + + if (fSetTMode) { + /* + * Set the TMode configuration: + * Enable line editing + * Delete seq = bksp-sp-bksp + * Enable echo + * Handshake (hb) = off + * Output newline seq = CR-LF + * Input newline seq = CR + */ + if ((vend_id != VENDOR_SUPERMICROX) && + (vend_id != VENDOR_SUPERMICRO)) { +#ifdef TEST + SerRecord.data[0] = 0xA6; /* sets bit for volatile - wrong */ + SerRecord.data[1] = 0x11; + ret = SetSerEntry(29, &SerRecord,2); +#endif + SerRecord.data[0] = 0x66; + SerRecord.data[1] = 0x11; + ret = SetSerEntry(29, &SerRecord,2); + printf("SetSerEntry(29), ret = %d\n",ret); + } + + /* Force mux switch to the BMC and start talking... */ + /* Set Serial/Modem Mux */ + /* cmdtool 20 30 12 1 4 */ + SerRecord.data[0] = ser_ch; /* channel 1 = EMP */ + SerRecord.data[1] = 0x02; /* was 0x04 to force switch to BMC */ + i = SetMiscEntry(SET_SER_MUX, &SerRecord, 2); + printf("SetSerialMux(BMC), ret = %d, value = %02x\n", + i,SerRecord.data[0]); + } /*endif fSetTMode*/ + + else { /* fBMode */ + if (fShared) { + uchar bval; + /* workaround for BMC bug w BIOS Console Redirect */ + SerRecord.data[0] = 0x03; /* Boot Param 3 */ + if (bootflags < 16) { /* user specified a boot flag */ + SerRecord.data[1] = bootflags; /* Flags */ + bval = SerRecord.data[1]; + ret = SetMiscEntry(SET_BOOT_OPTIONS, &SerRecord, 2); + printf("SetBootOptions(3), new value = %02x, ret = %d\n", + bval,ret); + } + + /* Force mux switch to the Baseboard initially */ + SerRecord.data[0] = ser_ch; /* channel 1 = EMP */ + SerRecord.data[1] = 0x03; /* force switch to Baseboard */ + i = SetMiscEntry(SET_SER_MUX, &SerRecord, 2); + printf("SetSerialMux(System), ret = %d, value = %02x\n", + i,SerRecord.data[0]); + } else { /* not shared, BMode only */ + /* Force mux switch to the BMC and start talking... */ + SerRecord.data[0] = ser_ch; /* channel 1 = EMP */ + SerRecord.data[1] = 0x04; /* 0x04 to force switch to BMC */ + i = SetMiscEntry(SET_SER_MUX, &SerRecord, 2); + printf("SetSerialMux(BMC), ret = %d, value = %02x\n", + i,SerRecord.data[0]); + } + } /*end-else BMode*/ + } /*end-else Enable (not Disable) */ + else { /*not enable or disable BMode/TMode */ + if (!fcanonical) + printf("Please specify a configuration mode (b,d,e,m,s,t)\n"); + } + } /*endif not readonly */ + } /* endif ok */ +do_exit: + ipmi_close_(); + // show_outcome(progname,ret); + return(ret); +} /* end main()*/ + +/************************ +DPC configuration stuff on serial. +16:25:08.165 outgoing: set system boot options[08] 20 00 E0 81 6C 08 02 02 07 +16:25:08.165 outgoing: set system boot options[08] 20 00 E0 81 70 08 06 01 0B 28 11 02 45 1F 96 3C 84 +16:25:08.165 outgoing: set system boot options[08] 20 00 E0 81 74 08 04 FF FF 01 +16:25:08.165 outgoing: set system boot options[08] 20 00 E0 81 78 08 03 00 FC +16:25:08.245 INCOMING: SET SYSTEM BOOT OPTIONS[08] 81 04 7B 20 6C 08 -[00]- 6C +16:25:08.245 INCOMING: SET SYSTEM BOOT OPTIONS[08] 81 04 7B 20 70 08 -[00]- 68 +16:25:08.245 outgoing: set system boot options[08] 20 00 E0 81 7C 08 05 80 00 4A 00 00 2C +16:25:08.255 outgoing: chassis control[02] 20 00 E0 81 80 02 03 FA + ************************/ +/* end iserial.c */ diff --git a/util/isol.c b/util/isol.c new file mode 100644 index 0000000..381668e --- /dev/null +++ b/util/isol.c @@ -0,0 +1,1347 @@ +/* + * isol.c (was isolconsole.c) + * IPMI Serial-Over-LAN console application + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2007 Intel Corporation + * Copyright (c) 2009 Kontron America, Inc. + * + * 10/12/06 Andy Cress - created, just a framework for now + * 02/08/07 Andy Cress - now working for IPMI LAN 2.0 SOL in Linux, + * still stdio problems in Windows + * 02/23/07 Andy Cress - fixed Windows stdin, still Windows output issues, + * need more in xlate_vt100_win(). + * 04/06/07 Andy Cress - more vt100-to-windows translation, + * added -r for raw termio + * 04/19/07 Andy Cress - more vt100-to-windows translation, + * 05/08/07 Andy Cress - more logic for 1.5 SOL. Session opens but + * 1.5 SOL data packets are not yet working. + * 05/24/07 Andy Cress - Fix Enter key confusion in BIOS Setup (use CR+LF) + * 06/15/07 Andy Cress - More fixes to Windows translation (fUseWinCon) + * 08/20/07 Andy Cress - moved Windows translation to isolwin.c + * See ChangeLog for further changes + * + * NOTE: There are a few other options for Serial-Over-LAN console + * applications: + * ipmitool.sf.net has v2 sol console capability for Linux (BSD) + * Intel dpccli, a CLI console for Linux and Windows (proprietary) + * Intel ISM console for Windows (proprietary) + * Intel System Management Software (LANDesk) console, proprietary + * The Intel applications support both IPMI 1.5 and 2.0 SOL + * protocols. + */ +/*M* +Copyright (c) 2007 Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#if defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "getopt.h" +int i_sol(int argc, char **argv) +{ + printf("IPMI SOL console is not supported under DOS.\n"); + return(1); +} +#else + +/* All other OSs: Linux, Windows, Solaris, BSD */ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <winsock.h> +#include <io.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdarg.h> +#include <termios.h> +#include <unistd.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include <string.h> +#include <time.h> +#include "ipmicmd.h" +#include "ipmilanplus.h" + +#define ACTIVATE_PAYLOAD 0x48 +#define DEACTIVATE_PAYLOAD 0x49 +#define PAYLOAD_TYPE_SOL 0x01 +#define SOL_SERIAL_ALERT_MASK_DEFERRED 0x04 +#define SOL_BMC_ASSERTS_CTS_MASK_TRUE 0x00 +#define SOL_BMC_ASSERTS_CTS_MASK_FALSE 0x02 +#define IPMI_PAYLOAD_TYPE_SOL 0x01 +#define AUTHTYPE_RMCP_PLUS 0x06 +#define RV_END -2 +#define CH_CR '\r' /*0x0D =='\r'*/ +#define CH_LF '\n' /*0x0A =='\n' LineFeed(Down) */ +#define CH_ESC '\033' /*0x1B == ASCII Escape */ +#define CH_CTL '\316' /*0xCE == VT100 Control */ +#define CH_DEL '\177' /*0x7F == Delete key */ +#define CH_BS '\010' /*0x08 == Backspace */ +#define CH_TAB '\011' /*0x09 == Tab */ +#define CH_UP '\013' /*0x0B == Up Arrow */ + +/* Input data buffer size: screen size (80*24) = 1920 */ +/* IPMI_BUF_SIZE = 1024, less RMCP+IPMI hdr */ +/* IDATA_SZ=2048 was too big, used =300 thru v2.1.0 */ +#define IDATA_SZ 512 +#define IPKT_SZ 512 +#define MAX_INTEL_DATA 203 /*sol_send >= 204 bytes gives error w Intel BMC*/ +#define MAX_DELL_DATA 46 /*sol_send >= 46 bytes gives error w Dell BMC*/ +#define MAX_KONTRON_DATA 74 /*sol_send >= 75 bytes gives error w Kontron BMC*/ +#define MAX_OTHER_DATA 45 /*use a small sol_send limit of 45 by default */ + +typedef struct { + int type; + int len; + char *data; + } SOL_RSP_PKT; + +extern void tty_setraw(int mode); /*from ipmicmd.c*/ +extern void tty_setnormal(int mode); /*from ipmicmd.c*/ +/* extern int tty_getattr(int *lflag,int *oflag,int *iflag); *from ipmicmd.c*/ +extern SockType lan_get_fd(void); /*from ipmilan.c*/ +extern int lan_send_sol( uchar *payload, int len, SOL_RSP_PKT *rsp); +extern int lan_recv_sol( SOL_RSP_PKT *rsp ); +extern int lan_keepalive(int type); +extern void lan_get_sol_data(uchar fEnc, uchar iseed, uint32 *seed); +extern void lan_set_sol_data(uchar fEnc, uchar auth, uchar iseed, + int insize, int outsize); +/* lan2 routines, from ipmilanplus.c, even if not HAVE_LANPLUS: */ +extern int lan2_get_fd(void); /*from ipmilanplus.c*/ +extern int lan2_send_sol( uchar *payload, int len, SOL_RSP_PKT *rsp); +extern int lan2_recv_sol( SOL_RSP_PKT *rsp ); +extern void lan2_set_sol_data(int in, int out, int port, void*hnd, char esc); +extern int lan2_keepalive(int type, SOL_RSP_PKT *rsp); +extern void lan2_recv_handler( void *rs ); +extern long lan2_get_latency( void ); /*from ipmilanplus.c*/ +extern void lanplus_set_recvdelay( int delay ); /*lib/lanplus/lanplus.c*/ +extern int lan2_send_break( SOL_RSP_PKT *rsp ); + +extern char fdbglog; /*see ipmilanplus.c*/ +extern char log_name[]; /*see ipmicmd.c*/ +extern int is_lan2intel(int vend, int prod); /*see oem_intel.c*/ +void dbglog( char *pattn, ... ); /*local prototype*/ + +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "isol"; +static char fdebug = 0; +static char fpicmg = 0; +static char factivate = 0; +static char fdeactivate = 0; +static char fScript = 0; +static char fTrace = 0; +static char fprivset = 0; +static char bDriver = 0; +static uchar bSolVer = 0; +static uchar bKeepAlive = 1; /*1=GetDeviceID, 2=empty SOL data*/ +static char sol_esc_len = 2; /* SOL escape seq ("~.") */ +static char sol_esc_ch = '~'; +static char sol_esc_pending = 0; +static char sol_esc_fn[4] = {'.','b','d', '?'}; /* SOL escape functions */ +static char file_scr[80] = {""}; +static char file_trc[80] = {""}; +static char dbglog_name[40] = "isoldbg.log"; +static FILE *fp_scr = NULL; +static FILE *fp_trc = NULL; +static uchar ipmi_maj = 0; +static uchar ipmi_min = 0; +static int vend_id = 0; /* Manufacturer IANA vendor id */ +static int prod_id = 0; +static uchar fSolEncryption = 1; +static uchar fSolAuthentication = 1; +static int sol_timeout = 30; /* default: send keepalive every 30 seconds */ +static time_t keepalive_start; +static int max_bmc_data = MAX_OTHER_DATA; +static int fgotrecv = 0; +static int fsentok = 0; +static uchar payload_instance = 1; +char fUseWinCon = 1; +uchar fCRLF = 0; /* 0=use CR, 1=use legacy CR+LF, 2=use LF (like raw) */ +uchar fRaw = 0; +uchar bTextMode = 0; +int sol_done = 0; +int wait_time = 500; /*number of msec to wait*/ +int retry_time = 5; /*number of msec between retries*/ + +static int sol_ver = 2; /*use IPMI 2.0 SOL by default*/ +static int sol_retries = 1; /*send retries for sol_input_handler*/ +static int sol_recvdelay = 0; /*if != 0, num us to delay before recv*/ +static uchar sol15_iseed = 0x01; /*initial seed count, usu 0 or 1 */ +static uint32 sol15_wseed = 0; /*32-bit seed value*/ +static long lan2_latency = 0; /*lan2 latency in msec */ +static long lan2_slow = 100; /*slow if latency > 100 msec */ + +extern FILE *fplog; /*see ipmicmd.c*/ +#ifdef WIN32 +/* these routines are in isolwin.c */ +extern DWORD WINAPI input_thread( LPVOID lpParam); +extern void console_open(char fdebugcmd); +extern void console_close(void); +extern void console_out(uchar *pdata, int len); +extern int console_in(DWORD keydata, uchar *pdata, int len); +extern int os_select(int infd, SockType sfd, fd_set *read_fds, fd_set *error_fds); +extern int os_read(int fd, uchar *buf, int sz); +extern void Ascii2KeyCode(uchar c, uchar *buf); +#else + +/*======== start Linux ===============================*/ +int os_read(int fd, uchar *buf, int sz) +{ + int len = 0; + len = read(fd, buf, sz); + return(len); +} + +int os_select(int infd, SockType sfd, fd_set *read_fds, fd_set *error_fds) +{ + int rv = 0; + struct timeval tv; + + /* Linux handles both stdin & socket via select() */ + FD_ZERO(read_fds); + FD_SET(infd, read_fds); + FD_SET(sfd, read_fds); + FD_ZERO(error_fds); + FD_SET(sfd, error_fds); + tv.tv_sec = 0; + tv.tv_usec = wait_time * 1000; /* 500000 usec, 500 msec, 0.5 sec*/ + rv = select((int)(sfd + 1), read_fds, NULL, error_fds, &tv); + return rv; +} + +void CheckTextMode(uchar *buffer, int sbuf) +{ + int c, i, j, imatch; + uchar pattern[5] = {CH_ESC,'[','0','0','m'}; /*was [0m */ + int spattern = 5; + + /* if CH_ESC,"[0m", TextMode change */ + j = 0; + imatch = 0; + for (j = 0; j < sbuf; j++) { + if ((sbuf - j) < spattern && imatch == 0) break; + c = buffer[j]; + if (c == pattern[imatch]) { + imatch++; + } else if (pattern[imatch] == '?') { /*wildcard char*/ + imatch++; + } else if (pattern[imatch] == '0' && (c>='0' && c <='9')) { /*numeric*/ + imatch++; + } else { + if (imatch > 0) { + if (j > 0) j--; /* try again with the first match char */ + imatch = 0; + } + } + if (imatch == spattern) { /*match found*/ + char mystr[5]; + i = (j+1) - imatch; /*buffer[i] is the match */ + // bTextMode = buffer[i+2] & 0x0f; /* usu 0 or 1 */ + mystr[0] = buffer[i+2]; + mystr[1] = buffer[i+3]; + mystr[2] = 0; + bTextMode = atob(mystr); + dbglog("TextMode changed to %d\n",bTextMode); + } + else if (imatch > spattern) break; + } + return; +} + +/*======== end Linux =================================*/ +#endif + +void printm( char *pattn, ... ) +{ /* all sol error/info messages go to log or stderr by default */ + va_list arglist; + FILE *fp; + if (fdbglog && fplog != NULL) fp = fplog; + else fp = stderr; + va_start(arglist, pattn); + vfprintf(fp, pattn, arglist); + va_end(arglist); + fprintf(fp,"\r\n"); +} + +void dbglog( char *pattn, ... ) +{ + va_list arglist; + int fadd = 0; + int l; +#ifdef WIN32 + FILE *fp; + // char _pattn[80]; + if (fdebug == 0 && fdbglog == 0) return; + if (fdbglog && fplog != NULL) fp = fplog; + else fp = stderr; + l = (int)strlen(pattn); + if ((l >= 1) && (pattn[l-1] == '\n')) { /*check EOL chars*/ + if (pattn[l-2] == '\r') fadd = 0; + else fadd = 0; /* '\n' only */ + // else _pattn[l-1] = 0; /*truncate, add \r\n below, dangerous*/ + } else fadd = 1; /*no line-end, so add it below*/ + va_start(arglist, pattn); + vfprintf(fp, pattn, arglist); + va_end(arglist); + if (fadd) fprintf(fp,"\r\n"); +#else + char logtmp[LOG_MSG_LENGTH]; + if (fdebug == 0 && fdbglog == 0) return; + l = strlen(pattn); + if ((l >= 1) && (pattn[l-1] == '\n')) fadd = 0; + else fadd = 1; + va_start( arglist, pattn ); + vsnprintf(logtmp, LOG_MSG_LENGTH, pattn, arglist); + va_end( arglist ); + if (fadd) strcat(logtmp,"\n"); + if (fdbglog) print_log(logtmp); + else if (fdebug) fprintf( stderr, "%s", logtmp); +#endif +} + +void dbg_dump(char *tag, uchar *pdata, int len, int fascii) +{ + FILE *fp = NULL; + if (fdebug == 0 && fdbglog == 0) return; + if (fdbglog && (fplog != NULL)) fp = fplog; + dump_log(fp,tag,pdata,len,(char)fascii); /*uses fplog or fpdbg */ +} + +#ifdef OLD +static void set_latency( struct timeval *t1, struct timeval *t2, long *latency) +{ + long nsec; + nsec = t2->tv_sec - t1->tv_sec; + if ((ulong)(nsec) > 1) nsec = 1; + *latency = nsec*1000 + (t2->tv_usec - t1->tv_usec)/1000; +} +#endif + +static int sol_send(uchar *buf, int len, SOL_RSP_PKT *rsp) +{ + int rv = 0; + if (bSolVer == 1) { + rv = lan_send_sol(buf, len, rsp); + } else { + rv = lan2_send_sol(buf, len, rsp); + if (rv == 0x01) rv = 0; + /* else bit-mapped error, 0x02 = need retry*/ + } + return(rv); +} + +static int sol_recv( SOL_RSP_PKT *rsp) +{ + int rv = 0; + if (bSolVer == 1) { + rv = lan_recv_sol( rsp ); + } else + rv = lan2_recv_sol( rsp ); + return(rv); +} + +static SockType sol_get_fd(void) +{ + SockType fd = 0; + if (bSolVer == 1) { + fd = lan_get_fd(); + } else + fd = lan2_get_fd(); + return(fd); +} + +/* + * sol_output_handler + * This routine is called both in isol.c and ipmilanplus.c/lan2_recv_handler + * whenever SOL data is received from the BMC for output to the console. + */ +void sol_output_handler(SOL_RSP_PKT *rsp) +{ + if (rsp == NULL) return; + if (rsp->type == PAYLOAD_TYPE_SOL) + { +#ifdef WIN32 + fgotrecv = 1; + if (fdbglog) dbg_dump("sol_output(console_out)",rsp->data,rsp->len,1); + console_out(rsp->data,rsp->len); +#else + uchar *pdata; + int len; + int i; + uchar c; + // int mode; + + fgotrecv = 1; + pdata = rsp->data; + len = rsp->len; + if (fdbglog) { + // dbglog("sol_output: len = %d\n",len); + dbg_dump("sol_output",pdata,len,1); /*like printlog*/ + } + CheckTextMode(pdata,len); + for (i = 0; i < len; i++) { + c = pdata[i]; + /* do special character handling here? + * CH_CR, 0xb0-0xb3, 0xdb */ + putc(c, stdout); + } + fflush(stdout); +#endif + if (fTrace) { fwrite(rsp->data,1,rsp->len,fp_trc); fflush(fp_trc); } + } else { + dbglog("sol_output: rsp.type=%x, rsp.len=%d\n", rsp->type, rsp->len); + } +} + +static int sol_keepalive(int type) +{ + int rv = 0; + time_t end; + + time(&end); + if (sol_timeout == 0) return(rv); + if ((end - keepalive_start) > sol_timeout) { + dbglog("sol_keepalive: timeout, lan%d\n",bSolVer); /*++++*/ + if (bSolVer == 1) { + rv = lan_keepalive(type); + } else { + SOL_RSP_PKT rs; + rv = lan2_keepalive(type, &rs); + if (rv >= 0 && rs.len != 0) { /*handle any rsp data*/ + if (rs.type == IPMI_PAYLOAD_TYPE_SOL) { + dbglog("keepalive: output_handler(%d)\n",rs.len); + sol_output_handler(&rs); + } + } + } + time(&keepalive_start); /*time in seconds*/ + dbglog("sol_keepalive sent, rv = %d\n",rv); + flush_log(); + } + return(rv); +} + +static void sol_keepalive_reset(void) +{ + /* not idle, so reset the keepalive timer */ + time(&keepalive_start); /*time in seconds*/ +} + +static int send_break( void ) +{ + SOL_RSP_PKT rs; + int rv; + + if (sol_ver == 1) return LAN_ERR_NOTSUPPORT; + rv = lan2_send_break(&rs); + dbglog("lan2_send_break rv=%d rs.len=%d\n", rv,rs.len); + return(rv); +} + +static int send_ctlaltdel( void ) +{ + uchar buf[8]; + int rv, rlen; + +// #define TESTALT 1 +#ifdef TESTALT + SOL_RSP_PKT rs; + /* This doesn't work. Fix it later. */ + /* Problem is that keycodes must be translated for serial console */ + /* CtrlL = 0x0706, AltL = 0x0703, Del = 0x007f, MetaDel = 0x087f + * Del = keycode 0x53 + * 1b 53 33 7e = alt+del + * 1b 4f 48 = ctl-alt-home + * 1b 4f 46 = ctl-alt-end + * 1b 53 33 3b 38 7e = ctl+alt+shift+del + * 1b 53 33 3b 33 7e = ctl+alt+ins + * 1b 53 33 3b 35 7e = ctl+alt+ins + * 1b 53 35 3b 37 7e = ctl+alt+pgup + * 1b 53 36 3b 37 7e = ctl+alt+pgdn + * Need to find a sequence at serial console that does a reboot + * when the command prompt is not up. + */ + buf[0] = 0x1b; + buf[1] = 0x53; + buf[2] = 0x33; + buf[3] = 0x3b; + buf[4] = 0x36; + buf[5] = 0x7e; + rv = sol_send(buf, 6, &rs); + rlen = rs.len; +#else + uchar rbuf[16]; + uchar cc; + + rlen = sizeof(rbuf); + buf[0] = 5; /*soft reset via ACPI */ + rv = ipmi_cmdraw(CHASSIS_CTL,NETFN_CHAS,BMC_SA, PUBLIC_BUS, BMC_LUN, + buf,1,rbuf,&rlen,&cc,fdebug); + if (rv == 0 && cc != 0) rv = cc; +#endif + dbglog("send_ctlaltdel rv=%d rlen=%d\n", rv,rlen); + return(rv); +} + +static void show_esc_help( void ) +{ + printf("%c?\r\n",sol_esc_ch); + printf("Supported SOL escape sequences:\r\n"); + printf("\t%c. - terminate connection\r\n",sol_esc_ch); + printf("\t%cB - send break\r\n",sol_esc_ch); + printf("\t%cD - send ctl-alt-delete (chassis soft reset)\r\n",sol_esc_ch); + printf("\t%c? - show this help message\r\n",sol_esc_ch); + printf("\t%c%c - send the escape character by typing it twice\r\n", + sol_esc_ch, sol_esc_ch); +} + +int sol_input_handler( uchar *input, int ilen) +{ + int rv = 0; + uchar payload[IPKT_SZ]; + SOL_RSP_PKT rs; + int i, length, t; + static uchar lastc = 0; + char rvend = 0; + char fdoinput = 1; + uchar c; +#ifdef WIN32 + uchar c1, c2, c3; + unsigned long dwKeyCode; +#endif + + memset(&payload, 0, sizeof(payload)); + length = 0; + rs.len = 0; + + if ((fdebug > 2) && (ilen > 4)) + dbg_dump("sol_input dump:",input,ilen,1); + // i = 0; + for (i = 0; i < ilen; i++) + { + if (fdebug > 2) + dbglog("sol_input keys[%d]: %02x %02x %02x %02x, ilen=%d\n", + i, input[i], input[i+1], input[i+2], input[i+3], ilen); + /* look for console escape sequences (~) */ + + if (sol_esc_pending) { + sol_esc_pending = 0; + /* next char in 2-char esc seq */ +#ifdef WIN32 + if ( ((input[i+3] & 0x01) == 0) || /* h.o byte, if not keydown */ + (i < 0)) { /* skip h.o. bytes in dwChar for windows */ + fdoinput = 0; /*skip this input*/ + sol_esc_pending = 1; /*if here, esc was pending*/ + if (fdebug > 2) + dbglog("sol_input: skip, %02x!=X1 for i=%d\n",input[i+3],i); + } else +#endif + switch(input[i]) { + case '.': + dbglog("sol_input RV_END (%02x %02x)\n",sol_esc_ch,input[i]); + rvend = 1; + fdoinput = 0; + break; + case 'b': + case 'B': + rv = send_break(); + fdoinput = 0; + break; + case 'd': + case 'D': + rv = send_ctlaltdel(); + fdoinput = 0; + break; + case '?': + show_esc_help(); + fdoinput = 0; + break; + default: + /* includes entering "~~" to output '~' */ + dbglog("sol_input sol_esc no match (%02x %02x/%c%c)\n", + sol_esc_ch,input[i], sol_esc_ch,input[i]); + fdoinput = 1; + break; + } + } else if (input[i] == sol_esc_ch) { + /* start of new sol_esc seq */ + if (fdebug > 2) + dbglog("sol_input esc_pending (%02x %02x)\n",input[i],input[i+1]); + if ((sol_esc_len == 1) || + ((ilen > (i+1)) && (input[i+1] == '.')) ) { /*then exit now*/ + dbglog("sol_input RV_END (%02x %02x)\n",input[i],input[i+1]); + rvend = 1; + } + fdoinput = 0; + sol_esc_pending = 1; + } + else fdoinput = 1; /*send as normal input*/ + + if (fdoinput) + { + c = input[i]; +#ifdef WIN32 + c1 = input[i+1]; + c2 = input[i+2]; + c3 = input[i+3]; + + dwKeyCode = (c << 24) | (c1 << 16) | (c2 << 8) | c3; + dbglog("sol_input[%d]: KeyCode=0x%08X, '%c'\n", + i, dwKeyCode, (0x20 <= c && c <= 0x7E ? c : '.') ); + + /* check Windows input to see if it should be sent */ + t = console_in(dwKeyCode, &payload[length], sizeof(payload) - length); + if (t > 0) length += t; + lastc = c; +#else + /* + * Linux end-of-line handling with fCRLF: + * (0) CR, (1) CR+LF, (2) LF + * Note that the CR+LF logic works for BIOS, but causes + * extra returns after Linux commands. Using -l sets CR+LF. + * Using bTextMode detects if bg color, as in BIOS Setup + * or other apps that need CR+LF. + * + * If stty has '-onlcr', then LF (fCRLF=2) is fine, but + * if stty has 'onlcr', LF causes two output lines, + * so CR is the default (fCRLF=0), which works for + * either 'onlcr' or '-onlcr'. + * Using -r (fRaw) has the same effect as LF (fCRLF=2). + */ + if (c == CH_LF && !fRaw) { // input=enter/LF and not raw (-r) + if ((fCRLF == 1) || (bTextMode > 40)) { /*-l option or bg color*/ + /*CR+LF: insert CR here, LF below*/ + payload[length++] = CH_CR; + } + else if (fCRLF == 2) ; /*LF: same as raw, use CH_LF*/ + else c = CH_CR; /* CR: switch LF to CR */ + } + /* copy other data to payload */ + payload[length++] = c; + lastc = c; + if (c == CH_CR || c == CH_LF) + dbglog("sol_input[%d] payload: %02x %02x, bTextMode=%d\n", + i,payload[0],payload[1],bTextMode); +#endif + if (length >= max_bmc_data) { /*overflow, truncate*/ + dbglog("sol_send: ilen(%d) >= BMC max data(%d), truncated\n", + ilen,max_bmc_data); + break; + } else if (length >= sizeof(payload)) { /*overflow, truncate*/ + dbglog("sol_send: ilen(%d) >= buffer size(%d), truncated\n", + ilen,sizeof(payload)); + break; + } + } /*endif fdoinput*/ +#ifdef WIN32 + i += 3; /*increment to next dwKeyCode (3+1)*/ +#endif + } /*end-for input[ilen] */ + + if (length > 0) { + /* Send the SOL payload */ + for (t = 0; t < sol_retries; t++) + { + if (t > 0) + os_usleep(0,(retry_time * 1000)); /*wait between retries 5000 us*/ + rv = sol_send(payload, length, &rs); + dbglog("sol_send(%d,%d) rv=%d rs.len=%d\n", t,length,rv,rs.len); + if (rv >= 0) { /* rv ok */ + if (rs.len != 0) { /* have some rsp data, so handle it */ + if (rs.type == IPMI_PAYLOAD_TYPE_SOL) { + dbglog("output: handler(%d)\n",rs.len); + sol_output_handler(&rs); + } else { + dbglog("WARNING: after sol_send, rs.type=%d, not SOL\n",rs.type); + } + } /*endif have rsp data*/ + rv = 0; /*recvd something, so dont retry */ + } + if (rv == 0) break; + /* else retry again if rv < 0 or rv == 0x02 */ + } /*end for loop*/ + if (rv < 0) rv = LAN_ERR_DROPPED; + } + if (rvend) rv = RV_END; + return(rv); +} + +static int send_activate_15sol(void) +{ + int rv = 0; + uchar actcmd; + uchar netfn; + uchar ibuf[64]; + uchar rbuf[64]; + int rlen; + uchar ilen, cc; + + lan_get_sol_data(fSolEncryption,sol15_iseed,&sol15_wseed); + actcmd = (uchar)(ACTIVATE_SOL1 & 0x00ff); + netfn = NETFN_SOL; + if (fSolEncryption) ibuf[0] = 0x11; /* use encryption, activate SOL */ + else ibuf[0] = 0x01; /*no encryptionn, no serial alerts, activate SOL */ + memcpy(&ibuf[1],&sol15_wseed,4); /*32-bit seed*/ + ilen = 5; + rlen = sizeof(rbuf); + rv = ipmi_cmdraw(actcmd,netfn,BMC_SA, PUBLIC_BUS, BMC_LUN, + ibuf,ilen,rbuf,&rlen,&cc,fdebug); + if (rv == 0 && cc != 0) rv = cc; + /* switch(cc) { case 0x80: SOL already active on another session + * case 0x81: SOL disabled + * case 0x82: SOL activation limit reached } + */ + if (rv == 0) { /*success*/ + dbg_dump("sol 15 act_resp",rbuf,rlen,0); + /* sol 15 act_resp (len=4): 0000: 00 01 64 64 */ + /* 00=auth, 01=seed_cnt, 64=in_payload_sz, 64=out_payload_sz */ + lan_set_sol_data(fSolEncryption,rbuf[0],rbuf[1], rbuf[2], rbuf[3]); + } + return(rv); +} + +static int send_deactivate_15sol(void) +{ + int rv = -1; + + uchar actcmd; + uchar netfn; + uchar ibuf[64]; + uchar rbuf[64]; + int rlen; + uchar ilen, cc; + + /* SOL for IPMI 1.5 does not have an explicit deactivate, so + * use an activate with data0 = 00. + */ + actcmd = (uchar)(ACTIVATE_SOL1 & 0x00ff); + netfn = NETFN_SOL; + if (fSolEncryption) ibuf[0] = 0x10; /* deactivate, use encryption */ + else ibuf[0] = 0x00; /*deactivate*/ + memcpy(&ibuf[1],&sol15_wseed,4); /*32-bit seed*/ + ilen = 5; + rlen = sizeof(rbuf); + rv = ipmi_cmdraw(actcmd,netfn,BMC_SA, PUBLIC_BUS, BMC_LUN, + ibuf,ilen,rbuf,&rlen,&cc,fdebug); + if (rv == 0 && cc != 0) rv = cc; + dbg_dump("sol 15 deact_resp",rbuf,rlen,0); /* 80 00 32 ff */ + return(rv); +} + +int send_activate_sol(uchar verSOL) +{ + int rv = 0; + int in_payload_size, out_payload_size, udp_port; + uchar actcmd; + uchar netfn; + uchar ibuf[64]; + uchar rbuf[64]; + int rlen; + uchar ilen, cc; + + sol_ver = verSOL; + /* activate SOL = 0x01, get SOL status = 0x05 */ + if (verSOL == 1) { + rv = send_activate_15sol(); + return(rv); + } else { /* use IPMI 2.0 method */ + actcmd = ACTIVATE_PAYLOAD; + netfn = NETFN_APP; + ibuf[0] = PAYLOAD_TYPE_SOL; + ibuf[1] = payload_instance; /* payload instance */ + ibuf[2] = SOL_SERIAL_ALERT_MASK_DEFERRED; + if (fSolEncryption) ibuf[2] |= 0x80; + if (fSolAuthentication) ibuf[2] |= 0x40; + if (vend_id == VENDOR_INTEL) + ibuf[2] |= SOL_BMC_ASSERTS_CTS_MASK_TRUE; + else ibuf[2] |= SOL_BMC_ASSERTS_CTS_MASK_FALSE; + ibuf[3] = 0; + ibuf[4] = 0; + ibuf[5] = 0; + ilen = 6; + } + rlen = sizeof(rbuf); + rv = ipmi_cmdraw(actcmd,netfn,BMC_SA, PUBLIC_BUS, BMC_LUN, + ibuf,ilen,rbuf,&rlen,&cc,fdebug); + dbg_dump("sol act_cmd",ibuf,ilen,0); + dbglog("send_activate v2(%x,%x) rv = %d cc = %x\n",actcmd,netfn,rv,cc); + if (rv >= 0) { + rv = cc; + switch(cc) { + case 0x00: + if (rlen != 12) { + printm("Unexpected SOL response data received, len=%d\n",rlen); + rv = -1; + } + break; + case 0x80: + printm("SOL payload already active on another session\n"); + break; + case 0x81: + printm("SOL payload disabled\n"); + break; + case 0x82: + printm("SOL payload activation limit reached\n"); + break; + case 0x83: + printm("Cannot activate SOL payload with encryption\n"); + break; + case 0x84: + printm("Cannot activate SOL payload without encryption\n"); + break; + default: + printm("Cannot activate SOL, ccode = 0x%02x\n",cc); + break; + } + } + if (rv == 0) { /* success, use the response data */ + /* only here if response data is from IPMI 2.0 method */ + dbg_dump("sol act_resp",rbuf,rlen,0); + in_payload_size = rbuf[4] + (rbuf[5] << 8); + out_payload_size = rbuf[6] + (rbuf[7] << 8); + udp_port = rbuf[8] + (rbuf[9] << 8); + dbglog("activate ok, in=%d out=%d port=%d\n", + in_payload_size, out_payload_size, udp_port); + if (bSolVer == 2) + lan2_set_sol_data(in_payload_size, out_payload_size, udp_port, + (void *)lan2_recv_handler, sol_esc_ch); + } + return(rv); +} + +int send_deactivate_sol(uchar verSOL) +{ + int rv = 0; + uchar deactcmd; + uchar netfn; + uchar ibuf[64]; + uchar rbuf[64]; + int rlen; + uchar ilen, cc; + + if (verSOL == 1) { + return(send_deactivate_15sol()); + } else { /* use IPMI 2.0 method */ + deactcmd = DEACTIVATE_PAYLOAD; + netfn = NETFN_APP; + ibuf[0] = PAYLOAD_TYPE_SOL; /* payload type */ + ibuf[1] = payload_instance; /* payload instance */ + ibuf[2] = 0; + ibuf[3] = 0; + ibuf[4] = 0; + ibuf[5] = 0; + ilen = 6; + } + rlen = sizeof(rbuf); + rv = ipmi_cmdraw(deactcmd,netfn,BMC_SA, PUBLIC_BUS, BMC_LUN, + ibuf,ilen,rbuf,&rlen,&cc,fdebug); + dbglog("sol deactivate rv = %d, cc = %x\n",rv,cc); + if (rv == 0 && cc != 0) rv = cc; + return(rv); +} + +int sol_data_loop( void ) +{ + int istdin; + int rv = 0; + uchar ibuf[IDATA_SZ]; + uchar cbuf[IDATA_SZ]; + int szibuf, szcbuf; + SockType fd; + int len; + fd_set read_fds; + fd_set error_fds; + static uchar lastc = 0; + int c; +#ifdef WIN32 + int c1; + time_t ltime1 = 0; + time_t ltime2 = 0; + HANDLE thnd; + istdin = 0; +#else + long ltime1 = 0; + long ltime2 = 0; + istdin = fileno(stdin); +#endif + + /* + * OK, now loop and listen to + * stdin for user input + * interface fd for incoming SOL data + */ + /* sizeof(ibuf/cbuf)=IDATA_SZ(512), max_bmc_data=203 for sol data */ + szibuf = max_bmc_data; + szcbuf = max_bmc_data; + fd = sol_get_fd(); + if (fScript) { /* open file_scr */ + fp_scr = fopen(file_scr,"r"); + if (fp_scr == NULL) { + printm("Cannot open %s, ignoring\n",file_scr); + fScript = 0; + } + } + if (fTrace) { /* open file_trc for writing */ + fp_trc = fopen(file_trc,"a"); + if (fp_trc == NULL) { + printm("Cannot open %s, ignoring\n",file_trc); + fTrace = 0; + } + } + + dbglog("stdin = %d, intf->fd = %d\n",istdin,fd); + if (sol_esc_len == 1) + printf("[SOL session is running, use '%c' to end session.]\n",sol_esc_ch); + else + printf("[SOL session is running, use '%c.' to end, '%c?' for help.]\n", + sol_esc_ch, sol_esc_ch); + + tty_setraw(2); + sol_keepalive_reset(); +#ifdef WIN32 + thnd = CreateThread(NULL, 0, &input_thread, NULL, 0, NULL); + if (thnd == NULL) { + printm("CreateThread error, aborting\n"); + rv = -1; + sol_done = 1; + } + console_open(fdebug); +#else + if (bSolVer == 1) { /* jump start the session v1.5 data */ + ibuf[0] = 0x1b; /*escape*/ + ibuf[1] = '{'; + rv = sol_input_handler(ibuf,2); + } +#endif + if (fdbglog) time((time_t *)<ime1); + + while (sol_done == 0) + { + if (bKeepAlive > 0) { /* send KeepAlive if needed */ + rv = sol_keepalive(bKeepAlive); + /* if keepalive error, try to keep going anyway */ + } + if (fdebug > 2) dbglog("os_select(%d,%d) called\n",istdin,fd); + + rv = os_select(istdin,fd, &read_fds, &error_fds); + if (rv < 0) { + dbglog("os_select(%d,%d) error %d\n",istdin,fd,rv); + perror("select"); + sol_done = 1; + } else if (rv > 0) { + if (fdbglog) { + time((time_t *)<ime2); + dbglog("select rv = %d sockfd=%x stdin=%x time=%ld\n", rv, + FD_ISSET(fd, &read_fds),FD_ISSET(istdin, &read_fds), + (ltime2 - ltime1)); + } + + if (FD_ISSET(fd, &read_fds)) { + SOL_RSP_PKT rs; + rs.len = 0; + /* receive output from BMC SOL */ + rv = sol_recv(&rs); +#ifdef WIN32 + /* Windows sometimes gets rv = -1 here */ + if (rv == -1) rv = -(WSAGetLastError()); +#endif + dbglog("output: recv rv = %d, len = %d\n",rv,rs.len); + if (rv < 0) { + dbglog("Error %d reading SOL socket\n",rv); + printm("Error %d reading SOL socket\n",rv); + sol_done = 1; + } else { + /*sol_output_handler sets fgotrecv*/ + sol_output_handler(&rs); + sol_keepalive_reset(); + /* go back to select until there is no more socket data */ + continue; + } + } /*endif fd*/ + + if (FD_ISSET(fd, &error_fds)) { + dbglog("Error selecting SOL socket\n",rv); + } /*endif fd*/ + + if (FD_ISSET(istdin, &read_fds)) { + /* input from stdin (user) if not WIN32 */ + memset(ibuf,0,szibuf); + len = os_read(istdin, ibuf, szibuf); + dbglog("stdin: read len=%d, %02x %02x %02x %02x\n", + len,ibuf[0],ibuf[1],ibuf[2],ibuf[3]); + if (len <= 0) { + dbglog("Error %d reading stdin\n",len); + printm("Error %d reading stdin\n",len); + sol_done = 1; + } else { + rv = sol_input_handler(ibuf,len); + dbglog("sol_input: handler rv = %d\n",rv); + if (rv < 0) { + sol_done = 1; + if (rv == RV_END) { + dbglog("sol_data RV_END\n"); + printf("\n%s exit via user input \n",progname); + } /* else drop through to show_outcomes */ + } + else sol_keepalive_reset(); + } + } /*endif stdin*/ + + } /*endif select rv > 0 */ + else if (fScript) { /*rv == 0*/ + /* if we sent a script line, but no receive yet, keep waiting*/ + if (fsentok && (fgotrecv == 0)) { + dbglog("sol_data script sentok, but no recv\n"); + // continue; + } + fsentok = 0; + /* read input stream from script file */ + memset(cbuf,0,szcbuf); + /* read one line at a time */ + rv = 0; + for (len = 0; len < szcbuf; ) { + c = fgetc(fp_scr); + if (c == EOF) { rv = -2; break; } +#ifdef WIN32 + if ((c == '\n') && (lastc != '\r')) c1 = '\r'; /*Enter*/ + else c1 = c; + Ascii2KeyCode((uchar)c1,&cbuf[len]); + len += 4; +#else + cbuf[len++] = c; +#endif + if (c == '\n') break; + lastc = (uchar)c; + } + dbglog("script: read len=%d, %02x %02x %02x\n", + len,cbuf[0],cbuf[1],cbuf[2]); + if (rv != 0 || len == 0) { + dbglog("Stop reading file %s, rv=%d\n",file_scr,rv); + fclose(fp_scr); + fScript = 0; + } else { + /* TODO: add processing for some wait/sleep/prompt commands */ + rv = sol_input_handler(cbuf,len); + dbglog("input: handler rv = %d\n",rv); + if (rv < 0) { + sol_done = 1; + if (rv == RV_END) { + dbglog("sol_data RV_END\n"); + printf("\n%s exit via user input \n",progname); + } else printf("Error %d processing input\n",rv); + } else { + fsentok = 1; /*sent a script line successfully*/ + fgotrecv = 0; /*need to wait for recv*/ + } + } + } /*endif fScript*/ + } /*end while*/ + if (rv == RV_END) rv = 0; +#ifdef WIN32 + os_usleep(0,5000); /*wait 5 ms for thread to close itself*/ + CloseHandle(thnd); + console_close(); +#endif + tty_setnormal(2); + if (fScript) fclose(fp_scr); /* close file_scr */ + if (fTrace) fclose(fp_trc); /* close file_trc */ + return(rv); +} + +static void show_usage(void) +{ + printf("Usage: %s [-acdeiolnrsvxz -NUPREFTVY]\n", progname); + printf(" where -a activate SOL console session\n"); + printf(" -d deactivate SOL console session\n"); + printf(" -c'^' set escape Char to '^', default='~'\n"); + printf(" -e Encryption off for SOL session\n"); + printf(" -i file Input script file\n"); + printf(" -o file Output trace file\n"); + printf(" -l Legacy mode for BIOS/DOS CR+LF\n"); + printf(" -n 1 Payload instance Number, default=1\n"); + printf(" -r Raw termio, no VT-ANSI translation\n"); + printf(" -s NNN Slow link delay, default=100usec\n"); +#ifdef NOT_DOCUMENTED + printf(" -t N SOL send timeout reTries, default=1\n"); + printf(" -u N Wait time in msec for tuning, default=500\n"); +#endif +#ifdef WIN32 + printf(" -w do not use Windows Console buffer, use stdio\n"); +#endif + printf(" -v debug log filename (default=isoldbg.log)\n"); + printf(" -x show eXtra debug messages in debug log\n"); + printf(" -z show even more debug messages\n"); + print_lan_opt_usage(); +} + +#ifdef METACOMMAND +int i_sol(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret = 0; + int i; + uchar devrec[16]; + uchar bmcver[2]; + int c; + + printf("%s ver %s\n", progname,progver); + + parse_lan_options('V',"2",0); /*default to user priv*/ + + while ( (c = getopt( argc, argv,"ac:dei:k:ln:o:rs:t:u:wv:xzEF:J:N:P:R:T:U:V:YZ:?")) != EOF ) + switch(c) { + case 'a': factivate = 1; break; /*activate*/ + case 'd': fdeactivate = 1; break; /*deactivate*/ + case 'c': /* escape char */ + if (strncmp(optarg,"0x",2) == 0) + sol_esc_ch = htoi(&optarg[2]); /*hex char value*/ + else if (optarg[0] >= '0' && optarg[0] <= '9') + sol_esc_ch = atob(optarg); /*decimal char value*/ + else sol_esc_ch = optarg[0]; /*single ascii char*/ + sol_esc_len = 1; /*set single-char esc sequence */ + break; + case 'e': fSolEncryption = 0; break; /*encryption off*/ + case 'k': i = atoi(optarg); /*sol keepalive timeout, default = 30*/ + if (i < 0) + printf("Invalid keepalive timeout %d, ignoring.\n",i); + else sol_timeout = i; + if (i == 0) bKeepAlive = 0; + if (i == 32) bKeepAlive = 2; /*++++ for debug*/ + break; + case 'l': fCRLF = 1; break; /*do legacy CR+LF translation*/ + case 'i': strncpy(file_scr,optarg,sizeof(file_scr)); + fScript = 1; break; /*script input file*/ + case 'n': i = atoi(optarg); /* payload_instance */ + if ((i <= 0) || (i > 255)) + printf("Invalid payload instance %d, ignoring.\n",i); + else payload_instance = i; + break; + case 'o': strncpy(file_trc,optarg,sizeof(file_trc)); + fTrace = 1; break; /*trace output file*/ + case 'r': fRaw = 1; fCRLF = 0; fUseWinCon = 0; + break; /*raw termio, xlate off*/ + case 's': sol_recvdelay = atoi(optarg); break; /*slow recv delay*/ + case 't': sol_retries = atoi(optarg); break; /*timeout/retries*/ + case 'u': wait_time = atoi(optarg); break; /*wait_time for tuning*/ + case 'v': strncpy(dbglog_name,optarg,sizeof(dbglog_name)); + fdbglog = 1; break; /*name of debug log file*/ + case 'w': fUseWinCon = 0; break; /*do not use Console routines*/ + case 'x': + if (fdebug == 0) fdebug = 2; /*only normal via dbglog */ + else fdebug++; /* -xx = full, -xxx = max */ + break; + case 'z': fdebug = 3; break; /*full debug messages */ + case 'V': /* priv level */ + fprivset = 1; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + show_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + if (is_remote() == 0) { /* no node specified */ + printf("Serial-Over-Lan Console requires a -N nodename\n"); + ret = ERR_BAD_PARAM; + goto do_exit; + } + if (fdeactivate && !fprivset) + parse_lan_options('V',"4",0); /*deactivate requires admin priv */ + + /* fdebug: 1=debug/no packets, 2=debug log only, 3=full debug, 4=max debug*/ + if (fdebug > 1) fdbglog = 1; + + if (factivate == 0 && fdeactivate == 0) { + show_usage(); + printf("Error: Need either -a or -d for sol\n"); + ret = ERR_BAD_PARAM; + goto do_exit; + } +#ifdef WIN32 + else if (factivate) { + if (fdebug) printf("%s activate, connecting ...\n", progname); + } +#endif + if (fdbglog) { + // strcpy(log_name,dbglog_name); + open_log(dbglog_name); + dbglog("%s ver %s\r\n", progname,progver); + } + + i = get_driver_type(); /*see if user explictly set type*/ + if (i == DRV_UNKNOWN) bDriver = DRV_UNKNOWN; /*no driver type specified*/ + else bDriver = (uchar)i; + + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + goto do_exit; + } else { + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + prod_id = devrec[9] + (devrec[10] << 8); + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + bmcver[0] = devrec[2]; + bmcver[1] = devrec[3]; + switch(vend_id) { + case VENDOR_DELL: /*Dell == 0x0002A2*/ + max_bmc_data = MAX_DELL_DATA; /*shorter max data*/ + break; + case VENDOR_SUPERMICRO: + case VENDOR_LMC: + case VENDOR_PEPPERCON: /* 0x0028C5 Peppercon/Raritan*/ + sol_timeout = 10; /* shorter 10 sec SOL keepalive timeout */ + max_bmc_data = MAX_OTHER_DATA; + break; + case VENDOR_INTEL: + max_bmc_data = MAX_INTEL_DATA; + break; + case VENDOR_KONTRON: + max_bmc_data = MAX_KONTRON_DATA; + // bKeepAlive = 1; + break; + default: + max_bmc_data = MAX_OTHER_DATA; + break; + } + } + + ret = ipmi_getpicmg(devrec,16,fdebug); + if (ret == 0) fpicmg = 1; + + dbglog("driver=%d fdebug=%d vend_id=%x bmcver=%x.%x ipmi %d.%d\n", + bDriver,fdebug,vend_id,bmcver[0],bmcver[1],ipmi_maj,ipmi_min); + /* check for SOL support */ + if (ipmi_maj >= 2) { + if ((bDriver == DRV_LAN) && (vend_id == VENDOR_INTEL)) { + /* user specified to use IPMI LAN 1.5 SOL on Intel */ + bSolVer = 1; /*IPMI 1.5 SOL*/ + } else { + bSolVer = 2; /*IPMI 2.0 SOL*/ + if (get_driver_type() == DRV_LAN) { /*now using IPMI LAN 1.5*/ + char *ptyp; + ipmi_close_(); /*close current IPMI LAN 1.5*/ + if (is_lan2intel(vend_id,prod_id)) ptyp = "lan2i"; + else ptyp = "lan2"; + i = set_driver_type(ptyp); /*switch to IPMI LAN 2.0*/ + } + } + } else if (ipmi_maj == 1) { + if (ipmi_min >= 5) bSolVer = 1; /* IPMI 1.5 */ + else bSolVer = 0; /* IPMI 1.0 */ + } else bSolVer = 0; + if (bSolVer == 0) { + printf("Serial Over Lan not supported for this IPMI version\n"); + ret = LAN_ERR_NOTSUPPORT; + goto do_exit; + } +#ifndef HAVE_LANPLUS + if (bSolVer == 2) { + printf("2.0 LanPlus module not available, trying 1.5 SOL instead\n"); + bSolVer = 1; + } +#endif + /* May also want to verify that SOL is implemented here */ + + /* + * Spawn a console raw terminal thread now, which will wait for the + * "Activating cmd (0x02)" on success + * Using globals: gnode,guser,gpswd, gauth_type, gpriv_level + */ + if (fdeactivate) { + /* Request admin privilege by default, since deactivate requires it. */ + ret = send_deactivate_sol(bSolVer); + dbglog("send_deactivate_sol rv = %d\n",ret); + } else if (factivate) { + ret = send_activate_sol(bSolVer); + dbglog("send_activate_sol(%d) rv = %d\n",bSolVer,ret); + if (bSolVer == 2) { + lan2_latency = lan2_get_latency(); + retry_time = lan2_latency; + dbglog("lan2_latency = %ld msec (slow > %ld msec)\n", + lan2_latency,lan2_slow); + if ((sol_recvdelay == 0) && (lan2_latency > lan2_slow)) + sol_recvdelay = 500; /* it is slow, set recvdelay */ + if (sol_recvdelay != 0) { + dbglog("set_recvdelay to %dus\n",sol_recvdelay); + lanplus_set_recvdelay(sol_recvdelay); + } + } /*endif bSolVer==2*/ + if (ret == 0) { + ret = sol_data_loop(); + } /*endif activate ok*/ + } /*endif do activate */ + +do_exit: + if (ret != LAN_ERR_DROPPED) { /*if link dropped, no need to close*/ + ipmi_close_(); + os_usleep(0,(wait_time * 1000)); /*wait 0.5 sec for BMC teardown*/ + } + if (fdebug) show_outcome(progname,ret); + if (fdbglog) close_log(); + return(ret); +} /* end main()*/ +#endif + +/* end isol.c */ diff --git a/util/isolwin.c b/util/isolwin.c new file mode 100644 index 0000000..b8f7926 --- /dev/null +++ b/util/isolwin.c @@ -0,0 +1,293 @@ +/* + * isolwin.c + * IPMI Serial-Over-LAN console Windows terminal emulation + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 08/20/07 Andy Cress - extracted from isolconsole.c/WIN32, + * added os_usleep to input_thread + * 09/24/07 Andy Cress - various termio fixes, e.g. scroll(), BUF_SZ + */ +/*M* +Copyright (c) 2006-2007, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#include <windows.h> +#include <stdio.h> +#include <winsock.h> +#include <io.h> +#include <conio.h> +#include <string.h> +#include <time.h> + +#define SockType SOCKET +typedef struct { + int type; + int len; + char *data; + } SOL_RSP_PKT; + +extern void dbglog( char *pattn, ... ); /*from isolconsole.c*/ +extern void os_usleep(int s, int u); /*from ipmilan.c*/ + +typedef unsigned char uchar; + +/* + * Global variables + */ +extern int sol_done; +extern char fUseWinCon; +extern uchar fRaw; +extern uchar fCRLF; /* =1 to use legacy CR+LF translation for BIOS */ +extern uchar bTextMode; +extern char fdebug; /*from isolconsole.c*/ +extern int wait_time; /*from isolconsole.c*/ + +/*======== start Windows =============================*/ + /* Windows os_read, os_select and supporting code */ +#define INBUF_SZ 128 +static DWORD rg_stdin[INBUF_SZ]; +static int n_stdin = 0; +#define NSPECIAL 33 +static struct { uchar c; uchar code[4]; } special_keys[NSPECIAL] = { + ' ', {0x20,0x20,0x01,0x01}, + '!', {0x21,0x31,0x01,0x21}, + '"', {0x22,0xde,0x01,0x21}, + '#', {0x23,0x33,0x01,0x21}, + '$', {0x24,0x34,0x01,0x21}, + '%', {0x25,0x35,0x01,0x21}, + '&', {0x26,0x37,0x01,0x21}, + 0x27, {0x27,0xde,0x01,0x01}, /*'''*/ + '(', {0x28,0x39,0x01,0x21}, + ')', {0x29,0x30,0x01,0x21}, + '*', {0x2a,0x38,0x01,0x21}, + '+', {0x2b,0xbb,0x01,0x21}, + ',', {0x2c,0xbc,0x01,0x01}, + '-', {0x2d,0xbd,0x01,0x01}, + '.', {0x2e,0xbe,0x01,0x01}, + '/', {0x2f,0xbf,0x01,0x01}, + ':', {0x3a,0xba,0x01,0x21}, + ';', {0x3b,0xba,0x01,0x01}, + '<', {0x3c,0xbc,0x01,0x21}, + '=', {0x3d,0xbb,0x01,0x01}, + '>', {0x3e,0xbe,0x01,0x21}, + '?', {0x3f,0xbf,0x01,0x21}, + '@', {0x40,0x32,0x01,0x21}, + '[', {0x5b,0xdb,0x01,0x01}, + 0x5c, {0x5c,0xdc,0x01,0x01}, /*'\'*/ + ']', {0x5d,0xdd,0x01,0x01}, + '^', {0x5e,0x36,0x01,0x21}, + '_', {0x5f,0xbd,0x01,0x21}, + '`', {0x60,0xc0,0x01,0x01}, + '{', {0x7b,0xdb,0x01,0x21}, + '|', {0x7c,0xdc,0x01,0x21}, + '}', {0x7d,0xdd,0x01,0x21}, + '~', {0x7e,0xc0,0x01,0x21} +}; + +void Ascii2KeyCode(uchar c, uchar *buf) +{ + int i; + int j = 0; + /* Convert ascii chars from script file into KeyCodes*/ + for (i = 0; i < NSPECIAL; i++) + if (c == special_keys[i].c) break; + if (i < NSPECIAL) { /* special chars */ + buf[j++] = c; + buf[j++] = special_keys[i].code[1]; + buf[j++] = special_keys[i].code[2]; + buf[j++] = special_keys[i].code[3]; + } else if (c < 0x0D) { /* control chars, like Ctl-c */ + buf[j++] = c; + buf[j++] = (c | 0x40); + buf[j++] = 0x01; + buf[j++] = 0x41; + } else { /* alphanumeric chars */ + buf[j++] = c; + if (c > 0x60) + buf[j++] = c - 0x20; /*drop 0x20 bit if upper case*/ + else buf[j++] = c; + buf[j++] = 0x01; + buf[j++] = 0x01; + } +} + +DWORD WINAPI input_thread( LPVOID lpParam) +{ + HANDLE hstdin; + DWORD rv = 0; + INPUT_RECORD inrecords[10]; + DWORD nread; + DWORD oldmode; + + hstdin = GetStdHandle(STD_INPUT_HANDLE); + + GetConsoleMode(hstdin, &oldmode); + SetConsoleMode(hstdin, ENABLE_WINDOW_INPUT); + + while (!sol_done) + { + DWORD dwResult = WaitForSingleObject(hstdin, wait_time * 2); /*1000 msec*/ + + if (dwResult != WAIT_OBJECT_0) + { + if (dwResult != WAIT_TIMEOUT) + dbglog("input_thread: Wait result = %x\n",dwResult); + continue; + } + + if (ReadConsoleInput(hstdin, inrecords, 10, &nread)) + { + DWORD index; + + for (index = 0; index < nread; index++) + { + /* Pack the char info into a DWORD */ + INPUT_RECORD *precord = &inrecords[index]; + DWORD dwChar; + + if (precord->EventType == KEY_EVENT) + { + if (precord->Event.KeyEvent.wVirtualKeyCode == VK_SHIFT || + precord->Event.KeyEvent.wVirtualKeyCode == VK_CONTROL || + precord->Event.KeyEvent.wVirtualKeyCode == VK_MENU || + precord->Event.KeyEvent.wVirtualKeyCode == VK_CAPITAL) + { + continue; + } + + dwChar = (((precord->Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0) << 31) | + (((precord->Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0) << 30) | + (((precord->Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) != 0) << 29) | + (((precord->Event.KeyEvent.dwControlKeyState & NUMLOCK_ON) != 0) << 28) | + (((precord->Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON) != 0) << 27) | + (((precord->Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON) != 0) << 26) | + (((precord->Event.KeyEvent.dwControlKeyState & ENHANCED_KEY) != 0) << 25) | + ((precord->Event.KeyEvent.bKeyDown != 0) << 24) | + ((precord->Event.KeyEvent.wRepeatCount & 0xFF) << 16) | + ((precord->Event.KeyEvent.wVirtualKeyCode & 0xFF) << 8) | + (precord->Event.KeyEvent.uChar.AsciiChar & 0xFF); + } + else if (precord->EventType == WINDOW_BUFFER_SIZE_EVENT) + { + dwChar = ~0; + } + else + { + continue; + } + if (precord->Event.KeyEvent.bKeyDown == 0) { + if (fdebug > 2) + dbglog("input_thread: key up event (%08x)\n",dwChar); + continue; + } + + if (n_stdin < INBUF_SZ) { /* rg_stdin[INBUF_SZ] */ + if (fdebug > 2) + dbglog("input_thread: n=%d dwChar=%08x keystate=%x\n", + n_stdin, dwChar, + precord->Event.KeyEvent.dwControlKeyState); + rg_stdin[n_stdin++] = dwChar; + } else + dbglog("input_thread: overflow n=%d size=%d\n", + n_stdin,INBUF_SZ); + } /*end-for nread*/ + } /*endif ReadConsoleInput*/ + } /*end-while not sol_done*/ + + SetConsoleMode(hstdin, oldmode); + + CloseHandle(hstdin); + + return(rv); +} + +int os_read(int fd, uchar *buf, int sz) +{ + int len = 0; + + if (fd == 0) { + if (n_stdin > 0) { + /* get pending chars from stdin */ + int cnt = n_stdin * sizeof(rg_stdin[0]); + if (fdebug > 2) + dbglog("os_read: stdin n=%d %04x %04x \n", + n_stdin,rg_stdin[0],rg_stdin[1]); + memcpy(buf, rg_stdin, cnt); + len = cnt; + n_stdin = 0; + memset((uchar *)&rg_stdin,0,cnt); + } + } else { + // ReadFile(fd, buf, sz, &len, NULL); + // len = _read(fd, buf, sz); + len = recv(fd, buf, sz, 0); + } + return(len); +} + +int os_select(int infd, SockType sfd, fd_set *read_fds, fd_set *error_fds) +{ + int rv = 0; + struct timeval tv; + + /* check the socket for new data via select */ + /* Windows select only works on WSA sockets */ + { + FD_ZERO(read_fds); + FD_SET(sfd, read_fds); + FD_ZERO(error_fds); + FD_SET(sfd, error_fds); + tv.tv_sec = 0; + tv.tv_usec = wait_time * 100; /* 50000 usec, 50 msec, 0.05 sec */ + // rv = select(sfd + 1, read_fds, NULL, error_fds, &tv); + rv = select((int)(sfd+1), read_fds, NULL, error_fds, &tv); + if (rv < 0) { + rv = -(WSAGetLastError()); + if (fdebug) dbglog("select(%d) error %d\r\n",sfd,rv); + } + else if (FD_ISSET(sfd, error_fds)) { + if (fdebug) dbglog("select(%d) error_fds rv=%d err=%d\r\n",sfd, rv, + WSAGetLastError()); + } + if (rv > 0 && fdebug) + dbglog("select(%d) got socket data %d\r\n",sfd,rv); + } + if (infd == 0) { /* check stdin */ + if (n_stdin > 0) { + FD_SET(infd, read_fds); + if (rv < 0) rv = 1; + else rv++; + } + } + return rv; +} +/*======== end Windows ===============================*/ + + +/*end solwin.c*/ diff --git a/util/itsol.c b/util/itsol.c new file mode 100644 index 0000000..dc4d9fb --- /dev/null +++ b/util/itsol.c @@ -0,0 +1,725 @@ +/* + * Copyright (c) 2005 Tyan Computer Corp. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#ifdef WIN32 +#include <windows.h> +#include <winsock.h> +#include <io.h> +#include <time.h> +#include "getopt.h" +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +typedef uint32_t socklen_t; +#define inet_ntop InetNtop +#define inet_pton InetPton +int InetPton(int af, char *pstr, void *addr); /*see ws2_32.dll*/ +char *InetNtop(int af, void *addr, char *pstr, int sz); +char *InetNtop(int af, void *addr, char *pstr, int sz) { return NULL; }; +int gettimeofday(struct timeval *tv, struct timezone *tz); +#undef POLL_OK + +#else +#include <unistd.h> +#include <errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/time.h> +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#undef POLL_OK +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#include <stdint.h> +#undef POLL_OK +#else +#include <getopt.h> +#include <sys/poll.h> +#define POLL_OK 1 +#endif + +#if defined (HAVE_SYS_TERMIOS_H) +#include <sys/termios.h> +#else +// #if defined(HAVE_TERMIOS_H) +#include <termios.h> +#endif + +#endif + +#include "ipmicmd.h" +#include "itsol.h" + +extern int verbose; +extern char fdebug; /*from ipmicmd.c*/ +static char * progname = "itsol"; +static char * progver = "2.93"; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static char hostname[SZGNODE]; +static SockType sockfd = -1; +static char sol_escape_char = '~'; +static struct timeval _start_keepalive; +static int _in_raw_mode = 0; +static int _altterm = 0; +static SOCKADDR_T haddr; +static int haddrlen = 0; +static int hauth, hpriv, hcipher; +#ifdef WIN32 +#define NI_MAXHOST 80 +#define NI_MAXSERV 80 +struct pollfd { int fd; short events; short revents; }; +struct winsize { int x; int y; }; +#else +static struct termios _saved_tio; +static struct winsize _saved_winsize; +#endif + + +static int +ipmi_tsol_command(void * intf, char *recvip, int port, unsigned char cmd) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char data[6]; + unsigned ip1, ip2, ip3, ip4; + + if (sscanf(recvip, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) != 4) { + lprintf(LOG_ERR, "Invalid IP address: %s", recvip); + return -1; + } + + memset(&req, 0, sizeof(struct ipmi_rq)); + req.msg.netfn = IPMI_NETFN_TSOL; + req.msg.cmd = cmd; + req.msg.data_len = 6; + req.msg.data = data; + + memset(data, 0, sizeof(data)); + data[0] = ip1; + data[1] = ip2; + data[2] = ip3; + data[3] = ip4; + data[4] = (port & 0xff00) >> 8; + data[5] = (port & 0xff); + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) { + lprintf(LOG_ERR, "Unable to perform TSOL command"); + return rv; + } + if (rv > 0) { + lprintf(LOG_ERR, "Unable to perform TSOL command: %s", + decode_cc(0,rv)); + return -1; + } + + return 0; +} + +static int +ipmi_tsol_start(void * intf, char *recvip, int port) +{ + return ipmi_tsol_command(intf, recvip, port, IPMI_TSOL_CMD_START); +} + +static int +ipmi_tsol_stop(void * intf, char *recvip, int port) +{ + return ipmi_tsol_command(intf, recvip, port, IPMI_TSOL_CMD_STOP); +} + +static int +ipmi_tsol_send_keystroke(void * intf, char *buff, int length) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char data[16]; + static unsigned char keyseq = 0; + + memset(&req, 0, sizeof(struct ipmi_rq)); + req.msg.netfn = IPMI_NETFN_TSOL; + req.msg.cmd = IPMI_TSOL_CMD_SENDKEY; + req.msg.data_len = length + 2; + req.msg.data = data; + + memset(data, 0, sizeof(data)); + data[0] = length + 1; + memcpy(data + 1, buff, length); + data[length + 1] = keyseq++; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (verbose) { + if (rv < 0) { + lprintf(LOG_ERR, "Unable to send keystroke"); + return rv; + } + if (rv > 0) { + lprintf(LOG_ERR, "Unable to send keystroke: %s", + decode_cc(0,rv)); + return -1; + } + } + + return length; +} + +static int +tsol_keepalive(void * intf) +{ + struct timeval end; + int rv; + + gettimeofday(&end, 0); + + if (end.tv_sec - _start_keepalive.tv_sec <= 30) + return 0; + + // intf->keepalive(intf); + rv = lan_keepalive(1); /*1=getdevid, 2=empty sol*/ + + gettimeofday(&_start_keepalive, 0); + + return rv; +} + +static void +print_escape_seq(void *intf) +{ + lprintf(LOG_NOTICE, + " %c. - terminate connection\r\n" + " %c^Z - suspend ipmiutil\r\n" + " %c^X - suspend ipmiutil, but don't restore tty on restart\r\n" + " %c? - this message\r\n" + " %c%c - send the escape character by typing it twice\r\n" + " (Note that escapes are only recognized immediately after newline.)\r", + sol_escape_char, + sol_escape_char, + sol_escape_char, + sol_escape_char, + sol_escape_char, + sol_escape_char); +} + +#ifdef WIN32 +static int leave_raw_mode(void) { return(0); } +static int enter_raw_mode(void) { return(0); } +static void set_terminal_size(int rows, int cols) { return; } +static void do_terminal_cleanup(void) { + int err; + err = get_LastError(); + lprintf(LOG_ERR, "Exiting due to error %d", err); + show_LastError("",err); +} +static void suspend_self(int restore_tty) { return; } +#else +static int +leave_raw_mode(void) +{ + if (!_in_raw_mode) + return -1; + else if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1) + lperror(LOG_ERR, "tcsetattr(stdin)"); + else if (tcsetattr(fileno(stdout), TCSADRAIN, &_saved_tio) == -1) + lperror(LOG_ERR, "tcsetattr(stdout)"); + else + _in_raw_mode = 0; + + return 0; +} + +static int +enter_raw_mode(void) +{ + struct termios tio; + + if (tcgetattr(fileno(stdout), &_saved_tio) < 0) { + lperror(LOG_ERR, "tcgetattr failed"); + return -1; + } + + tio = _saved_tio; + + if (_altterm) { + tio.c_iflag &= (ISTRIP | IGNBRK ); + tio.c_cflag &= ~(CSIZE | PARENB | IXON | IXOFF | IXANY); + tio.c_cflag |= (CS8 |CREAD) | (IXON|IXOFF|IXANY); + tio.c_lflag &= 0; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + } else { + tio.c_iflag |= IGNPAR; + tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); + tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN); + tio.c_oflag &= ~OPOST; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + } + + if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0) + lperror(LOG_ERR, "tcsetattr(stdin)"); + else if (tcsetattr(fileno(stdout), TCSADRAIN, &tio) < 0) + lperror(LOG_ERR, "tcsetattr(stdout)"); + else + _in_raw_mode = 1; + + return 0; +} + +static void +do_terminal_cleanup(void) +{ + if (_saved_winsize.ws_row > 0 && _saved_winsize.ws_col > 0) + ioctl(fileno(stdout), TIOCSWINSZ, &_saved_winsize); + + leave_raw_mode(); + + if (errno) + lprintf(LOG_ERR, "Exiting due to error %d -> %s", + errno, strerror(errno)); +} + +static void +set_terminal_size(int rows, int cols) +{ + struct winsize winsize; + + if (rows <= 0 || cols <= 0) + return; + + /* save initial winsize */ + ioctl(fileno(stdout), TIOCGWINSZ, &_saved_winsize); + + /* set new winsize */ + winsize.ws_row = rows; + winsize.ws_col = cols; + ioctl(fileno(stdout), TIOCSWINSZ, &winsize); +} + +static void +suspend_self(int restore_tty) +{ + leave_raw_mode(); + + kill(getpid(), SIGTSTP); + + if (restore_tty) + enter_raw_mode(); +} +#endif + +static int +do_inbuf_actions(void *intf, char *in_buff, int len) +{ + static int in_esc = 0; + static int last_was_cr = 1; + int i; + + for(i = 0; i < len ;) { + if (!in_esc) { + if (last_was_cr && + (in_buff[i] == sol_escape_char)) { + in_esc = 1; + memmove(in_buff, in_buff + 1, len - i - 1); + len--; + continue; + } + } + if (in_esc) { + if (in_buff[i] == sol_escape_char) { + in_esc = 0; + i++; + continue; + } + + switch (in_buff[i]) { + case '.': + printf("%c. [terminated ipmiutil]\r\n", + sol_escape_char); + return -1; + + case 'Z' - 64: + printf("%c^Z [suspend ipmiutil]\r\n", + sol_escape_char); + suspend_self(1); /* Restore tty back to raw */ + break; + + case 'X' - 64: + printf("%c^X [suspend ipmiutil]\r\n", + sol_escape_char); + suspend_self(0); /* Don't restore to raw mode */ + break; + + case '?': + printf("%c? [ipmiutil help]\r\n", + sol_escape_char); + print_escape_seq(intf); + break; + } + + memmove(in_buff, in_buff + 1, len - i - 1); + len--; + in_esc = 0; + + continue; + } + + last_was_cr = (in_buff[i] == '\r' || in_buff[i] == '\n'); + + i++; + } + + return len; +} + + +static void +print_tsol_usage(void) +{ + lprintf(LOG_NOTICE, "Usage: tsol [recvip] [port=NUM] [ro|rw] [rows=NUM] [cols=NUM] [altterm]"); + lprintf(LOG_NOTICE, " recvip Receiver IP Address [default=local]"); + lprintf(LOG_NOTICE, " port=NUM Receiver UDP Port [default=%d]", + IPMI_TSOL_DEF_PORT); + lprintf(LOG_NOTICE, " ro|rw Set Read-Only or Read-Write [default=rw]"); +#ifdef POLL_OK + { + struct winsize winsize; + ioctl(fileno(stdout), TIOCGWINSZ, &winsize); + lprintf(LOG_NOTICE, " rows=NUM Set terminal rows [default=%d]", + winsize.ws_row); + lprintf(LOG_NOTICE, " cols=NUM Set terminal columns [default=%d]", + winsize.ws_col); + } +#endif + lprintf(LOG_NOTICE, " altterm Alternate terminal setup [default=off]"); +} + + +int +ipmi_tsol_main(void * intf, int argc, char ** argv) +{ + char *recvip = NULL; + int result, i; + int ip1, ip2, ip3, ip4; + int read_only = 0, rows = 0, cols = 0; + int port = IPMI_TSOL_DEF_PORT; +#ifdef POLL_OK + SOCKADDR_T sin, myaddr; + socklen_t mylen; + struct pollfd fds_wait[3], fds_data_wait[3], *fds; + int fd_socket; + int out_buff_fill, in_buff_fill; + char out_buff[IPMI_BUF_SIZE * 8], in_buff[IPMI_BUF_SIZE]; + char buff[IPMI_BUF_SIZE + 4]; + char mystr[NI_MAXHOST]; +#endif + + if (! is_remote()) { + lprintf(LOG_ERR, "Error: Tyan SOL is only available over lan interface"); + return -1; + } + + for (i = 0; i<argc; i++) { + if (sscanf(argv[i], "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) == 4) + recvip = strdup_(argv[i]); + else if (sscanf(argv[i], "port=%d", &ip1) == 1) + port = ip1; + else if (sscanf(argv[i], "rows=%d", &ip1) == 1) + rows = ip1; + else if (sscanf(argv[i], "cols=%d", &ip1) == 1) + cols = ip1; + else if (strlen(argv[i]) == 2 && strncmp(argv[i], "ro", 2) == 0) + read_only = 1; + else if (strlen(argv[i]) == 2 && strncmp(argv[i], "rw", 2) == 0) + read_only = 0; + else if (strlen(argv[i]) == 7 && strncmp(argv[i], "altterm", 7) == 0) + _altterm = 1; + else if (strlen(argv[i]) == 4 && strncmp(argv[i], "help", 4) == 0) { + print_tsol_usage(); + return 0; + } + else { + print_tsol_usage(); + return 0; + } + } + + get_lan_options(hostname,NULL,NULL,&hauth, &hpriv, &hcipher,NULL,NULL); + result = open_sockfd(hostname, &sockfd, &haddr, &haddrlen, 1); + if (result) { + lperror(LOG_ERR, "Connect to %s failed",hostname); + return result; + } + +#ifdef WIN32 + /* TODO: implement terminal handling for Windows here. */ + printf("Windows TSOL terminal handling not yet implemented\n"); + if (recvip != NULL) + result = ipmi_tsol_stop(intf, recvip, port); + return LAN_ERR_NOTSUPPORT; +#elif defined(MACOS) + printf("MacOS TSOL terminal handling not yet implemented\n"); + if (recvip != NULL) + result = ipmi_tsol_stop(intf, recvip, port); + return LAN_ERR_NOTSUPPORT; +#else + /* + * retrieve local IP address if not supplied on command line + */ + if (recvip == NULL) { + set_lan_options(hostname,NULL,NULL,hauth, hpriv, hcipher, + (void *)&haddr,haddrlen); + result = ipmi_open(fdebug); /* must connect first */ + if (result < 0) + return -1; + + memset(&myaddr, 0, sizeof(myaddr)); + memset(mystr, 0, sizeof(mystr)); + mylen = sizeof(myaddr); + if (getsockname(sockfd, (struct sockaddr *)&myaddr, &mylen) < 0) { + lperror(LOG_ERR, "getsockname failed"); + return -1; + } + + recvip = (char *)inet_ntop(((struct sockaddr *)&myaddr)->sa_family, &myaddr, mystr, sizeof(mystr)-1); + if (recvip == NULL) { + lprintf(LOG_ERR, "Unable to find local IP address"); + return -1; + } + } + + printf("[Starting %sSOL with receiving address %s:%d]\r\n", + read_only ? "Read-only " : "", recvip, port); + + set_terminal_size(rows, cols); + enter_raw_mode(); + + /* + * talk to smdc to start Console redirect - IP address and port as parameter + * ipmiutil -I lan -H 192.168.168.227 -U Administrator raw 0x30 0x06 0xC0 0xA8 0xA8 0x78 0x1A 0x0A + */ + result = ipmi_tsol_start(intf, recvip, port); + if (result < 0) { + leave_raw_mode(); + lprintf(LOG_ERR, "Error starting SOL"); + return -1; + } + + printf("[SOL Session operational. Use %c? for help]\r\n", + sol_escape_char); + + gettimeofday(&_start_keepalive, 0); + + fd_socket = sockfd; + fds_wait[0].fd = fd_socket; + fds_wait[0].events = POLLIN; + fds_wait[0].revents = 0; + fds_wait[1].fd = fileno(stdin); + fds_wait[1].events = POLLIN; + fds_wait[1].revents = 0; + fds_wait[2].fd = -1; + fds_wait[2].events = 0; + fds_wait[2].revents = 0; + + fds_data_wait[0].fd = fd_socket; + fds_data_wait[0].events = POLLIN | POLLOUT; + fds_data_wait[0].revents = 0; + fds_data_wait[1].fd = fileno(stdin); + fds_data_wait[1].events = POLLIN; + fds_data_wait[1].revents = 0; + fds_data_wait[2].fd = fileno(stdout); + fds_data_wait[2].events = POLLOUT; + fds_data_wait[2].revents = 0; + + out_buff_fill = 0; + in_buff_fill = 0; + fds = fds_wait; + + for (;;) { + result = poll(fds, 3, 15*1000); + if (result < 0) + break; + + /* send keepalive packet */ + tsol_keepalive(intf); + + if ((fds[0].revents & POLLIN) && (sizeof(out_buff) > out_buff_fill)){ + socklen_t sin_len = sizeof(sin); + result = recvfrom(fd_socket, buff, sizeof(out_buff) - out_buff_fill + 4, 0, + (struct sockaddr *)&sin, &sin_len); + + /* read the data from udp socket, skip some bytes in the head */ + if((result - 4) > 0 ){ + int length = result - 4; +#if 1 + length = (unsigned char)buff[2] & 0xff; + length *= 256; + length += ((unsigned char)buff[3] & 0xff); + if ((length <= 0) || (length > (result - 4))) + length = result - 4; +#endif + memcpy(out_buff + out_buff_fill, buff + 4, length); + out_buff_fill += length; + } + } + if ((fds[1].revents & POLLIN) && (sizeof(in_buff) > in_buff_fill)) { + result = read(fileno(stdin), in_buff + in_buff_fill, + sizeof(in_buff) - in_buff_fill); // read from keyboard + if (result > 0) { + int bytes; + bytes = do_inbuf_actions(intf, in_buff + in_buff_fill, result); + if(bytes < 0) { + result = ipmi_tsol_stop(intf, recvip, port); + do_terminal_cleanup(); + return result; + } + if (read_only) + bytes = 0; + in_buff_fill += bytes; + } + } + if ((fds[2].revents & POLLOUT) && out_buff_fill) { + result = write(fileno(stdout), out_buff, out_buff_fill); // to screen + if (result > 0) { + out_buff_fill -= result; + if (out_buff_fill) { + memmove(out_buff, out_buff + result, out_buff_fill); + } + } + } + if ((fds[0].revents & POLLOUT) && in_buff_fill) { + /* + * translate key and send that to SMDC using IPMI + * ipmiutil cmd -N 192.168.168.227 -U Administrator 0x30 0x03 0x04 0x1B 0x5B 0x43 + */ + result = ipmi_tsol_send_keystroke(intf, in_buff, + MIN(in_buff_fill,14)); + if (result > 0) { + gettimeofday(&_start_keepalive, 0); + in_buff_fill -= result; + if (in_buff_fill) { + memmove(in_buff, in_buff + result, in_buff_fill); + } + } + } + fds = (in_buff_fill || out_buff_fill )? + fds_data_wait : fds_wait; + } +#endif + + return 0; +} + +#ifdef METACOMMAND +int i_tsol(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + void *intf = NULL; + int rc = 0; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + set_loglevel(LOG_NOTICE); + + while ( (c = getopt( argc, argv,"m:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'x': fdebug = 1; verbose = 1; + set_loglevel(LOG_DEBUG); + break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + print_tsol_usage(); + return ERR_USAGE; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + rc = ipmi_tsol_main(intf, argc, argv); + + ipmi_close_(); + // show_outcome(progname,rc); + return rc; +} +/* end itsol.c */ + diff --git a/util/itsol.h b/util/itsol.h new file mode 100644 index 0000000..ec28d3f --- /dev/null +++ b/util/itsol.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2005 Tyan Computer Corp. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef IPMI_TSOL_H +#define IPMI_TSOL_H + +// #include <ipmitool/ipmi.h> + +#define IPMI_TSOL_CMD_SENDKEY 0x03 +#define IPMI_TSOL_CMD_START 0x06 +#define IPMI_TSOL_CMD_STOP 0x02 +#define IPMI_NETFN_TSOL 0x30 + +#define IPMI_TSOL_DEF_PORT 6230 + +#define IPMI_BUF_SIZE 1024 /* for ipmi_rs in defs.h */ + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) + +#ifdef HAVE_IPV6 +#define SOCKADDR_T struct sockaddr_storage +#else +#define SOCKADDR_T struct sockaddr_in +#endif +int get_LastError( void ); /* ipmilan.c */ +void show_LastError(char *tag, int err); +void lprintf(int level, const char * format, ...); /*subs.c*/ +int lan_keepalive(int type); /*ipmilan.c*/ +void set_loglevel(int level); +void lperror(int level, const char * format, ...); +int ipmi_open(char fdebugcmd); +int open_sockfd(char *node, SockType *sfd, SOCKADDR_T *daddr, + int *daddr_len, int foutput); + +int ipmi_tsol_main(void *, int, char **); + +#endif /* IPMI_TSOL_H */ diff --git a/util/iwdt.c b/util/iwdt.c new file mode 100644 index 0000000..96d21c0 --- /dev/null +++ b/util/iwdt.c @@ -0,0 +1,415 @@ +/* + * wdt.c + * + * This tool reads and enables the watchdog timer via IPMI. + * Note that there are other methods for doing this, and the + * standard interface is for the driver to expose a /dev/watchdog + * device interface. + * WARNING: If you enable the watchdog, make sure you have something + * set up to keep resetting the timer at regular intervals, or it + * will reset your system. + * The Intel Server Management software does this automatically, + * and also continues to reset the timer as long as it is running. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2003-2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 02/25/03 Andy Cress - created + * 03/05/03 Andy Cress - added -d option to disable watchdog timer + * 06/11/03 Andy Cress - new ver 1.2 for EMSGSIZE fix + * 10/28/03 Andy Cress - fixed cc error in set_wdt (idata size), + * show action. + * 02/06/04 Andy Cress - added WIN32 flags + * 03/11/04 Andy Cress - 1.4 fixed cc=0xcc if pretimeout not zero. + * 05/05/04 Andy Cress - 1.5 call ipmi_close before exit + * 11/01/04 Andy Cress - 1.6 add -N / -R for remote nodes + * 11/16/04 Andy Cress - 1.7 add -U for remote username + * 12/02/04 Andy Cress - 1.8 add counter & pretimeout display in show_wdt + * added EFI ifdefs + * 04/13/06 Andy Cress - 1.9 fix -t if nsec > 255 + * 06/22/06 Andy Cress - 1.10 add -a action and -l dontlog options + * 06/25/08 Andy Cress - 2.13 add -p for pre-timeout action + */ +/*M* +Copyright (c) 2006, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include "getopt.h" +#elif defined(EFI) + // EFI: defined (EFI32) || defined (EFI64) || defined(EFIX64) + #ifndef NULL + #define NULL 0 + #endif + #include <types.h> + #include <libdbg.h> + #include <unistd.h> + #include <errno.h> +#elif defined(DOS) + #include <dos.h> + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include "getopt.h" +#else +/* Linux, Solaris, BSD */ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include <string.h> +#include "ipmicmd.h" + +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "iwdt"; +static char fdebug = 0; +static char fdontlog = 0; +static char fcanonical = 0; +static char bdelim = BDELIM; /* '|' */ +static uchar action = 1; /* default is Hard Reset */ + /* 0 = "No action" + * 1 = "Hard Reset" + * 2 = "Power down" + * 3 = "Power cycle" */ +static uchar preaction = 0; /* default is None */ + /* 1 = "SMI " + * 2 = "NMI " + * 3 = "Messaging Interrupt" */ +static uchar pretime = 0; /* usually 30 second default pre-timeout */ +static uchar ipmi_maj = 0; +static uchar ipmi_min = 0; + +static int reset_wdt(void) +{ + uchar idata[4]; + uchar rdata[16]; + int rlen = 4; + uchar ccode; + int ret; + + ret = ipmi_cmd(WATCHDOG_RESET, idata, 0, rdata, &rlen, &ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} + +static int get_wdt(uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + + ret = ipmi_cmd(WATCHDOG_GET, idata, 0, rdata, &rlen, &ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_wdt()*/ + +static int set_wdt(int val) +{ + uchar idata[6]; + uchar rdata[16]; + int rlen = 8; + uchar ccode, bl; + int ret, t; + + t = val * 10; /* val is in sec, make timeout in 100msec */ + if (fdontlog) bl = 0x80; + else bl = 0x00; + if ((ipmi_maj > 1) || /* IPMI 1.5 or greater */ + (ipmi_maj == 1 && ipmi_min >= 5)) { + idata[0] = 0x44 | bl; /* DontLog=0, DontStop=1 & use SMS/OS */ + } else idata[0] = 0x04 | bl; /* IPMI 1.0 or less */ + idata[1] = (preaction << 4) | action; /* preaction/action */ + idata[2] = 0; /* pretimeout: 0=disabled, or less than timeout */ + if (preaction != 0) { /* enabled pretimeout */ + idata[2] = pretime; /* pretimeout value in seconds */ + } /*endif preaction/pretime */ + idata[3] = 0x10; /* clear SMS/OS when done */ + idata[4] = t & 0x00ff; /*timeout in 100msec: 0x4B0 = 1200. */ + idata[5] = (t & 0xff00) >> 8; + ret = ipmi_cmd(WATCHDOG_SET, idata, 6, rdata, &rlen, &ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end set_wdt()*/ + +static int clear_wdt(void) +{ + uchar idata[6]; + uchar rdata[16]; + int rlen = 8; + uchar ccode = 0; + int ret; + + idata[0] = 0x01; /* Use FRB2, stop timer */ + idata[1] = 0x00; /* no action */ + idata[2] = 30; /* pretimeout: 30 sec (disabled anyway) */ + idata[3] = 0x02; /* clear FRB2*/ + idata[4] = 0xB0; + idata[5] = 0x04; + ret = ipmi_cmd(WATCHDOG_SET, idata, 6, rdata, &rlen, &ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end clear_wdt()*/ + +char *usedesc[6] = {"reserved", "BIOS FRB2", "BIOS/POST", + "OS Load", "SMS/OS", "OEM" }; + +void show_wdt(uchar *wdt) +{ + uchar use; + char *pstr; + char *pstr2; + int i,j; + + if (!fcanonical) { + printf("wdt data: "); + for (i=0; i<8; i++) printf("%02x ",wdt[i]); + printf("\n"); + } + + use = wdt[0] & 0x07; + if (use > 5) use = 0; + if ((wdt[0] & 0x40) == 0x40) pstr = "started"; + else pstr = "stopped"; + if ((wdt[0] & 0x80) == 0x80) pstr2 = "DontLog"; + else pstr2 = "Logging"; + if (fcanonical) { + printf("Watchdog timer state\t%c %s\n",bdelim,pstr); + printf(" Use with \t\t%c %s\n", bdelim,usedesc[use]); + printf(" Log mode \t\t%c %s\n", bdelim,pstr2); + } else { + printf("Watchdog timer is %s for use with %s. %s\n",pstr,usedesc[use],pstr2); + } + switch (wdt[1] & 0x70) + { + case 0x10: pstr = "SMI"; break; + case 0x20: pstr = "NMI"; break; + case 0x30: pstr = "MsgInt"; break; + default: pstr = "None"; + } + if (fcanonical) { + printf(" Pretimeout\t\t%c %d seconds\n", bdelim,wdt[2]); + printf(" Pre-action\t\t%c %s\n", bdelim,pstr); + } else { + printf(" pretimeout is %d seconds, pre-action is %s\n", + wdt[2],pstr); + } + /* wdt[3] is the TimerUseExpFlags */ + i = (wdt[4] + (wdt[5] << 8)) / 10; + j = (wdt[6] + (wdt[7] << 8)) / 10; + if (fcanonical) { + printf(" Timeout \t\t%c %d seconds\n", bdelim,i); + printf(" Counter \t\t%c %d seconds\n", bdelim,j); + } else { + printf(" timeout is %d seconds, counter is %d seconds\n",i,j); + } + switch (wdt[1] & 0x07) + { + case 0: pstr = "No action"; break; + case 1: pstr = "Hard Reset"; break; + case 2: pstr = "Power down"; break; + case 3: pstr = "Power cycle"; break; + default: pstr = "Reserved"; + } + if (fcanonical) { + printf(" Action \t\t%c %s\n", bdelim,pstr); + } else { + printf(" action is %s\n",pstr); + } +} + + +#ifdef METACOMMAND +int i_wdt(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret = 0; + int rv = 0; + int c; + uchar freadonly = 1; + uchar freset = 0; + uchar fdisable = 0; + uchar wdtbuf[8]; + uchar devrec[16]; + int t = 0; + int a; + +#if defined (EFI) + InitializeLib(_LIBC_EFIImageHandle, _LIBC_EFISystemTable); +#else + printf("%s ver %s\n", progname,progver); +#endif + parse_lan_options('V',"4",0); /*default to admin priv*/ + + while ((c = getopt(argc,argv,"cdelra:p:q:t:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch(c) { + case 'r': freset = 1; break; /* reset watchdog timer */ + case 'l': fdontlog = 1; break; /* dont log the wdt events */ + case 'a': a = atoi(optarg); /* set wd action */ + if (a >= 0 && a < 4) action = (uchar)a; + freadonly = 0; + break; + case 'p': a = atoi(optarg); /* set wd preaction */ + if (a >= 0 && a < 4) preaction = (uchar)a; + freadonly = 0; + break; + case 'q': a = atoi(optarg); /* set wd pretimeout */ + if (a > 255) pretime = 255; + else if (a >= 5) pretime = (uchar)a; + /* else arg is out of bounds */ + freadonly = 0; + break; + case 'c': fcanonical = 1; break; /* canonical output */ + case 'd': fdisable = 1; break; /* disable wdt */ + case 'e': freadonly = 0; break; /* enable wdt */ + case 't': t = atoi(optarg); freadonly = 0; break; /*timeout*/ + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-acdelpqrx -t sec -NUPRETVF]\n", progname); + printf(" where -r reset watchdog timer\n"); + printf(" -a N set watchdog Action (N=0,1,2,3)\n"); + printf(" -c canonical output format\n"); + printf(" -d disable watchdog timer\n"); + printf(" -e enable watchdog timer\n"); + printf(" -l don't Log watchdog events\n"); + printf(" -p N set watchdog Preaction (N=0,1,2,3)\n"); + printf(" -q N set watchdog pretimeout to N sec\n"); + printf(" -t N set timeout to N seconds\n"); + printf(" -x show eXtra debug messages\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + if (t == 0) t = 120; /* default timeout, 120 seconds*/ + if ((pretime != 0) && (preaction == 0)) preaction = 2; /*default is NMI*/ + if (preaction != 0) { + if (pretime == 0) { + if (t >= 280) { pretime = 255; + } else { + a = t * 10; /* t is in sec, make timeout(a) in 100msec */ + pretime = (a - t)/10; /*90% of timeout, in seconds*/ + } + } + if ((t - pretime) < 5) { /*if not enough difference*/ + /* (timeout - pretimeout) must be >= 5 sec */ + /* if val < 50 sec, 10% diff < 5 */ + if (t < 20) pretime = 0; /* not enough headroom */ + else pretime = t - 5; + } + } + + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + goto do_exit; + } else { + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; +#ifndef EFI + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); +#endif + } + + ret = get_wdt(&wdtbuf[0],8); + if (ret != 0) { + printf("get_wdt error: ret = %x\n",ret); + goto do_exit; + } + show_wdt(wdtbuf); + + if (fdisable) { + printf("Disabling watchdog timer ...\n"); + ret = clear_wdt(); + if (ret != 0) printf("clear_wdt error: ret = %x\n",ret); + ret = get_wdt(wdtbuf,8); + show_wdt(wdtbuf); + } else if (!freadonly) { + printf("Setting watchdog timer to %d seconds ...\n",t); + ret = set_wdt(t); + if (ret != 0) printf("set_wdt error: ret = %x\n",ret); + rv = get_wdt(wdtbuf,8); + show_wdt(wdtbuf); + /* + * If we set the wd timer, we need to set up a cron job, daemon, + * or script to reset the timer also. (e.g.: "sleep 1; wdt -r") + */ + } + if (freset && !fdisable) { + printf("Resetting watchdog timer ...\n"); + ret = reset_wdt(); + if (ret == 0xC0) /*node busy*/ + printf("Node busy: set the timeout longer.\n"); +#ifndef EFI + printf("reset_wdt: ret = %d\n",ret); + rv = get_wdt(wdtbuf,8); + show_wdt(wdtbuf); +#endif + } +#ifndef EFI + printf("\n"); +#endif +do_exit: + ipmi_close_(); + // show_outcome(progname,ret); + return (ret); +} /* end main()*/ + +/* end wdt.c */ diff --git a/util/md2.c b/util/md2.c new file mode 100644 index 0000000..f1b4796 --- /dev/null +++ b/util/md2.c @@ -0,0 +1,99 @@ +/* + * md2.c + * Used in ipmilan.c + * + * 05/26/2006 ARCress - copied from freeipmi ipmi-md2.c, + * added md2_sum() subroutine, added WIN32 flag + * 08/14/2008 ARCress - moved md2 routines from md2.c to md2.h + */ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2002-2008, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <errno.h> + +#undef MD2_GPL +#undef MD2_LIB +#if defined(ALLOW_GNU) +#define MD2_GPL 1 /*use md2.h GPL code*/ +#else +/* if here, ALLOW_GPL is not defined, check for lanplus libcrypto. */ +#if defined(HAVE_LANPLUS) +#define MD2_LIB 1 /*use MD2 version from lanplus libcrypto */ +#endif +/* if libcrypto does not have EVP_md2, then skip MD2. */ +#if defined(SKIP_MD2) +#undef MD2_LIB +#endif +#endif + +/* use GPL md2.h only if "configure --enable-gpl" set ALLOW_GPL */ +#ifdef MD2_GPL +/* + * The md2.h contains some GPL code that may not be desired in some cases. + * If GPL is not desired, the md2.h can be deleted without modifying the + * configure/make process. + * If GPL is ok, then "configure --enable-gpl" should be used. + */ +#include "md2.h" +#else +/* else MD2_GPL is not set */ + +#ifdef MD2_LIB +/* Use EVP_md2() from the openssl libcrypto.so */ +#include <openssl/evp.h> +void md2_sum(unsigned char *pdata, int sdata, unsigned char *digest) +{ + EVP_MD_CTX ctx; + unsigned int mdlen; + static int fmd2added = 0; + const EVP_MD *md = NULL; + + md = EVP_md2(); + if (fmd2added == 0) { + EVP_add_digest(md); + fmd2added = 1; + } + EVP_MD_CTX_init(&ctx); + EVP_DigestInit_ex(&ctx, md, NULL); + EVP_DigestUpdate(&ctx, pdata, sdata); + mdlen = 16; + EVP_DigestFinal_ex(&ctx, digest, &mdlen); + EVP_MD_CTX_cleanup(&ctx); +} +#endif + +#endif + +/*end md2.c */ diff --git a/util/md2.h b/util/md2.h new file mode 100644 index 0000000..29c77fd --- /dev/null +++ b/util/md2.h @@ -0,0 +1,269 @@ +/* + * md2.h + * Used in ipmilan.c + * + * 05/26/2006 ARCress - copied from freeipmi ipmi-md2.c, + * added md2_sum() subroutine, added WIN32 flag + * 08/14/2008 ARCress - moved md2 routines from md2.c to md2.h + */ +/* + Copyright (C) 2003 FreeIPMI Core Team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + A copy of the GNU General Public License is available as + /usr/share/common-licenses/GPL-2 in the Debian distribution or on + the World Wide Web at http://www.gnu.org/copyleft/gpl.html. You can + also obtain it by writing to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +/* only include this file if MD2OK was defined */ + +#ifdef WIN32 +#define u_int32_t unsigned int +#define u_int8_t unsigned char +#endif +/* start ipmi-md2.h */ +#define IPMI_MD2_BLOCK_LEN 16 +#define IPMI_MD2_BUFFER_LEN 48 +#define IPMI_MD2_CHKSUM_LEN 16 +#define IPMI_MD2_DIGEST_LEN 16 +#define IPMI_MD2_PADDING_LEN 16 +#define IPMI_MD2_ROUNDS_LEN 18 + +typedef struct __md2 { + u_int32_t magic; + u_int8_t l; + unsigned int mlen; + u_int8_t x[IPMI_MD2_BUFFER_LEN]; + u_int8_t c[IPMI_MD2_CHKSUM_LEN]; + u_int8_t m[IPMI_MD2_BLOCK_LEN]; +} ipmi_md2_t; + +int ipmi_md2_init(ipmi_md2_t *ctx); +int ipmi_md2_update_data(ipmi_md2_t *ctx, u_int8_t *buf, unsigned int buflen); +int ipmi_md2_finish(ipmi_md2_t *ctx, u_int8_t *digest, unsigned int digestlen); +/* end ipmi-md2.h */ + +static char padding[16][16] = + { + {0x01}, + {0x02,0x02}, + {0x03,0x03,0x03}, + {0x04,0x04,0x04,0x04}, + {0x05,0x05,0x05,0x05,0x05}, + {0x06,0x06,0x06,0x06,0x06,0x06}, + {0x07,0x07,0x07,0x07,0x07,0x07,0x07}, + {0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08}, + {0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09}, + {0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A}, + {0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B}, + {0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C}, + {0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, + {0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E}, + {0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F}, + {0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10} + }; + +static unsigned char S[256] = + { + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, + 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, + 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, + 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, + 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, + 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, + 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, + 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, + 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, + 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, + 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, + 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, + 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, + 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, + 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, + 0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, + 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, + 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, + 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, + 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, + 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, + 0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, + 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, + 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, + 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, + 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, + 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, + 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, + 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, + 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14 + }; + +#define L ctx->l +#define X ctx->x +#define C ctx->c +#define M ctx->m +#define Mlen ctx->mlen +#define IPMI_MD2_MAGIC 0xf00fd00d + +int +ipmi_md2_init(ipmi_md2_t *ctx) +{ + + if (ctx == NULL) + { + errno = EINVAL; + return -1; + } + + ctx->magic = IPMI_MD2_MAGIC; + + L = 0; + Mlen = 0; + memset(X, '\0', IPMI_MD2_BUFFER_LEN); + memset(C, '\0', IPMI_MD2_CHKSUM_LEN); + memset(M, '\0', IPMI_MD2_BLOCK_LEN); + + return 0; +} + +static void +_ipmi_md2_update_digest_and_checksum(ipmi_md2_t *ctx) +{ + int j, k; + u_int8_t c, t; + + /* Update X */ + + for (j = 0; j < IPMI_MD2_BLOCK_LEN; j++) + { + X[16+j] = M[j]; + X[32+j] = (X[16+j] ^ X[j]); + } + + t = 0; + + for (j = 0; j < IPMI_MD2_ROUNDS_LEN; j++) + { + for (k = 0; k < IPMI_MD2_BUFFER_LEN; k++) + { + t = X[k] = (X[k] ^ S[t]); + } + t = (t + j) % 256; + } + + /* Update C and L */ + + /* achu: Note that there is a typo in the RFC 1319 specification. + * In section 3.2, the line: + * + * Set C[j] to S[c xor L] + * + * should read: + * + * Set C[j] to C[j] xor S[c xor L]. + */ + + for (j = 0; j < IPMI_MD2_BLOCK_LEN; j++) + { + c = M[j]; + C[j] = C[j] ^ S[c ^ L]; + L = C[j]; + } +} + +int +ipmi_md2_update_data(ipmi_md2_t *ctx, u_int8_t *buf, unsigned int buflen) +{ + + if (ctx == NULL || ctx->magic != IPMI_MD2_MAGIC || buf == NULL) + { + errno = EINVAL; + return -1; + } + + if (buflen == 0) + return 0; + + if ((Mlen + buflen) >= IPMI_MD2_BLOCK_LEN) + { + unsigned int bufcount; + + bufcount = (IPMI_MD2_BLOCK_LEN - Mlen); + memcpy(M + Mlen, buf, bufcount); + _ipmi_md2_update_digest_and_checksum(ctx); + + while ((buflen - bufcount) >= IPMI_MD2_BLOCK_LEN) + { + memcpy(M, buf + bufcount, IPMI_MD2_BLOCK_LEN); + bufcount += IPMI_MD2_BLOCK_LEN; + _ipmi_md2_update_digest_and_checksum(ctx); + } + + Mlen = buflen - bufcount; + if (Mlen > 0) + memcpy(M, buf + bufcount, Mlen); + } + else + { + /* Not enough data to update X and C, just copy in data */ + memcpy(M + Mlen, buf, buflen); + Mlen += buflen; + } + + return buflen; +} + +static void +_ipmi_md2_append_padding_and_checksum(ipmi_md2_t *ctx) +{ + unsigned int padlen; + int padindex; + + padlen = IPMI_MD2_PADDING_LEN - Mlen; + padindex = padlen - 1; + + ipmi_md2_update_data(ctx, padding[padindex], padlen); + + ipmi_md2_update_data(ctx, C, IPMI_MD2_CHKSUM_LEN); +} + +int +ipmi_md2_finish(ipmi_md2_t *ctx, u_int8_t *digest, unsigned int digestlen) +{ + + if (ctx == NULL || ctx->magic != IPMI_MD2_MAGIC + || digest == NULL || digestlen < IPMI_MD2_DIGEST_LEN) + { + errno = EINVAL; + return -1; + } + + _ipmi_md2_append_padding_and_checksum(ctx); + memcpy(digest, X, IPMI_MD2_DIGEST_LEN); + + return IPMI_MD2_DIGEST_LEN; +} + +/* added - ARCress */ +void md2_sum(unsigned char *pdata, int sdata, unsigned char *digest) +{ + ipmi_md2_t ctx; + + ipmi_md2_init(&ctx); + ipmi_md2_update_data(&ctx, pdata, sdata); + ipmi_md2_finish(&ctx, digest, 16); +} +/*end md2.h */ diff --git a/util/md5.c b/util/md5.c new file mode 100644 index 0000000..9f4db4e --- /dev/null +++ b/util/md5.c @@ -0,0 +1,413 @@ +/* + * md5.c + * Used in ipmilan.c + * + * 05/26/2006 ARCress - copied from sf.net/projects/libmd5-rfc/, + * added md5-sum() subroutine. + */ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include <string.h> + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include <stdio.h> in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include <string.h> + +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +void md5_init(md5_state_t *pms); +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); +/* end md5.h */ + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X = NULL; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} + +/* added - ARCress */ +void md5_sum(unsigned char *pdata, int sdata, unsigned char *digest) +{ + md5_state_t state; + + md5_init(&state); + md5_append(&state, pdata, sdata); + md5_finish(&state, digest); +} diff --git a/util/mem_if.c b/util/mem_if.c new file mode 100644 index 0000000..c445138 --- /dev/null +++ b/util/mem_if.c @@ -0,0 +1,900 @@ +/*----------------------------------------------------------------------* + * mem_if.c + * Get SMBIOS Tables and associated data. + * This code is 64-bit safe. + * Note that for Windows, this should be compiled with /TP (as C++). + * + * 12/17/07 ARCress - created + * 02/26/08 ARCress - decode type 15 log structure + * 07/21/08 ARCress - fixed for 64-bit memory model + * 08/12/08 ARCress - trim out extra stuff, consolidated + *----------------------------------------------------------------------*/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2002-2008, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#ifdef WIN32 +#define _WIN32_DCOM +#pragma once +#include <windows.h> +#include <stdio.h> +#include <iostream> //deprecated iostream.h +#include <Objbase.h> //ole32.lib +#include <comutil.h> +#include <Wbemcli.h> //Wbemcli.h,Wbemidl.h Wbemuuid.lib + +#elif defined(DOS) +#include <dos.h> +#include <stdlib.h> +#include <string.h> + +#else // Linux or Solaris +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#endif +#if defined(SOLARIS) || defined(BSD) +#define EXEC_PAGESIZE 4096 +#endif + +#define DOS_MEM_RANGE_BASE 0xF0000 //starting memory range for smbios tables +#define DOS_NUM_BYTES_TO_MAP 0x0FFFE //number bytes to map for smbios tables + +//smbios defines +#define SMBIOS_STRING "_SM_" //server management bios string +#define SMBIOS_MAJOR_REV 2 //major rev for smbios spec 2.3 +#define SMBIOS_MINOR_REV 1 //minor rev for smbios spce 2.3 +#define SMBIOS_STRUCTURE_TYPE_OFFSET 0 //offset in structure for type +#define SMBIOS_STRUCTURE_LENGTH_OFFSET 1 //offset in structure for length +#define SMBIOS_TABLE_LENGTH_OFFSET 0x5 //offset for length of table +#define SMBIOS_MAJOR_REV_OFFSET 0x6 //offset for major rev of smbios +#define SMBIOS_MINOR_REV_OFFSET 0x7 //offset for minor rev of smbios +#define SMBIOS_TABLE_ENTRY_POINT_OFFSET 0x18 //offset for smbios structure table entry point +#define SMBIOS_TABLE_SIZE_OFFSET 0x16 //offset for smbios structure table size +#define NIBBLE_SIZE 4 //bit size of a nibble + +#ifdef WIN32 +extern "C" { char fsm_debug = 0; } /*=1 to show smbios debug messages*/ +#else +char fsm_debug = 0; /*=1 to show smbios debug messages*/ +#endif +static int s_iTableRev = 0; //static globabl var to store table revision + +#ifndef WIN32 +typedef int BOOL; +typedef unsigned long ULONG; +typedef unsigned char UCHAR; +typedef unsigned short USHORT; + +BOOL MapPhysicalMemory(ULONG tdStartAddress, ULONG ulSize, + ULONG* ptdVirtualAddress); +BOOL UnMapPhysicalMemory(ULONG tdVirtualAddress, ULONG ulSize); +int OpenIMemoryInterface(void); +int CloseIMemoryInterface(void); +#endif // Linux, not __WINDOWS__ + +#ifdef WIN32 + /* Windows Memory routines */ +static BYTE m_byMajorVersion = 0; +static BYTE m_byMinorVersion = 0; +static BYTE * m_pbBIOSData = NULL; +static DWORD m_dwLen = 0; + +extern "C" { + +int getSmBiosTables(UCHAR **ptableAddress) +{ + int bRet = 0; + HRESULT hres; + IWbemLocator *pLoc = 0; + IWbemServices *pSvc = 0; + IEnumWbemClassObject* pEnumerator = NULL; + + // Initialize COM. + hres = CoInitializeEx(0, COINIT_MULTITHREADED); + if (FAILED(hres)) { + return bRet; + } + + // Obtain the initial locator to Windows Management + // on a particular host computer. + hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID *) &pLoc); + if (FAILED(hres)) { + CoUninitialize(); + return bRet; + } + + + // Connect to the root\cimv2 namespace with the + // current user and obtain pointer pSvc + // to make IWbemServices calls. + hres = pLoc->ConnectServer( + _bstr_t(L"ROOT\\WMI"), // WMI namespace + NULL, // User name + NULL, // User password + 0, // Locale + NULL, // Security flags + 0, // Authority + 0, // Context object + &pSvc // IWbemServices proxy + ); + if (FAILED(hres)) { + pLoc->Release(); + CoUninitialize(); + return bRet; + } + + // Set the IWbemServices proxy so that impersonation + // of the user (client) occurs. + hres = CoSetProxyBlanket( + pSvc, // the proxy to set + RPC_C_AUTHN_WINNT, // authentication service + RPC_C_AUTHZ_NONE, // authorization service + NULL, // Server principal name + RPC_C_AUTHN_LEVEL_CALL, // authentication level + RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level + NULL, // client identity + EOAC_NONE // proxy capabilities + ); + if (FAILED(hres)) { + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return bRet; // Program has failed. + } + + hres = pSvc->CreateInstanceEnum( L"MSSMBios_RawSMBiosTables", 0, + NULL, &pEnumerator); + if (FAILED(hres)) { + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return bRet; // Program has failed. + } else { + do { + IWbemClassObject* pInstance = NULL; + ULONG dwCount = NULL; + + hres = pEnumerator->Next(WBEM_INFINITE, 1, &pInstance, &dwCount); + if (SUCCEEDED(hres)) + { + VARIANT varBIOSData; + VariantInit(&varBIOSData); + CIMTYPE type; + + hres = pInstance->Get(bstr_t("SmbiosMajorVersion"),0,&varBIOSData,&type,NULL); + if (FAILED(hres)) { + VariantClear(&varBIOSData); + } else { + m_byMajorVersion = (BYTE)varBIOSData.iVal; + VariantInit(&varBIOSData); + hres = pInstance->Get(bstr_t("SmbiosMinorVersion"),0,&varBIOSData,&type,NULL); + if(FAILED(hres)) { + VariantClear(&varBIOSData); + } else { + m_byMinorVersion = (BYTE)varBIOSData.iVal; + s_iTableRev = (m_byMajorVersion << 4) + m_byMinorVersion; + + VariantInit(&varBIOSData); + hres = pInstance->Get(bstr_t("SMBiosData"),0,&varBIOSData,&type,NULL); + if(SUCCEEDED(hres)) { + if ( ( VT_UI1 | VT_ARRAY ) != varBIOSData.vt ) { + } else { + SAFEARRAY *parray = NULL; + parray = V_ARRAY(&varBIOSData); + BYTE* pbData = (BYTE*)parray->pvData; + + m_dwLen = parray->rgsabound[0].cElements; + + m_pbBIOSData = (BYTE *)malloc(m_dwLen); + memcpy(m_pbBIOSData,pbData,m_dwLen); + *ptableAddress = m_pbBIOSData; + bRet = m_dwLen; + } + } + VariantClear(&varBIOSData); + } + } + break; + } + } while (hres == WBEM_S_NO_ERROR); + } + + // Cleanup + // ======== + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return(bRet); +} /*end getSmBiosTables*/ + +int closeSmBios(UCHAR *ptableAddress, ULONG ulSmBiosLen) +{ + int rv = 0; + /* memory interface already closed */ + free(ptableAddress); + return(rv); +} + +} /*end extern C*/ + +#else + /* Linux Memory routines */ +#define MEM_DRIVER "/dev/mem" +#define FALSE 0 +#define TRUE 1 +//intialize static handle amd counter +static int m_iDriver = 0; +static int m_iCount = 0; + +////////////////////////////////////////////////////////////////////////////// +// OpenIMemoryInterface +////////////////////////////////////////////////////////////////////////////// +// Name: OpenIMemoryInterface +// Purpose: create handle to driver if first time +// Context: static m_iDriver & m_iCount +// Returns: int rv (0 = success) +// Parameters: none +// Notes: +/////////////////////////////////////////////////////////////////////////////// +int OpenIMemoryInterface(void) +{ + int rv = -1; + //check to see if driver has been previously defined + if (!m_iDriver) { //open the driver + m_iDriver = open(MEM_DRIVER, O_RDONLY); + if (m_iDriver > 0) { //increment instance counter + m_iCount++; + } else { //couldn't open the driver...so make it zero again + m_iDriver = 0; + } + } else { //handle exists...so inc instance counter. + m_iCount++; + } + if (m_iDriver > 0) rv = 0; + return(rv); +} + +/////////////////////////////////////////////////////////////////////////////// +// CloseIMemoryInterface +// Name: destructor +// Purpose: close driver handle and null out field +// Context: +// Returns: +// Parameters: none +// Notes: +/////////////////////////////////////////////////////////////////////////////// +int CloseIMemoryInterface(void) +{ + int rv = 0; + //check if an instance has been created by looking at the counter + if (!m_iCount) { + m_iCount--; //decrement instance counter + if (m_iCount == 0) { + close(m_iDriver); + m_iDriver = 0; //and null it out + } + } + return(rv); +} + +/////////////////////////////////////////////////////////////////////////////// +// MapPhysicalMemory +/////////////////////////////////////////////////////////////////////////////// +// Name: MapPhysicalMemory +// Purpose: given the starting address and size, the virtualize +// memory is mapped. +// Returns: True if success +// Parameters: [IN] tdStartAddress = physical address to map +// [IN] ulSize = number of bytes to map +// [OUT] ptdVirtualAddress = ptr to virtual address +/////////////////////////////////////////////////////////////////////////////// +BOOL MapPhysicalMemory(ULONG tdStartAddress, + ULONG ulSize, + ULONG* ptdVirtualAddress) +{ + long tdVirtualAddr = 0; + ULONG ulDiff; + //check if we have a valid driver handle + if (!m_iDriver) return FALSE; //error + //check for valid input params + if (!tdStartAddress || !ulSize) return FALSE; //error + //align the offset to a valid page boundary and adust its length + ulDiff = (ULONG)(tdStartAddress % EXEC_PAGESIZE); + if (fsm_debug) printf("MapPhys: tdStart=%lx, page=%x, diff=%lx\n", + tdStartAddress,EXEC_PAGESIZE,ulDiff); + tdStartAddress -= ulDiff; + ulSize += ulDiff; + tdVirtualAddr = (long)mmap((caddr_t)0, + (size_t)ulSize, + PROT_READ, + MAP_SHARED, + m_iDriver, + (off_t)tdStartAddress); + if (fsm_debug) printf("MapPhys: mmap(tdStart=%lx,size=%lx) = %lx\n", + tdStartAddress,ulSize,tdVirtualAddr); + if (tdVirtualAddr == -1) + return FALSE; + *ptdVirtualAddress = tdVirtualAddr + ulDiff; + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// +// UnMapPhysicalMemory +/////////////////////////////////////////////////////////////////////////////// +// Name: UnMapPhysicalMemory +// Purpose: given the virtual address, unmaps it...frees memory. +// Returns: True if success +// Parameters: [IN] tdVirtualAddress = virtual address to unmap +// [IN] ulSize = not needed for windows +// Notes: none +/////////////////////////////////////////////////////////////////////////////// +BOOL UnMapPhysicalMemory(ULONG tdVirtualAddress, + ULONG ulSize) +{ + ULONG ulDiff = 0; + ulDiff = (ULONG)(tdVirtualAddress % EXEC_PAGESIZE); + tdVirtualAddress -= ulDiff; + ulSize += ulDiff; + if (munmap((void *)tdVirtualAddress,ulSize) != 0) return FALSE; + return TRUE; +} + + +/////////////////////////////////////////////////////////////////////////////// +// getSmBiosTables +// Purpose: returns smbios tables pointer +// Returns: pointer to the virtual address where SMBIOS tables begins +////////////////////////////////////////////////////////////////////////////// +int getSmBiosTables(UCHAR **ptableAddress) +{ + ULONG tdStartAddress = DOS_MEM_RANGE_BASE; + ULONG ulSize = DOS_NUM_BYTES_TO_MAP; + ULONG ulSmBiosLen = 0; + ULONG tdVirtualAddress = 0; + int iInc; + UCHAR *pSmBios = NULL; + UCHAR ucCheckSum = 0; + UCHAR ucVal, ucVal1; + int rv; + + if (fsm_debug) printf("getSmBiosTables start\n"); + //get interface to Memory + rv = OpenIMemoryInterface(); + if (fsm_debug) printf("OpenIMemoryInterface rv = %d\n",rv); + + //map memory into user space + if ((rv != 0) || + !MapPhysicalMemory(tdStartAddress,ulSize,&tdVirtualAddress)) + { +#ifdef SOLARIS + /* mmap always fails on Solaris, so skip the error message, + * unless in debug mode. */ + if (fsm_debug) +#endif + fprintf(stderr, "Cannot map memory.\n"); + return ulSmBiosLen; /*==0*/ + } + + //now find the entry point for smbios + for(iInc=0; iInc < (long)ulSize; iInc+=sizeof(int) ) + { + if (!memcmp((UCHAR *)(tdVirtualAddress+iInc),SMBIOS_STRING,sizeof(int))) + { + //cast entry point to a byte pointer + pSmBios = (UCHAR *)(tdVirtualAddress+iInc); + break; + } + } + + if (pSmBios == NULL) + { + fprintf(stderr, "Can't find SMBIOS address entry point.\n"); + UnMapPhysicalMemory(tdVirtualAddress,ulSize); + return ulSmBiosLen; + } + + if (fsm_debug) { + printf("Found pSmBios=%p tdV=%lx, inc=%x\n",pSmBios, + tdVirtualAddress,iInc); + // dump_buf("SMBIOS",pSmBios,64,1); + } + //now sum up the bytes in the table for checksum checking + for(iInc=0; iInc<pSmBios[SMBIOS_TABLE_LENGTH_OFFSET]; iInc++) + ucCheckSum += pSmBios[iInc]; + + if (ucCheckSum) + { + UnMapPhysicalMemory(tdVirtualAddress,ulSize); + fprintf(stderr, "_SM_ Checksum != 0.\n"); + return ulSmBiosLen; + } + + //save smbios revision for future calls...bcd format + s_iTableRev = (pSmBios[SMBIOS_MAJOR_REV_OFFSET]<<NIBBLE_SIZE) | pSmBios[SMBIOS_MINOR_REV_OFFSET]; + + //find smbios table entry point and size of tables + memcpy(&tdStartAddress,&pSmBios[SMBIOS_TABLE_ENTRY_POINT_OFFSET],4); + //sizeof(ULONG)); + memcpy(&ulSmBiosLen,&pSmBios[SMBIOS_TABLE_SIZE_OFFSET],sizeof(USHORT)); + memcpy(&ucVal,&pSmBios[SMBIOS_TABLE_SIZE_OFFSET],sizeof(UCHAR)); + memcpy(&ucVal1,&pSmBios[SMBIOS_TABLE_SIZE_OFFSET+1],sizeof(UCHAR)); + + + //unmap physical memory (f0000-ffffe) + UnMapPhysicalMemory(tdVirtualAddress,ulSize); + + if (!MapPhysicalMemory(tdStartAddress,ulSmBiosLen,&tdVirtualAddress)) { +#ifdef SOLARIS + /* mmap always fails on Solaris, so skip the error message, + * unless in debug mode. */ + if (fsm_debug) +#endif + fprintf(stderr, "Cannot map memory.\n"); + return 0; + } + + if (fsm_debug) { + printf("MapMemory(%lx,%lx) ok = %lx\n",tdStartAddress, + ulSmBiosLen,tdVirtualAddress); + // dump_buf("Table",(UCHAR *)tdVirtualAddress,256,1); + } + //set size_t smbios tables starting address to ptr + *ptableAddress = (UCHAR*)tdVirtualAddress; + + //Not doing this since the map is needed + // UnMapPhysicalMemory(tdVirtualAddress,ulSmBiosLen); + // rv = CloseIMemoryInterface(); + return ulSmBiosLen; +} + +int closeSmBios(UCHAR *ptableAddress, ULONG ulSmBiosLen) +{ + int rv; + UnMapPhysicalMemory((size_t)ptableAddress,ulSmBiosLen); + rv = CloseIMemoryInterface(); + return(rv); +} +#endif // Linux (not WIN32) + +#ifdef WIN32 +extern "C" { +#endif +/////////////////////////////////////////////////////////////////////////////// +// getSmBiosRev +// return the revision of smbios...in bcd format +// Integer +/////////////////////////////////////////////////////////////////////////////// +int getSmBiosRev() +{ + return s_iTableRev; +} + + +/////////////////////////////////////////////////////////////////////////////// +// get_IpmiStruct +////////////////////////////////////////////////////////////////////////////// +// Name: get_IpmiStruct +// Purpose: find Type 38 record to get the IPMI Version. +// Returns: 0 for success, or -1 if not found. +// if success, all 4 parameters will have valid data +////////////////////////////////////////////////////////////////////////////// +int get_IpmiStruct(UCHAR *iftype, UCHAR *ver, UCHAR *sa, int *base, UCHAR *inc) +{ + UCHAR *VirtualAddress; + ULONG SMBiosLen = 0; + int length, j, i; + UCHAR Type; + int rv = -1; + + SMBiosLen = getSmBiosTables( &VirtualAddress); + if ((SMBiosLen == 0) || !VirtualAddress) return rv; + + for(i=0; i<(int)SMBiosLen; ) + { + Type = VirtualAddress[i]; + length = (int)VirtualAddress[i+1]; + + if (Type == 127) //end of table record + break; + else if (Type == 38) //Found the IPMI Device Information record + { + if (fsm_debug) { + int j; + printf("IPMI record: "); + for (j = i; j < i+length; j++) + printf("%02x ",VirtualAddress[j]); + printf("\n"); + } + /* + * Byte 05h is the IPMI version as X.Y + * where X is bits 7:4 and Y bits 3:0 + * + * KCS Iv sa nv base_addr + * 26 12 01 00 01 20 20 ff a3 0c 00 00 00 00 00 00 00 00 + * IPMI 2.0 KCS, sa=0x20 Base=0x0ca2, spacing=1 + * 26 12 73 00 01 20 20 ff a9 0c 00 00 00 00 00 00 40 00 + * IPMI 2.0 KCS, sa=0x20 Base=0x0ca8, spacing=4 + * 26 10 44 00 04 15 84 01 01 04 00 00 00 00 00 00 + * IPMI v1.5 SMBus sa=0x42, base=0x0000000401 + */ + *iftype = VirtualAddress[i+4]; + *ver = VirtualAddress[i+5]; + *sa = VirtualAddress[i+6]; + j = VirtualAddress[i+8] + + (VirtualAddress[i+9] << 8) + + (VirtualAddress[i+10] << 16) + + (VirtualAddress[i+11] << 24); + /*if odd, then subtract 1 from base addr*/ + if (j & 0x01) j -= 1; + *base = j; + /* detect Register Spacing */ + *inc = 1; /*default*/ + if ((*iftype != 0x04) && (length >= 18)) { + switch(VirtualAddress[i+16] >>6) { + case 0x00: *inc = 1; break; /* 1-byte bound*/ + case 0x01: *inc = 4; break; /* 4-byte bound*/ + case 0x02: *inc = 16; break; /*16-byte bound*/ + default: break; /**inc = 1; above*/ + } + } + rv = 0; + break; + } + + //Skip this record and go to the end of it. + for (j = i+length; j < (int)SMBiosLen; j++) { + if (VirtualAddress[j] == 0x00 && + VirtualAddress[j+1] == 0x00) { + i = j+2; + break; + } + } + } + closeSmBios(VirtualAddress,SMBiosLen); + return rv; +} //getIPMI_struct + +/////////////////////////////////////////////////////////////////////////////// +// get_MemDesc +////////////////////////////////////////////////////////////////////////////// +// Name: get_MemDesc +// Purpose: find Type 17 record to get the Memory Locator Description +// Returns: 0 for success, or -1 if not found. +// if success, the desc string will have valid data +////////////////////////////////////////////////////////////////////////////// +int get_MemDesc(UCHAR array, UCHAR dimm, char *desc, int *psize) +{ + UCHAR *VirtualAddress; + ULONG SMBiosLen = 0; + int length, j, i; + int iarray, idimm; + UCHAR Type; + int rv = -1; + char dimmstr[32]; + char bankstr[32]; + + SMBiosLen = getSmBiosTables( &VirtualAddress); + if ((SMBiosLen == 0) || !VirtualAddress) return rv; + if (desc == NULL) return(-1); + bankstr[0] = 0; + dimmstr[0] = 0; + + if (fsm_debug) printf("get_MemDesc(%d,%d)\n",array,dimm); + iarray = 0; + idimm = 0; + for(i=0; i<(int)SMBiosLen; ) + { + Type = VirtualAddress[i]; + length = (int)VirtualAddress[i+1]; + + if (Type == 127) //end of table record + break; + else if (Type == 16) //Found a Memory Array */ + { + /* usually only one onboard memory array */ + if (array == iarray) ; /*match*/ + else iarray++; + } + else if (Type == 17) //Found a Memory Device */ + { + int bank, k, n, nStr, nBLoc, sz; + if (dimm == idimm) + { + if (fsm_debug) { + printf("Memory record %d.%d: ",iarray,idimm); + for (j = i; j < (i+length+16); j++) { + if (((j-i) % 16) == 0) printf("\n"); + printf("%02x ",VirtualAddress[j]); + } + printf("\n"); + } + /* + * Memory Device record + * walk through strings to find Locator + */ + sz = VirtualAddress[i+12] + (VirtualAddress[i+13] << 8); /*Size*/ + bank = VirtualAddress[i+15]; /*Set*/ + nStr = VirtualAddress[i+16]; /*Locator string num*/ + nBLoc = VirtualAddress[i+17]; /*BankLocator string num*/ + if (fsm_debug) + printf("bank=%d nStr=%d sz=%x\n",bank,nStr,sz); + k = i + length; /*hdr len (usu 0x1B)*/ + n = 1; /* string number index */ + for (j = k; j < (int)SMBiosLen; j++) { + if (VirtualAddress[j] == 0x00 && + VirtualAddress[j-1] == 0x00) break; + else if (VirtualAddress[j] == 0x00) { + if (fsm_debug) printf("str[%d] = %s\n", + n,&VirtualAddress[k]); + if (n == nBLoc) { /*bank string*/ + strcpy(bankstr,(char *)&VirtualAddress[k]); + break; /*string number*/ + } + if (n == nStr) { + strcpy(dimmstr,(char *)&VirtualAddress[k]); + } + n++; k = j + 1; + } + } + if ((desc != NULL) && (j < (int)SMBiosLen)) { + sprintf(desc,"%s/%s",bankstr,dimmstr); + rv = 0; + } else { /* have header, but not string */ + char b; + if ((idimm % 2) == 0) b = 'A'; + else b = 'B'; + sprintf(desc,"DIMM%d%c",bank,b); + rv = 0; + } + *psize = sz; + break; + } else idimm++; /*else go to next dimm*/ + } + + //Skip this record and go to the end of it. + for (j = i+length; j < (int)SMBiosLen; j++) { + if (VirtualAddress[j] == 0x00 && + VirtualAddress[j+1] == 0x00) { + i = j+2; + break; + } + } + } + closeSmBios(VirtualAddress,SMBiosLen); + /* fill in a default if error */ + if ((rv != 0) && (desc != NULL)) sprintf(desc,"DIMM[%d]",dimm); + return rv; +} //get_MemDesc + +/////////////////////////////////////////////////////////////////////////////// +// get_BiosVersion +////////////////////////////////////////////////////////////////////////////// +// Name: get_BiosVersion +// Purpose: finds Type 0 record and gets the BIOS ID string +// Returns: -1 if not found and 0 if found. Param contains the string +////////////////////////////////////////////////////////////////////////////// +int get_BiosVersion(char *bios_str) +{ +#define BIOS_VERSION 0x05 //Specifies string number of BIOS Ver string + UCHAR *VirtualAddress; + ULONG SMBiosLen = 0; + int recLength, j, i, k = 0, str_num; + UCHAR recType; + int rv = -1; + + SMBiosLen = getSmBiosTables( &VirtualAddress); + if ((SMBiosLen == 0) || !VirtualAddress) return rv; + i=0; + while (i<(int)SMBiosLen) + { + recType = VirtualAddress[i]; + recLength = (int)VirtualAddress[i+1]; + + // end of table record, error + if (recType == 127) return -1; + else if (recType == 0) + { // BIOS Information (Type 0) record found + //Set index j to the end of the formated part of record. + j = i + recLength; + + //First grab string number of the BIOS Version string + //This non-zero number specifies which string at the end + //of the record is the BIOS Version string. + str_num = VirtualAddress[i + BIOS_VERSION]; + + //Now skip over strings at the end of the record till we + //get to the BIOS Version string + for (str_num--;str_num > 0; str_num--) + { + //Skipping over one string at a time + for (; VirtualAddress[j] != 0x00; j++); + j++; //Advance index past EOS. + } + + //Copy the BIOS Version string into buffer from caller. + for (; VirtualAddress[j] != 0x00; j++) + { + bios_str[k++] = VirtualAddress[j]; + } + bios_str[k] = '\0'; + rv = 0; + break; /*exit while loop*/ + } else { + //Not a Type 0, so skip to the end of this structure + for (j = i+recLength; j < (int)SMBiosLen; j++) + { + if (VirtualAddress[j] == 0x00 && + VirtualAddress[j+1] == 0x00) + { + i = j+2; + break; + } + } + } + } /*end while*/ + closeSmBios(VirtualAddress,SMBiosLen); + return rv; +} + +int get_ChassisSernum(char *chs_str, char fdbg) +{ +#define CHASSIS_SERNUM 0x07 //Specifies string number of BIOS Ver string + UCHAR *VirtualAddress; + ULONG SMBiosLen = 0; + int recLength, j, i, k = 0, str_num; + UCHAR recType; + int rv = -1; + + SMBiosLen = getSmBiosTables( &VirtualAddress); + if ((SMBiosLen == 0) || !VirtualAddress) return rv; + i=0; + while (i<(int)SMBiosLen) + { + recType = VirtualAddress[i]; + recLength = (int)VirtualAddress[i+1]; + if (recType == 127) return -1; // end of table record, error + else if (recType == 3) + { // Chassis Information (Type 3) record found + j = i + recLength; + str_num = VirtualAddress[i + CHASSIS_SERNUM]; + for (str_num--;str_num > 0; str_num--) + { + for (; VirtualAddress[j] != 0x00; j++); + j++; + } + for (; VirtualAddress[j] != 0x00; j++) + { chs_str[k++] = VirtualAddress[j]; } + chs_str[k] = '\0'; + /* also copy Chassis Manuf */ + j = i + recLength; + memcpy(&chs_str[k+1],&VirtualAddress[j],20); + rv = 0; + break; /*exit while loop*/ + } else { + //Not a Type 0, so skip to the end of this structure + for (j = i+recLength; j < (int)SMBiosLen; j++) + { + if (VirtualAddress[j] == 0x00 && + VirtualAddress[j+1] == 0x00) + { + i = j+2; + break; + } + } + } + } /*end while*/ + closeSmBios(VirtualAddress,SMBiosLen); + return rv; +} + +int get_SystemGuid(UCHAR *guid) +{ + UCHAR *VirtualAddress; + ULONG SMBiosLen = 0; + int recLength, i, j, n, k = 0; + UCHAR recType; + int rv = -1; + + SMBiosLen = getSmBiosTables( &VirtualAddress); + if ((SMBiosLen == 0) || !VirtualAddress) return rv; + i=0; + while (i<(int)SMBiosLen) + { + recType = VirtualAddress[i]; + recLength = (int)VirtualAddress[i+1]; + + // end of table record, error + if (recType == 127) return -1; + else if (recType == 1) + { // System Board Information (Type 1) record found + //Set index j to the end of the formated part of record. + j = i + recLength; + n = i + 8; /*UUID offset 8*/ + //Copy the UUID string into buffer from caller. + for (k = 0; k < 16; k++) + { + guid[k] = VirtualAddress[n + k]; + } + rv = 0; + break; /*exit while loop*/ + } else { + //else skip to the end of this structure + for (j = i+recLength; j < (int)SMBiosLen; j++) + { + if (VirtualAddress[j] == 0x00 && + VirtualAddress[j+1] == 0x00) + { + i = j+2; + break; + } + } + } + } /*end while*/ + closeSmBios(VirtualAddress,SMBiosLen); + return rv; +} +#ifdef WIN32 +} +#endif + + +#ifdef COMP_BIN +int +main(int argc, char **argv) +{ + char biosver[80]; + UCHAR ifs,ver,sa,inc; + int rv; + int base; + + biosver[0] = 0; + rv = get_BiosVersion(biosver); + printf("get_BiosVersion rv=%d Ver=%s\n",rv,biosver); + + rv = get_IpmiStruct( &ifs, &ver, &sa, &base, &inc); + printf("get_IpmiStruct rv=%d if=%02x ver=%02x sa=%02x base=%x, spacing=%d\n", + rv, ifs,ver,sa,base,inc); + + rv = get_SystemGuid(biosver); + printf("get_SystemGuid rv=%d Ver=%s\n",rv,biosver); + // exit(rv); + return(rv); +} +#endif + +/* end mem_if.c */ diff --git a/util/mem_if_cpp.cpp b/util/mem_if_cpp.cpp new file mode 100644 index 0000000..19468f2 --- /dev/null +++ b/util/mem_if_cpp.cpp @@ -0,0 +1,5 @@ +// mem_if_cpp.cpp
+// Include the actual mem_if source into this .cpp file.
+// This is a wrapper for build.exe to detect its type as C++.
+//
+#include "mem_if.c"
diff --git a/util/oem_dell.c b/util/oem_dell.c new file mode 100644 index 0000000..1911d96 --- /dev/null +++ b/util/oem_dell.c @@ -0,0 +1,6095 @@ +/* + * oem_dell.c + * Handle Dell OEM command functions + * + * Change history: + * 08/17/2011 ARCress - included in ipmiutil source tree + * + */ +/****************************************************************** +Copyright (c) 2008, Dell Inc +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +- Neither the name of Dell Inc nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************/ +/* +* Thursday Oct 7 17:30:12 2009 +* <deepaganesh_paulraj@dell.com> +* +* This code implements a dell OEM proprietary commands. +* This Code is edited and Implemented the License feature for Delloem +* Author Harsha S <Harsha_S1@dell.com> +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#ifdef WIN32 +#include <windows.h> +#define int8_t char +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +#define uint64_t unsigned long +#include "getopt.h" +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <ctype.h> +#include <limits.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#include <stdint.h> +#else +#include <getopt.h> +#endif +#endif + +#include <time.h> +#include "ipmicmd.h" +#include "isensor.h" +#include "ievents.h" +#include "oem_dell.h" + +// #ifdef METACOMMAND is assumed +extern int i_sol(int argc, char **argv); /*isol.c*/ +extern void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/ +extern void set_loglevel(int level); +extern void printbuf(const uint8_t * buf, int len, const char * desc); + +#define IPMI_DELL_OEM_NETFN (uint8_t)(0x30) +#define GET_CHASSIS_LED_STATE (uint8_t)(0x32) +#define GET_IDRAC_VIRTUAL_MAC (uint8_t)(0xC9) +// 11g Support Macros +#define INVALID -1 +#define SHARED 0 +#define SHARED_WITH_FAILOVER_LOM2 1 +#define DEDICATED 2 +#define SHARED_WITH_FAILOVER_ALL_LOMS 3 +char ActiveLOM_String[6][10] = {"None","LOM1","LOM2","LOM3","LOM4","dedicated"}; +#define INVAILD_FAILOVER_MODE -2 +#define INVAILD_FAILOVER_MODE_SETTINGS -3 +#define INVAILD_SHARED_MODE -4 + +#define INVAILD_FAILOVER_MODE_STRING "ERROR: Cannot set shared with failover lom same as current shared lom.\n" +#define INVAILD_FAILOVER_MODE_SET "ERROR: Cannot set shared with failover loms when NIC is set to dedicated Mode.\n" +#define INVAILD_SHARED_MODE_SET_STRING "ERROR: Cannot set shared Mode for Blades.\n" + +// 11g Support Strings for nic selection +char NIC_Selection_Mode_String [4] [50] = { "shared", + "shared with failover lom2", + "dedicated", + "shared with Failover all loms" + }; + +// 11g Support Macros (dups) +//#define SHARED 0 +//#define SHARED_WITH_FAILOVER_LOM2 1 +//#define DEDICATED 2 +//#define SHARED_WITH_FAILOVER_ALL_LOMS 3 + +// 12g Support Strings for nic selection +char NIC_Selection_Mode_String_12g[] [50] = { + "dedicated", + "shared with lom1", + "shared with lom2", + "shared with lom3", + "shared with lom4", + "shared with failover lom1", + "shared with failover lom2", + "shared with failover lom3", + "shared with failover lom4", + "shared with failover all loms" + }; + +static char * progver = "2.93"; +static char * progname = "idelloem"; +static int verbose = 0; +static char fdebug = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static uchar *sdrcache = NULL; +static char *sdrfile = NULL; +static int argc_sav; +static char **argv_sav; +static int current_arg =0; +uint8_t iDRAC_FLAG=0; +LCD_MODE lcd_mode; +static uint8_t LcdSupported=0; +static uint8_t SetLEDSupported=0; + +volatile uint8_t IMC_Type = IMC_IDRAC_10G; + + +const struct vFlashstr vFlash_completion_code_vals[] = { + {0x00, "SUCCESS"}, + {0x01, "NO_SD_CARD"}, + {0x63, "UNKNOWN_ERROR"}, + {0x00, NULL} +}; + + +POWER_HEADROOM powerheadroom; + +uint8_t PowercapSetable_flag=0; +uint8_t PowercapstatusFlag=0; + +static void usage(void); + +/* LCD Function prototypes */ +static int ipmi_delloem_lcd_main (void * intf, int argc, char ** argv); +static int ipmi_lcd_get_platform_model_name (void * intf,char* lcdstring, + uint8_t max_length,uint8_t field_type); +static int ipmi_idracvalidator_command (void * intf); +static int ipmi_lcd_get_configure_command_wh (void * intf); +static int ipmi_lcd_get_configure_command (void * intf,uint8_t *command); +static int ipmi_lcd_set_configure_command (void * intf, int command); +static int ipmi_lcd_set_configure_command_wh (void * intf, uint32_t mode, + uint16_t lcdqualifier,uint8_t errordisp); +static int ipmi_lcd_get_single_line_text (void * intf, char* lcdstring, uint8_t max_length); +static int ipmi_lcd_get_info_wh(void * intf); +static int ipmi_lcd_get_info(void * intf); +static int ipmi_lcd_get_status_val(void * intf, LCD_STATUS* lcdstatus); +static int IsLCDSupported (); +static void CheckLCDSupport(void * intf); +static void ipmi_lcd_status_print( LCD_STATUS lcdstatus); +static int ipmi_lcd_get_status(void * intf ); +static int ipmi_lcd_set_kvm(void * intf, char status); +static int ipmi_lcd_set_lock(void * intf, char lock); +static int ipmi_lcd_set_single_line_text (void * intf, char * text); +static int ipmi_lcd_set_text(void * intf, char * text, int line_number); +static int ipmi_lcd_configure_wh (void * intf, uint32_t mode , + uint16_t lcdqualifier, uint8_t errordisp, + int8_t line_number, char * text); +static int ipmi_lcd_configure (void * intf, int command, + int8_t line_number, char * text); +static void ipmi_lcd_usage(void); + +/* MAC Function prototypes */ +static int ipmi_delloem_mac_main (void * intf, int argc, char ** argv); +static int make_int(const char *str, int *value); +static void InitEmbeddedNICMacAddressValues (); +static int ipmi_macinfo_drac_idrac_virtual_mac(void* intf,uint8_t NicNum); +static int ipmi_macinfo_drac_idrac_mac(void* intf,uint8_t NicNum); +static int ipmi_macinfo_10g (void* intf, uint8_t NicNum); +static int ipmi_macinfo_11g (void* intf, uint8_t NicNum); +static int ipmi_macinfo (void* intf, uint8_t NicNum); +static void ipmi_mac_usage(void); + +/* LAN Function prototypes */ +static int ipmi_delloem_lan_main (void * intf, int argc, char ** argv); +static int IsLANSupported (); +static int get_nic_selection_mode (int current_arg, char ** argv); +static int ipmi_lan_set_nic_selection (void* intf, uint8_t nic_selection); +static int ipmi_lan_get_nic_selection (void* intf); +static int get_nic_selection_mode_12g (void* intf,int iarg, char **argv, char *nic_set); +static int ipmi_lan_get_active_nic (void* intf); +static void ipmi_lan_usage(void); +static int ipmi_lan_set_nic_selection_12g (void* intf, uint8_t* nic_selection); + +/* POwer monitor Function prototypes */ +static int ipmi_delloem_powermonitor_main (void * intf, int argc, char **argv); +static void ipmi_time_to_str(time_t rawTime, char* strTime); +static int ipmi_get_power_capstatus_command (void * intf); +static int ipmi_set_power_capstatus_command (void * intf,uint8_t val); +static int ipmi_powermgmt(void* intf); +static int ipmi_powermgmt_clear(void* intf,uint8_t clearValue); +static uint64_t watt_to_btuphr_conversion(uint32_t powerinwatt); +static uint32_t btuphr_to_watt_conversion(uint64_t powerinbtuphr); +static int ipmi_get_power_headroom_command (void * intf,uint8_t unit); +static int ipmi_get_power_consumption_data(void* intf,uint8_t unit); +static int ipmi_get_instan_power_consmpt_data(void* intf, + IPMI_INST_POWER_CONSUMPTION_DATA* instpowerconsumptiondata); +static void ipmi_print_get_instan_power_Amps_data(IPMI_INST_POWER_CONSUMPTION_DATA instpowerconsumptiondata); +static int ipmi_print_get_power_consmpt_data(void* intf,uint8_t unit); +static int ipmi_get_avgpower_consmpt_history(void* intf,IPMI_AVGPOWER_CONSUMP_HISTORY* pavgpower ); +static int ipmi_get_peakpower_consmpt_history(void* intf,IPMI_POWER_CONSUMP_HISTORY * pstPeakpower); +static int ipmi_get_minpower_consmpt_history(void* intf,IPMI_POWER_CONSUMP_HISTORY * pstMinpower); +static int ipmi_print_power_consmpt_history(void* intf,int unit ); +static int ipmi_get_power_cap(void* intf,IPMI_POWER_CAP* ipmipowercap ); +static int ipmi_print_power_cap(void* intf,uint8_t unit ); +static int ipmi_set_power_cap(void* intf,int unit,int val ); +static void ipmi_powermonitor_usage(void); + +/* vFlash Function prototypes */ +static int ipmi_delloem_vFlash_main(void * intf, int argc, char ** argv); +const char * get_vFlash_compcode_str(uint8_t vflashcompcode, const struct vFlashstr *vs); +static int ipmi_get_sd_card_info(void* intf); +static int ipmi_delloem_vFlash_process(void* intf, int current_arg, char ** argv); +static void ipmi_vFlash_usage(void); + + +/* windbg Function prototypes */ +volatile uint8_t windbgsession = 0; +static int ipmi_delloem_windbg_main (void * intf, int argc, char ** argv); +static int ipmi_windbg_start (void * intf); +static int ipmi_windbg_end (void * intf); +static void ipmi_windbg_usage (void); + + + +/* LED Function prototypes */ + +static int ipmi_getsesmask(int, char **); +static int CheckSetLEDSupport(void * intf); +static int IsSetLEDSupported(void); +static void ipmi_setled_usage(void); +static int ipmi_delloem_setled_main(void *intf, int argc, char ** argv); +static int ipmi_delloem_getled_main(void *intf, int argc, char ** argv); +static int ipmi_setled_state (void * intf, int bayId, int slotId, int state); +static int ipmi_getdrivemap (void * intf, int b, int d, int f, int *bayId, int *slotId); +//extern int optind; /*from getopt*/ + +static int ipmi_sol_activate(void *intf, int j, int k) +{ + char **args; + int rv, i, n; + int x = 0; + n = argc_sav; + args = argv_sav; + /* use the user-specified args, but switch to sol */ + for (i = 0; i < n; i++) { + if (strcmp(args[i],"ipmiutil") == 0) { x = 1; } + else if (strcmp(args[i],"delloem") == 0) args[i] = "sol"; + else if (strcmp(args[i],"windbg") == 0) args[i] = "-a"; + else if (strcmp(args[i],"start") == 0) args[i] = "-a"; + } + ipmi_close_(); + if (x == 1) { args++; n--; } + optind = 0; + rv = i_sol(n, args); + return rv; +} + +static int ipmi_sol_deactivate(void *intf) +{ + char **args; + int rv, i, n; + int x = 0; + n = argc_sav; + args = argv_sav; + /* use the user-specified args, but switch to sol */ + for (i = 0; i < n; i++) { + if (strcmp(args[i],"ipmiutil") == 0) { x = 1; } + else if (strcmp(args[i],"delloem") == 0) args[i] = "sol"; + else if (strcmp(args[i],"windbg") == 0) args[i] = "-d"; + else if (strcmp(args[i],"end") == 0) args[i] = "-d"; + } + ipmi_close_(); + if (x == 1) { args++; n--; } + optind = 0; + rv = i_sol(n, args); + return rv; +} + +static int sysinfo_param(const char *str) { + // SysInfo Parameters + // 1 = system firmware version + // 2 = system hostname + // 3 = primary operating system name (non-volatile) + // 4 = operating system name (volatile) + // 0xe3 = dell: os version + // 0xde = dell: url + if (!strcmp(str, "system_name")) return 0x02; + if (!strcmp(str, "primary_os_name")) return 0x03; + if (!strcmp(str, "os_name")) return 0x04; + if (!strcmp(str, "dell_os_version")) return 0xe4; + if (!strcmp(str, "dell_url")) return 0xde; + return strtoul(str, 0, 16); +} + +static void ipmi_sysinfo_usage() +{ + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " getsysinfo (os_name|primary_os_name|dell_os_version|dell_url)"); + lprintf(LOG_NOTICE, " Retrieves system info from bmc for given argument"); + lprintf(LOG_NOTICE, " setsysinfo (os_name|primary_os_name|dell_os_version|dell_url)"); + lprintf(LOG_NOTICE, " Stores system Info for given argument to bmc"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " primary_os_name = primary operating system name"); + lprintf(LOG_NOTICE, " os_name = secondary operating system name"); + lprintf(LOG_NOTICE, " system_name = system hostname of server"); + lprintf(LOG_NOTICE, " dell_os_version = running version of operating system (Dell)"); + lprintf(LOG_NOTICE, " dell_url = url of bmc webserver (Dell)"); + + lprintf(LOG_NOTICE, ""); +} + +static int +ipmi_delloem_sysinfo_main(void * intf, int argc, char ** argv) +{ + int param, isset; + char *str; + unsigned char infostr[256], *pos; + int j, ret; + + /* Is this a setsysinfo or getsysinfo */ + isset = !strncmp(argv[current_arg], "setsysinfo\0",10); + + current_arg++; + if (argc < current_arg) { + usage(); + return -1; + } + if (argc == 1 || strcmp(argv[current_arg], "help") == 0 || + argc < (isset ? current_arg+2 : current_arg+1)) { + ipmi_sysinfo_usage(); + return 0; + } + memset(infostr, 0, sizeof(infostr)); + + param = sysinfo_param(argv[current_arg++]); + + if (isset) { + str = argv[current_arg]; + j = strlen_(str); + ret = set_system_info(param,str,j); + } else { + pos = infostr; + j = sizeof(infostr); + ret = get_system_info(param,infostr,&j); + printf("%s\n", infostr); + } + return ret; +} + +static void ipmi_password_policy_usage(void) +{ + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " passwordpolicy <on | off>"); + lprintf(LOG_NOTICE, " Set the OEM Password Policy Check on or off"); + lprintf(LOG_NOTICE, " This parameter is write-only"); + lprintf(LOG_NOTICE, ""); +} + +static int +ipmi_delloem_password_policy(void * intf, int argc, char ** argv) +{ + int rv = 0; + int rsp_len; + struct ipmi_rq req = {0}; + uint8_t data[4]; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + uint8_t bval; + + + current_arg++; + if (argc < current_arg) { + usage(); + return -1; + } + + if (strcmp(argv[current_arg], "on") == 0) { + bval = 0x01; + } else if (strcmp(argv[current_arg], "off") == 0) { + bval = 0x00; + } else { /* other or "help" */ + ipmi_password_policy_usage(); + return 0; + } + + printf("Setting OEM Password Policy Check to %s ...\n", argv[current_arg]); + req.msg.netfn = 0x30; /*Dell OEM netfn*/ + req.msg.lun = 0; + req.msg.cmd = 0x51; + req.msg.data_len = 1; + req.msg.data = data; + data[0] = bval; + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error setting OEM password policy: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + } + if (rv == 0) printf("successful\n"); + /* This works for DELL C6220 with firmware >= 1.23 */ + + return(rv); +} + +/***************************************************************** +* Function Name: ipmi_delloem_main +* +* Description: This function processes the delloem command +* Input: intf - ipmi interface + argc - no of arguments + argv - argument string array +* Output: +* +* Return: return code 0 - success +* -1 - failure +* +******************************************************************/ + +int +ipmi_delloem_main(void * intf, int argc, char ** argv) +{ + int rc = 0; + + // ipmi_idracvalidator_command(intf); + // CheckLCDSupport (intf); + // CheckSetLEDSupport (intf); + + if (argc == 0 || strncmp(argv[0], "help\0", 5) == 0) + { + usage(); + return 0; + } + + if (0 ==strncmp(argv[current_arg], "lcd\0", 4) ) + { + rc = ipmi_delloem_lcd_main (intf,argc,argv); + } + /* mac address*/ + else if (strncmp(argv[current_arg], "mac\0", 4) == 0) + { + rc = ipmi_delloem_mac_main (intf,argc,argv); + } + /* lan address*/ + else if (strncmp(argv[current_arg], "lan\0", 4) == 0) + { + rc = ipmi_delloem_lan_main (intf,argc,argv); + } + /* SetLED support */ + else if (strncmp(argv[current_arg], "setled\0", 7) == 0) + { + rc = ipmi_delloem_setled_main (intf,argc,argv); + } + else if (strncmp(argv[current_arg], "getled\0", 13) == 0) + { + rc = ipmi_delloem_getled_main (intf,argc,argv); + } + else if (strncmp(argv[current_arg], "passwordpolicy\0", 14) == 0) + { + rc = ipmi_delloem_password_policy (intf,argc,argv); + } + /*Powermanagement report processing*/ + else if (strncmp(argv[current_arg], "powermonitor\0", 13) == 0) + { + rc = ipmi_delloem_powermonitor_main (intf,argc,argv); + } + /* vFlash Support */ + else if (strncmp(argv[current_arg], "vFlash\0", 7) == 0) + { + rc = ipmi_delloem_vFlash_main (intf,argc,argv); + } + else if (strncmp(argv[current_arg], "windbg\0", 7) == 0) + { + rc = ipmi_delloem_windbg_main (intf,argc,argv); + } + else if ((strncmp(argv[current_arg], "getsysinfo\0", 10) == 0) || + (strncmp(argv[current_arg], "setsysinfo\0", 10) == 0)) + { + rc = ipmi_delloem_sysinfo_main (intf,argc,argv); + } + else + { + usage(); + return ERR_USAGE; + } + return rc; +} + +/***************************************************************** +* Function Name: usage +* +* Description: This function prints help message for delloem command +* Input: +* Output: +* +* Return: +* +******************************************************************/ + +static void usage(void) +{ + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, "usage: delloem <command> [option...]"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, "commands:"); + lprintf(LOG_NOTICE, " lcd"); + lprintf(LOG_NOTICE, " mac"); + lprintf(LOG_NOTICE, " lan"); + lprintf(LOG_NOTICE, " setled"); + lprintf(LOG_NOTICE, " getled"); + lprintf(LOG_NOTICE, " powermonitor"); + lprintf(LOG_NOTICE, " windbg"); + lprintf(LOG_NOTICE, " vFlash"); + lprintf(LOG_NOTICE, " getsysinfo"); + lprintf(LOG_NOTICE, " setsysinfo"); + lprintf(LOG_NOTICE, " passwordpolicy"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, "For help on individual commands type:"); + lprintf(LOG_NOTICE, "delloem <command> help"); + +} + +/***************************************************************** +* Function Name: ipmi_delloem_lcd_main +* +* Description: This function processes the delloem lcd command +* Input: intf - ipmi interface + argc - no of arguments + argv - argument string array +* Output: +* +* Return: return code 0 - success +* -1 - failure +* +******************************************************************/ + +static int ipmi_delloem_lcd_main (void * intf, int argc, char ** argv) +{ + int rc = 0; + + current_arg++; + if (argc < current_arg) + { + usage(); + return -1; + } + + + /* ipmitool delloem lcd info*/ + if (argc == 1 || strcmp(argv[current_arg], "help") == 0) + { + ipmi_lcd_usage(); + return 0; + } + CheckLCDSupport (intf); + ipmi_idracvalidator_command(intf); + if (!IsLCDSupported()) { + printf("lcd is not supported on this system.\n"); + return -1; + } + else if (strncmp(argv[current_arg], "info\0", 5) == 0) + { + if((iDRAC_FLAG==IDRAC_11G) || (iDRAC_FLAG==IDRAC_12G) ) + rc = ipmi_lcd_get_info_wh(intf); + else + rc = ipmi_lcd_get_info(intf); + } + else if (strncmp(argv[current_arg], "status\0", 7) == 0) + { + rc = ipmi_lcd_get_status(intf); + } + /* ipmitool delloem lcd set*/ + else if (strncmp(argv[current_arg], "set\0", 4) == 0) + { + uint8_t line_number = 0; + current_arg++; + if (argc <= current_arg) + { + ipmi_lcd_usage(); + return -1; + } + if (strncmp(argv[current_arg], "line\0", 5) == 0) + { + current_arg++; + if (argc <= current_arg) {usage();return -1;} + line_number = (uint8_t)strtoul(argv[current_arg], NULL, 0); + current_arg++; + if (argc <= current_arg) {usage();return -1;} + } + + + if ((strncmp(argv[current_arg], "mode\0", 5) == 0)&&((iDRAC_FLAG==IDRAC_11G) || (iDRAC_FLAG==IDRAC_12G) )) + { + current_arg++; + if (argc <= current_arg) + { + ipmi_lcd_usage(); + return -1; + } + if (argv[current_arg] == NULL) + { + ipmi_lcd_usage(); + return -1; + } + if (strncmp(argv[current_arg], "none\0", 5) == 0) + { + rc = ipmi_lcd_configure_wh (intf, IPMI_DELL_LCD_CONFIG_NONE,0xFF,0XFF, 0, NULL); + } + else if (strncmp(argv[current_arg], "modelname\0", 10) == 0) + { + rc = ipmi_lcd_configure_wh (intf, IPMI_DELL_LCD_CONFIG_DEFAULT,0xFF,0XFF, 0, NULL); + } + else if (strncmp(argv[current_arg], "userdefined\0", 12) == 0) + { + current_arg++; + if (argc <= current_arg) + { + ipmi_lcd_usage();return -1; + } + rc = ipmi_lcd_configure_wh (intf, IPMI_DELL_LCD_CONFIG_USER_DEFINED,0xFF,0XFF, line_number, argv[current_arg]); + } + else if (strncmp(argv[current_arg], "ipv4address\0", 12) == 0) + { + rc = ipmi_lcd_configure_wh (intf, IPMI_DELL_LCD_iDRAC_IPV4ADRESS ,0xFF,0XFF, 0, NULL); + } + else if (strncmp(argv[current_arg], "macaddress\0", 11) == 0) + { + rc = ipmi_lcd_configure_wh (intf, IPMI_DELL_LCD_IDRAC_MAC_ADDRESS,0xFF,0XFF, 0, NULL); + } + else if (strncmp(argv[current_arg], "systemname\0", 11) == 0) + { + rc = ipmi_lcd_configure_wh (intf, IPMI_DELL_LCD_OS_SYSTEM_NAME,0xFF,0XFF, 0, NULL); + } + else if (strncmp(argv[current_arg], "servicetag\0", 11) == 0) + { + rc = ipmi_lcd_configure_wh (intf, IPMI_DELL_LCD_SERVICE_TAG, 0xFF,0XFF,0, NULL); + } + else if (strncmp(argv[current_arg], "ipv6address\0", 12) == 0) + { + rc = ipmi_lcd_configure_wh (intf, IPMI_DELL_LCD_iDRAC_IPV6ADRESS ,0xFF,0XFF, 0, NULL); + } + else if (strncmp(argv[current_arg], "ambienttemp\0", 12) == 0) + { + rc = ipmi_lcd_configure_wh (intf, IPMI_DELL_LCD_AMBEINT_TEMP, 0xFF,0XFF,0, NULL); + + } + else if (strncmp(argv[current_arg], "systemwatt\0", 11) == 0) + { + rc = ipmi_lcd_configure_wh (intf, IPMI_DELL_LCD_SYSTEM_WATTS , 0xFF,0XFF,0, NULL); + + } + else if (strncmp(argv[current_arg], "assettag\0", 9) == 0) + { + rc = ipmi_lcd_configure_wh (intf, IPMI_DELL_LCD_ASSET_TAG , 0xFF,0XFF,0, NULL); + + } + else if (strncmp(argv[current_arg], "help\0", 5) == 0) + { + ipmi_lcd_usage(); + } + else + { + ipmi_lcd_usage(); + } + } + else if ((strncmp(argv[current_arg], "lcdqualifier\0", 13)== 0) &&((iDRAC_FLAG==IDRAC_11G) || (iDRAC_FLAG==IDRAC_12G) ) ) + { + + current_arg++; + if (argc <= current_arg) + { + ipmi_lcd_usage(); + return -1; + } + if (argv[current_arg] == NULL) + { + ipmi_lcd_usage(); + return -1; + } + + if (strncmp(argv[current_arg], "watt\0", 5) == 0) { + + + rc = ipmi_lcd_configure_wh (intf, 0xFF,0x00,0XFF, 0, NULL); + } + else if (strncmp(argv[current_arg], "btuphr\0",7) == 0) { + rc = ipmi_lcd_configure_wh (intf, 0xFF,0x01,0XFF, 0, NULL); + + } else if (strncmp(argv[current_arg], "celsius\0", 8) == 0) { + rc = ipmi_lcd_configure_wh (intf, 0xFF,0x02,0xFF, 0, NULL); + } else if (strncmp(argv[current_arg], "fahrenheit", 11) == 0) { + rc = ipmi_lcd_configure_wh (intf, 0xFF,0x03,0xFF, 0, NULL); + + }else if (strncmp(argv[current_arg], "help\0", 5) == 0) { + ipmi_lcd_usage(); + } + else { + ipmi_lcd_usage(); + } + } + else if( (strncmp(argv[current_arg], "errordisplay\0", 13) == 0)&&((iDRAC_FLAG==IDRAC_11G) || (iDRAC_FLAG==IDRAC_12G) )) + { + + current_arg++; + if (argc <= current_arg) + { + ipmi_lcd_usage(); + return -1; + } + if (argv[current_arg] == NULL) + { + ipmi_lcd_usage(); + return -1; + } + + if (strncmp(argv[current_arg], "sel\0", 4) == 0) + { + rc = ipmi_lcd_configure_wh (intf, 0xFF,0xFF,IPMI_DELL_LCD_ERROR_DISP_SEL , 0, NULL); + } + else if (strncmp(argv[current_arg], "simple\0", 7) == 0) + { + rc = ipmi_lcd_configure_wh (intf, 0xFF,0xFF,IPMI_DELL_LCD_ERROR_DISP_VERBOSE , 0, NULL); + + } + else if (strncmp(argv[current_arg], "help\0", 5) == 0) + { + ipmi_lcd_usage(); + } + else + { + ipmi_lcd_usage(); + } + } + + else if ((strncmp(argv[current_arg], "none\0", 5) == 0)&&(iDRAC_FLAG==0)) + { + rc = ipmi_lcd_configure (intf, IPMI_DELL_LCD_CONFIG_NONE, 0, NULL); + } + else if ((strncmp(argv[current_arg], "default\0", 8) == 0)&&(iDRAC_FLAG==0)) + { + rc = ipmi_lcd_configure (intf, IPMI_DELL_LCD_CONFIG_DEFAULT, 0, NULL); + + } + else if ((strncmp(argv[current_arg], "custom\0", 7) == 0)&&(iDRAC_FLAG==0)) + { + current_arg++; + if (argc <= current_arg) + { + ipmi_lcd_usage(); + return -1; + } + rc = ipmi_lcd_configure (intf, IPMI_DELL_LCD_CONFIG_USER_DEFINED, line_number, argv[current_arg]); + } + + else if (strncmp(argv[current_arg], "vkvm\0", 5) == 0) + { + current_arg++; + if (argc <= current_arg) + { + ipmi_lcd_usage(); + return -1; + } + + if (strncmp(argv[current_arg], "active\0", 7) == 0) + { + rc = ipmi_lcd_set_kvm (intf, 1); + } + else if (strncmp(argv[current_arg], "inactive\0", 9)==0) + { + rc = ipmi_lcd_set_kvm (intf, 0); + + } + else if (strncmp(argv[current_arg], "help\0", 5) == 0) + { + ipmi_lcd_usage(); + } + else + { + ipmi_lcd_usage(); + } + + } + else if (strncmp(argv[current_arg], "frontpanelaccess\0", 17) == 0) + { + current_arg++; + if (argc <= current_arg) + { + ipmi_lcd_usage(); + return -1; + } + if (strncmp(argv[current_arg], "viewandmodify\0", 14) == 0) + { + rc = ipmi_lcd_set_lock (intf, 0); + } + else if (strncmp(argv[current_arg], "viewonly\0", 9)==0) + { + rc = ipmi_lcd_set_lock (intf, 1); + + } + else if (strncmp(argv[current_arg], "disabled\0", 9)==0) + { + rc = ipmi_lcd_set_lock (intf, 2); + + } + else if (strncmp(argv[current_arg], "help\0", 5) == 0) + { + ipmi_lcd_usage(); + } + else + { + ipmi_lcd_usage(); + } + + } + else if( (strncmp(argv[current_arg], "help\0", 5) == 0)&&(iDRAC_FLAG==0)) + { + ipmi_lcd_usage(); + } + else + { + ipmi_lcd_usage(); + return -1; + } + } + else + { + ipmi_lcd_usage(); + return -1; + } + return(rc); +} + + + +/***************************************************************** +* Function Name: ipmi_lcd_get_platform_model_name +* +* Description: This function retrieves the platform model name, or any other parameter +* which stores data in the same format +* Input: intf - pointer to interface +* max_length - length of the platform model string +* field_type - either hostname / platform model +* Output: lcdstring - hostname / platform model string +* +* Return: +* +******************************************************************/ +static int +ipmi_lcd_get_platform_model_name (void * intf, + char* lcdstring, + uint8_t max_length, + uint8_t field_type) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + IPMI_DELL_LCD_STRING * lcdstringblock; + int lcdstring_len = 0; + int bytes_copied = 0; + + int ii; + + for (ii = 0; ii < 4; ii++) + { + int bytes_to_copy; + memset (&req,0,sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; /* get parameter*/ + data[1] = field_type; + data[2] = ii; + data[3] = 0; + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error getting platform model name: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + + lcdstringblock = (IPMI_DELL_LCD_STRING *) (void *) rsp; + + /* first block is different - 14 bytes*/ + if (0 == ii) { + lcdstring_len = lcdstringblock->lcd_string.selector_0_string.length; + + lcdstring_len = MIN (lcdstring_len,max_length); + + bytes_to_copy = MIN(lcdstring_len, IPMI_DELL_LCD_STRING1_SIZE); + memcpy (lcdstring, lcdstringblock->lcd_string.selector_0_string.data, bytes_to_copy); + } else { + int string_offset; + + bytes_to_copy = MIN(lcdstring_len - bytes_copied, IPMI_DELL_LCD_STRINGN_SIZE); + if (bytes_to_copy < 1) + break; + string_offset = IPMI_DELL_LCD_STRING1_SIZE + IPMI_DELL_LCD_STRINGN_SIZE * (ii-1); + memcpy (lcdstring+string_offset, lcdstringblock->lcd_string.selector_n_data, bytes_to_copy); + } + + + bytes_copied += bytes_to_copy; + + if (bytes_copied >= lcdstring_len) + + break; + } + return rv; +} + +/***************************************************************** +* Function Name: ipmi_idracvalidator_command +* +* Description: This function returns the iDRAC6 type +* Input: intf - ipmi interface +* Output: +* +* Return: iDRAC6 type 1 - whoville +* 0 - others +* +******************************************************************/ + +static int +ipmi_idracvalidator_command (void * intf) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + + memset (&req,0,sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; + data[1] = IPMI_DELL_IDRAC_VALIDATOR; + data[2] = 2; + data[3] = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv && fdebug) { + printf(" Error getting IMC type"); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + IMC_Type = rsp[10]; + if( (IMC_Type == IMC_IDRAC_11G_MONOLITHIC) || (IMC_Type == IMC_IDRAC_11G_MODULAR) ) + { + iDRAC_FLAG=IDRAC_11G; + } + else if( (IMC_Type == IMC_IDRAC_12G_MONOLITHIC) || (IMC_Type == IMC_IDRAC_12G_MODULAR) ) + { + iDRAC_FLAG=IDRAC_12G; + } + else + { + iDRAC_FLAG=0; + } + + return 0; +} + +/***************************************************************** +* Function Name: ipmi_lcd_get_configure_command_wh +* +* Description: This function returns current lcd configuration for Dell OEM LCD command +* Input: intf - ipmi interface +* Global: lcd_mode - lcd mode setting +* Output: +* +* Return: returns the current lcd configuration +* 0 = User defined +* 1 = Default +* 2 = None +* +******************************************************************/ +static int +ipmi_lcd_get_configure_command_wh (void * intf) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; + data[1] = IPMI_DELL_LCD_CONFIG_SELECTOR; + data[2] = 0; + data[3] = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error getting LCD configuration: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + lcd_mode= *((LCD_MODE*)(&rsp[0])); + return 0; +} + + +/***************************************************************** +* Function Name: ipmi_lcd_get_configure_command +* +* Description: This function returns current lcd configuration for Dell OEM LCD command +* Input: intf - ipmi interface +* Output: command - user defined / default / none / ipv4 / mac address / + system name / service tag / ipv6 / temp / system watt / asset tag +* +* Return: +* +******************************************************************/ + +static int +ipmi_lcd_get_configure_command (void * intf, + uint8_t *command) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; + data[1] = IPMI_DELL_LCD_CONFIG_SELECTOR; + data[2] = 0; + data[3] = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error getting LCD configuration: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + /* rsp->data[0] is the rev */ + *command = rsp[1]; + + return 0; +} + +/***************************************************************** +* Function Name: ipmi_lcd_set_configure_command +* +* Description: This function updates current lcd configuration +* Input: intf - ipmi interface +* command - user defined / default / none / ipv4 / mac address / +* system name / service tag / ipv6 / temp / system watt / asset tag +* Output: +* Return: +* +******************************************************************/ + +static int +ipmi_lcd_set_configure_command (void * intf, int command) +{ +#define LSCC_DATA_LEN 2 + + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[2]; + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_SET_SYS_INFO; + req.msg.data_len = 2; + req.msg.data = data; + data[0] = IPMI_DELL_LCD_CONFIG_SELECTOR; + data[1] = command; /* command - custom, default, none */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error setting LCD configuration: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + + +/***************************************************************** +* Function Name: ipmi_lcd_set_configure_command +* +* Description: This function updates current lcd configuration +* Input: intf - ipmi interface +* mode - user defined / default / none +* lcdqualifier - lcd quallifier id +* errordisp - error number +* Output: +* Return: +* +******************************************************************/ +static int +ipmi_lcd_set_configure_command_wh (void * intf, + uint32_t mode, + uint16_t lcdqualifier, + uint8_t errordisp) +{ +#define LSCC_DATA_LEN 2 + + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[13]; + + ipmi_lcd_get_configure_command_wh(intf); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_SET_SYS_INFO; + req.msg.data_len = 13; + req.msg.data = data; + data[0] = IPMI_DELL_LCD_CONFIG_SELECTOR; + + if(mode!=0xFF) + { + + data[1] = mode&0xFF; /* command - custom, default, none*/ + data[2]=(mode&0xFF00)>>8; + data[3]=(mode&0xFF0000)>>16; + data[4]=(mode&0xFF000000)>>24; + } + else + { + data[1] = (lcd_mode.lcdmode)&0xFF; /* command - custom, default, none*/ + data[2]=((lcd_mode.lcdmode)&0xFF00)>>8; + data[3]=((lcd_mode.lcdmode)&0xFF0000)>>16; + data[4]=((lcd_mode.lcdmode)&0xFF000000)>>24; + } + + if(lcdqualifier!=0xFF) + { + if(lcdqualifier==0x01) + { + data[5] =(lcd_mode.lcdqualifier)|0x01; /* command - custom, default, none*/ + + } + else if(lcdqualifier==0x00) + { + data[5] =(lcd_mode.lcdqualifier)&0xFE; /* command - custom, default, none*/ + } + else if (lcdqualifier==0x03) + { + data[5] =(lcd_mode.lcdqualifier)|0x02; /* command - custom, default, none*/ + } + else if (lcdqualifier==0x02) + { + data[5] =(lcd_mode.lcdqualifier)&0xFD; + } + } + else + { + data[5]=(uchar)lcd_mode.lcdqualifier; + } + if(errordisp!=0xFF) + { + data[11]=errordisp; + } + else + { + data[11]=lcd_mode.error_display; + } + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error setting LCD configuration: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + + + +/***************************************************************** +* Function Name: ipmi_lcd_get_single_line_text +* +* Description: This function updates current lcd configuration +* Input: intf - ipmi interface +* lcdstring - new string to be updated +* max_length - length of the string +* Output: +* Return: +* +******************************************************************/ + +static int +ipmi_lcd_get_single_line_text (void * intf, char* lcdstring, uint8_t max_length) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + IPMI_DELL_LCD_STRING * lcdstringblock; + int lcdstring_len = 0; + int bytes_copied = 0; + int ii; + + for (ii = 0; ii < 4; ii++) { + int bytes_to_copy; + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; /* get parameter*/ + data[1] = IPMI_DELL_LCD_STRING_SELECTOR; + data[2] = ii; /* block selector*/ + data[3] = 0; /* set selector (n/a)*/ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error getting text data: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + lcdstringblock = (IPMI_DELL_LCD_STRING *) (void *) rsp; + + /* first block is different - 14 bytes*/ + if (0 == ii) + { + lcdstring_len = lcdstringblock->lcd_string.selector_0_string.length; + + if (lcdstring_len < 1 || lcdstring_len > max_length) + break; + + bytes_to_copy = MIN(lcdstring_len, IPMI_DELL_LCD_STRING1_SIZE); + memcpy (lcdstring, lcdstringblock->lcd_string.selector_0_string.data, bytes_to_copy); + } + else + { + int string_offset; + + bytes_to_copy = MIN(lcdstring_len - bytes_copied, IPMI_DELL_LCD_STRINGN_SIZE); + if (bytes_to_copy < 1) + break; + string_offset = IPMI_DELL_LCD_STRING1_SIZE + IPMI_DELL_LCD_STRINGN_SIZE * (ii-1); + memcpy (lcdstring+string_offset, lcdstringblock->lcd_string.selector_n_data, bytes_to_copy); + } + + bytes_copied += bytes_to_copy; + if (bytes_copied >= lcdstring_len) + break; + } + return 0; +} + +/***************************************************************** +* Function Name: ipmi_lcd_get_info_wh +* +* Description: This function prints current lcd configuration for whoville platform +* Input: intf - ipmi interface +* Output: +* Return: +* +******************************************************************/ + +static int +ipmi_lcd_get_info_wh(void * intf) + +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + uint8_t command = 0; + IPMI_DELL_LCD_CAPS* lcd_caps; + char lcdstring[IPMI_DELL_LCD_STRING_LENGTH_MAX+1] = {0}; + int rc; + + + printf("LCD info\n"); + + if (ipmi_lcd_get_configure_command_wh (intf) != 0) + { + return -1; + } + else + { + if (lcd_mode.lcdmode== IPMI_DELL_LCD_CONFIG_DEFAULT) + { + char text[IPMI_DELL_LCD_STRING_LENGTH_MAX+1] = {0}; + + ipmi_lcd_get_platform_model_name(intf, text, + IPMI_DELL_LCD_STRING_LENGTH_MAX, + IPMI_DELL_PLATFORM_MODEL_NAME_SELECTOR); + + if (text == NULL) + return -1; + printf(" Setting:Model name\n"); + printf(" Line 1: %s\n", text); + } + else if (lcd_mode.lcdmode == IPMI_DELL_LCD_CONFIG_NONE) + { + printf(" Setting: none\n"); + } + else if (lcd_mode.lcdmode == IPMI_DELL_LCD_CONFIG_USER_DEFINED) + { + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; /* get parameter*/ + data[1] = IPMI_DELL_LCD_GET_CAPS_SELECTOR; + data[2] = 0; /* set selector (n/a)*/ + data[3] = 0; /* block selector (n/a)*/ + + printf(" Setting: User defined\n"); + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error getting LCD capabilities: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + lcd_caps = (IPMI_DELL_LCD_CAPS *)rsp; + if (lcd_caps->number_lines > 0) + { + memset(lcdstring, 0, IPMI_DELL_LCD_STRING_LENGTH_MAX+1); + + rc = ipmi_lcd_get_single_line_text (intf, lcdstring, lcd_caps->max_chars[0]); + printf(" Text: %s\n", lcdstring); + } + else + { + printf(" No lines to show\n"); + } + } + else if (lcd_mode.lcdmode == IPMI_DELL_LCD_iDRAC_IPV4ADRESS) + { + printf(" Setting: IPV4 Address\n"); + } + else if (lcd_mode.lcdmode == IPMI_DELL_LCD_IDRAC_MAC_ADDRESS) + { + printf(" Setting: MAC Address\n"); + } + else if (lcd_mode.lcdmode == IPMI_DELL_LCD_OS_SYSTEM_NAME) + { + printf(" Setting: OS System Name\n"); + } + else if (lcd_mode.lcdmode == IPMI_DELL_LCD_SERVICE_TAG) + { + printf(" Setting: System Tag\n"); + } + else if (lcd_mode.lcdmode == IPMI_DELL_LCD_iDRAC_IPV6ADRESS) + { + printf(" Setting: IPV6 Address\n"); + } + else if (lcd_mode.lcdmode == IPMI_DELL_LCD_AMBEINT_TEMP) + { + printf(" Setting: Ambient Temp\n"); + if(lcd_mode.lcdqualifier&0x02) + printf(" Unit: F\n"); + else + printf(" Unit: C\n"); + } + else if (lcd_mode.lcdmode == IPMI_DELL_LCD_SYSTEM_WATTS) + { + printf(" Setting: System Watts\n"); + + if(lcd_mode.lcdqualifier&0x01) + printf(" Unit: BTU/hr\n"); + else + printf(" Unit: Watt\n"); + + } + if(lcd_mode.error_display==IPMI_DELL_LCD_ERROR_DISP_SEL) + printf(" Error Display: SEL\n"); + else if(lcd_mode.error_display==IPMI_DELL_LCD_ERROR_DISP_VERBOSE) + printf(" Error Display: Simple\n"); + } + + return 0; +} + +/***************************************************************** +* Function Name: ipmi_lcd_get_info +* +* Description: This function prints current lcd configuration for platform other than whoville +* Input: intf - ipmi interface +* Output: +* Return: +* +******************************************************************/ +static int ipmi_lcd_get_info(void * intf) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + IPMI_DELL_LCD_CAPS * lcd_caps; + uint8_t command = 0; + char lcdstring[IPMI_DELL_LCD_STRING_LENGTH_MAX+1] = {0}; + int rc; + + printf("LCD info\n"); + + if (ipmi_lcd_get_configure_command (intf, &command) != 0) + { + return -1; + } + else + { + if (command == IPMI_DELL_LCD_CONFIG_DEFAULT) + { + memset (lcdstring,0,IPMI_DELL_LCD_STRING_LENGTH_MAX+1); + + ipmi_lcd_get_platform_model_name(intf, lcdstring, IPMI_DELL_LCD_STRING_LENGTH_MAX, + IPMI_DELL_PLATFORM_MODEL_NAME_SELECTOR); + + printf(" Setting: default\n"); + printf(" Line 1: %s\n", lcdstring); + } + else if (command == IPMI_DELL_LCD_CONFIG_NONE) + { + printf(" Setting: none\n"); + } + else if (command == IPMI_DELL_LCD_CONFIG_USER_DEFINED) + { + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; /* get parameter */ + data[1] = IPMI_DELL_LCD_GET_CAPS_SELECTOR; + data[2] = 0; /* set selector (n/a) */ + data[3] = 0; /* block selector (n/a) */ + + printf(" Setting: custom\n"); + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error getting LCD capabilities: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + lcd_caps = (IPMI_DELL_LCD_CAPS *)(void *)rsp; + if (lcd_caps->number_lines > 0) + { + memset (lcdstring,0,IPMI_DELL_LCD_STRING_LENGTH_MAX+1); + rc = ipmi_lcd_get_single_line_text (intf, lcdstring, lcd_caps->max_chars[0]); + printf(" Text: %s\n", lcdstring); + } + else + { + printf(" No lines to show\n"); + } + } + } + + return 0; +} + +/***************************************************************** +* Function Name: ipmi_lcd_get_status_val +* +* Description: This function gets current lcd configuration +* Input: intf - ipmi interface +* Output: lcdstatus - KVM Status & Lock Status +* Return: +* +******************************************************************/ + +static int +ipmi_lcd_get_status_val(void * intf, LCD_STATUS* lcdstatus) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; /* get parameter */ + data[1] = IPMI_DELL_LCD_STATUS_SELECTOR; + data[2] = 0; /* block selector */ + data[3] = 0; + /* set selector (n/a) */ + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error getting LCD status: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + /*lcdstatus= (LCD_STATUS* ) rsp->data; */ + + lcdstatus->vKVM_status=rsp[1]; + lcdstatus->lock_status=rsp[2]; + + return 0; +} + + +/***************************************************************** +* Function Name: IsLCDSupported +* +* Description: This function returns whether lcd supported or not +* Input: +* Output: +* Return: +* +******************************************************************/ +static int IsLCDSupported () +{ + return LcdSupported; +} + +/***************************************************************** +* Function Name: CheckLCDSupport +* +* Description: This function checks whether lcd supported or not +* Input: intf - ipmi interface +* Output: +* Return: +* +******************************************************************/ +static void CheckLCDSupport(void * intf) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + + LcdSupported = 0; + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; /* get parameter */ + data[1] = IPMI_DELL_LCD_STATUS_SELECTOR; + data[2] = 0; /* block selector */ + data[3] = 0; + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { return; } + LcdSupported = 1; + +} + +/***************************************************************** +* Function Name: ipmi_lcd_status_print +* +* Description: This function prints current lcd configuration KVM Status & Lock Status +* Input: lcdstatus - KVM Status & Lock Status +* Output: +* Return: +* +******************************************************************/ + +static void ipmi_lcd_status_print( LCD_STATUS lcdstatus) +{ + switch (lcdstatus.vKVM_status) + { + case 0x00: + printf("LCD KVM Status :Inactive\n"); + break; + case 0x01: + printf("LCD KVM Status :Active\n"); + break; + default: + printf("LCD KVM Status :Invalid Status\n"); + + break; + } + + switch (lcdstatus.lock_status) + { + case 0x00: + printf("LCD lock Status :View and modify\n"); + break; + case 0x01: + printf("LCD lock Status :View only\n"); + break; + case 0x02: + printf("LCD lock Status :disabled\n"); + break; + default: + printf("LCD lock Status :Invalid\n"); + break; + } + +} + +/***************************************************************** +* Function Name: ipmi_lcd_get_status +* +* Description: This function gets current lcd KVM active status & lcd access mode +* Input: intf - ipmi interface +* Output: +* Return: -1 on error +* 0 if successful +* +******************************************************************/ +static int +ipmi_lcd_get_status(void * intf ) +{ + int rc=0; + LCD_STATUS lcdstatus; + + rc =ipmi_lcd_get_status_val( intf, &lcdstatus); + if (rc <0) + return -1; + ipmi_lcd_status_print(lcdstatus); + + return rc; + +} + +/***************************************************************** +* Function Name: ipmi_lcd_set_kvm +* +* Description: This function sets lcd KVM active status +* Input: intf - ipmi interface +* status - Inactive / Active +* Output: +* Return: -1 on error +* 0 if successful +* +******************************************************************/ +static int +ipmi_lcd_set_kvm(void * intf, char status) +{ +#define LSCC_DATA_LEN 2 + LCD_STATUS lcdstatus; + int rc=0; + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[5]; + rc=ipmi_lcd_get_status_val(intf,&lcdstatus); + if (rc < 0) + return -1; + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_SET_SYS_INFO; + req.msg.data_len = 5; + req.msg.data = data; + data[0] = IPMI_DELL_LCD_STATUS_SELECTOR; + data[1] = status; /* active- incative*/ + data[2] = lcdstatus.lock_status; /* full-veiw-locked */ + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error setting LCD status: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + return rc; +} + +/***************************************************************** +* Function Name: ipmi_lcd_set_lock +* +* Description: This function sets lcd access mode +* Input: intf - ipmi interface +* lock - View and modify / View only / Diabled +* Output: +* Return: -1 on error +* 0 if successful +* +******************************************************************/ +static int +ipmi_lcd_set_lock(void * intf, char lock) +{ +#define LSCC_DATA_LEN 2 + LCD_STATUS lcdstatus; + int rc =0; + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[5]; + rc=ipmi_lcd_get_status_val(intf,&lcdstatus); + if (rc < 0) + return -1; + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_SET_SYS_INFO; + req.msg.data_len = 5; + req.msg.data = data; + data[0] = IPMI_DELL_LCD_STATUS_SELECTOR; + data[1] = lcdstatus.vKVM_status; /* active- incative */ + data[2] = lock; /* full- veiw-locked */ + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error setting LCD status: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + return rc; +} + +/***************************************************************** +* Function Name: ipmi_lcd_set_single_line_text +* +* Description: This function sets lcd line text +* Input: intf - ipmi interface +* text - lcd string +* Output: +* Return: -1 on error +* 0 if successful +* +******************************************************************/ + +static int +ipmi_lcd_set_single_line_text (void * intf, char * text) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[18]; + int bytes_to_store = strlen_(text); + int bytes_stored = 0; + int ii; + int rc = 0; + if (bytes_to_store>IPMI_DELL_LCD_STRING_LENGTH_MAX) + { + lprintf(LOG_ERR, " Out of range Max limit is 62 characters"); + return 1; + + } + else + { + bytes_to_store = MIN(bytes_to_store, IPMI_DELL_LCD_STRING_LENGTH_MAX); + for (ii = 0; ii < 4; ii++) { + /*first block, 2 bytes parms and 14 bytes data*/ + if (0 == ii) { + int size_of_copy = + MIN((bytes_to_store - bytes_stored), IPMI_DELL_LCD_STRING1_SIZE); + if (size_of_copy < 0) /* allow 0 string length*/ + break; + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_SET_SYS_INFO; + req.msg.data_len = size_of_copy + 4; /* chars, selectors and sizes*/ + req.msg.data = data; + data[0] = IPMI_DELL_LCD_STRING_SELECTOR; + data[1] = ii; /* block number to use (0)*/ + data[2] = 0; /*string encoding*/ + data[3] = bytes_to_store; /* total string length*/ + memcpy (data+4, text+bytes_stored, size_of_copy); + bytes_stored += size_of_copy; + } else { + int size_of_copy = + MIN((bytes_to_store - bytes_stored), IPMI_DELL_LCD_STRINGN_SIZE); + if (size_of_copy <= 0) + break; + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_SET_SYS_INFO; + req.msg.data_len = size_of_copy + 2; + req.msg.data = data; + data[0] = IPMI_DELL_LCD_STRING_SELECTOR; + data[1] = ii; /* block number to use (1,2,3)*/ + memcpy (data+2, text+bytes_stored, size_of_copy); + bytes_stored += size_of_copy; + } + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error setting text data: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + } + } + return rc; +} + +/***************************************************************** +* Function Name: ipmi_lcd_set_text +* +* Description: This function sets lcd line text +* Input: intf - ipmi interface +* text - lcd string +* line_number- line number + +* Output: +* Return: -1 on error +* 0 if successful +* +******************************************************************/ + +static int +ipmi_lcd_set_text(void * intf, char * text, int line_number) +{ + int rc = 0; + + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + IPMI_DELL_LCD_CAPS * lcd_caps; + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; /* get parameter*/ + data[1] = IPMI_DELL_LCD_GET_CAPS_SELECTOR; + data[2] = 0; /* set selector (n/a)*/ + data[3] = 0; /* block selector (n/a)*/ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error getting LCD capabilities: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + lcd_caps = (IPMI_DELL_LCD_CAPS *)(void *)rsp; + + if (lcd_caps->number_lines > 0) { + rc = ipmi_lcd_set_single_line_text (intf, text); + } else { + lprintf(LOG_ERR, "LCD does not have any lines that can be set"); + rc = -1; + } + + + return rc; +} + +/***************************************************************** +* Function Name: ipmi_lcd_configure_wh +* +* Description: This function updates the current lcd configuration +* Input: intf - ipmi interface +* lcdqualifier- lcd quallifier +* errordisp - error number +* line_number-line number +* text - lcd string +* Output: +* Return: -1 on error +* 0 if successful +* +******************************************************************/ + +static int +ipmi_lcd_configure_wh (void * intf, uint32_t mode , + uint16_t lcdqualifier, uint8_t errordisp, + int8_t line_number, char * text) +{ + int rc = 0; + + + if (IPMI_DELL_LCD_CONFIG_USER_DEFINED == mode) + /* Any error was reported earlier. */ + rc = ipmi_lcd_set_text(intf, text, line_number); + + + if (rc == 0) + + rc = ipmi_lcd_set_configure_command_wh (intf, mode ,lcdqualifier,errordisp); + + return rc; +} + + +/***************************************************************** +* Function Name: ipmi_lcd_configure +* +* Description: This function updates the current lcd configuration +* Input: intf - ipmi interface +* command- lcd command +* line_number-line number +* text - lcd string +* Output: +* Return: -1 on error +* 0 if successful +* +******************************************************************/ + +static int +ipmi_lcd_configure (void * intf, int command, + int8_t line_number, char * text) +{ + int rc = 0; + + if (IPMI_DELL_LCD_CONFIG_USER_DEFINED == command) + rc = ipmi_lcd_set_text(intf, text, line_number); + + if (rc == 0) + rc = ipmi_lcd_set_configure_command (intf, command); + + return rc; +} + + +/***************************************************************** +* Function Name: ipmi_lcd_usage +* +* Description: This function prints help message for lcd command +* Input: +* Output: +* +* Return: +* +******************************************************************/ + +static void +ipmi_lcd_usage(void) +{ + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, "Generic DELL HW:"); + lprintf(LOG_NOTICE, " lcd set {none}|{default}|{custom <text>}"); + lprintf(LOG_NOTICE, " Set LCD text displayed during non-fault conditions"); + + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, "iDRAC 11g or iDRAC 12g:"); + lprintf(LOG_NOTICE, " lcd set {mode}|{lcdqualifier}|{errordisplay}"); + lprintf(LOG_NOTICE, " Allows you to set the LCD mode and user-definedstring."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " lcd set mode {none}|{modelname}|{ipv4address}|{macaddress}|"); + lprintf(LOG_NOTICE, " {systemname}|{servicetag}|{ipv6address}|{ambienttemp}"); + lprintf(LOG_NOTICE, " {systemwatt }|{assettag}|{userdefined}<text>"); + lprintf(LOG_NOTICE, " Allows you to set the LCD display mode to any of the preceding parameters"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " lcd set lcdqualifier {watt}|{btuphr}|{celsius}|{fahrenheit}"); + lprintf(LOG_NOTICE, " Allows you to set the unit for the system ambient temperature mode."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " lcd set errordisplay {sel}|{simple}"); + lprintf(LOG_NOTICE, " Allows you to set the error display."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " lcd info"); + lprintf(LOG_NOTICE, " Show LCD text that is displayed during non-fault conditions"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " lcd set vkvm{active}|{inactive}"); + lprintf(LOG_NOTICE, " Set vKVM active and inactive, message will be displayed on lcd"); + lprintf(LOG_NOTICE, " when vKVM is active and vKVM session is in progress"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " lcd set frontpanelaccess {viewandmodify}|{viewonly}|{disabled}"); + lprintf(LOG_NOTICE, " Set LCD mode to view and modify, view only or disabled "); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " lcd status"); + lprintf(LOG_NOTICE, " Show LCD Status for vKVM display<active|inactive>"); + lprintf(LOG_NOTICE, " and Front Panel access mode {viewandmodify}|{viewonly}|{disabled} "); + lprintf(LOG_NOTICE, ""); +} + +/***************************************************************** +* Function Name: ipmi_delloem_mac_main +* +* Description: This function processes the delloem mac command +* Input: intf - ipmi interface + argc - no of arguments + argv - argument string array +* Output: +* +* Return: return code 0 - success +* -1 - failure +* +******************************************************************/ + + +static int ipmi_delloem_mac_main (void * intf, int argc, char ** argv) +{ + int rc = 0; + + current_arg++; + if (argc > 1 && strcmp(argv[current_arg], "help") == 0) + { + ipmi_mac_usage(); + return 0; + } + ipmi_idracvalidator_command(intf); + if (argc == 1) /*( || (strncmp(argv[current_arg], "list\0", 5) == 0) )*/ + { + rc = ipmi_macinfo(intf, 0xff); + } + else if (strncmp(argv[current_arg], "get\0", 4) == 0) + { + int currIdInt; + current_arg++; + if (argv[current_arg] == NULL) + { + ipmi_mac_usage(); + return -1; + } + if(make_int(argv[current_arg],&currIdInt) < 0) { + lprintf(LOG_ERR, "Invalid NIC number. The NIC number should be between 0-8\n"); + return -1; + } + if( (currIdInt > 8) || (currIdInt < 0) ) + { + lprintf(LOG_ERR, "Invalid NIC number. The NIC number should be between 0-8\n"); + return -1; + } + rc = ipmi_macinfo(intf, currIdInt); + } + else + { + ipmi_mac_usage(); + } + return(rc); +} + + +/***************************************************************** +* Function Name: make_int +* +* Description: This function convert string into integer +* Input: str - decimal number string +* Output: value - integer value +* Return: +* +******************************************************************/ +static int make_int(const char *str, int *value) +{ + char *tmp=NULL; + *value = (int)strtol(str,&tmp,0); + if ( tmp-str != strlen(str) ) + { + return -1; + } + return 0; +} + + + + + +EmbeddedNICMacAddressType EmbeddedNICMacAddress; + +EmbeddedNICMacAddressType_10G EmbeddedNICMacAddress_10G; + +static void InitEmbeddedNICMacAddressValues () +{ + uint8_t i; + uint8_t j; + + + for (i=0;i<MAX_LOM;i++) + { +#ifdef LOM_OLD + EmbeddedNICMacAddress.LOMMacAddress[i].BladSlotNumber = 0; + EmbeddedNICMacAddress.LOMMacAddress[i].MacType = LOM_MACTYPE_RESERVED; + EmbeddedNICMacAddress.LOMMacAddress[i].EthernetStatus = LOM_ETHERNET_RESERVED; + EmbeddedNICMacAddress.LOMMacAddress[i].NICNumber = 0; + EmbeddedNICMacAddress.LOMMacAddress[i].Reserved = 0; +#else + EmbeddedNICMacAddress.LOMMacAddress[i].b0 = 0xF0; + EmbeddedNICMacAddress.LOMMacAddress[i].b1 = 0x00; +#endif + for (j=0;j<MACADDRESSLENGH;j++) + { + EmbeddedNICMacAddress.LOMMacAddress[i].MacAddressByte[j] = 0; + EmbeddedNICMacAddress_10G.MacAddress[i].MacAddressByte[j] = 0; + } + } +} + +uint8_t UseVirtualMacAddress = 0; +#define VIRTUAL_MAC_OFFSET (2) +static int ipmi_macinfo_drac_idrac_virtual_mac(void* intf,uint8_t NicNum) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + + uint8_t msg_data[30]; + uint8_t VirtualMacAddress [MACADDRESSLENGH]; + uint8_t input_length=0; + uint8_t j; + //uint8_t length; + uint8_t i; + + + if (0xff==NicNum || IDRAC_NIC_NUMBER==NicNum ) + { + UseVirtualMacAddress = 0; + + input_length = 0; + msg_data[input_length++] = 1; /*Get*/ + + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = GET_IDRAC_VIRTUAL_MAC; + req.msg.data = msg_data; + req.msg.data_len = input_length; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { return rv; } + + if( (IMC_IDRAC_12G_MODULAR == IMC_Type) || (IMC_IDRAC_12G_MONOLITHIC== IMC_Type) ) { + // Get the Chasiss Assigned MAC Addresss for 12g Only + memcpy(VirtualMacAddress,&rsp[1],MACADDRESSLENGH); + + for (i=0;i<MACADDRESSLENGH;i++) + { + if (0 != VirtualMacAddress [i]) + { + UseVirtualMacAddress = 1; + } + } + // Get the Server Assigned MAC Addresss for 12g Only + if(!UseVirtualMacAddress) { + memcpy(VirtualMacAddress,&rsp[1+MACADDRESSLENGH],MACADDRESSLENGH); + + for (i=0;i<MACADDRESSLENGH;i++) + { + if (0 != VirtualMacAddress [i]) + { + UseVirtualMacAddress = 1; + } + } + } + } else { + memcpy(VirtualMacAddress,&rsp[VIRTUAL_MAC_OFFSET],MACADDRESSLENGH); + + for (i=0;i<MACADDRESSLENGH;i++) + { + if (0 != VirtualMacAddress [i]) + { + UseVirtualMacAddress = 1; + } + } + } + if (0 == UseVirtualMacAddress) + return -1; + if (IMC_IDRAC_10G == IMC_Type) + printf ("\nDRAC MAC Address "); + else if ( (IMC_IDRAC_11G_MODULAR == IMC_Type) || (IMC_IDRAC_11G_MONOLITHIC== IMC_Type) ) + printf ("\niDRAC6 MAC Address "); + else if ( (IMC_IDRAC_12G_MODULAR == IMC_Type) || (IMC_IDRAC_12G_MONOLITHIC== IMC_Type) ) + printf ("\niDRAC7 MAC Address "); + + for (j=0;j<5;j++) + printf("%02x:",VirtualMacAddress[j]); + printf("%02x",VirtualMacAddress[j]); /*5*/ + + printf ("\n\r"); + + } + return 0; +} + + +/***************************************************************** +* Function Name: ipmi_macinfo_drac_idrac_mac +* +* Description: This function retrieves the mac address of DRAC or iDRAC +* Input: NicNum +* Output: +* Return: +* +******************************************************************/ + +static int ipmi_macinfo_drac_idrac_mac(void* intf,uint8_t NicNum) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + + uint8_t msg_data[30]; + uint8_t input_length=0; + uint8_t iDRAC6MacAddressByte[MACADDRESSLENGH]; + uint8_t j; + + ipmi_macinfo_drac_idrac_virtual_mac (intf,NicNum); + + + if ((0xff==NicNum || IDRAC_NIC_NUMBER==NicNum) && 0 == UseVirtualMacAddress) + { + + input_length = 0; + + msg_data[input_length++] = LAN_CHANNEL_NUMBER; + msg_data[input_length++] = MAC_ADDR_PARAM; + msg_data[input_length++] = 0x00; + msg_data[input_length++] = 0x00; + + req.msg.netfn = TRANSPORT_NETFN; + req.msg.lun = 0; + req.msg.cmd = GET_LAN_PARAM_CMD; + req.msg.data = msg_data; + req.msg.data_len = input_length; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error in getting MAC Address: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + memcpy(iDRAC6MacAddressByte,&rsp[PARAM_REV_OFFSET],MACADDRESSLENGH); + + if (IMC_IDRAC_10G == IMC_Type) + printf ("\n\rDRAC MAC Address "); + else if ((IMC_IDRAC_11G_MODULAR == IMC_Type) || (IMC_IDRAC_11G_MONOLITHIC== IMC_Type)) + printf ("\n\riDRAC6 MAC Address "); + else if ((IMC_IDRAC_12G_MODULAR == IMC_Type) || (IMC_IDRAC_12G_MONOLITHIC== IMC_Type)) + printf ("\n\riDRAC7 MAC Address "); + else + printf ("\n\riDRAC6 MAC Address "); + + for (j=0;j<5;j++) + printf("%02x:",iDRAC6MacAddressByte[j]); + printf("%02x",iDRAC6MacAddressByte[j]); + + printf ("\n\r"); + } + return 0; +} + + +/***************************************************************** +* Function Name: ipmi_macinfo_10g +* +* Description: This function retrieves the mac address of LOMs +* Input: intf - ipmi interface + NicNum - NIC number +* Output: +* Return: +* +******************************************************************/ + +static int ipmi_macinfo_10g (void* intf, uint8_t NicNum) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + + uint8_t msg_data[30]; + uint8_t input_length=0; + + uint8_t j; + uint8_t i; + + uint8_t Total_No_NICs = 0; + + + InitEmbeddedNICMacAddressValues (); + + memset(msg_data, 0, sizeof(msg_data)); + input_length = 0; + msg_data[input_length++] = 0x00; /* Get Parameter Command */ + msg_data[input_length++] = EMB_NIC_MAC_ADDRESS_9G_10G; /* OEM Param */ + + msg_data[input_length++] = 0x00; + msg_data[input_length++] = 0x00; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = APP_NETFN; + req.msg.lun = 0; + req.msg.cmd = GET_SYSTEM_INFO_CMD; + req.msg.data = msg_data; + + + req.msg.data_len = input_length; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error in getting MAC Address: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + if (fdebug) dump_buf("GetMacResp_10G",rsp,rsp_len,0); + + Total_No_NICs = (uint8_t) rsp[PARAM_REV_OFFSET]; /* Byte 1: Total Number of Embedded NICs */ + + if (IDRAC_NIC_NUMBER != NicNum) + { + if (0xff == NicNum) + { + printf ("\n\rSystem LOMs"); + } + printf("\n\rNIC Number\tMAC Address\n\r"); + + memcpy(&EmbeddedNICMacAddress_10G,&rsp[PARAM_REV_OFFSET+TOTAL_N0_NICS_INDEX],Total_No_NICs* MACADDRESSLENGH); + + + /*Read the LOM type and Mac Addresses */ + + for (i=0;i<Total_No_NICs;i++) + { + if ((0xff==NicNum) || (i == NicNum) ) + { + printf ("\n\r%d",i); + printf ("\t\t"); + for (j=0;j<5;j++) + { + printf("%02x:",EmbeddedNICMacAddress_10G.MacAddress[i].MacAddressByte[j]); + } + printf("%02x",EmbeddedNICMacAddress_10G.MacAddress[i].MacAddressByte[j]); + } + } + printf ("\n\r"); + + } + + ipmi_macinfo_drac_idrac_mac(intf,NicNum); + + + return 0; +} + + +/***************************************************************** +* Function Name: ipmi_macinfo_11g +* +* Description: This function retrieves the mac address of LOMs +* Input: intf - ipmi interface +* Output: +* Return: +* +******************************************************************/ + +static int ipmi_macinfo_11g (void* intf, uint8_t NicNum) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + uint8_t msg_data[30]; + uint8_t input_length=0; + uint8_t len; + uint8_t j; + uint8_t offset; + uint8_t maxlen; + uint8_t loop_count; + uint8_t i; + uint8_t lom_mactype; + uint8_t lom_nicnum; + uint8_t lom_ethstat; + uint8_t *lom_mac; + // uint8_t LOMStatus = 0; + // uint8_t PlayingDead = 0; + + offset = 0; + len = 8; /*eigher 8 or 16 */ + maxlen = 64; + loop_count = maxlen / len; + + InitEmbeddedNICMacAddressValues (); + + memset(msg_data, 0, sizeof(msg_data)); + input_length = 0; + msg_data[input_length++] = 0x00; /* Get Parameter Command */ + msg_data[input_length++] = EMB_NIC_MAC_ADDRESS_11G; /* OEM Param */ + + msg_data[input_length++] = 0x00; + msg_data[input_length++] = 0x00; + msg_data[input_length++] = 0x00; + msg_data[input_length++] = 0x00; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = APP_NETFN; + req.msg.lun = 0; + req.msg.cmd = GET_SYSTEM_INFO_CMD; + req.msg.data = msg_data; + + + req.msg.data_len = input_length; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error in getting MAC Address: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + + len = 8; /*eigher 8 or 16 */ + maxlen = (uint8_t) rsp[0+PARAM_REV_OFFSET]; + loop_count = maxlen / len; + + if (IDRAC_NIC_NUMBER != NicNum) + { + if (0xff == NicNum) + { + printf ("\n\rSystem LOMs"); + } + printf("\n\rNIC Number\tMAC Address\t\tStatus\n\r"); + + + /*Read the LOM type and Mac Addresses */ + offset=0; + for (i=0;i<loop_count;i++,offset=offset+len) + { + input_length = 4; + msg_data[input_length++] = offset; + msg_data[input_length++] = len; + + req.msg.netfn = APP_NETFN; + req.msg.lun = 0; + req.msg.cmd = GET_SYSTEM_INFO_CMD; + req.msg.data = msg_data; + req.msg.data_len = input_length; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error in getting MAC Address: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x\n", rv); + return rv; + } + if (fdebug) { + printf("ipmi_macinfo_11g(%d) i=%d offset=%d\n",NicNum,i,offset); + dump_buf("GetMacResp",rsp,rsp_len,0); + } + + memcpy(&(EmbeddedNICMacAddress.LOMMacAddress[i]),&rsp[PARAM_REV_OFFSET],len); + +#ifdef LOM_OLD + lom_ethstat = EmbeddedNICMacAddress.LOMMacAddress[i].EthernetStatus; + lom_mactype = EmbeddedNICMacAddress.LOMMacAddress[i].MacType; + lom_nicnum = EmbeddedNICMacAddress.LOMMacAddress[i].NICNumber; + lom_mac = &EmbeddedNICMacAddress.LOMMacAddress[i].MacAddressByte[0]; +#else + lom_ethstat = ((EmbeddedNICMacAddress.LOMMacAddress[i].b0 & 0xc0) >> 6); + lom_mactype = ((EmbeddedNICMacAddress.LOMMacAddress[i].b0 & 0x30) >> 4); + /* lom_bladslot = (b0 & 0x0f); */ + lom_nicnum = (EmbeddedNICMacAddress.LOMMacAddress[i].b1 & 0x1f); + lom_mac = &EmbeddedNICMacAddress.LOMMacAddress[i].MacAddressByte[0]; + if (fdebug) { + printf("\n\rlom_ethstat=%x lom_mactype=%x lom_nicnum=%x\n", + lom_ethstat,lom_mactype,lom_nicnum); + printf("MacAdrB=%02x:%02x:%02x:%02x:%02x:%02x\n", + lom_mac[0], lom_mac[1], lom_mac[2], + lom_mac[3], lom_mac[4], lom_mac[5]); + printf("\n\rrsp_mac=%02x:%02x:%02x:%02x:%02x:%02x\n", + rsp[3], rsp[4], rsp[5], rsp[6], rsp[7], rsp[8]); + } + lom_mac = &rsp[3]; +#endif + + if (LOM_MACTYPE_ETHERNET == lom_mactype) + { + + if ( (0xff==NicNum) || (NicNum == lom_nicnum) ) + { + printf ("\n\r%d",lom_nicnum); + printf ("\t\t"); + for (j=0;j<5;j++) + printf("%02x:",lom_mac[j]); + printf("%02x",lom_mac[j]); + + if (LOM_ETHERNET_ENABLED == lom_ethstat) + printf ("\tEnabled"); + else + printf ("\tDisabled"); + } + } + + } + printf ("\n\r"); + + } + + ipmi_macinfo_drac_idrac_mac(intf,NicNum); + + return 0; + +} + + + +/***************************************************************** +* Function Name: ipmi_macinfo +* +* Description: This function retrieves the mac address of LOMs +* Input: intf - ipmi interface +* Output: +* Return: +* +******************************************************************/ + +static int ipmi_macinfo (void* intf, uint8_t NicNum) +{ + if (IMC_IDRAC_10G == IMC_Type) + { + return ipmi_macinfo_10g (intf,NicNum); + } + else if ((IMC_IDRAC_11G_MODULAR == IMC_Type || IMC_IDRAC_11G_MONOLITHIC== IMC_Type ) || + (IMC_IDRAC_12G_MODULAR == IMC_Type || IMC_IDRAC_12G_MONOLITHIC== IMC_Type ) ) + { + return ipmi_macinfo_11g (intf,NicNum); + } + else + { + lprintf(LOG_ERR, " Error in getting MAC Address : Not supported platform"); + return 0; + } +} + + +/***************************************************************** +* Function Name: ipmi_mac_usage +* +* Description: This function prints help message for mac command +* Input: +* Output: +* +* Return: +* +******************************************************************/ + +static void +ipmi_mac_usage(void) +{ + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " mac list"); + lprintf(LOG_NOTICE, " Lists the MAC address of LOMs"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " mac get <NIC number>"); + lprintf(LOG_NOTICE, " Shows the MAC address of specified LOM. 0-7 System LOM, 8- DRAC/iDRAC."); + lprintf(LOG_NOTICE, ""); +} + +/***************************************************************** +* Function Name: ipmi_delloem_lan_main +* +* Description: This function processes the delloem lan command +* Input: intf - ipmi interface + argc - no of arguments + argv - argument string array +* Output: +* +* Return: return code 0 - success +* -1 - failure +* +******************************************************************/ + +static int ipmi_delloem_lan_main (void * intf, int argc, char ** argv) +{ + int rc = 0; + + int nic_selection = 0; + char nic_set[2] = {0}; + current_arg++; + if (argv[current_arg] == NULL || strcmp(argv[current_arg], "help") == 0) + { + ipmi_lan_usage(); + return 0; + } + ipmi_idracvalidator_command(intf); + if (!IsLANSupported()) + { + printf("lan is not supported on this system.\n"); + return -1; + } + else if (strncmp(argv[current_arg], "set\0", 4) == 0) + { + current_arg++; + if (argv[current_arg] == NULL) + { + ipmi_lan_usage(); + return -1; + } + if(iDRAC_FLAG == IDRAC_12G) { + nic_selection = get_nic_selection_mode_12g(intf,current_arg,argv,nic_set); + if (INVALID == nic_selection) + { + ipmi_lan_usage(); + return -1; + } else if(INVAILD_FAILOVER_MODE == nic_selection) { + printf(INVAILD_FAILOVER_MODE_STRING); + return 0; + } else if(INVAILD_FAILOVER_MODE_SETTINGS == nic_selection){ + printf(INVAILD_FAILOVER_MODE_SET); + return 0; + } else if(INVAILD_SHARED_MODE == nic_selection){ + printf(INVAILD_SHARED_MODE_SET_STRING); + return 0; + } + + rc = ipmi_lan_set_nic_selection_12g(intf,nic_set); + } + else + { + nic_selection = get_nic_selection_mode(current_arg,argv); + + if (INVALID == nic_selection) + { + ipmi_lan_usage(); + return -1; + } + if(IMC_IDRAC_11G_MODULAR == IMC_Type) { + printf(INVAILD_SHARED_MODE_SET_STRING); + return 0; + } + rc = ipmi_lan_set_nic_selection(intf,nic_selection); + } + return 0; + } + else if (strncmp(argv[current_arg], "get\0", 4) == 0) + { + current_arg++; + if (argv[current_arg] == NULL) + { + rc = ipmi_lan_get_nic_selection(intf); + return rc; + } + else if (strncmp(argv[current_arg], "active\0", 7) == 0) + { + rc = ipmi_lan_get_active_nic(intf); + return rc; + } + else + { + ipmi_lan_usage(); + } + + } + else + { + ipmi_lan_usage(); + return -1; + } + return(rc); +} + + +static int IsLANSupported () +{ + if (IMC_IDRAC_11G_MODULAR == IMC_Type) + return 0; + return 1; +} + + +int get_nic_selection_mode_12g (void* intf,int current_arg, char ** argv, char *nic_set) +{ + int failover = 0; + + // First get the current settings. + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + + uint8_t msg_data[30]; + uint8_t input_length=0; + + input_length = 0; + + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + + req.msg.cmd = GET_NIC_SELECTION_12G_CMD; + + req.msg.data = msg_data; + req.msg.data_len = input_length; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error in getting NIC selection: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n", + rv,decode_cc(0,rv)); + return rv; + } + + nic_set[0] = rsp[0]; + nic_set[1] = rsp[1]; + + + if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "dedicated\0", 10)) + { + nic_set[0] = 1; + nic_set[1] = 0; + return 0; + } + if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "shared\0", 7)) + { + + } + else + return INVALID; + + current_arg++; + if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "with\0", 5)) + { + } + else + return INVALID; + + current_arg++; + if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "failover\0", 9)) + { + failover = 1; + } + if(failover) + current_arg++; + if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "lom1\0", 5)) + { + if(IMC_IDRAC_12G_MODULAR == IMC_Type) + { + return INVAILD_SHARED_MODE; + } + if(failover) { + if(nic_set[0] == 2) + { + return INVAILD_FAILOVER_MODE; + } else if(nic_set[0] == 1) { + return INVAILD_FAILOVER_MODE_SETTINGS; + } + nic_set[1] = 2; + } + else { + nic_set[0] = 2; + if(nic_set[1] == 2) + nic_set[1] = 0; + } + return 0; + } + else if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "lom2\0", 5)) + { + if(IMC_IDRAC_12G_MODULAR == IMC_Type) + { + return INVAILD_SHARED_MODE; + } + if(failover) { + if(nic_set[0] == 3) + { + return INVAILD_FAILOVER_MODE; + } else if(nic_set[0] == 1) { + return INVAILD_FAILOVER_MODE_SETTINGS; + } + nic_set[1] = 3; + } + else { + nic_set[0] = 3; + if(nic_set[1] == 3) + nic_set[1] = 0; + + } + return 0; + } + else if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "lom3\0", 5)) + { + if(IMC_IDRAC_12G_MODULAR == IMC_Type) + { + return INVAILD_SHARED_MODE; + } + if(failover) { + if(nic_set[0] == 4) + { + return INVAILD_FAILOVER_MODE; + } else if(nic_set[0] == 1) { + return INVAILD_FAILOVER_MODE_SETTINGS; + } + nic_set[1] = 4; + } + else { + nic_set[0] = 4; + if(nic_set[1] == 4) + nic_set[1] = 0; + } + return 0; + } + else if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "lom4\0", 5)) + { + if(IMC_IDRAC_12G_MODULAR == IMC_Type) + { + return INVAILD_SHARED_MODE; + } + if(failover) { + if(nic_set[0] == 5) + { + return INVAILD_FAILOVER_MODE; + } else if(nic_set[0] == 1) { + return INVAILD_FAILOVER_MODE_SETTINGS; + } + nic_set[1] = 5; + } + else { + nic_set[0] = 5; + if(nic_set[1] == 5) + nic_set[1] = 0; + } + return 0; + } + else if (failover && NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "none\0", 5)) + { + if(IMC_IDRAC_12G_MODULAR == IMC_Type) + { + return INVAILD_SHARED_MODE; + } + if(failover) { + if(nic_set[0] == 1) { + return INVAILD_FAILOVER_MODE_SETTINGS; + } + nic_set[1] = 0; + } + return 0; + } + else if (failover && NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "all\0", 4)) + { + } + else + return INVALID; + + current_arg++; + if (failover && NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "loms\0", 5)) + { + if(IMC_IDRAC_12G_MODULAR == IMC_Type) + { + return INVAILD_SHARED_MODE; + } + if(nic_set[0] == 1) { + return INVAILD_FAILOVER_MODE_SETTINGS; + } + nic_set[1] = 6; + return 0; + } + + return INVALID; + +} + + +static int get_nic_selection_mode (int current_arg, char ** argv) +{ + if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "dedicated\0", 10)) + { + return DEDICATED; + } + if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "shared\0", 7)) + { + if (NULL == argv[current_arg+1] ) + return SHARED; + } + current_arg++; + if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "with\0", 5)) + { + } + else + return INVALID; + + current_arg++; + if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "failover\0", 9)) + { + } + else + return INVALID; + + current_arg++; + if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "lom2\0", 5)) + { + return SHARED_WITH_FAILOVER_LOM2; + } + else if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "all\0", 4)) + { + } + else + return INVALID; + + current_arg++; + if (NULL!= argv[current_arg] && 0 == strncmp(argv[current_arg], "loms\0", 5)) + { + return SHARED_WITH_FAILOVER_ALL_LOMS; + } + + return INVALID; + +} + + +static int ipmi_lan_set_nic_selection_12g (void* intf, uint8_t* nic_selection) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + + uint8_t msg_data[30]; + uint8_t input_length=0; + + input_length = 0; + + msg_data[input_length++] = nic_selection[0]; + msg_data[input_length++] = nic_selection[1]; + + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = SET_NIC_SELECTION_12G_CMD; + req.msg.data = msg_data; + req.msg.data_len = input_length; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error in setting NIC selection: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n", + rv,decode_cc(0,rv)); + return rv; + } + printf("configured successfully"); + + return 0; +} + + +static int ipmi_lan_set_nic_selection (void* intf, uint8_t nic_selection) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + + uint8_t msg_data[30]; + uint8_t input_length=0; + //uint8_t j; + + input_length = 0; + + msg_data[input_length++] = nic_selection; + + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = SET_NIC_SELECTION_CMD; + req.msg.data = msg_data; + req.msg.data_len = input_length; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error in setting NIC selection: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n", + rv,decode_cc(0,rv)); + return rv; + } + printf("configured successfully"); + + return 0; +} + +static int ipmi_lan_get_nic_selection (void* intf) +{ + uint8_t nic_selection=-1; + uint8_t nic_selection_failover = 0; + + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + + uint8_t msg_data[30]; + uint8_t input_length=0; + //uint8_t j; + + input_length = 0; + + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + if(iDRAC_FLAG == IDRAC_12G) + req.msg.cmd = GET_NIC_SELECTION_12G_CMD; + else + req.msg.cmd = GET_NIC_SELECTION_CMD; + req.msg.data = msg_data; + req.msg.data_len = input_length; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error in getting NIC selection: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n", + rv,decode_cc(0,rv)); + return rv; + } + nic_selection = rsp[0]; + + if(iDRAC_FLAG == IDRAC_12G) + { + + nic_selection_failover = rsp[1]; + if ((nic_selection < 6) && (nic_selection > 0) && (nic_selection_failover < 7)) + { + if(nic_selection == 1) { + printf ("%s\n",NIC_Selection_Mode_String_12g[nic_selection-1]); + } else if(nic_selection) { + printf ("Shared LOM : %s\n",NIC_Selection_Mode_String_12g[nic_selection-1]); + if(nic_selection_failover == 0) + printf ("Failover LOM : None\n"); + else if(nic_selection_failover >= 2 && nic_selection_failover <= 6) + printf ("Failover LOM : %s\n",NIC_Selection_Mode_String_12g[nic_selection_failover + 3]); + } + + } + else + { + lprintf(LOG_ERR, " Error Outof bond Value received (%d) (%d) \n",nic_selection,nic_selection_failover); + return -1; + } + } + else + { + printf ("%s\n",NIC_Selection_Mode_String[nic_selection]); + } + + return 0; +} + +static int ipmi_lan_get_active_nic (void* intf) +{ + uint8_t active_nic=0; + uint8_t current_lom =0; + + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + + uint8_t msg_data[30]; + uint8_t input_length=0; + + input_length = 0; + + msg_data[input_length++] = 0; /*Get current LOM*/ + msg_data[input_length++] = 0; /*Reserved*/ + msg_data[input_length++] = 0; /*Reserved*/ + + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = GET_ACTIVE_NIC_CMD; + req.msg.data = msg_data; + req.msg.data_len = input_length; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error in getting Current LOM: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n", + rv,decode_cc(0,rv)); + return rv; + } + current_lom = rsp[0]; + + input_length = 0; + + msg_data[input_length++] = 1; //Get Link status + msg_data[input_length++] = 0; //Reserved + msg_data[input_length++] = 0; //Reserved + + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = GET_ACTIVE_NIC_CMD; + req.msg.data = msg_data; + req.msg.data_len = input_length; + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error in getting Active LOM Status: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n", + rv,decode_cc(0,rv)); + return rv; + } + + active_nic = rsp[1]; + if (current_lom < 5 && active_nic) + printf ("\n%s\n",ActiveLOM_String[current_lom]); + else + printf ("\n%s\n",ActiveLOM_String[5]); + + return 0; +} + + +static void +ipmi_lan_usage(void) +{ + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " lan set <Mode> "); + lprintf(LOG_NOTICE, " sets the NIC Selection Mode :"); + lprintf(LOG_NOTICE, " on iDRAC12g :"); + + lprintf(LOG_NOTICE, " dedicated, shared with lom1, shared with lom2,shared with lom3,shared "); + lprintf(LOG_NOTICE, " with lom4,shared with failover lom1,shared with failover lom2,shared "); + lprintf(LOG_NOTICE, " with failover lom3,shared with failoverlom4,shared with Failover all "); + lprintf(LOG_NOTICE, " loms, shared with Failover None)."); + lprintf(LOG_NOTICE, " on other systems :"); + lprintf(LOG_NOTICE, " dedicated, shared, shared with failoverlom2,"); + lprintf(LOG_NOTICE, " shared with Failover all loms."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " lan get "); + lprintf(LOG_NOTICE, " on iDRAC12g :"); + lprintf(LOG_NOTICE, " returns the current NIC Selection Mode (dedicated, shared with lom1, shared "); + lprintf(LOG_NOTICE, " with lom2, shared with lom3, shared with lom4,shared with failover lom1,"); + lprintf(LOG_NOTICE, " shared with failover lom2,shared with failover lom3,shared with failover "); + lprintf(LOG_NOTICE, " lom4,shared with Failover all loms,shared with Failover None)."); + lprintf(LOG_NOTICE, " on other systems :"); + lprintf(LOG_NOTICE, " dedicated, shared, shared with failover,"); + lprintf(LOG_NOTICE, " lom2, shared with Failover all loms."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " lan get active"); + lprintf(LOG_NOTICE, " Get the current active LOMs (LOM1, LOM2, LOM3, LOM4, NONE)."); + lprintf(LOG_NOTICE, ""); + +} + +/***************************************************************** +* Function Name: ipmi_delloem_powermonitor_main +* +* Description: This function processes the delloem powermonitor command +* Input: intf - ipmi interface + argc - no of arguments + argv - argument string array +* Output: +* +* Return: return code 0 - success +* -1 - failure +* +******************************************************************/ + +static int ipmi_delloem_powermonitor_main (void * intf, int argc, char ** argv) +{ + int rc = 0; + + current_arg++; + if (argc > 1 && strcmp(argv[current_arg], "help") == 0) + { + ipmi_powermonitor_usage(); + return 0; + } + ipmi_idracvalidator_command(intf); + if (argc == 1) + { + rc = ipmi_powermgmt(intf); + } + else if (strncmp(argv[current_arg], "status\0", 7) == 0) + { + rc = ipmi_powermgmt(intf); + } + + else if (strncmp(argv[current_arg], "clear\0", 6) == 0) + { + current_arg++; + if (argv[current_arg] == NULL) + { + ipmi_powermonitor_usage(); + return -1; + } + else if (strncmp(argv[current_arg], "peakpower\0", 10) == 0) + { + rc = ipmi_powermgmt_clear(intf, 1); + } + else if (strncmp(argv[current_arg], "cumulativepower\0", 16) == 0) + { + rc = ipmi_powermgmt_clear(intf, 0); + } + else + { + ipmi_powermonitor_usage(); + return -1; + } + + } + + + else if (strncmp(argv[current_arg], "powerconsumption\0", 17) == 0) + { + current_arg++; + + if (argv[current_arg] == NULL) + { + + rc=ipmi_print_get_power_consmpt_data(intf,watt); + + } + else if (strncmp(argv[current_arg], "watt\0", 5) == 0) + { + + rc = ipmi_print_get_power_consmpt_data(intf, watt); + } + else if (strncmp(argv[current_arg], "btuphr\0", 7) == 0) + { + rc = ipmi_print_get_power_consmpt_data(intf, btuphr); + } + else + { + ipmi_powermonitor_usage(); + return -1; + } + } + else if (strncmp(argv[current_arg], "powerconsumptionhistory\0", 23) == 0) + { + current_arg++; + if (argv[current_arg] == NULL) + { + rc=ipmi_print_power_consmpt_history(intf,watt); + + } + else if (strncmp(argv[current_arg], "watt\0", 5) == 0) + { + rc = ipmi_print_power_consmpt_history(intf, watt); + } + else if (strncmp(argv[current_arg], "btuphr\0", 7) == 0) + { + rc = ipmi_print_power_consmpt_history(intf, btuphr); + } + else + { + ipmi_powermonitor_usage(); + return -1; + } + + } + + else if (strncmp(argv[current_arg], "getpowerbudget\0", 15) == 0) + { + current_arg++; + if (argv[current_arg] == NULL) + { + rc=ipmi_print_power_cap(intf,watt); + + } + else if (strncmp(argv[current_arg], "watt\0", 5) == 0) + { + rc = ipmi_print_power_cap(intf, watt); + } + else if (strncmp(argv[current_arg], "btuphr\0", 7) == 0) + { + rc = ipmi_print_power_cap(intf, btuphr); + } + else + { + ipmi_powermonitor_usage(); + return -1; + } + + } + + else if (strncmp(argv[current_arg], "setpowerbudget\0", 15) == 0) + { + int val; + current_arg++; + if (argv[current_arg] == NULL) + { + ipmi_powermonitor_usage(); + return -1; + } + if (strchr(argv[current_arg], '.')) + { + lprintf(LOG_ERR, " Cap value in Watts, Btu/hr or percent should be whole number"); + return -1; + } + make_int(argv[current_arg],&val); + current_arg++; + if (argv[current_arg] == NULL) + { + ipmi_powermonitor_usage(); + } + else if (strncmp(argv[current_arg], "watt\0", 5) == 0) + { + rc=ipmi_set_power_cap(intf,watt,val); + } + else if (strncmp(argv[current_arg], "btuphr\0", 7) == 0) + { + rc=ipmi_set_power_cap(intf, btuphr,val); + } + else if (strncmp(argv[current_arg], "percent\0", 8) == 0) + { + rc=ipmi_set_power_cap(intf,percent,val); + } + else + { + ipmi_powermonitor_usage(); + return -1; + } + + } + + else if (strncmp(argv[current_arg], "enablepowercap\0", 15) == 0) + { + rc = ipmi_set_power_capstatus_command(intf,1); + } + + else if (strncmp(argv[current_arg], "disablepowercap\0", 16) == 0) + { + rc = ipmi_set_power_capstatus_command(intf,0); + } + else + { + ipmi_powermonitor_usage(); + return -1; + } + if (sdrcache != NULL) free_sdr_cache(sdrcache); + return(rc); +} + + +/***************************************************************** +* Function Name: ipmi_time_to_str +* +* Description: This function converts ipmi time format into gmtime format +* Input: rawTime - ipmi time format +* Output: strTime - gmtime format +* +* Return: +* +******************************************************************/ + +static void +ipmi_time_to_str(time_t rawTime, char* strTime) +{ + struct tm * tm; + char *temp; + tm = gmtime(&rawTime); + + temp = asctime(tm); + + strcpy(strTime,temp); +} + +#ifdef NOT_USED +static int ipmi_get_sensor_reading(void *intf , + unsigned char sensorNumber, + SensorReadingType* pSensorReadingData); +/***************************************************************** +* Function Name: ipmi_get_sensor_reading +* +* Description: This function retrieves a raw sensor reading +* Input: sensorOwner - sensor owner id +* sensorNumber - sensor id +* intf - ipmi interface +* Output: sensorReadingData - ipmi response structure +* Return: 1 on error +* 0 if successful +* +******************************************************************/ +static int +ipmi_get_sensor_reading(void *intf , + unsigned char sensorNumber, + SensorReadingType* pSensorReadingData) +{ + struct ipmi_rq req; + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len; + int rc = 0; + // uint8_t save_addr; + + memset(&req, 0, sizeof (req)); + req.msg.netfn = IPMI_NETFN_SE; + req.msg.lun = 0; + req.msg.cmd = (uint8_t)(GET_SENSOR_READING | 0x0ff); + req.msg.data = &sensorNumber; + req.msg.data_len = 1; + + if (NULL == pSensorReadingData) + return -1; + memset(pSensorReadingData,0, sizeof(SensorReadingType)); + + rc = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rc) return 1; + + memcpy(pSensorReadingData, rsp, sizeof(SensorReadingType)); + + /* if sensor messages are disabled, return error*/ + if ((!(rsp[1]& 0xC0)) || ((rsp[1] & 0x20))) { + rc =1; + } + return rc; +} +#endif + + +/***************************************************************** +* Function Name: ipmi_get_power_capstatus_command +* +* Description: This function gets the power cap status +* Input: intf - ipmi interface +* Global: PowercapSetable_flag - power cap status +* Output: +* +* Return: +* +******************************************************************/ +static int +ipmi_get_power_capstatus_command (void * intf) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[2]; + + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = IPMI_DELL_POWER_CAP_STATUS; + req.msg.data_len = 2; + req.msg.data = data; + data[0] = 01; + data[1] = 0xFF; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error getting powercap status: "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n", + rv,decode_cc(0,rv)); + return rv; + } + if (rsp[0]&0x02) + PowercapSetable_flag=1; + if(rsp[0]&0x01) + PowercapstatusFlag=1; + return 0; +} + +/***************************************************************** +* Function Name: ipmi_set_power_capstatus_command +* +* Description: This function sets the power cap status +* Input: intf - ipmi interface +* val - power cap status +* Output: +* +* Return: +* +******************************************************************/ + +static int +ipmi_set_power_capstatus_command (void * intf,uint8_t val) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[2]; + if(ipmi_get_power_capstatus_command(intf) < 0) + return -1; + + if (PowercapSetable_flag!=1) + { + lprintf(LOG_ERR, " Can not set powercap on this system"); + return -1; + } + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = IPMI_DELL_POWER_CAP_STATUS; + req.msg.data_len = 2; + req.msg.data = data; + + data[0] = 00; + data[1] = val; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error setting powercap status: "); + if (rv < 0) printf("no response\n"); + else if((iDRAC_FLAG == IDRAC_12G) && (rv == LICENSE_NOT_SUPPORTED)) { + printf("FM001 : A required license is missing or expired\n"); + return rv; //return unlicensed Error code + } + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + + return 0; +} + + + +/***************************************************************** +* Function Name: ipmi_powermgmt +* +* Description: This function print the powermonitor details +* Input: intf - ipmi interface +* Output: +* +* Return: +* +******************************************************************/ +static int ipmi_powermgmt(void* intf) +{ + time_t now; + struct tm* tm; + char* dte; + + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + uint8_t msg_data[2]; + uint32_t cumStartTimeConv; + uint32_t cumReadingConv; + uint32_t maxPeakStartTimeConv; + uint32_t ampPeakTimeConv; + uint16_t ampReadingConv; + uint32_t wattPeakTimeConv; + uint32_t wattReadingConv; + uint32_t bmctimeconv; + uint32_t * bmctimeconvval; + + IPMI_POWER_MONITOR* pwrMonitorInfo; + + + char cumStartTime[26]; + char maxPeakStartTime[26]; + char ampPeakTime[26]; + char wattPeakTime[26]; + char bmctime[26]; + + // float cumReading; + int ampReading; + int wattReading; + int ampReadingRemainder; + // int round; + // int round2; + int remainder; + + now = time(0); + tm = gmtime(&now); + dte = asctime(tm); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.lun = 0; + req.msg.cmd = IPMI_CMD_GET_SEL_TIME; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error getting BMC time info "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + bmctimeconvval=(uint32_t*)rsp; +#if WORDS_BIGENDIAN + bmctimeconv=BSWAP_32(*bmctimeconvval); +#else + bmctimeconv=*bmctimeconvval; +#endif + + /* get powermanagement info*/ + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0x0; + req.msg.cmd = GET_PWRMGMT_INFO_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + + memset(msg_data, 0, 2); + msg_data[0] = 0x07; + msg_data[1] = 0x01; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error getting power management info "); + if (rv < 0) printf("no response\n"); + else if((iDRAC_FLAG == IDRAC_12G) && (rv == LICENSE_NOT_SUPPORTED)) { + printf("FM001 : A required license is missing or expired\n"); + return rv; + } + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + + pwrMonitorInfo = (IPMI_POWER_MONITOR*)rsp; + +#if WORDS_BIGENDIAN + cumStartTimeConv = BSWAP_32(pwrMonitorInfo->cumStartTime); + cumReadingConv = BSWAP_32(pwrMonitorInfo->cumReading); + maxPeakStartTimeConv = BSWAP_32(pwrMonitorInfo->maxPeakStartTime); + ampPeakTimeConv = BSWAP_32(pwrMonitorInfo->ampPeakTime); + ampReadingConv = BSWAP_16(pwrMonitorInfo->ampReading); + wattPeakTimeConv = BSWAP_32(pwrMonitorInfo->wattPeakTime); + wattReadingConv = BSWAP_16(pwrMonitorInfo->wattReading); +#else + cumStartTimeConv = pwrMonitorInfo->cumStartTime; + cumReadingConv = pwrMonitorInfo->cumReading; + maxPeakStartTimeConv = pwrMonitorInfo->maxPeakStartTime; + ampPeakTimeConv = pwrMonitorInfo->ampPeakTime; + ampReadingConv = pwrMonitorInfo->ampReading; + wattPeakTimeConv = pwrMonitorInfo->wattPeakTime; + wattReadingConv = pwrMonitorInfo->wattReading; +#endif + + ipmi_time_to_str(cumStartTimeConv, cumStartTime); + + ipmi_time_to_str(maxPeakStartTimeConv, maxPeakStartTime); + ipmi_time_to_str(ampPeakTimeConv, ampPeakTime); + ipmi_time_to_str(wattPeakTimeConv, wattPeakTime); + ipmi_time_to_str(bmctimeconv, bmctime); + + now = time(0); + + + remainder = (cumReadingConv % 1000); + cumReadingConv = cumReadingConv / 1000; + remainder = (remainder + 50) / 100; + + ampReading = ampReadingConv; + ampReadingRemainder = ampReading%10; + ampReading = ampReading/10; + + wattReading = wattReadingConv; + + printf("Power Tracking Statistics\n"); + printf("Statistic : Cumulative Energy Consumption\n"); + printf("Start Time : %s", cumStartTime); + printf("Finish Time : %s", bmctime); + printf("Reading : %d.%d kWh\n\n", cumReadingConv, remainder); + + printf("Statistic : System Peak Power\n"); + printf("Start Time : %s", maxPeakStartTime); + printf("Peak Time : %s", wattPeakTime); + printf("Peak Reading : %d W\n\n", wattReading); + + printf("Statistic : System Peak Amperage\n"); + printf("Start Time : %s", maxPeakStartTime); + printf("Peak Time : %s", ampPeakTime); + printf("Peak Reading : %d.%d A\n", ampReading, ampReadingRemainder); + + + return 0; + +} +/***************************************************************** +* Function Name: ipmi_powermgmt_clear +* +* Description: This function clears peakpower / cumulativepower value +* Input: intf - ipmi interface +* clearValue - peakpower / cumulativepower +* Output: +* +* Return: +* +******************************************************************/ +static int +ipmi_powermgmt_clear(void* intf,uint8_t clearValue) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + uint8_t clearType; + uint8_t msg_data[3]; + + if (clearValue) { + clearType = 2; + } else { + clearType = 1; + } + + /* clear powermanagement info*/ + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = CLEAR_PWRMGMT_INFO_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + + memset(msg_data, 0, 3); + msg_data[0] = 0x07; + msg_data[1] = 0x01; + msg_data[2] = clearType; + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error clearing power values: "); + if (rv < 0) printf("no response\n"); + else if((iDRAC_FLAG == IDRAC_12G) && (rv == LICENSE_NOT_SUPPORTED)) { + printf("FM001 : A required license is missing or expired\n"); + return rv; + } + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + return 0; + +} + +/***************************************************************** +* Function Name: watt_to_btuphr_conversion +* +* Description: This function converts the power value in watt to btuphr +* Input: powerinwatt - power in watt +* +* Output: power in btuphr +* +* Return: +* +******************************************************************/ +static uint64_t watt_to_btuphr_conversion(uint32_t powerinwatt) +{ + uint64_t powerinbtuphr; + powerinbtuphr=(uint64_t)(3.413*powerinwatt); + + return(powerinbtuphr); +} + +/***************************************************************** +* Function Name: btuphr_to_watt_conversion +* +* Description: This function converts the power value in btuphr to watt +* Input: powerinbtuphr - power in btuphr +* +* Output: power in watt +* +* Return: +* +******************************************************************/ +static uint32_t btuphr_to_watt_conversion(uint64_t powerinbtuphr) +{ + uint32_t powerinwatt; + /*returning the floor value*/ + powerinwatt= (uint32_t)(powerinbtuphr/3.413); + return (powerinwatt); +} + +/***************************************************************** +* Function Name: ipmi_get_power_headroom_command +* +* Description: This function prints the Power consumption information +* Input: intf - ipmi interface +* unit - watt / btuphr +* Output: +* +* Return: +* +******************************************************************/ +static int ipmi_get_power_headroom_command (void * intf,uint8_t unit) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint64_t peakpowerheadroombtuphr; + uint64_t instantpowerhearoom; + + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = GET_PWR_HEADROOM_CMD; + req.msg.data_len = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error getting power headroom status: "); + if (rv < 0) printf("no response\n"); + else if((iDRAC_FLAG == IDRAC_12G) && (rv == LICENSE_NOT_SUPPORTED)) { + printf("FM001 : A required license is missing or expired\n"); + return rv; + } + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + if(verbose>1) + printf("power headroom Data : %x %x %x %x ", + /*need to look into */ rsp[0], rsp[1], rsp[2], rsp[3]); + powerheadroom= *(( POWER_HEADROOM *)rsp); +#if WORDS_BIGENDIAN + powerheadroom.instheadroom = BSWAP_16(powerheadroom.instheadroom); + powerheadroom.peakheadroom = BSWAP_16(powerheadroom.peakheadroom); +#endif + + printf ("Headroom\n\r"); + printf ("Statistic Reading\n\r"); + + if(unit == btuphr) + { + peakpowerheadroombtuphr=watt_to_btuphr_conversion(powerheadroom.peakheadroom); + instantpowerhearoom= watt_to_btuphr_conversion(powerheadroom.instheadroom); + + printf ("System Instantaneous Headroom : %ld BTU/hr\n",instantpowerhearoom); + printf ("System Peak Headroom : %ld BTU/hr\n",peakpowerheadroombtuphr); + } + else + { + printf ("System Instantaneous Headroom : %ld W\n",powerheadroom.instheadroom); + printf ("System Peak Headroom : %ld W\n",powerheadroom.peakheadroom); + } + + return 0; +} + +/***************************************************************** +* Function Name: ipmi_get_power_consumption_data +* +* Description: This function updates the instant Power consumption information +* Input: intf - ipmi interface +* Output: power consumption current reading +* Assumption value will be in Watt. +* +* Return: +* +******************************************************************/ +static int ipmi_get_power_consumption_data(void* intf,uint8_t unit) +{ + int rc = 0; + SensorReadingType sensorReadingData; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + struct sdr_record_list *sdr = NULL; + uchar sdrbuf[SDR_SZ]; + double readingf, warningf, failuref; + int readingbtuphr=0; + int warning_threshbtuphr=0; + int failure_thresbtuphr=0; + int status=0; + int sensor_number = 0; + + if (sdrfile != NULL) { + rc = get_sdr_file(sdrfile,&sdrcache); + if (rc) printf ("Error 0x%02x: Cannot get SDRs from %s\n",rc,sdrfile); + } else if (sdrcache == NULL) { + rc = get_sdr_cache(&sdrcache); + if (rc) printf ("Error 0x%02x: Cannot get SDRs\n",rc); + } + + rc = find_sdr_by_tag(sdrbuf, sdrcache, "System Level", fdebug); + if (rc != 0) + { + printf ("Error %d: Cannot access the System Level sensor data\n",rc); + return rc; + } + sdr = (struct sdr_record_list *)sdrbuf; + + sensor_number = sdrbuf[7]; // sdr->record.full->keys.sensor_num; + if (fdebug) printf("calling GetSensorReading(%x)\n",sensor_number); + rc = GetSensorReading(sensor_number, sdrbuf, + (uchar *)&sensorReadingData.sensorReading); + if (rc != 0) + printf("Error %d getting sensor %x reading\n",rc,sensor_number); + + rc = GetSensorThresholds( sensor_number, rsp); + if (fdebug) printf("GetSensorThresholds(%x) rc = %d\n",sensor_number,rc); + if (rc == 0) + { + readingf = RawToFloat(sensorReadingData.sensorReading,sdrbuf); + warningf = RawToFloat(rsp[4], sdrbuf); + failuref = RawToFloat(rsp[5], sdrbuf); + readingbtuphr = (int)readingf; + warning_threshbtuphr = (int)warningf; + failure_thresbtuphr = (int)failuref; + + if (fdebug) { + printf("Reading 0x%02x = %.2f, Warning 0x%02x = %.2f, Failure 0x%02x = %.2f\n", + sensorReadingData.sensorReading, readingf, + rsp[4], warningf, rsp[5], failuref); + } + + printf ("System Board System Level\n\r"); + if (unit==btuphr) + { + readingbtuphr= watt_to_btuphr_conversion(readingbtuphr); + warning_threshbtuphr= watt_to_btuphr_conversion(warning_threshbtuphr); + failure_thresbtuphr= watt_to_btuphr_conversion( failure_thresbtuphr); + + printf ("Reading : %d BTU/hr\n",readingbtuphr); + printf ("Warning threshold : %d BTU/hr\n",warning_threshbtuphr); + printf ("Failure threshold : %d BTU/hr\n",failure_thresbtuphr); + } + else + { + printf ("Reading : %d W \n",readingbtuphr); + printf ("Warning threshold : %d W \n",(warning_threshbtuphr)); + printf ("Failure threshold : %d W \n",(failure_thresbtuphr)); + } + } + else + { + printf ("Error %d: Cannot access the System Level threshold data\n",rc); + return -1; + } + return status; +} + + + + +/***************************************************************** +* Function Name: ipmi_get_instan_power_consmpt_data +* +* Description: This function updates the instant Power consumption information +* Input: intf - ipmi interface +* Output: instpowerconsumptiondata - instant Power consumption information +* +* Return: +* +******************************************************************/ + +static int ipmi_get_instan_power_consmpt_data(void* intf, + IPMI_INST_POWER_CONSUMPTION_DATA* instpowerconsumptiondata) +{ + + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req={0}; + + uint8_t msg_data[2]; + + + /*get instantaneous power consumption command*/ + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = GET_PWR_CONSUMPTION_CMD; + + req.msg.data = msg_data; + req.msg.data_len = 2; + + + + memset(msg_data, 0, 2); + + msg_data[0] = 0x0A; + msg_data[1] = 0x00; + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error getting power consumption data: "); + if (rv < 0) printf("no response\n"); + else if((iDRAC_FLAG == IDRAC_12G) && (rv == LICENSE_NOT_SUPPORTED)) { + printf("FM001 : A required license is missing or expired\n"); + return rv; + } + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + + * instpowerconsumptiondata = * ( (IPMI_INST_POWER_CONSUMPTION_DATA*) (rsp)); +#if WORDS_BIGENDIAN + instpowerconsumptiondata->instanpowerconsumption = BSWAP_16(instpowerconsumptiondata->instanpowerconsumption); + instpowerconsumptiondata->instanApms = BSWAP_16(instpowerconsumptiondata->instanApms); + instpowerconsumptiondata->resv1 = BSWAP_16(instpowerconsumptiondata->resv1); +#endif + + return 0; + + +} + + +/***************************************************************** +* Function Name: ipmi_print_get_instan_power_Amps_data +* +* Description: This function prints the instant Power consumption information +* Input: instpowerconsumptiondata - instant Power consumption information +* Output: +* +* Return: +* +******************************************************************/ +static void ipmi_print_get_instan_power_Amps_data(IPMI_INST_POWER_CONSUMPTION_DATA instpowerconsumptiondata) +{ + uint16_t intampsval=0; + uint16_t decimalampsval=0; + + + if (instpowerconsumptiondata.instanApms>0) + { + decimalampsval=(instpowerconsumptiondata.instanApms%10); + intampsval=instpowerconsumptiondata.instanApms/10; + } + printf("\nAmperage value: %d.%d A \n",intampsval,decimalampsval); +} +/***************************************************************** +* Function Name: ipmi_print_get_power_consmpt_data +* +* Description: This function prints the Power consumption information +* Input: intf - ipmi interface +* unit - watt / btuphr +* Output: +* +* Return: +* +******************************************************************/ +static int ipmi_print_get_power_consmpt_data(void* intf,uint8_t unit) +{ + + int rc = 0; + IPMI_INST_POWER_CONSUMPTION_DATA instpowerconsumptiondata = {0,0,0,0}; + // int i; + //uint16_t inputwattageL=0; + //int sensorIndex = 0; + //uint32_t readingbtuphr; + //uint32_t warning_threshbtuphr; + //uint32_t failure_thresbtuphr; + + printf ("\nPower consumption information\n"); + + + rc=ipmi_get_power_consumption_data(intf,unit); + if (-1 == rc) + return rc; + + rc=ipmi_get_instan_power_consmpt_data(intf,&instpowerconsumptiondata); + if (-1 == rc) + return rc; + + ipmi_print_get_instan_power_Amps_data(instpowerconsumptiondata); + + + rc=ipmi_get_power_headroom_command(intf,unit); + + if (-1 == rc) + return rc; + + return rc; + + +} + + +/***************************************************************** +* Function Name: ipmi_get_avgpower_consmpt_history +* +* Description: This function updates the average power consumption information +* Input: intf - ipmi interface +* Output: pavgpower- average power consumption information +* +* Return: +* +******************************************************************/ +static int ipmi_get_avgpower_consmpt_history(void* intf,IPMI_AVGPOWER_CONSUMP_HISTORY* pavgpower ) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; + data[1] = 0xeb; + data[2] = 0; + data[3] = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error getting average power consumption data: "); + if (rv < 0) printf("no response\n"); + else if((iDRAC_FLAG == IDRAC_12G) && (rv == LICENSE_NOT_SUPPORTED)) { + printf("FM001 : A required license is missing or expired\n"); + return rv; + } + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + + if (verbose > 1) + { + printf("Average power consumption history Data :%x %x %x %x %x %x %x %x\n\n", + rsp[0], rsp[1], rsp[2], rsp[3], + rsp[4], rsp[5], rsp[6], rsp[7]); + + } + + *pavgpower = *( (IPMI_AVGPOWER_CONSUMP_HISTORY*) rsp); +#if WORDS_BIGENDIAN + pavgpower->lastminutepower = BSWAP_16(pavgpower->lastminutepower); + pavgpower->lasthourpower = BSWAP_16(pavgpower->lasthourpower); + pavgpower->lastdaypower = BSWAP_16(pavgpower->lastdaypower); + pavgpower->lastweakpower = BSWAP_16(pavgpower->lastweakpower); +#endif + + return 0; +} + +/***************************************************************** +* Function Name: ipmi_get_peakpower_consmpt_history +* +* Description: This function updates the peak power consumption information +* Input: intf - ipmi interface +* Output: pavgpower- peak power consumption information +* +* Return: +* +******************************************************************/ +static int ipmi_get_peakpower_consmpt_history(void* intf,IPMI_POWER_CONSUMP_HISTORY * pstPeakpower) +{ + + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; + data[1] = 0xec; + data[2] = 0; + data[3] = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error getting peak power consumption history: "); + if (rv < 0) printf("no response\n"); + else if((iDRAC_FLAG == IDRAC_12G) && (rv == LICENSE_NOT_SUPPORTED)) { + printf("FM001 : A required license is missing or expired\n"); + return rv; + } + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + + if (verbose > 1) + { + printf("Peak power consmhistory Data : %x %x %x %x %x %x %x %x %x %x\n %x %x %x %x %x %x %x %x %x %x %x %x %x\n\n", + rsp[0], rsp[1], rsp[2], rsp[3], + rsp[4], rsp[5], rsp[6], rsp[7], + rsp[8], rsp[9], rsp[10], rsp[11], + rsp[12], rsp[13], rsp[14], rsp[15], + rsp[16], rsp[17], rsp[18], rsp[19], + rsp[20], rsp[21], rsp[22], rsp[23] + ); + + } + *pstPeakpower =* ((IPMI_POWER_CONSUMP_HISTORY*)rsp); +#if WORDS_BIGENDIAN + pstPeakpower->lastminutepower = BSWAP_16(pstPeakpower->lastminutepower); + pstPeakpower->lasthourpower = BSWAP_16(pstPeakpower->lasthourpower); + pstPeakpower->lastdaypower = BSWAP_16(pstPeakpower->lastdaypower); + pstPeakpower->lastweakpower = BSWAP_16(pstPeakpower->lastweakpower); + pstPeakpower->lastminutepowertime = BSWAP_32(pstPeakpower->lastminutepowertime); + pstPeakpower->lasthourpowertime = BSWAP_32(pstPeakpower->lasthourpowertime); + pstPeakpower->lastdaypowertime = BSWAP_32(pstPeakpower->lastdaypowertime); + pstPeakpower->lastweekpowertime = BSWAP_32(pstPeakpower->lastweekpowertime); +#endif + return 0; +} + + +/***************************************************************** +* Function Name: ipmi_get_minpower_consmpt_history +* +* Description: This function updates the peak power consumption information +* Input: intf - ipmi interface +* Output: pavgpower- peak power consumption information +* +* Return: +* +******************************************************************/ +static int ipmi_get_minpower_consmpt_history(void* intf,IPMI_POWER_CONSUMP_HISTORY * pstMinpower) +{ + + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[4]; + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + data[0] = 0; + data[1] = 0xed; + data[2] = 0; + data[3] = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error getting min power consumption history: "); + if (rv < 0) printf("no response\n"); + else if((iDRAC_FLAG == IDRAC_12G) && (rv == LICENSE_NOT_SUPPORTED)) { + printf("FM001 : A required license is missing or expired\n"); + return rv; + } + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + + if (verbose > 1) + { + printf("Peak power consmhistory Data : %x %x %x %x %x %x %x %x %x %x\n %x %x %x %x %x %x %x %x %x %x %x %x %x\n\n", + rsp[0], rsp[1], rsp[2], rsp[3], + rsp[4], rsp[5], rsp[6], rsp[7], + rsp[8], rsp[9], rsp[10], rsp[11], + rsp[12], rsp[13], rsp[14], rsp[15], + rsp[16], rsp[17], rsp[18], rsp[19], + rsp[20], rsp[21], rsp[22], rsp[23] + ); + + } + *pstMinpower =* ((IPMI_POWER_CONSUMP_HISTORY*)rsp); +#if WORDS_BIGENDIAN + pstMinpower->lastminutepower = BSWAP_16(pstMinpower->lastminutepower); + pstMinpower->lasthourpower = BSWAP_16(pstMinpower->lasthourpower); + pstMinpower->lastdaypower = BSWAP_16(pstMinpower->lastdaypower); + pstMinpower->lastweakpower = BSWAP_16(pstMinpower->lastweakpower); + pstMinpower->lastminutepowertime = BSWAP_32(pstMinpower->lastminutepowertime); + pstMinpower->lasthourpowertime = BSWAP_32(pstMinpower->lasthourpowertime); + pstMinpower->lastdaypowertime = BSWAP_32(pstMinpower->lastdaypowertime); + pstMinpower->lastweekpowertime = BSWAP_32(pstMinpower->lastweekpowertime); +#endif + return 0; +} + + + +/***************************************************************** +* Function Name: ipmi_print_power_consmpt_history +* +* Description: This function print the average and peak power consumption information +* Input: intf - ipmi interface +* unit - watt / btuphr +* Output: +* +* Return: +* +******************************************************************/ +static int ipmi_print_power_consmpt_history(void* intf,int unit ) +{ + + char timestr[30]; + + uint32_t lastminutepeakpower; + uint32_t lasthourpeakpower; + uint32_t lastdaypeakpower; + uint32_t lastweekpeakpower; + + IPMI_AVGPOWER_CONSUMP_HISTORY avgpower; + IPMI_POWER_CONSUMP_HISTORY stMinpower; + IPMI_POWER_CONSUMP_HISTORY stPeakpower; + int rc=0; + + uint64_t tempbtuphrconv; + //uint16_t temp; + + + rc= ipmi_get_avgpower_consmpt_history(intf,&avgpower); + if (-1 == rc) + return rc; + + rc= ipmi_get_peakpower_consmpt_history(intf,&stPeakpower); + if (-1 == rc) + return rc; + + rc= ipmi_get_minpower_consmpt_history(intf,&stMinpower); + if (-1 == rc) + return rc; + + + if(rc==0) + { + printf ("Power Consumption History\n\r\n\r"); + /* The fields are alligned manually changing the spaces will alter the alignment*/ + printf ("Statistic Last Minute Last Hour Last Day Last Week\n\r\n\r"); + + if (unit ==btuphr) + { + printf ("Average Power Consumption "); + tempbtuphrconv=watt_to_btuphr_conversion(avgpower.lastminutepower); + printf ("%4d BTU/hr ",tempbtuphrconv); + tempbtuphrconv=watt_to_btuphr_conversion(avgpower.lasthourpower); + printf ("%4d BTU/hr ",tempbtuphrconv); + tempbtuphrconv=watt_to_btuphr_conversion(avgpower.lastdaypower); + printf ("%4d BTU/hr ",tempbtuphrconv); + tempbtuphrconv=watt_to_btuphr_conversion(avgpower.lastweakpower); + printf ("%4d BTU/hr\n\r",tempbtuphrconv); + + printf ("Max Power Consumption "); + tempbtuphrconv=watt_to_btuphr_conversion(stPeakpower.lastminutepower); + printf ("%4d BTU/hr ",tempbtuphrconv); + tempbtuphrconv=watt_to_btuphr_conversion(stPeakpower.lasthourpower); + printf ("%4d BTU/hr ",tempbtuphrconv); + tempbtuphrconv=watt_to_btuphr_conversion(stPeakpower.lastdaypower); + printf ("%4d BTU/hr ",tempbtuphrconv); + tempbtuphrconv=watt_to_btuphr_conversion(stPeakpower.lastweakpower); + printf ("%4d BTU/hr\n\r",tempbtuphrconv); + + printf ("Min Power Consumption "); + tempbtuphrconv=watt_to_btuphr_conversion(stMinpower.lastminutepower); + printf ("%4d BTU/hr ",tempbtuphrconv); + tempbtuphrconv=watt_to_btuphr_conversion(stMinpower.lasthourpower); + printf ("%4d BTU/hr ",tempbtuphrconv); + tempbtuphrconv=watt_to_btuphr_conversion(stMinpower.lastdaypower); + printf ("%4d BTU/hr ",tempbtuphrconv); + tempbtuphrconv=watt_to_btuphr_conversion(stMinpower.lastweakpower); + printf ("%4d BTU/hr\n\r\n\r",tempbtuphrconv); + + } + else + { + + printf ("Average Power Consumption "); + tempbtuphrconv=(avgpower.lastminutepower); + printf ("%4ld W ",tempbtuphrconv); + tempbtuphrconv=(avgpower.lasthourpower); + printf ("%4ld W ",tempbtuphrconv); + tempbtuphrconv=(avgpower.lastdaypower); + printf ("%4ld W ",tempbtuphrconv); + tempbtuphrconv=(avgpower.lastweakpower); + printf ("%4ld W \n\r",tempbtuphrconv); + + printf ("Max Power Consumption "); + tempbtuphrconv=(stPeakpower.lastminutepower); + printf ("%4ld W ",tempbtuphrconv); + tempbtuphrconv=(stPeakpower.lasthourpower); + printf ("%4ld W ",tempbtuphrconv); + tempbtuphrconv=(stPeakpower.lastdaypower); + printf ("%4ld W ",tempbtuphrconv); + tempbtuphrconv=(stPeakpower.lastweakpower); + printf ("%4ld W \n\r",tempbtuphrconv); + + printf ("Min Power Consumption "); + tempbtuphrconv=(stMinpower.lastminutepower); + printf ("%4ld W ",tempbtuphrconv); + tempbtuphrconv=(stMinpower.lasthourpower); + printf ("%4ld W ",tempbtuphrconv); + tempbtuphrconv=(stMinpower.lastdaypower); + printf ("%4ld W ",tempbtuphrconv); + tempbtuphrconv=(stMinpower.lastweakpower); + printf ("%4ld W \n\r\n\r",tempbtuphrconv); + } + + lastminutepeakpower=stPeakpower.lastminutepowertime; + lasthourpeakpower=stPeakpower.lasthourpowertime; + lastdaypeakpower=stPeakpower.lastdaypowertime; + lastweekpeakpower=stPeakpower.lastweekpowertime; + + printf ("Max Power Time\n\r"); + ipmi_time_to_str(lastminutepeakpower, timestr); + printf ("Last Minute : %s",timestr); + ipmi_time_to_str(lasthourpeakpower, timestr); + printf ("Last Hour : %s",timestr); + ipmi_time_to_str(lastdaypeakpower, timestr); + printf ("Last Day : %s",timestr); + ipmi_time_to_str(lastweekpeakpower, timestr); + printf ("Last Week : %s",timestr); + + + lastminutepeakpower=stMinpower.lastminutepowertime; + lasthourpeakpower=stMinpower.lasthourpowertime; + lastdaypeakpower=stMinpower.lastdaypowertime; + lastweekpeakpower=stMinpower.lastweekpowertime; + + printf ("Min Power Time\n\r"); + ipmi_time_to_str(lastminutepeakpower, timestr); + printf ("Last Minute : %s",timestr); + ipmi_time_to_str(lasthourpeakpower, timestr); + printf ("Last Hour : %s",timestr); + ipmi_time_to_str(lastdaypeakpower, timestr); + printf ("Last Day : %s",timestr); + ipmi_time_to_str(lastweekpeakpower, timestr); + printf ("Last Week : %s",timestr); + + } + return rc; + +} + + + +/***************************************************************** +* Function Name: ipmi_get_power_cap +* +* Description: This function updates the power cap information +* Input: intf - ipmi interface +* Output: ipmipowercap - power cap information +* +* Return: +* +******************************************************************/ + +static int ipmi_get_power_cap(void* intf,IPMI_POWER_CAP* ipmipowercap ) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req={0}; + //uint64_t tempbtuphrconv; + uint8_t data[4]; + + /* power supply rating command*/ + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + + data[0] = 0; + data[1] = IPMI_DELL_POWER_CAP; + data[2] = 0; + data[3] = 0; + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error getting power cap: "); + if (rv < 0) printf("no response\n"); + else if((iDRAC_FLAG == IDRAC_12G) && (rv == LICENSE_NOT_SUPPORTED)) { + printf("FM001 : A required license is missing or expired\n"); + return rv; + } + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + if (verbose > 1){ + printf("power cap Data :%x %x %x %x %x %x %x %x %x %x %x", + rsp[1], rsp[2], rsp[3], + rsp[4], rsp[5], rsp[6], rsp[7], + rsp[8], rsp[9], rsp[10],rsp[11]); + + } + + * ipmipowercap = *((IPMI_POWER_CAP*)(rsp)); +#if WORDS_BIGENDIAN + ipmipowercap->PowerCap = BSWAP_16(ipmipowercap->PowerCap); + ipmipowercap->MaximumPowerConsmp = BSWAP_16(ipmipowercap->MaximumPowerConsmp); + ipmipowercap->MinimumPowerConsmp = BSWAP_16(ipmipowercap->MinimumPowerConsmp); + ipmipowercap->totalnumpowersupp = BSWAP_16(ipmipowercap->totalnumpowersupp); + ipmipowercap->AvailablePower = BSWAP_16(ipmipowercap->AvailablePower); + ipmipowercap->SystemThrottling = BSWAP_16(ipmipowercap->SystemThrottling); + ipmipowercap->Resv = BSWAP_16(ipmipowercap->Resv); +#endif + + return 0; +} + +/***************************************************************** +* Function Name: ipmi_print_power_cap +* +* Description: This function print the power cap information +* Input: intf - ipmi interface +* unit - watt / btuphr +* Output: +* Return: +* +******************************************************************/ +static int ipmi_print_power_cap(void* intf,uint8_t unit ) +{ + uint64_t tempbtuphrconv; + int rc; + IPMI_POWER_CAP ipmipowercap; + + memset(&ipmipowercap,0,sizeof(ipmipowercap)); + rc=ipmi_get_power_cap(intf,&ipmipowercap); + + + if (rc==0) + { + if (unit ==btuphr){ + tempbtuphrconv=watt_to_btuphr_conversion(ipmipowercap.MaximumPowerConsmp); + printf ("Maximum power: %ld BTU/hr\n",tempbtuphrconv); + tempbtuphrconv=watt_to_btuphr_conversion(ipmipowercap.MinimumPowerConsmp); + printf ("Minimum power: %ld BTU/hr\n",tempbtuphrconv); + tempbtuphrconv=watt_to_btuphr_conversion(ipmipowercap.PowerCap); + printf ("Power cap : %ld BTU/hr\n",tempbtuphrconv); + }else{ + + printf ("Maximum power: %ld Watt\n",ipmipowercap.MaximumPowerConsmp); + printf ("Minimum power: %ld Watt\n",ipmipowercap.MinimumPowerConsmp); + printf ("Power cap : %ld Watt\n",ipmipowercap.PowerCap); + } + } + return rc; + +} + +/***************************************************************** +* Function Name: ipmi_set_power_cap +* +* Description: This function updates the power cap information +* Input: intf - ipmi interface +* unit - watt / btuphr +* val - new power cap value +* Output: +* Return: +* +******************************************************************/ +static int ipmi_set_power_cap(void* intf,int unit,int val ) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req={0}; + uint8_t data[13]; + uint16_t powercapval; + uint64_t maxpowerbtuphr; + uint64_t maxpowerbtuphr1; + uint64_t minpowerbtuphr; + IPMI_POWER_CAP ipmipowercap; + + if(ipmi_get_power_capstatus_command(intf) < 0) + return -1; // Adding the failed condition check + + if (PowercapSetable_flag!=1) + { + lprintf(LOG_ERR, " Can not set powercap on this system"); + return -1; + } + else if(PowercapstatusFlag!=1) + { + lprintf(LOG_ERR, " Power cap set feature is not enabled"); + return -1; + } + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + memset(data, 0, 4); + req.msg.data = data; + + data[0] = 0; + data[1] = IPMI_DELL_POWER_CAP; + data[2] = 0; + data[3] = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error getting power cap: "); + if (rv < 0) printf("no response\n"); + else if((iDRAC_FLAG == IDRAC_12G) && (rv == LICENSE_NOT_SUPPORTED)) { + printf("FM001 : A required license is missing or expired\n"); + return rv; + } + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + if (verbose > 1) + { + printf("power cap Data :%x %x %x %x %x %x %x %x %x %x ", + rsp[1], rsp[2], rsp[3], + rsp[4], rsp[5], rsp[6], rsp[7], + rsp[8], rsp[9], rsp[10],rsp[11]); + + } + + ipmipowercap.PowerCap=((rsp[1]<<8)+rsp[2]); + ipmipowercap.unit=rsp[3]; + ipmipowercap.MaximumPowerConsmp=((rsp[4]<<8)+rsp[5]); + ipmipowercap.MinimumPowerConsmp=((rsp[6]<<8)+rsp[7]); + /* ARC: need Dell to verify these 3 values */ + ipmipowercap.totalnumpowersupp = rsp[8]; + ipmipowercap.AvailablePower = ((rsp[9]<<8)+rsp[10]); + ipmipowercap.SystemThrottling = rsp[11]; + + memset(data, 0, 13); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_SET_SYS_INFO; + req.msg.data_len = 13; + req.msg.data = data; + data[0] = IPMI_DELL_POWER_CAP; + powercapval=val; + + + data[1] = (powercapval&0XFF); + data[2] = ((powercapval&0XFF00)>>8); + data[3] = unit; + + data[4]=((ipmipowercap.MaximumPowerConsmp&0xFF)); + data[5]=((ipmipowercap.MaximumPowerConsmp&0xFF00)>>8); + data[6]=((ipmipowercap.MinimumPowerConsmp&0xFF)); + data[7]=((ipmipowercap.MinimumPowerConsmp&0xFF00)>>8); + data[8]=(uint8_t)(ipmipowercap.totalnumpowersupp); + data[9]=((ipmipowercap.AvailablePower&0xFF)); + data[10]=((ipmipowercap.AvailablePower&0xFF00)>>8); + data[11]=(uint8_t)(ipmipowercap.SystemThrottling); + data[12]=0x00; + + ipmipowercap.MaximumPowerConsmp = BSWAP_16(ipmipowercap.MaximumPowerConsmp); + ipmipowercap.MinimumPowerConsmp = BSWAP_16(ipmipowercap.MinimumPowerConsmp); + ipmipowercap.PowerCap = BSWAP_16(ipmipowercap.PowerCap); + if(unit==btuphr) + { + val = btuphr_to_watt_conversion(val); + + } + else if(unit ==percent) + { + if((val <0)||(val>100)) + { + lprintf(LOG_ERR, " Cap value is out of boundary conditon it should be between 0 - 100"); + return -1; + } + val =( (val*(ipmipowercap.MaximumPowerConsmp -ipmipowercap.MinimumPowerConsmp))/100)+ipmipowercap.MinimumPowerConsmp; + lprintf(LOG_ERR, " Cap value in percentage is %d ",val); + data[1] = (val&0XFF); + data[2] = ((val&0XFF00)>>8); + data[3] = watt; + } + if(((val<ipmipowercap.MinimumPowerConsmp)||(val>ipmipowercap.MaximumPowerConsmp))&&(unit==watt)) + { + lprintf(LOG_ERR, " Cap value is out of boundary conditon it should be between %d - %d", + ipmipowercap.MinimumPowerConsmp,ipmipowercap.MaximumPowerConsmp); + return -1; + } + else if(((val<ipmipowercap.MinimumPowerConsmp)||(val>ipmipowercap.MaximumPowerConsmp))&&(unit==btuphr)) + { + minpowerbtuphr= watt_to_btuphr_conversion(ipmipowercap.MinimumPowerConsmp); + maxpowerbtuphr=watt_to_btuphr_conversion(ipmipowercap.MaximumPowerConsmp); + maxpowerbtuphr1= watt_to_btuphr_conversion(ipmipowercap.MaximumPowerConsmp); + lprintf(LOG_ERR, " Cap value is out of boundary conditon it should be between %d", + minpowerbtuphr); + lprintf(LOG_ERR, " -%d", + maxpowerbtuphr1); + + return -1; + } + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error setting power cap: "); + if (rv < 0) printf("no response\n"); + else if((iDRAC_FLAG == IDRAC_12G) && (rv == LICENSE_NOT_SUPPORTED)) { + printf("FM001 : A required license is missing or expired\n"); + return rv; + } + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + if (verbose > 1) + { + printf("CC for setpowercap :%d ",rv); + } + return 0; +} + +#ifdef NOT_USED +static int getpowersupplyfruinfo(void *intf, uint8_t id, + struct fru_header header, struct fru_info fru); +/***************************************************************** +* Function Name: getpowersupplyfruinfo +* +* Description: This function retrieves the FRU header +* Input: intf - ipmi interface +* header - watt / btuphr +* fru - FRU information +* Output: header - FRU header +* Return: +* +******************************************************************/ +static int getpowersupplyfruinfo(void *intf, uint8_t id, + struct fru_header header, struct fru_info fru) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + + uint8_t msg_data[4]; + + memset(&fru, 0, sizeof(struct fru_info)); + memset(&header, 0, sizeof(struct fru_header)); + + /* + * get info about this FRU + */ + memset(msg_data, 0, 4); + msg_data[0] = id; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.lun = 0; + req.msg.cmd = GET_FRU_INFO; + req.msg.data = msg_data; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Device not present, "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + + fru.size = (rsp[1] << 8) | rsp[0]; + fru.access = rsp[2] & 0x1; + + lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)", + fru.size, fru.access ? "words" : "bytes"); + + if (fru.size < 1) { + printf(" Invalid FRU size %d", fru.size); + return -1; + } + + /* + * retrieve the FRU header + */ + msg_data[0] = id; + msg_data[1] = 0; + msg_data[2] = 0; + msg_data[3] = 8; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.lun = 0; + req.msg.cmd = GET_FRU_DATA; + req.msg.data = msg_data; + req.msg.data_len = 4; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Device not present, "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + + if (verbose > 1) + printbuf(rsp, rsp_len, "FRU DATA"); + + memcpy(&header, &rsp[1], 8); + + return 0; + + +} +#endif + +/***************************************************************** +* Function Name: ipmi_powermonitor_usage +* +* Description: This function prints help message for powermonitor command +* Input: +* Output: +* +* Return: +* +******************************************************************/ +static void +ipmi_powermonitor_usage(void) +{ + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " powermonitor"); + lprintf(LOG_NOTICE, " Shows power tracking statistics "); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " powermonitor clear cumulativepower"); + lprintf(LOG_NOTICE, " Reset cumulative power reading"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " powermonitor clear peakpower"); + lprintf(LOG_NOTICE, " Reset peak power reading"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " powermonitor powerconsumption"); + lprintf(LOG_NOTICE, " Displays power consumption in <watt|btuphr>"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " powermonitor powerconsumptionhistory <watt|btuphr>"); + lprintf(LOG_NOTICE, " Displays power consumption history "); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " powermonitor getpowerbudget"); + lprintf(LOG_NOTICE, " Displays power cap in <watt|btuphr>"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " powermonitor setpowerbudget <val><watt|btuphr|percent>"); + lprintf(LOG_NOTICE, " Allows user to set the power cap in <watt|BTU/hr|percentage>"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " powermonitor enablepowercap "); + lprintf(LOG_NOTICE, " To enable set power cap"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " powermonitor disablepowercap "); + lprintf(LOG_NOTICE, " To disable set power cap"); + lprintf(LOG_NOTICE, ""); + +} +/***************************************************************** +* Function Name: ipmi_delloem_vFlash_main +* +* Description: This function processes the delloem vFlash command +* Input: intf - ipmi interface + argc - no of arguments + argv - argument string array +* Output: +* +* Return: return code 0 - success +* -1 - failure +* +******************************************************************/ + +static int ipmi_delloem_vFlash_main (void * intf, int argc, char ** argv) +{ + int rc = 0; + + current_arg++; + rc = ipmi_delloem_vFlash_process(intf, current_arg, argv); + return(rc); +} + + + +/***************************************************************** +* Function Name: get_vFlash_compcode_str +* +* Description: This function maps the vFlash completion code +* to a string +* Input : vFlash completion code and static array of codes vs strings +* Output: - +* Return: returns the mapped string +* +******************************************************************/ +const char * +get_vFlash_compcode_str(uint8_t vflashcompcode, const struct vFlashstr *vs) +{ + static char un_str[32]; + int i; + + for (i = 0; vs[i].str != NULL; i++) { + if (vs[i].val == vflashcompcode) + return vs[i].str; + } + + memset(un_str, 0, 32); + snprintf(un_str, 32, "Unknown (0x%02X)", vflashcompcode); + + return un_str; +} + +/***************************************************************** +* Function Name: ipmi_get_sd_card_info +* +* Description: This function prints the vFlash Extended SD card info +* Input : ipmi interface +* Output: prints the sd card extended info +* Return: 0 - success -1 - failure +* +******************************************************************/ +static int +ipmi_get_sd_card_info(void* intf) { + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req; + + uint8_t msg_data[2]; + uint8_t input_length=0; + uint8_t cardstatus=0x00; + + IPMI_DELL_SDCARD_INFO * sdcardinfoblock; + + input_length = 2; + msg_data[0] = msg_data[1] = 0x00; + + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_EXT_SD_CARD_INFO; + req.msg.data = msg_data; + req.msg.data_len = input_length; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error getting SD Card Extended info, "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n",rv,decode_cc(0,rv)); + return rv; + } + + sdcardinfoblock = (IPMI_DELL_SDCARD_INFO *) (void *) rsp; + + if( (iDRAC_FLAG == IDRAC_12G) && (sdcardinfoblock->vflashcompcode == VFL_NOT_LICENSED)) + { + printf("FM001 : A required license is missing or expired\n"); + return -1; + } + else if (sdcardinfoblock->vflashcompcode != 0x00) + { + lprintf(LOG_ERR, " Error in getting SD Card Extended Information (%s) \n", get_vFlash_compcode_str(sdcardinfoblock->vflashcompcode, + vFlash_completion_code_vals)); + return -1; + } + + if (!(sdcardinfoblock->sdcardstatus & 0x04)) + { + lprintf(LOG_ERR, " vFlash SD card is unavailable, please insert the card\n of size 256MB or greater\n"); + return 0; + } + + printf("vFlash SD Card Properties\n"); + printf("SD Card size : %8dMB\n",sdcardinfoblock->sdcardsize); + printf("Available size : %8dMB\n",sdcardinfoblock->sdcardavailsize); + printf("Initialized : %10s\n", (sdcardinfoblock->sdcardstatus & 0x80) ? + "Yes" : "No"); + printf("Licensed : %10s\n", (sdcardinfoblock->sdcardstatus & 0x40) ? + "Yes" : "No"); + printf("Attached : %10s\n", (sdcardinfoblock->sdcardstatus & 0x20) ? + "Yes" : "No"); + printf("Enabled : %10s\n", (sdcardinfoblock->sdcardstatus & 0x10) ? + "Yes" : "No"); + printf("Write Protected : %10s\n", (sdcardinfoblock->sdcardstatus & 0x08) ? + "Yes" : "No"); + cardstatus = sdcardinfoblock->sdcardstatus & 0x03; + printf("Health : %10s\n", ((0x00 == cardstatus + ) ? "OK" : ((cardstatus == 0x03) ? + "Undefined" : ((cardstatus == 0x02) ? + "Critical" : "Warning")))); + printf("Bootable partition : %10d\n",sdcardinfoblock->bootpartion); + return 0; +} + +/***************************************************************** +* Function Name: ipmi_delloem_vFlash_process +* +* Description: This function processes the args for vFlash subcmd +* Input : intf - ipmi interface, arg index, argv array +* Output: prints help or error with help +* Return: 0 - Success -1 - failure +* +******************************************************************/ +static int +ipmi_delloem_vFlash_process(void* intf, int current_arg, char ** argv) +{ + int rc = 0; + int drv; + + drv = get_driver_type(); + if (drv != DRV_MV) /* MV open driver */ + { + lprintf(LOG_ERR, " vFlash support is enabled only for wmi and open interface.\n Its not enabled for lan and lanplus interface."); + return -1; + } + + if (argv[current_arg] == NULL || strcmp(argv[current_arg], "help") == 0) + { + ipmi_vFlash_usage(); + return 0; + } + ipmi_idracvalidator_command(intf); + if (!strncmp(argv[current_arg], "info\0", 5)) + { + current_arg++; + if (argv[current_arg] == NULL) + { + ipmi_vFlash_usage(); + return -1; + } + else if (strncmp(argv[current_arg], "Card\0", 5) == 0) + { + current_arg++; + if (argv[current_arg] != NULL) + { + ipmi_vFlash_usage(); + return -1; + } + rc = ipmi_get_sd_card_info(intf); + return rc; + } + else /* TBD: many sub commands are present */ + { + ipmi_vFlash_usage(); + return -1; + } + } + /* TBD other vFlash subcommands */ + else + { + ipmi_vFlash_usage(); + return -1; + } + return(rc); +} + +/***************************************************************** +* Function Name: ipmi_vFlash_usage +* +* Description: This function displays the usage for using vFlash +* Input : void +* Output: prints help +* Return: void +* +******************************************************************/ +static void +ipmi_vFlash_usage(void) +{ + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " vFlash info Card"); + lprintf(LOG_NOTICE, " Shows Extended SD Card information"); + lprintf(LOG_NOTICE, ""); +} +/***************************************************************** +* Function Name: ipmi_delloem_windbg_main +* +* Description: This function processes the delloem windbg command +* Input: intf - ipmi interface + argc - no of arguments + argv - argument string array +* Output: +* +* Return: return code 0 - success +* -1 - failure +* +******************************************************************/ + +static int ipmi_delloem_windbg_main (void * intf, int argc, char ** argv) +{ + int rc = 0; + + current_arg++; + if (argv[current_arg] == NULL) + { + ipmi_windbg_usage(); + return -1; + } + if (strncmp(argv[current_arg], "start\0", 6) == 0) + { + rc = ipmi_windbg_start(intf); + } + else if (strncmp(argv[current_arg], "end\0", 4) == 0) + { + rc = ipmi_windbg_end(intf); + } + else + { + ipmi_windbg_usage(); + } + return(rc); +} + +/***************************************************************** +* Function Name: ipmi_windbg_start +* +* Description: This function Starts the windbg +* Input : void +* Output: Start the debug +* Return: void +* +******************************************************************/ +static int +ipmi_windbg_start (void * intf) +{ + int rc; + lprintf(LOG_NOTICE, "Issuing sol activate"); + lprintf(LOG_NOTICE, ""); + + rc = ipmi_sol_activate(intf,0,0); + if (rc) lprintf(LOG_NOTICE, "Can not issue sol activate"); + else windbgsession = 1; + return(rc); +} + +/***************************************************************** +* Function Name: ipmi_windbg_end +* +* Description: This function ends the windbg +* Input : void +* Output: End the debug +* Return: void +* +******************************************************************/ + +static int +ipmi_windbg_end(void * intf) +{ + int rc; + lprintf(LOG_NOTICE, "Issuing sol deactivate"); + lprintf(LOG_NOTICE, ""); + rc = ipmi_sol_deactivate(intf); + if (rc) lprintf(LOG_NOTICE, "Can not issue sol deactivate"); + else windbgsession = 0; + return(rc); +} + + +/***************************************************************** +* Function Name: ipmi_windbg_usage +* +* Description: This function displays the usage for using windbg +* Input : void +* Output: prints help +* Return: void +* +******************************************************************/ + +static void +ipmi_windbg_usage(void) +{ + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " windbg start"); + lprintf(LOG_NOTICE, " Starts the windbg session (Cold Reset & SOL Activation)"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " windbg end"); + lprintf(LOG_NOTICE, " Ends the windbg session (SOL Deactivation"); + lprintf(LOG_NOTICE, ""); +} + + + +/********************************************************************** +* Function Name: ipmi_setled_usage +* +* Description: This function prints help message for setled command +* Input: +* Output: +* +* Return: +* +***********************************************************************/ +static void +ipmi_setled_usage(void) +{ + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " setled <b:d.f> <state..>"); + lprintf(LOG_NOTICE, " Set backplane LED state"); + lprintf(LOG_NOTICE, " b:d.f = PCI Bus:Device.Function of drive (lspci format)"); + lprintf(LOG_NOTICE, " state = present|online|hotspare|identify|rebuilding|"); + lprintf(LOG_NOTICE, " fault|predict|critical|failed"); + lprintf(LOG_NOTICE, ""); +} + +static void +ipmi_delloem_getled_usage(void) +{ + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " getled "); + lprintf(LOG_NOTICE, " Get Chassis ID LED state"); + lprintf(LOG_NOTICE, ""); +} + +static int +IsSetLEDSupported(void) +{ + return SetLEDSupported; +} + +static int +CheckSetLEDSupport(void * intf) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[10]; + + SetLEDSupported = 0; + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = 0xD5; /* Storage */ + req.msg.data_len = sizeof(data); /*10*/ + req.msg.data = data; + + memset(data, 0, sizeof(data)); + data[0] = 0x01; // get + data[1] = 0x00; // subcmd:get firmware version + data[2] = 0x08; // length lsb + data[3] = 0x00; // length msb + data[4] = 0x00; // offset lsb + data[5] = 0x00; // offset msb + data[6] = 0x00; // bay id + data[7] = 0x00; + data[8] = 0x00; + data[9] = 0x00; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv == 0) SetLEDSupported = 1; + return(rv); +} + +/***************************************************************** +* Function Name: ipmi_getdrivemap +* +* Description: This function returns mapping of BDF to Bay:Slot +* Input: intf - ipmi interface +* bdf - PCI Address of drive +* *bay - Returns bay ID + *slot - Returns slot ID +* Output: +* +* Return: +* +******************************************************************/ +static int +ipmi_getdrivemap(void * intf, int b, int d, int f, int *bay, int *slot) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[8]; + + /* Get mapping of BDF to bay:slot */ + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = 0xD5; + req.msg.data_len = 8; + req.msg.data = data; + + memset(data, 0, sizeof(data)); + data[0] = 0x01; // get + data[1] = 0x07; // storage map + data[2] = 0x06; // length lsb + data[3] = 0x00; // length msb + data[4] = 0x00; // offset lsb + data[5] = 0x00; // offset msb + data[6] = b; // bus + data[7] = (d << 3) + f; // devfn + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error issuing getdrivemap command, "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n", rv, decode_cc(0,rv)); + return rv; + } + + *bay = rsp[7]; + *slot = rsp[8]; + if (*bay == 0xFF || *slot == 0xFF) + { + lprintf(LOG_ERR, "Error could not get drive bay:slot mapping"); + return -1; + } + return 0; +} + +/***************************************************************** +* Function Name: ipmi_setled_state +* +* Description: This function updates the LED on the backplane +* Input: intf - ipmi interface +* bdf - PCI Address of drive +* state - SES Flags state of drive +* Output: +* +* Return: +* +******************************************************************/ +static int +ipmi_setled_state (void * intf, int bayId, int slotId, int state) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[20]; + + /* Issue Drive Status Update to bay:slot */ + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = 0xD5; + req.msg.data_len = 20; + req.msg.data = data; + + memset(data, 0, sizeof(data)); + data[0] = 0x00; // set + data[1] = 0x04; // set drive status + data[2] = 0x0e; // length lsb + data[3] = 0x00; // length msb + data[4] = 0x00; // offset lsb + data[5] = 0x00; // offset msb + data[6] = 0x0e; // length lsb + data[7] = 0x00; // length msb + data[8] = bayId; // bayid + data[9] = slotId; // slotid + data[10] = state & 0xff; // state LSB + data[11] = state >> 8; // state MSB; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error issuing setled command, "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n", rv, decode_cc(0,rv)); + return rv; + } + + return 0; +} + +int ipmi_delloem_getled_state (void * intf, uint8_t *state) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; int rsp_len, rv; + struct ipmi_rq req = {0}; + uint8_t data[2]; + uint8_t led_state = 0; + + req.msg.netfn = IPMI_DELL_OEM_NETFN; + req.msg.lun = 0; + req.msg.cmd = GET_CHASSIS_LED_STATE; + req.msg.data_len = 0; + req.msg.data = data; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf(" Error issuing getled command, "); + if (rv < 0) printf("no response\n"); + else printf("Completion Code 0x%02x %s\n", rv, decode_cc(0,rv)); + } else { + led_state = rsp[0]; + } + *state = led_state; + return rv; +} + +/***************************************************************** +* Function Name: ipmi_getsesmask +* +* Description: This function calculates bits in SES drive update +* Return: Mask set with bits for SES backplane update +* +******************************************************************/ +static int ipmi_getsesmask(int argc, char **argv) +{ + int mask = 0; + //int idx; + + while (current_arg < argc) { + if (!strcmp(argv[current_arg], "present")) + mask |= (1L << 0); + if (!strcmp(argv[current_arg], "online")) + mask |= (1L << 1); + if (!strcmp(argv[current_arg], "hotspare")) + mask |= (1L << 2); + if (!strcmp(argv[current_arg], "identify")) + mask |= (1L << 3); + if (!strcmp(argv[current_arg], "rebuilding")) + mask |= (1L << 4); + if (!strcmp(argv[current_arg], "fault")) + mask |= (1L << 5); + if (!strcmp(argv[current_arg], "predict")) + mask |= (1L << 6); + if (!strcmp(argv[current_arg], "critical")) + mask |= (1L << 9); + if (!strcmp(argv[current_arg], "failed")) + mask |= (1L << 10); + current_arg++; + } + return mask; +} + +/***************************************************************** +* Function Name: ipmi_delloem_setled_main +* +* Description: This function processes the delloem setled command +* Input: intf - ipmi interface + argc - no of arguments + argv - argument string array +* Output: +* +* Return: return code 0 - success +* -1 - failure +* +******************************************************************/ +static int +ipmi_delloem_setled_main(void * intf, int argc, char ** argv) +{ + int rc = -1; + int b,d,f, mask; + int bayId, slotId; + + bayId = 0xFF; + slotId = 0xFF; + + current_arg++; + if (argc < current_arg) + { + usage(); + return rc; + } + + /* ipmitool delloem setled info*/ + if (argc == 1 || strcmp(argv[current_arg], "help") == 0) + { + ipmi_setled_usage(); + return 0; + } + CheckSetLEDSupport (intf); + if (!IsSetLEDSupported()) + { + printf("'setled' is not supported on this system.\n"); + return rc; + } + else if (sscanf(argv[current_arg], "%*x:%x:%x.%x", &b,&d,&f) == 3) { + /* We have bus/dev/function of drive */ + current_arg++; + ipmi_getdrivemap (intf, b, d, f, &bayId, &slotId); + } + else if (sscanf(argv[current_arg], "%x:%x.%x", &b,&d,&f) == 3) { + /* We have bus/dev/function of drive */ + current_arg++; + } + else { + ipmi_setled_usage(); + return -1; + } + /* Get mask of SES flags */ + mask = ipmi_getsesmask(argc, argv); + + /* Get drive mapping */ + if (ipmi_getdrivemap (intf, b, d, f, &bayId, &slotId)) + return -1; + + /* Set drive LEDs */ + return ipmi_setled_state (intf, bayId, slotId, mask); +} + +static int +ipmi_delloem_getled_main(void * intf, int argc, char ** argv) +{ + int rc = 0; + uint8_t state; + + if (argc == 1 || strncmp(argv[0], "help\0", 5) == 0) + { + ipmi_delloem_getled_usage(); + return(0); + } else { + rc = ipmi_delloem_getled_state (intf, &state); + if (rc != 0) printf("getled_state error %d\n",rc); + else { + if (state == 0x01) + printf("Chassis ID LED Status = ON\n"); + else printf("Chassis ID LED Status = off\n"); + } + } + return (rc); +} + +/* + * decode_sensor_dell + * inputs: + * sdr = the SDR buffer + * reading = the 3 or 4 bytes of data from GetSensorReading + * pstring = points to the output string buffer + * slen = size of the output buffer + * outputs: + * rv = 0 if this sensor was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * pstring = contains the sensor reading interpretation string (if rv==0) + */ +int decode_sensor_dell(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + uchar stype, evtype; + + if (sdr == NULL || reading == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + /* sdr[3] is SDR type: 1=full, 2=compact, 0xC0=oem */ + if (sdr[3] != 0x02) return(rv); /*return if not compact SDR */ + stype = sdr[12]; /*sensor type*/ + evtype = sdr[13]; /*event type */ + if (stype == 0x02) { /* Discrete Voltage */ + /* Dell Discrete Voltage is opposite from normal */ + if (evtype == 0x03) { /*oem interpretation */ + if (reading[2] & 0x01) strncpy(pstring,"OK",slen); + else strncpy(pstring,"Exceeded",slen); /*LimitExceeded*/ + rv = 0; + } + } + return(rv); +} + +#define BIT(x) (1 << x) +#define SIZE_OF_DESC 128 + +char * get_dell_evt_desc(uchar *sel_rec) +{ + struct sel_event_record * rec = (struct sel_event_record *)sel_rec; + int data1, data2, data3; + int code; + char *desc = NULL; + + unsigned char count; + unsigned char node; + //unsigned char num; + unsigned char dimmNum; + unsigned char dimmsPerNode; + char dimmStr[32]; + //char cardStr[32]; + //char numStr[32]; + char tmpdesc[SIZE_OF_DESC]; + static char rgdesc[SIZE_OF_DESC]; + char* str; + unsigned char incr = 0; + unsigned char i = 0; + //unsigned char postCode; + // struct ipmi_rs *rsp; + // struct ipmi_rq req; + char tmpData; + int version; + // uint8_t devid[20]; /*usually 16 bytes*/ + uint8_t iver; + // int rv; + + data1 = rec->sel_type.standard_type.event_data[0]; + data2 = rec->sel_type.standard_type.event_data[1]; + data3 = rec->sel_type.standard_type.event_data[2]; + if ( (rec->sel_type.standard_type.event_type == 0x0B) || + (rec->sel_type.standard_type.event_type == 0x6F) || + (rec->sel_type.standard_type.event_type == 0x07)) + { + code = rec->sel_type.standard_type.sensor_type; + /* BDF or Slot */ + desc = rgdesc; + memset(desc,0,SIZE_OF_DESC); + switch (code) { + case 0x07: + if( ((data1 & DATA_BYTE2_SPECIFIED_MASK) == 0x80)) + { + if((data1 & 0x0f) == 0x00) + snprintf(desc,SIZE_OF_DESC,"CPU Internal Err | "); + if((data1 & 0x0f) == 0x06) + { + snprintf(desc,SIZE_OF_DESC,"CPU Protocol Err | "); + } + /* change bit location to a number */ + for (count= 0; count < 8; count++) + { + if (BIT(count)& data2) + { + count++; + if( ((data1 & 0x0f) == 0x06) && (rec->sel_type.standard_type.sensor_num == 0x0A)) + snprintf(desc,SIZE_OF_DESC,"FSB %d ",count); + else + snprintf(desc,SIZE_OF_DESC,"CPU %d | APIC ID %d ",count,data3); + break; + } + } + } + break; + case 0x0C: + if ( (rec->sel_type.standard_type.event_type == 0x0B) && + !(data1 & 0x03) ) + { + if(data2 & 0x04) + strcpy(desc,"Memory is in Spare Mode"); + else if(data2 & 0x02) + strcpy(desc,"Memory is in Raid Mode "); + else if(data2 & 0x01) + strcpy(desc,"Memory is in Mirror Mode "); + break; + } + case 0x10: + get_devid_ver(NULL,NULL,&iver); + // rv = ipmi_getdeviceid(devid,sizeof(devid),fdbg); + // if (rv != 0) return NULL; + version = iver; + /* Memory DIMMS */ + if( (data1 & 0x80) || (data1 & 0x20 ) ) + { + if( (code == 0x0c) && (rec->sel_type.standard_type.event_type == 0x0B) ) + { + if((data1 & 0x0f) == 0x00) + { + snprintf(desc,SIZE_OF_DESC," Redundancy Regained | "); + } + else if((data1 & 0x0f) == 0x01) + { + snprintf(desc,SIZE_OF_DESC,"Redundancy Lost | "); + } + } + else if(code == 0x0c) + { + if((data1 & 0x0f) == 0x00) + { + if(rec->sel_type.standard_type.sensor_num == 0x1C) + { + if((data1 & 0x80) && (data1 & 0x20 )) + { + count = 0; + snprintf(desc,SIZE_OF_DESC,"CRC Error on:"); + for(i=0;i<4;i++) + { + if((BIT(i))&(data2)) + { + if(count) + { + str = desc+strlen(desc); + *str++ = ','; + str = '\0'; + count = 0; + } + switch(i) + { + case 0: snprintf(tmpdesc,SIZE_OF_DESC,"South Bound Memory"); + strcat(desc,tmpdesc); + count++; + break; + case 1: snprintf(tmpdesc,SIZE_OF_DESC,"South Bound Config"); + strcat(desc,tmpdesc); + count++; + break; + case 2: snprintf(tmpdesc,SIZE_OF_DESC,"North Bound memory"); + strcat(desc,tmpdesc); + count++; + break; + case 3: snprintf(tmpdesc,SIZE_OF_DESC,"North Bound memory-corr"); + strcat(desc,tmpdesc); + count++; + break; + default: + break; + } + } + } + if(data3>=0x00 && data3<0xFF) + { + snprintf(tmpdesc,SIZE_OF_DESC,"|Failing_Channel:%d",data3); + strcat(desc,tmpdesc); + } + } + break; + } + snprintf(desc,SIZE_OF_DESC,"Correctable ECC | "); + } + else if((data1 & 0x0f) == 0x01) + { + snprintf(desc,SIZE_OF_DESC,"UnCorrectable ECC | "); + } + } + else if(code == 0x10) + { + if((data1 & 0x0f) == 0x00) + snprintf(desc,SIZE_OF_DESC,"Corr Memory Log Dissabled | "); + } + } + else + { + if(code == 0x12) + { + if((data1 & 0x0f) == 0x02) + snprintf(desc,SIZE_OF_DESC,"Unknown System Hardware Failure "); + } + if(code == 0x10) + { + if((data1 & 0x0f) == 0x03) + snprintf(desc,SIZE_OF_DESC,"All Even Logging Dissabled"); + } + } + if(data1 & 0x80 ) + { + if(((data2 >> 4) != 0x0f) && ((data2 >> 4) < 0x08)) + { + tmpData = ('A'+ (data2 >> 4)); + if( (code == 0x0c) && (rec->sel_type.standard_type.event_type == 0x0B) ) + { + snprintf(tmpdesc, SIZE_OF_DESC, "Bad Card %c", tmpData); + } + else + { + snprintf(tmpdesc, SIZE_OF_DESC, "Card %c", tmpData); + } + strcat(desc, tmpdesc); + } + if (0x0F != (data2 & 0x0f)) + { + if(0x51 == version) + { + snprintf(tmpdesc, SIZE_OF_DESC, "Bank %d", ((data2 & 0x0f)+1)); + strcat(desc, tmpdesc); + } + else + { + incr = (data2 & 0x0f) << 3; + } + } + + } + if(data1 & 0x20 ) + { + if(0x51 == version) + { + snprintf(tmpdesc, SIZE_OF_DESC, "DIMM %s", ('A'+ data3)); + strcat(desc, tmpdesc); + } + else if( ((data2 >> 4) > 0x07) && ((data2 >> 4) != 0x0F)) + { + strcpy(dimmStr, " DIMM_"); + str = desc+strlen(desc); + dimmsPerNode = 4; + if( (data2 >> 4) == 0x09) dimmsPerNode = 6; + else if( (data2 >> 4) == 0x0A) dimmsPerNode = 8; + else if( (data2 >> 4) == 0x0B) dimmsPerNode = 9; + else if( (data2 >> 4) == 0x0C) dimmsPerNode = 12; + else if( (data2 >> 4) == 0x0D) dimmsPerNode = 24; + else if( (data2 >> 4) == 0x0E) dimmsPerNode = 3; + count = 0; + for (i = 0; i < 8; i++) + { + if (BIT(i) & data3) + { + if (count) + { + *str++ = ','; + count = 0; + } + node = (incr + i)/dimmsPerNode; + dimmNum = ((incr + i)%dimmsPerNode)+1; + dimmStr[5] = node + 'A'; + sprintf(tmpdesc,"%d",dimmNum); + dimmStr[6] = tmpdesc[0]; + dimmStr[7] = '\0'; + strcat(str,dimmStr); + count++; + } + } + } + else + { + strcpy(dimmStr, " DIMM"); + str = desc+strlen(desc); + count = 0; + for (i = 0; i < 8; i++) + { + if (BIT(i) & data3) + { + // check if more than one DIMM, if so add a comma to the string. + if (count) + { + *str++ = ','; + count = 0; + } + sprintf(tmpdesc,"%d",(i + incr + 1)); + dimmStr[4] = tmpdesc[0]; + dimmStr[5] = '\0'; + strcat(str, dimmStr); + count++; + } + } + } + } + break; + case 0x20: + if(((data1 & 0x0f)== 0x00)&&((data1 & 0x80) && (data1 & 0x20))) + { + if((data2 > 0x00)&&(data2<0xFF)) + { + //Add the code to display 194 entries.This sensor present only in ORCA + + } + switch(data3) + { + case 0x01: + snprintf(desc,SIZE_OF_DESC,"BIOS TXT Error"); + break; + case 0x02: + snprintf(desc,SIZE_OF_DESC,"Processor/FIT TXT"); + break; + case 0x03: + snprintf(desc,SIZE_OF_DESC,"BIOS ACM TXT Error"); + break; + case 0x04: + snprintf(desc,SIZE_OF_DESC,"SINIT ACM TXT Error"); + break; + case 0xff: + snprintf(desc,SIZE_OF_DESC,"Unrecognized TT Error12"); + break; + default: + break; + } + } + break; + case 0x23: + + if(data1 == 0xC1) + { + if(data2 == 0x04) + { + snprintf(desc,SIZE_OF_DESC,"Hard Reset|Interrupt type None,SMS/OS Timer used at expiration"); + } + } + + break; + case 0x2B: + if(((data1 & 0x0f)== 0x02)&&((data1 & 0x80) && (data1 & 0x20))) + { + if(data2 == 0x02) + { + if(data3 == 0x00) + { + snprintf(desc, SIZE_OF_DESC, "between BMC/iDRAC Firmware and other hardware"); + } + else if(data3 == 0x01) + { + snprintf(desc, SIZE_OF_DESC, "between BMC/iDRAC Firmware and CPU"); + } + } + } + break; + + case 0xC1: + if(rec->sel_type.standard_type.sensor_num == 0x25) + { + if((data1 & 0x0f) == 0x01) + { + snprintf(desc, SIZE_OF_DESC, "Failed to program Virtual Mac Address"); + if((data1 & 0x80)&&(data1 & 0x20)) + { + snprintf(tmpdesc, SIZE_OF_DESC, "PCI %.2x:%.2x.%x", + data3 &0x7f, (data2 >> 3) & 0x1F, + data2 & 0x7); + } + } + else if((data1 & 0x0f) == 0x02) + { + snprintf(desc, SIZE_OF_DESC, "Device option ROM failed to support link tuning or flex address"); + if((data1 & 0x80)&&(data1 & 0x20)) + { + //Add Mezzanine code here.DELLOEM SEL displayed unknown event + } + } + else if((data1 & 0x0f) == 0x03) + { + snprintf(desc, SIZE_OF_DESC, "Failed to get link tuning or flex address data from BMC/iDRAC"); + } + strcat(desc,tmpdesc); + } + break; + case 0x13: + case 0xC2: + case 0xC3: + if(rec->sel_type.standard_type.sensor_num == 0x29) + { + if(((data1 & 0x0f)== 0x02)&&((data1 & 0x80) && (data1 & 0x20))) + { + #if 1 /*This sensor is not implemented in iDRAC code*/ + snprintf(tmpdesc, SIZE_OF_DESC, "Partner-(LinkId:%d,AgentId:%d)|",(data2 & 0xC0),(data2 & 0x30)); + strcat(desc,tmpdesc); + snprintf(tmpdesc, SIZE_OF_DESC, "ReportingAgent(LinkId:%d,AgentId:%d)|",(data2 & 0x0C),(data2 & 0x03)); + strcat(desc,tmpdesc); + if((data3 & 0xFC) == 0x00) + { + snprintf(tmpdesc, SIZE_OF_DESC, "LinkWidthDegraded|"); + strcat(desc,tmpdesc); + } + if(BIT(1)& data3) + { + snprintf(tmpdesc,SIZE_OF_DESC,"PA_Type:IOH|"); + } + else + { + snprintf(tmpdesc,SIZE_OF_DESC,"PA-Type:CPU|"); + } + strcat(desc,tmpdesc); + if(BIT(0)& data3) + { + snprintf(tmpdesc,SIZE_OF_DESC,"RA-Type:IOH"); + } + else + { + snprintf(tmpdesc,SIZE_OF_DESC,"RA-Type:CPU"); + } + strcat(desc,tmpdesc); + #endif + } + } + else + { + + if((data1 & 0x0f) == 0x02) + { + sprintf(desc,"%s","IO channel Check NMI"); + } + else + { + if((data1 & 0x0f) == 0x00) + { + snprintf(desc, SIZE_OF_DESC, "%s","PCIe Error |"); + } + else if((data1 & 0x0f) == 0x01) + { + snprintf(desc, SIZE_OF_DESC, "%s","I/O Error |"); + } + else if((data1 & 0x0f) == 0x04) + { + snprintf(desc, SIZE_OF_DESC, "%s","PCI PERR |"); + } + else if((data1 & 0x0f) == 0x05) + { + snprintf(desc, SIZE_OF_DESC, "%s","PCI SERR |"); + } + else + { + snprintf(desc, SIZE_OF_DESC, "%s"," "); + } + if (data3 & 0x80) + snprintf(tmpdesc, SIZE_OF_DESC, "Slot %d", data3 & 0x7f); + else + snprintf(tmpdesc, SIZE_OF_DESC, "PCI %.2x:%.2x.%x", + data3 &0x7f, (data2 >> 3) & 0x1F, + data2 & 0x7); + strcat(desc,tmpdesc); + } + } + break; + case 0x0F: + if(((data1 & 0x0f)== 0x0F)&&(data1 & 0x80)) + { + switch(data2) + { + case 0x80: + snprintf(desc, SIZE_OF_DESC, "No memory is detected.");break; + case 0x81: + snprintf(desc,SIZE_OF_DESC, "Memory is detected but is not configurable.");break; + case 0x82: + snprintf(desc, SIZE_OF_DESC, "Memory is configured but not usable.");break; + case 0x83: + snprintf(desc, SIZE_OF_DESC, "System BIOS shadow failed.");break; + case 0x84: + snprintf(desc, SIZE_OF_DESC, "CMOS failed.");break; + case 0x85: + snprintf(desc, SIZE_OF_DESC, "DMA controller failed.");break; + case 0x86: + snprintf(desc, SIZE_OF_DESC, "Interrupt controller failed.");break; + case 0x87: + snprintf(desc, SIZE_OF_DESC, "Timer refresh failed.");break; + case 0x88: + snprintf(desc, SIZE_OF_DESC, "Programmable interval timer error.");break; + case 0x89: + snprintf(desc, SIZE_OF_DESC, "Parity error.");break; + case 0x8A: + snprintf(desc, SIZE_OF_DESC, "SIO failed.");break; + case 0x8B: + snprintf(desc, SIZE_OF_DESC, "Keyboard controller failed.");break; + case 0x8C: + snprintf(desc, SIZE_OF_DESC, "System management interrupt initialization failed.");break; + case 0x8D: + snprintf(desc, SIZE_OF_DESC, "TXT-SX Error.");break; + case 0xC0: + snprintf(desc, SIZE_OF_DESC, "Shutdown test failed.");break; + case 0xC1: + snprintf(desc, SIZE_OF_DESC, "BIOS POST memory test failed.");break; + case 0xC2: + snprintf(desc, SIZE_OF_DESC, "RAC configuration failed.");break; + case 0xC3: + snprintf(desc, SIZE_OF_DESC, "CPU configuration failed.");break; + case 0xC4: + snprintf(desc, SIZE_OF_DESC, "Incorrect memory configuration.");break; + case 0xFE: + snprintf(desc, SIZE_OF_DESC, "General failure after video."); + break; + } + } + break; + + default: + break; + } + } + else + { + code = rec->sel_type.standard_type.event_type; + } + return desc; +} + +/* + * decode_sel_dell + * inputs: + * evt = the 16-byte IPMI SEL event + * outbuf = points to the output string buffer + * outsz = size of the output buffer + * outputs: + * rv = 0 if this event was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * outbuf = will contain the interpreted event text string (if rv==0) + */ +int decode_sel_dell(uint8_t *evt, char *outbuf, int outsz, char fdesc, + char fdbg) +{ + int rv = -1; + uint16_t id, genid; + uint8_t rectype; + uint32_t timestamp; + char *type_str = NULL; + char *gstr = NULL; + char *pstr = NULL; + int sevid; + uchar stype, snum; + + fdebug = fdbg; + sevid = SEV_INFO; + id = evt[0] + (evt[1] << 8); + rectype = evt[2]; + timestamp = evt[3] + (evt[4] << 8) + (evt[5] << 16) + (evt[6] << 24); + genid = evt[7] | (evt[8] << 8); + stype = evt[10]; + snum = evt[11]; + gstr = "BMC "; + if (genid == 0x0033) gstr = "Bios"; + type_str = ""; + if (rectype == 0x02) type_str = get_sensor_type_desc(stype); + +#ifdef OTHER + /* evt[13] is data1/offset*/ + if ( ((evt[13] & DATA_BYTE2_SPECIFIED_MASK) == 0x80) || + ((evt[13] & DATA_BYTE3_SPECIFIED_MASK) == 0x20) ) { + // if (evt[13] & DATA_BYTE2_SPECIFIED_MASK) + // evt->data = rec->sel_type.standard_type.event_data[1]; + pstr = get_dell_evt_desc(evt); + } else if (evt[13] == 0xC1) { + if (snum == 0x23) { + // evt->data = rec->sel_type.standard_type.event_data[1]; + pstr = get_dell_evt_desc(evt); + } + } +#endif + pstr = get_dell_evt_desc(evt); + if (pstr != NULL) rv = 0; + + if (rv == 0) { + format_event(id,timestamp, sevid, genid, type_str, + snum,NULL,pstr,NULL,outbuf,outsz); + } + return rv; +} + +#ifdef METACOMMAND +int i_delloem(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int rv = 0; + uchar devrec[16]; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + set_loglevel(LOG_NOTICE); + argc_sav = argc; + argv_sav = argv; + parse_lan_options('V',"4",0); /*default to admin priv*/ + + while ( (c = getopt( argc, argv,"m:s:xzEF:J:N:P:R:T:U:V:YZ:?")) != EOF ) + switch(c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 's': sdrfile = optarg; break; + case 'x': fdebug = 2; /* normal (dbglog if isol) */ + verbose = 1; + break; + case 'z': fdebug = 3; /*full debug (for isol)*/ + verbose = 1; + break; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + usage(); + rv = ERR_USAGE; + goto do_exit; + break; + } + rv = ipmi_getdeviceid(devrec,16,fdebug); + if (rv == 0) { + char ipmi_maj, ipmi_min; + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + // vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + // prod_id = devrec[9] + (devrec[10] << 8); + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + rv = ipmi_delloem_main(NULL, argc, argv); + +do_exit: + ipmi_close_(); + return(rv); +} +/* end oem_dell.c */ diff --git a/util/oem_dell.h b/util/oem_dell.h new file mode 100644 index 0000000..a17a517 --- /dev/null +++ b/util/oem_dell.h @@ -0,0 +1,629 @@ +/**************************************************************************** +Copyright (c) 2008, Dell Inc +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +- Neither the name of Dell Inc nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +*****************************************************************************/ +#ifndef IPMI_DELLOEM_H +#define IPMI_DELLOEM_H + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef HAVE_ATTRIBUTE_PACKING +/* this attribute is not very portable */ +#define ATTRIBUTE_PACKING __attribute__ ((packed)) +#else +/* use #pragma pack(1) instead */ +#define ATTRIBUTE_PACKING +#endif + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + + + +#define IPMI_SET_SYS_INFO 0x58 +#define IPMI_GET_SYS_INFO 0x59 + +/* Dell selector for LCD control - get and set unless specified */ +#define IPMI_DELL_LCD_STRING_SELECTOR 0xC1 /* RW get/set the user string */ +#define IPMI_DELL_LCD_CONFIG_SELECTOR 0xC2 /* RW set to user/default/none */ +#define IPMI_DELL_LCD_GET_CAPS_SELECTOR 0xCF /* RO use when available*/ +#define IPMI_DELL_LCD_STRINGEX_SELECTOR 0xD0 /* RW get/set the user string use first when available*/ +#define IPMI_DELL_LCD_STATUS_SELECTOR 0xE7 /* LCD string when config set to default.*/ +#define IPMI_DELL_PLATFORM_MODEL_NAME_SELECTOR 0xD1 /* LCD string when config set to default.*/ + +/* Dell defines for picking which string to use */ +#define IPMI_DELL_LCD_CONFIG_USER_DEFINED 0x00 /* use string set by user*/ +#define IPMI_DELL_LCD_CONFIG_DEFAULT 0x01 /* use platform model name*/ +#define IPMI_DELL_LCD_CONFIG_NONE 0x02 /* blank*/ +#define IPMI_DELL_LCD_iDRAC_IPV4ADRESS 0x04 /* use string set by user*/ +#define IPMI_DELL_LCD_IDRAC_MAC_ADDRESS 0x08 /* use platform model name*/ +#define IPMI_DELL_LCD_OS_SYSTEM_NAME 0x10 /* blank*/ + +#define IPMI_DELL_LCD_SERVICE_TAG 0x20 /* use string set by user*/ +#define IPMI_DELL_LCD_iDRAC_IPV6ADRESS 0x40 /* use string set by user*/ +#define IPMI_DELL_LCD_AMBEINT_TEMP 0x80 /* use platform model name*/ +#define IPMI_DELL_LCD_SYSTEM_WATTS 0x100 /* blank*/ +#define IPMI_DELL_LCD_ASSET_TAG 0x200 + +#define IPMI_DELL_LCD_ERROR_DISP_SEL 0x01 /* use platform model name*/ +#define IPMI_DELL_LCD_ERROR_DISP_VERBOSE 0x02 /* blank*/ + +#define IPMI_DELL_IDRAC_VALIDATOR 0xDD +#define IPMI_DELL_POWER_CAP_STATUS 0xBA +#define IPMI_DELL_AVG_POWER_CONSMP_HST 0xEB +#define IPMI_DELL_PEAK_POWER_CONSMP_HST 0xEC +#define SYSTEM_BOARD_SYSTEM_LEVEL_SENSOR_NUM 0x98 + +#define IDRAC_11G 1 +#define IDRAC_12G 2 +// Return Error code for license +#define LICENSE_NOT_SUPPORTED 0x6F +#define VFL_NOT_LICENSED 0x33 +#define btuphr 0x01 +#define watt 0x00 +#define IPMI_DELL_POWER_CAP 0xEA +#define percent 0x03 + +/* Not on all Dell servers. If there, use it.*/ +#pragma pack(1) +typedef struct _tag_ipmi_dell_lcd_caps +{ + uint8_t parm_rev; /* 0x11 for IPMI 2.0 */ + uint8_t char_set; /* always 1 for printable ASCII 0x20-0x7E */ + uint8_t number_lines; /* 0-4, 1 for 9G. 10G tbd */ + uint8_t max_chars[4]; /* 62 for triathlon, 0 if not present (glacier) */ + /* [0] is max chars for line 1 */ +}IPMI_DELL_LCD_CAPS; + +#define IPMI_DELL_LCD_STRING_LENGTH_MAX 62 /* Valid for 9G. Glacier ??. */ +#define IPMI_DELL_LCD_STRING1_SIZE 14 +#define IPMI_DELL_LCD_STRINGN_SIZE 16 + +/* vFlash subcommands */ +#define IPMI_GET_EXT_SD_CARD_INFO 0xA4 + + +typedef struct _tag_ipmi_dell_lcd_string +{ + uint8_t parm_rev; /* 0x11 for IPMI 2.0 */ + uint8_t data_block_selector; /* 16-byte data block number to access, 0 based.*/ + union + { + struct + { + uint8_t encoding : 4; /* 0 is printable ASCII 7-bit */ + uint8_t length; /* 0 to max chars from lcd caps */ + uint8_t data[IPMI_DELL_LCD_STRING1_SIZE]; /* not zero terminated. */ + }selector_0_string; + uint8_t selector_n_data[IPMI_DELL_LCD_STRINGN_SIZE]; + }lcd_string; +} ATTRIBUTE_PACKING IPMI_DELL_LCD_STRING; + +/* Only found on servers with more than 1 line. Use if available. */ +typedef struct _tag_ipmi_dell_lcd_stringex +{ + uint8_t parm_rev; /* 0x11 for IPMI 2.0 */ + uint8_t line_number; /* LCD line number 1 to 4 */ + uint8_t data_block_selector; /* 16-byte data block number to access, 0 based.*/ + union + { + struct + { + uint8_t encoding : 4; /* 0 is printable ASCII 7-bit */ + uint8_t length; /* 0 to max chars from lcd caps */ + uint8_t data[IPMI_DELL_LCD_STRING1_SIZE]; /* not zero terminated. */ + } selector_0_string; + uint8_t selector_n_data[IPMI_DELL_LCD_STRINGN_SIZE]; + } lcd_string; +} ATTRIBUTE_PACKING IPMI_DELL_LCD_STRINGEX; + + +typedef struct _lcd_status +{ + char vKVM_status; + char lock_status; + char Resv1; + char Resv; +} ATTRIBUTE_PACKING LCD_STATUS; + +typedef struct _lcd_mode +{ + uint8_t parametersel; + uint32_t lcdmode; + uint16_t lcdqualifier; + uint32_t capabilites; + uint8_t error_display; + uint8_t Resv; +} ATTRIBUTE_PACKING LCD_MODE; +#pragma pack() + +#define PARAM_REV_OFFSET (uint8_t)(0x1) + +#define LOM_MACTYPE_ETHERNET 0 +#define LOM_MACTYPE_ISCSI 1 +#define LOM_MACTYPE_RESERVED 3 + +#define LOM_ETHERNET_ENABLED 0 +#define LOM_ETHERNET_DISABLED 1 +#define LOM_ETHERNET_PLAYINGDEAD 2 +#define LOM_ETHERNET_RESERVED 3 + +#define LOM_ACTIVE 1 +#define LOM_INACTIVE 0 + +#define MACADDRESSLENGH 6 +#define MAX_LOM 8 + +#define IPMI_NETFN_SE (uint8_t)(0x04) +#define IPMI_NETFN_APP (uint8_t)(0x06) //NETFN_APP +#define IPMI_NETFN_STORAGE (uint8_t)(0x0a) //NETFN_STOR +#define IPMI_CMD_GET_SEL_TIME 0x48 +#define GET_FRU_INFO 0x10 +#define GET_FRU_DATA 0x11 +#define BSWAP_16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8)) + +#define APP_NETFN (uint8_t)(0x6) + + +#define GET_SYSTEM_INFO_CMD (uint8_t)(0x59) +#define EMB_NIC_MAC_ADDRESS_11G (uint8_t)(0xDA) +#define EMB_NIC_MAC_ADDRESS_9G_10G (uint8_t)(0xCB) + +#define IMC_IDRAC_10G (uint8_t) (0x08) +#define IMC_CMC (uint8_t) (0x09) +#define IMC_IDRAC_11G_MONOLITHIC (uint8_t) (0x0A) +#define IMC_IDRAC_11G_MODULAR (uint8_t) (0x0B) +#define IMC_UNUSED (uint8_t) (0x0C) +#define IMC_MASER_LITE_BMC (uint8_t) (0x0D) +#define IMC_IDRAC_12G_MONOLITHIC (uint8_t) (0x10) +#define IMC_IDRAC_12G_MODULAR (uint8_t) (0x11) + + +#pragma pack(1) +#ifdef LOM_OLD +typedef struct +{ + unsigned int BladSlotNumber : 4; + unsigned int MacType : 2; + unsigned int EthernetStatus : 2; + unsigned int NICNumber : 5; + unsigned int Reserved : 3; + uint8_t MacAddressByte[MACADDRESSLENGH]; +} LOMMacAddressType; +#else +typedef struct +{ + uint8_t b0; + uint8_t b1; + uint8_t MacAddressByte[MACADDRESSLENGH]; +} LOMMacAddressType; +#endif +#pragma pack() + +#pragma pack(1) +typedef struct +{ + LOMMacAddressType LOMMacAddress [MAX_LOM]; +} EmbeddedNICMacAddressType; + +typedef struct +{ + uint8_t MacAddressByte[MACADDRESSLENGH]; +} MacAddressType; + +typedef struct +{ + MacAddressType MacAddress [MAX_LOM]; +} EmbeddedNICMacAddressType_10G; + +struct fru_info { + uint16_t size; + uint8_t access:1; +}; +struct fru_header { + uint8_t version; + struct { + uint8_t internal; + uint8_t chassis; + uint8_t board; + uint8_t product; + uint8_t multi; + } offset; + uint8_t pad; + uint8_t checksum; +} ATTRIBUTE_PACKING; + +struct entity_id { + uint8_t id; /* physical entity id */ +#if WORDS_BIGENDIAN + uint8_t logical : 1; /* physical/logical */ + uint8_t instance : 7; /* instance number */ +#else + uint8_t instance : 7; /* instance number */ + uint8_t logical : 1; /* physical/logical */ +#endif +} ATTRIBUTE_PACKING; +struct sdr_record_mask { + union { + struct { + uint16_t assert_event; /* assertion event mask */ + uint16_t deassert_event; /* de-assertion event ma +sk */ + uint16_t read; /* discrete reading mask */ + } ATTRIBUTE_PACKING discrete; + /*...*/ + } ATTRIBUTE_PACKING type; +} ATTRIBUTE_PACKING ; + +struct sdr_record_full_sensor { + struct { + uint8_t owner_id; +#if WORDS_BIGENDIAN + uint8_t channel:4; /* channel number */ + uint8_t __reserved1:2; + uint8_t lun:2; /* sensor owner lun */ +#else + uint8_t lun:2; /* sensor owner lun */ + uint8_t __reserved2:2; + uint8_t channel:4; /* channel number */ +#endif + uint8_t sensor_num; /* unique sensor number */ + } ATTRIBUTE_PACKING keys; + + struct entity_id entity; + + struct { + struct { +#if WORDS_BIGENDIAN + uint8_t __reserved3:1; + uint8_t scanning:1; + uint8_t events:1; + uint8_t thresholds:1; + uint8_t hysteresis:1; + uint8_t type:1; + uint8_t event_gen:1; + uint8_t sensor_scan:1; +#else + uint8_t sensor_scan:1; + uint8_t event_gen:1; + uint8_t type:1; + uint8_t hysteresis:1; + uint8_t thresholds:1; + uint8_t events:1; + uint8_t scanning:1; + uint8_t __reserved4:1; +#endif + } ATTRIBUTE_PACKING init; + struct { +#if WORDS_BIGENDIAN + uint8_t ignore:1; + uint8_t rearm:1; + uint8_t hysteresis:2; + uint8_t threshold:2; + uint8_t event_msg:2; +#else + uint8_t event_msg:2; + uint8_t threshold:2; + uint8_t hysteresis:2; + uint8_t rearm:1; + uint8_t ignore:1; +#endif + } ATTRIBUTE_PACKING capabilities; + uint8_t type; + } ATTRIBUTE_PACKING sensor; + + uint8_t event_type; /* event/reading type code */ + + struct sdr_record_mask mask; + + struct { +#if WORDS_BIGENDIAN + uint8_t analog:2; + uint8_t rate:3; + uint8_t modifier:2; + uint8_t pct:1; +#else + uint8_t pct:1; + uint8_t modifier:2; + uint8_t rate:3; + uint8_t analog:2; +#endif + struct { + uint8_t base; + uint8_t modifier; + } ATTRIBUTE_PACKING type; + } ATTRIBUTE_PACKING unit; + +#define SDR_SENSOR_L_LINEAR 0x00 +#define SDR_SENSOR_L_LN 0x01 +#define SDR_SENSOR_L_LOG10 0x02 +#define SDR_SENSOR_L_LOG2 0x03 +#define SDR_SENSOR_L_E 0x04 +#define SDR_SENSOR_L_EXP10 0x05 +#define SDR_SENSOR_L_EXP2 0x06 +#define SDR_SENSOR_L_1_X 0x07 +#define SDR_SENSOR_L_SQR 0x08 +#define SDR_SENSOR_L_CUBE 0x09 +#define SDR_SENSOR_L_SQRT 0x0a +#define SDR_SENSOR_L_CUBERT 0x0b +#define SDR_SENSOR_L_NONLINEAR 0x70 + uint8_t linearization; /* 70h=non linear, 71h-7Fh=non linear, OEM */ + uint16_t mtol; /* M, tolerance */ + uint32_t bacc; /* accuracy, B, Bexp, Rexp */ + + struct { +#if WORDS_BIGENDIAN + uint8_t __reserved5:5; + uint8_t normal_min:1; /* normal min field specified */ + uint8_t normal_max:1; /* normal max field specified */ + uint8_t nominal_read:1; /* nominal reading field specified */ +#else + uint8_t nominal_read:1; /* nominal reading field specified */ + uint8_t normal_max:1; /* normal max field specified */ + uint8_t normal_min:1; /* normal min field specified */ + uint8_t __reserved5:5; +#endif + } ATTRIBUTE_PACKING analog_flag; + + uint8_t nominal_read; /* nominal reading, raw value */ + uint8_t normal_max; /* normal maximum, raw value */ + uint8_t normal_min; /* normal minimum, raw value */ + uint8_t sensor_max; /* sensor maximum, raw value */ + uint8_t sensor_min; /* sensor minimum, raw value */ + + struct { + struct { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } ATTRIBUTE_PACKING upper; + struct { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } ATTRIBUTE_PACKING lower; + struct { + uint8_t positive; + uint8_t negative; + } ATTRIBUTE_PACKING hysteresis; + } ATTRIBUTE_PACKING threshold; + uint8_t __reserved6[2]; + uint8_t oem; /* reserved for OEM use */ + uint8_t id_code; /* sensor ID string type/length code */ + uint8_t id_string[16]; /* sensor ID string bytes, only if id_code != 0 */ +} ATTRIBUTE_PACKING; +struct sdr_record_list { + uint16_t id; + uint8_t version; + uint8_t type; + uint8_t length; + union { + struct sdr_record_full_sensor *full; + } ATTRIBUTE_PACKING record; + uint8_t *raw; + struct sdr_record_list *next; +} ATTRIBUTE_PACKING; +#pragma pack() + +#define TRANSPORT_NETFN (uint8_t)(0xc) +#define GET_LAN_PARAM_CMD (uint8_t)(0x02) +#define MAC_ADDR_PARAM (uint8_t)(0x05) +#define LAN_CHANNEL_NUMBER (uint8_t)(0x01) + +#define IDRAC_NIC_NUMBER (uint8_t)(0x8) + +#define TOTAL_N0_NICS_INDEX (uint8_t)(0x1) + + +// 12g supported +#define SET_NIC_SELECTION_12G_CMD (uint8_t)(0x28) +#define GET_NIC_SELECTION_12G_CMD (uint8_t)(0x29) + +// 11g supported +#define SET_NIC_SELECTION_CMD (uint8_t)(0x24) +#define GET_NIC_SELECTION_CMD (uint8_t)(0x25) +#define GET_ACTIVE_NIC_CMD (uint8_t)(0xc1) +#define POWER_EFFICENCY_CMD (uint8_t)(0xc0) +#define SERVER_POWER_CONSUMPTION_CMD (uint8_t)(0x8F) + +#define POWER_SUPPLY_INFO (uint8_t)(0xb0) +#define IPMI_ENTITY_ID_POWER_SUPPLY (uint8_t)(0x0a) +#define SENSOR_STATE_STR_SIZE (uint8_t)(64) +#define SENSOR_NAME_STR_SIZE (uint8_t)(64) + +#define GET_PWRMGMT_INFO_CMD (uint8_t)(0x9C) +#define CLEAR_PWRMGMT_INFO_CMD (uint8_t)(0x9D) +#define GET_PWR_HEADROOM_CMD (uint8_t)(0xBB) +#define GET_PWR_CONSUMPTION_CMD (uint8_t)(0xB3) +#define GET_FRONT_PANEL_INFO_CMD (uint8_t)0xb5 + + +#pragma pack(1) +typedef struct _ipmi_power_monitor +{ + uint32_t cumStartTime; + uint32_t cumReading; + uint32_t maxPeakStartTime; + uint32_t ampPeakTime; + uint16_t ampReading; + uint32_t wattPeakTime; + uint16_t wattReading; +} ATTRIBUTE_PACKING IPMI_POWER_MONITOR; + + +#define MAX_POWER_FW_VERSION 8 + +typedef struct _ipmi_power_supply_infoo +{ + /*No param_rev it is not a System Information Command */ + uint16_t ratedWatts; + uint16_t ratedAmps; + uint16_t ratedVolts; + uint32_t vendorid; + uint8_t FrimwareVersion[MAX_POWER_FW_VERSION]; + uint8_t Powersupplytype; + uint16_t ratedDCWatts; + uint16_t Resv; + +} ATTRIBUTE_PACKING IPMI_POWER_SUPPLY_INFO; + + +typedef struct ipmi_power_consumption_data +{ + uint16_t actualpowerconsumption; + uint16_t powerthreshold; + uint16_t warningthreshold; + uint8_t throttlestate; + uint16_t maxpowerconsumption; + uint16_t throttlepowerconsumption; + uint16_t Resv; +} ATTRIBUTE_PACKING IPMI_POWER_CONSUMPTION_DATA; + + +typedef struct ipmi_inst_power_consumption_data +{ + uint16_t instanpowerconsumption; + uint16_t instanApms; + uint16_t resv1; + uint8_t resv; +} ATTRIBUTE_PACKING IPMI_INST_POWER_CONSUMPTION_DATA; + +typedef struct _ipmi_avgpower_consump_histroy +{ + uint8_t parameterselector; + uint16_t lastminutepower; + uint16_t lasthourpower; + uint16_t lastdaypower; + uint16_t lastweakpower; + +} ATTRIBUTE_PACKING IPMI_AVGPOWER_CONSUMP_HISTORY; + +typedef struct _ipmi_power_consump_histroy +{ + uint8_t parameterselector; + uint16_t lastminutepower; + uint16_t lasthourpower; + uint16_t lastdaypower; + uint16_t lastweakpower; + uint32_t lastminutepowertime; + uint32_t lasthourpowertime; + uint32_t lastdaypowertime; + uint32_t lastweekpowertime; +} ATTRIBUTE_PACKING IPMI_POWER_CONSUMP_HISTORY; + + +typedef struct _ipmi_delloem_power_cap +{ + uint8_t parameterselector; + uint16_t PowerCap; + uint8_t unit; + uint16_t MaximumPowerConsmp; + uint16_t MinimumPowerConsmp; + uint16_t totalnumpowersupp; + uint16_t AvailablePower ; + uint16_t SystemThrottling; + uint16_t Resv; +} ATTRIBUTE_PACKING IPMI_POWER_CAP; + +typedef struct _power_headroom +{ + uint16_t instheadroom; + uint16_t peakheadroom; +} ATTRIBUTE_PACKING POWER_HEADROOM; + +struct vFlashstr { + uint8_t val; + const char * str; +}; +typedef struct ipmi_vFlash_extended_info +{ + uint8_t vflashcompcode; + uint8_t sdcardstatus; + uint32_t sdcardsize; + uint32_t sdcardavailsize; + uint8_t bootpartion; + uint8_t Resv; +} IPMI_DELL_SDCARD_INFO; +#pragma pack() + + +typedef struct _SensorReadingType +{ + uint8_t sensorReading; + uint8_t sensorFlags; + uint16_t sensorState; +}SensorReadingType; + +struct standard_spec_sel_rec{ + uint32_t timestamp; + uint16_t gen_id; + uint8_t evm_rev; + uint8_t sensor_type; + uint8_t sensor_num; +#if WORDS_BIGENDIAN + uint8_t event_dir : 1; + uint8_t event_type : 7; +#else + uint8_t event_type : 7; + uint8_t event_dir : 1; +#endif +#define DATA_BYTE2_SPECIFIED_MASK 0xc0 /* event_data[0] bit mask */ +#define DATA_BYTE3_SPECIFIED_MASK 0x30 /* event_data[0] bit mask */ +#define EVENT_OFFSET_MASK 0x0f /* event_data[0] bit mask */ + uint8_t event_data[3]; +}; + +#define SEL_OEM_TS_DATA_LEN 6 +#define SEL_OEM_NOTS_DATA_LEN 13 +struct oem_ts_spec_sel_rec{ + uint32_t timestamp; + uint8_t manf_id[3]; + uint8_t oem_defined[SEL_OEM_TS_DATA_LEN]; +}; + +struct oem_nots_spec_sel_rec{ + uint8_t oem_defined[SEL_OEM_NOTS_DATA_LEN]; +}; + +#pragma pack(1) +struct sel_event_record { + uint16_t record_id; + uint8_t record_type; + union{ + struct standard_spec_sel_rec standard_type; + struct oem_ts_spec_sel_rec oem_ts_type; + struct oem_nots_spec_sel_rec oem_nots_type; + } sel_type; +} ATTRIBUTE_PACKING; // __attribute__ ((packed)); +#pragma pack() + +uint16_t compareinputwattage(IPMI_POWER_SUPPLY_INFO* powersupplyinfo, uint16_t inputwattage); +int ipmi_delloem_main(void * intf, int argc, char ** argv); +int ipmi_delloem_getled_state (void * intf, uint8_t *state); +#endif /*IPMI_DELLOEM_H*/ diff --git a/util/oem_fujitsu.c b/util/oem_fujitsu.c new file mode 100644 index 0000000..362df96 --- /dev/null +++ b/util/oem_fujitsu.c @@ -0,0 +1,773 @@ +/* + * oem_fujitsu.c + * + * This module handles OEM-specific functions for Fujitsu-Siemens firmware. + * + * References: + * http://manuals.ts.fujitsu.com/file/4390/irmc_s2-ug-en.pdf + * + * Authors: Andy Cress arcress at users.sourceforge.net, and + * Dan Lukes dan at obluda.cz + * + * Copyright (c) 2010 Kontron America, Inc. + * + * 08/17/10 Andy Cress v1.0 new, with source input from Dan Lukes + */ +/*M* +Copyright (c) 2010 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#endif +#include <stdio.h> +#include <string.h> +#include <time.h> +#include "ipmicmd.h" +#include "ievents.h" +#include "oem_fujitsu.h" + +/* extern void get_mfgid(int *vend, int *prod); * from ipmicmd.h*/ +/* extern int get_lan_options(); * from ipmicmd.h */ +static char fdebug = 0; +static char freadok = 1; +#define ERRLED 0 /*GEL - red Global Error LED*/ +#define WARNLED 1 /*CSS - yellow warning LED*/ +#define IDLED 2 /*ID - blue Identify LED*/ + +#define NETFN_FUJITSU_IRMCS2 0xB8 +#define CMD_FUJITSU_IRMCS2 0xF5 +#define CMD_SPEC_FUJITSU_SET_ID_LED 0xB0 +#define CMD_SPEC_FUJITSU_GET_ID_LED 0xB1 +#define CMD_SPEC_FUJITSU_GET_ERR_LED 0xB3 +#define LED_OFF 0 +#define LED_ON 1 +#define LED_BLINK 2 + +/* + * get_alarmss_fujitsu + * returns an array of 3 bytes: + * offset 0 = ID blue LED state (0=off, 1=on, 2=blink) + * offset 1 = CSS yellow LED state (0=off, 1=on, 2=blink) + * offset 2 = GEL red LED state (0=off, 1=on, 2=blink) + */ +int get_alarms_fujitsu(uchar *rgalarms ) +{ + int rv = -1; + uchar idata[16]; + uchar rdata[16]; + int rlen; + ushort icmd; + uchar cc; + int vend_id, prod_id; + + if (rgalarms == NULL) return(ERR_BAD_PARAM); + memset(rgalarms,0,3); + /* check if iRMC s2 */ + get_mfgid(&vend_id,&prod_id); + if (vend_id != VENDOR_FUJITSU) return(LAN_ERR_NOTSUPPORT); + if (FUJITSU_PRODUCT_IS_iRMC_S1(prod_id)) return(LAN_ERR_NOTSUPPORT); + + /* get error, warning, id led statuses */ + icmd = CMD_FUJITSU_IRMCS2 | (IPMI_NET_FN_OEM_GROUP_RQ << 8); + idata[0] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0x0000FF); + idata[1] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0x00FF00) >> 8; + idata[2] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0xFF0000) >> 16; + idata[3] = CMD_SPEC_FUJITSU_GET_ID_LED; + rlen = sizeof(rdata); + rv = ipmi_cmd_mc(icmd, idata, 4, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv != 0) return(rv); + rgalarms[0] = (rdata[3] & 0x03); /*id led, after the IANA response */ + icmd = CMD_FUJITSU_IRMCS2 | (IPMI_NET_FN_OEM_GROUP_RQ << 8); + idata[0] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0x0000FF); + idata[1] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0x00FF00) >> 8; + idata[2] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0xFF0000) >> 16; + idata[3] = CMD_SPEC_FUJITSU_GET_ERR_LED; + rlen = sizeof(rdata); + rv = ipmi_cmd_mc(icmd, idata, 4, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + switch(rdata[3]) { + case 1: rgalarms[1] = LED_OFF; rgalarms[2] = LED_ON; break; + case 2: rgalarms[1] = LED_OFF; rgalarms[2] = LED_BLINK; break; + case 3: rgalarms[1] = LED_ON; rgalarms[2] = LED_OFF; break; + case 4: rgalarms[1] = LED_ON; rgalarms[2] = LED_ON; break; + case 5: rgalarms[1] = LED_ON; rgalarms[2] = LED_BLINK; break; + case 6: rgalarms[1] = LED_BLINK; rgalarms[2] = LED_OFF; break; + case 7: rgalarms[1] = LED_BLINK; rgalarms[2] = LED_ON; break; + case 8: rgalarms[1] = LED_BLINK; rgalarms[2] = LED_BLINK; break; + case 0: + default: rgalarms[1] = LED_OFF; rgalarms[2] = LED_OFF; break; + } + + return(rv); +} + +static char *led_str(uchar b) +{ + char *pstr; + switch(b) { + case LED_ON: pstr = "ON"; break; + case LED_BLINK: pstr = "Blink"; break; + case LED_OFF: + default: pstr = "off"; break; + } + return(pstr); +} + +/* + * show_alarms_fujitsu + * offset 0 = ID blue LED state (0=off, 1=on, 2=blink) + * offset 1 = CSS yellow LED state (0=off, 1=on, 2=blink) + * offset 2 = GEL red LED state (0=off, 1=on, 2=blink) + */ +int show_alarms_fujitsu(uchar *rgalarms) +{ + if (rgalarms == NULL) return(ERR_BAD_PARAM); + /* show error, warning, id led statuses */ + printf("iRMC S2 ID LED (blue) = %s\n",led_str(rgalarms[0])); + printf("iRMC S2 CSS LED (yellow) = %s\n",led_str(rgalarms[1])); + printf("iRMC S2 GEL LED (red) = %s\n",led_str(rgalarms[2])); + return(0); +} + +/* + * set_alarms_fujitsu + * num: only the ID LED can be set, so num==0 + * val: 0=LED_OFF, 1=LED_ON + */ +int set_alarms_fujitsu(uchar num, uchar val) +{ + int rv = -1; + uchar idata[16]; + uchar rdata[16]; + int rlen; + ushort icmd; + uchar cc; + int vend_id, prod_id; + + get_mfgid(&vend_id,&prod_id); + if (vend_id != VENDOR_FUJITSU) return(LAN_ERR_NOTSUPPORT); + if (FUJITSU_PRODUCT_IS_iRMC_S1(prod_id)) return(LAN_ERR_NOTSUPPORT); + + /* set the specified LED number to val */ + icmd = CMD_FUJITSU_IRMCS2 | (IPMI_NET_FN_OEM_GROUP_RQ << 8); + idata[0] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0x0000FF); + idata[1] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0x00FF00) >> 8; + idata[2] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0xFF0000) >> 16; + idata[3] = CMD_SPEC_FUJITSU_SET_ID_LED; + if (val == 0xFF) idata[4] = LED_ON; + else if (val == 0) idata[4] = LED_OFF; + else idata[4] = LED_BLINK; + rlen = sizeof(rdata); + rv = ipmi_cmd_mc(icmd, idata, 5, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + + return(rv); +} + +/* + * read_sel_fujitsu + * + * Fujitsu OEM + * http://manuals.ts.fujitsu.com/file/4390/irmc_s2-ug-en.pdf + * + * Request + * 0x2E - OEM network function + * 0xF5 - OEM cmd + * 0x?? - Fujitsu IANA (LSB first) + * 0x?? - Fujitsu IANA + * 0x?? - Fujitsu IANA + * 0x43 - Command Specifier + * 0x?? - Record ID (LSB first) + * 0x?? - Record ID ; 0x0000 = "first record", 0xFFFF = "last record" + * 0x?? - Offset (in response SEL text) + * 0x?? - MaxResponseDataSize (size of converted SEL data 16:n in response, + * maximum is 100, some only handle 64) + * + * Response + * 0xF5 - OEM cmd + * 0x?? - Completion code + * 0 0x?? - Fujitsu IANA (LSB first) + * 1 0x?? - Fujitsu IANA + * 2 0x?? - Fujitsu IANA + * 3 0x?? - Next Record ID (LSB) + * 4 0x?? - Next Record ID (MSB) + * 5 0x?? - Actual Record ID (LSB) + * 6 0x?? - Actual Record ID (MSB) + * 7 0x?? - Record type + * 8 0x?? - timestamp (LSB first) + * 9 0x?? - timestamp + * 10 0x?? - timestamp + * 11 0x?? - timestamp + * 12 0x?? - severity + * bit 7 - CSS component + * bit 6-4 - 000 = INFORMATIONAL + * 001 = MINOR + * 010 = MAJOR + * 011 = CRITICAL + * 1xx = unknown + * bit 3-0 - reserved + * 13 0x?? - data length (of the whole text) + * 14 0x?? - converted SEL data + * requested number of bytes starting at requested offset + * (MaxResponseDataSize-1 bytes of data) ..... + * 0x00 - trailing '\0' character + */ +int read_sel_fujitsu(uint16_t id, char *buf, int sz, char fdbg) +{ + int rv = -1; + uint8_t bytes_rq[IPMI_OEM_MAX_BYTES]; + uint8_t bytes_rs[IPMI_OEM_MAX_BYTES]; + char textbuf[IPMI_OEM_MAX_BYTES]; + int rs_len, text_len, data_len, chunk_len; + int max_read_length; + uint16_t actual_record_id = id; + uint32_t timestamp = 0; + // uint16_t next_record_id; + // uint8_t record_type; + uint8_t severity = 0; + uint8_t ccode; + char timestr[40]; + char *severity_text = NULL; + uint8_t offset = 0; + int vend_id, prod_id; + + fdebug = fdbg; + if (buf == NULL) return(rv); + max_read_length = IPMI_OEM_MAX_BYTES; + data_len = IPMI_OEM_MAX_BYTES; + /* This command requires admin privilege, so check and + print a warning if Fujitsu and not admin. */ + get_mfgid(&vend_id,&prod_id); + if (vend_id == VENDOR_FUJITSU) { /* connected to Fujitsu MC */ + int auth, priv; + if (FUJITSU_PRODUCT_IS_iRMC_S1(prod_id)) { + max_read_length = 32; + data_len = 80; + } + rv = get_lan_options(NULL,NULL,NULL,&auth,&priv,NULL,NULL,NULL); + if ((rv == 0) && (priv < 4)) { /*remote and not admin priv*/ + printf("*** Admin privilege (-V 4) required for full OEM decoding.\n"); + } + } + + memset(textbuf,0,sizeof(textbuf)); + bytes_rq[0] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0x0000FF); + bytes_rq[1] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0x00FF00) >> 8; + bytes_rq[2] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0xFF0000) >> 16; + bytes_rq[3] = IPMI_OEM_FUJITSU_COMMAND_SPECIFIER_GET_SEL_ENTRY_LONG_TEXT; + bytes_rq[4] = (id & 0x00FF); + bytes_rq[5] = (id & 0xFF00) >> 8; + bytes_rq[7] = (uchar)max_read_length; + + while (offset < data_len) + { + bytes_rq[6] = offset; + /* Do not ask BMC for data beyond data_len, request partial if so. */ + if (offset + max_read_length > data_len) + bytes_rq[7] = data_len - offset; + rs_len = sizeof(bytes_rs); + rv = ipmi_cmdraw(IPMI_CMD_OEM_FUJITSU_SYSTEM, IPMI_NET_FN_OEM_GROUP_RQ, + BMC_SA, PUBLIC_BUS, BMC_LUN, + bytes_rq, 9, bytes_rs, &rs_len, &ccode, fdebug); + if (fdebug) printf("read_sel_fujitsu rv = %d, cc = %x\n", rv, ccode); + if (rv == 0 && ccode != 0) rv = ccode; + if (rv != 0) return(rv); + if (fdebug) dump_buf("read_sel_fujitsu data",bytes_rs,rs_len,1); + + if (offset == 0) { /* only need to set these on the first pass */ + actual_record_id = bytes_rs[5] + (bytes_rs[6] << 8); + timestamp = bytes_rs[8] + (bytes_rs[9] << 8) + + (bytes_rs[10] << 16) + (bytes_rs[11] << 24); + severity = (bytes_rs[12] >> 3); + data_len = bytes_rs[13]; + if (data_len > IPMI_OEM_MAX_BYTES) data_len = IPMI_OEM_MAX_BYTES; + } + chunk_len = rs_len - 14; + if ((offset + chunk_len) > IPMI_OEM_MAX_BYTES) + chunk_len = IPMI_OEM_MAX_BYTES - offset; + memcpy(&textbuf[offset],&bytes_rs[14],chunk_len); + offset += (uint8_t)chunk_len; + } + textbuf[IPMI_OEM_MAX_BYTES-1]='\0'; /*stringify*/ + text_len = strlen_(textbuf); + + switch (severity) { + case 0: severity_text = "INFORMATIONAL:"; break; + case 1: severity_text = "MINOR:"; break; + case 2: severity_text = "MAJOR:"; break; + case 3: severity_text = "CRITICAL:"; break; + case 4: + case 5: + case 6: + case 7: severity_text = ""; break; + case 8: severity_text = "INFORMATIONAL/CSS:"; break; + case 9: severity_text = "MINOR/CSS:"; break; + case 10: severity_text = "MAJOR/CSS:"; break; + case 11: severity_text = "CRITICAL/CSS:"; break; + case 12: + case 13: + case 14: + case 15: severity_text = "unknown/CSS:"; break; + } + + fmt_time(timestamp, timestr, sizeof(timestr)); + snprintf(buf, sz, "%u | %s | %s %s\n", (int)actual_record_id, + timestr, severity_text, textbuf); + return rv; +} + +/* + * decode_sel_fujitsu + * inputs: + * evt = the 16-byte IPMI SEL event + * outbuf = points to the output string buffer + * outsz = size of the output buffer + * outputs: + * rv = 0 if this event was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * outbuf = will contain the interpreted event text string (if rv==0) + */ +int decode_sel_fujitsu(uint8_t *evt, char *outbuf, int outsz, char fdesc, + char fdbg) +{ + int rv = -1; + uint16_t id; + uint8_t rectype; + int oemid; + uint32_t timestamp; + char mybuf[64]; + char *type_str = NULL; + char *gstr = NULL; + char *pstr = NULL; + ushort genid; + int sevid; + + fdebug = fdbg; + id = evt[0] + (evt[1] << 8); + if (freadok) { + rv = read_sel_fujitsu(id, outbuf, outsz, fdbg); + if (rv == 0) return(rv); /*success, done*/ + } + freadok = 0; /*not fujitsu or not local, so do not retry */ + + sevid = SEV_INFO; + /* instead try to decode some events manually */ + rectype = evt[2]; + timestamp = evt[3] + (evt[4] << 8) + (evt[5] << 16) + (evt[6] << 24); + genid = evt[7] | (evt[8] << 8); + if (rectype == 0xc1) { /* OEM type C1 */ + oemid = evt[7] + (evt[8] << 8) + (evt[9] << 16); + if (oemid == VENDOR_FUJITSU) { + type_str = "Fujitsu"; + gstr = "BMC "; + switch(evt[10]) { + case 0x09: + sprintf(mybuf,"iRMC S2 CLI/Telnet user %d login from %d.%d.%d.%d", + evt[11], evt[12], evt[13], evt[14], evt[15]); + break; + case 0x0a: + sprintf(mybuf,"iRMC S2 CLI/Telnet user %d logout from %d.%d.%d.%d", + evt[11], evt[12], evt[13], evt[14], evt[15]); + break; + default: + sprintf(mybuf,"iRMC S2 Event %02x %02x %02x %02x %02x %02x", + evt[10], evt[11], evt[12], evt[13], evt[14], evt[15]); + break; + } + format_event(id,timestamp, sevid, genid, type_str, + evt[10],NULL,mybuf,NULL,outbuf,outsz); + rv = 0; + } /*endif fujitsu oem */ + } else if (rectype == 0x02) { + type_str = "iRMC S2"; + gstr = "BMC "; + sprintf(mybuf,"%02x [%02x %02x %02x]", evt[12],evt[13],evt[14],evt[15]); + switch(evt[10]) { /*sensor type*/ + case 0xc8: + switch(evt[13]) { + case 0x29: + sprintf(mybuf,"CLI/Telnet user %d login", evt[15]); + break; + case 0x2a: + sprintf(mybuf,"CLI/Telnet user %d logout", evt[15]); + break; + case 0x21: + sprintf(mybuf,"Browser user %d login", evt[15]); + break; + case 0x22: + sprintf(mybuf,"Browser user %d logout", evt[15]); + break; + case 0x23: + sprintf(mybuf,"Browser user %d auto-logout", evt[15]); + break; + default: /*mybuf has the raw bytes*/ + break; + } + pstr = mybuf; + rv = 0; + break; + case 0xca: + if (evt[13] == 0x26) pstr = "Paging: Email - notification failed"; + else if (evt[13] == 0xa6) pstr = "Paging: Email - DNS failed"; + else pstr = mybuf; + rv = 0; + break; + case 0xe1: + sevid = SEV_MAJ; + if (evt[13] == 0x0f) pstr = "MC access degraded"; + else pstr = mybuf; + rv = 0; + break; + case 0xec: + if (evt[13] == 0xa0) { + sprintf(mybuf,"Firmware flash version %d.%d", + (evt[14] & 0x0f),evt[15]); + } + pstr = mybuf; + rv = 0; + break; + case 0xee: + type_str = "iRMC S2"; + if (evt[12] == 0x0a && evt[13] == 0x80) + pstr = "Automatic restart after power fail"; + else pstr = mybuf; + rv = 0; + break; + default: break; + } + if (rv == 0) { + format_event(id,timestamp, sevid, genid, type_str, + evt[11],NULL,pstr,NULL,outbuf,outsz); + /*evt[11] = sensor number */ + } + } + return rv; +} + + +/* + * Fujitsu iRMC S1 / iRMC S2 OEM Sensor logic + */ + +/* 0xDD */ +const char * const ipmi_sensor_type_oem_fujitsu_system_power_consumption[] = + { + /* EN 0x00 */ "System Power Consumption within Limit", + /* EN 0x01 */ "System Power Consumption above Warning Level", + /* EN 0x02 */ "System Power Consumption above Critical Level", + /* EN 0x03 */ "System Power Consumption limiting disabled", + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_system_power_consumption_max_index = 0x03; + + +/* 0xDE */ +const char * const ipmi_sensor_type_oem_fujitsu_memory_status[] = + { + /* EN 0x00 */ "Empty slot", + /* EN 0x01 */ "OK", + /* EN 0x02 */ "Reserved", + /* EN 0x03 */ "Error", + /* EN 0x04 */ "Fail", + /* EN 0x05 */ "Prefailure", + /* EN 0x06 */ "Reserved", + /* EN 0x07 */ "Unknown", + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_memory_status_max_index = 0x07; + +/* 0xDF */ +const char * const ipmi_sensor_type_oem_fujitsu_memory_config[] = + { + /* EN 0x00 */ "Normal", + /* EN 0x01 */ "Disabled", + /* EN 0x02 */ "Spare module", + /* EN 0x03 */ "Mirrored module", + /* EN 0x04 */ "RAID module", + /* EN 0x05 */ "Not Usable", + /* EN 0x06 */ "Unspecified state(6)", + /* EN 0x07 */ "Unspecified state(7)", + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_memory_config_max_index = 0x07; + +/* 0xE1 */ +const char * const ipmi_sensor_type_oem_fujitsu_memory[] = + { + /* EN 0x00 */ "Non Fujitsu memory module detected", + /* EN 0x01 */ "Memory module replaced", + /* EN 0x02 */ "Fatal general memory error", + /* EN 0x03 */ "Recoverable general memory error", + /* EN 0x04 */ "Recoverable ECC memory error", + /* EN 0x05 */ "Recoverable CRC memory error", + /* EN 0x06 */ "Fatal CRC memory error", + /* EN 0x07 */ "Recoverable thermal memory event", + /* EN 0x08 */ "Fatal thermal memory error", + /* EN 0x09 */ "Too many correctable memory errors", + /* EN 0x0A */ "Uncorrectable Parity memory error", + /* EN 0x0B */ "Memory Modules swapped", + /* EN 0x0C */ "Memory Module moved", + /* EN 0x0D */ "Memory removed", + /* EN 0x0E */ "Memory Re-inserted", + /* EN 0x0F */ "Memory module(s) changed", + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_memory_max_index = 0x0F; + +/* 0xE3 */ +const char * const ipmi_sensor_type_oem_fujitsu_hw_error[] = + { + /* EN 0x00 */ "TPM Error", + /* EN 0x01 */ "Reserved", + /* EN 0x02 */ "No usable CPU", + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_hw_error_max_index = 0x02; + +/* 0xE4 */ +const char * const ipmi_sensor_type_oem_fujitsu_sys_error[] = + { + /* EN 0x00 */ "System configuration Data error", + /* EN 0x01 */ "Resource Conflict", /* Slot in EventData3 */ + /* EN 0x02 */ "IRQ not configured", /* Slot in EventData3 */ + /* EN 0x03 */ "Device node allocation error", /* Device in EventData3 */ + /* EN 0x04 */ "Expansion ROM Slot not initialized", /* Slot in EventData3 */ + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_sys_error_max_index = 0x04; + +/* 0xE6 */ +const char * const ipmi_sensor_type_oem_fujitsu_fan_status[] = + { + /* EN 0x00 */ "FAN on, running", + /* EN 0x01 */ "FAN failed", + /* EN 0x02 */ "FAN prefailure", + /* EN 0x03 */ "Redundant FAN failed", + /* EN 0x04 */ "FAN not manageable", + /* EN 0x05 */ "FAN not installed", + /* EN 0x06 */ "FAN unspecified state(6)", + /* EN 0x07 */ "FAN in init phase", + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_fan_status_max_index = 0x07; + +/* 0xE8 */ +const char * const ipmi_sensor_type_oem_fujitsu_psu_status[] = + { + /* EN 0x00 */ "Power supply - Not present", + /* EN 0x01 */ "Power supply - OK", + /* EN 0x02 */ "Power supply - Failed", + /* EN 0x03 */ "Redundant power supply - AC failed", + /* EN 0x04 */ "Redundant power supply - DC failed", + /* EN 0x05 */ "Power supply - Critical Temperature", + /* EN 0x06 */ "Power supply - Not manageable", + /* EN 0x07 */ "Power supply - Fan failure predicted", + /* EN 0x08 */ "Power supply - Fan failed", + /* EN 0x09 */ "Power supply - Power Save Mode", + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_psu_status_max_index = 0x09; + +/* 0xE9 */ +const char * const ipmi_sensor_type_oem_fujitsu_psu_redundancy[] = + { + /* EN 0x00 */ "Power Supply - redundancy present", + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_psu_redundancy_max_index = 0x00; + +/* 0xEC */ +const char * const ipmi_sensor_type_oem_fujitsu_flash[] = + { + /* EN 0x00 */ "Online firmware flash", + /* EN 0x01 */ "Online firmware flash: reboot", + /* EN 0x02 */ "BIOS TFTP Flash: OK", + /* EN 0x03 */ "BIOS TFTP Flash: failed", + /* EN 0x04 */ "iRMC TFTP Flash: OK", + /* EN 0x05 */ "iRMC TFTP Flash: failed", + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_flash_max_index = 0x05; + +/* 0xEF */ +const char * const ipmi_sensor_type_oem_fujitsu_config_backup[] = + { + /* EN 0x00 */ "Chassis IDPROM: Motherboard Exchange detected", + /* EN 0x01 */ "Chassis IDPROM: Read or Write error", + /* EN 0x02 */ "Chassis IDPROM: Restore successful", + /* EN 0x03 */ "Chassis IDPROM: Restore failed", + /* EN 0x04 */ "Chassis IDPROM: Backup successful", + /* EN 0x05 */ "Chassis IDPROM: Backup failed", + /* EN 0x06 */ "Chassis IDPROM: Feature disabled", + /* EN 0x07 */ "Chassis IDPROM: Function Not Available", + /* EN 0x08 */ "Reserved", + /* EN 0x09 */ "Reserved", + /* EN 0x0A */ "Reserved", + /* EN 0x0B */ "Reserved", + /* EN 0x0C */ "Reserved", + /* EN 0x0D */ "Reserved", + /* EN 0x0E */ "Reserved", + /* EN 0x0F */ "NVRAM defaults loaded", + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_config_backup_max_index = 0x0F; + +/* 0xEF */ +const char * const ipmi_sensor_type_oem_fujitsu_i2c_bus[] = + { + /* EN 0x00 */ "I2C Bus Error", + /* EN 0x01 */ "I2C Bus OK", + /* EN 0x02 */ "I2C Bus Disabled", + /* EN 0x03 */ "I2C Bus Failed", + NULL + }; +unsigned int ipmi_sensor_type_oem_fujitsu_i2c_bus_max_index = 0x03; + +static char * get_array_message (unsigned int offset, + unsigned int offset_max, + const char * const string_array[]) +{ + if (offset > offset_max) return("unknown"); + return((char *)string_array[offset]); +} + + +static char *get_oem_reading_string(uchar sensor_type, uchar offset) +{ + char * pstr = ""; + /* + * OEM Interpretation + * Fujitsu iRMC S1 / iRMC S2 + */ + switch (sensor_type) + { + case IPMI_SENSOR_TYPE_OEM_FUJITSU_I2C_BUS: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_i2c_bus_max_index, + ipmi_sensor_type_oem_fujitsu_i2c_bus)); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_SYSTEM_POWER_CONSUMPTION: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_system_power_consumption_max_index, + ipmi_sensor_type_oem_fujitsu_system_power_consumption)); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_MEMORY_STATUS: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_memory_status_max_index, + ipmi_sensor_type_oem_fujitsu_memory_status)); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_MEMORY_CONFIG: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_memory_config_max_index, + ipmi_sensor_type_oem_fujitsu_memory_config)); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_MEMORY: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_memory_max_index, + ipmi_sensor_type_oem_fujitsu_memory)); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_HW_ERROR: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_hw_error_max_index, + ipmi_sensor_type_oem_fujitsu_hw_error)); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_SYS_ERROR: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_sys_error_max_index, + ipmi_sensor_type_oem_fujitsu_sys_error)); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_FAN_STATUS: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_fan_status_max_index, + ipmi_sensor_type_oem_fujitsu_fan_status)); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_PSU_STATUS: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_psu_status_max_index, + ipmi_sensor_type_oem_fujitsu_psu_status)); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_PSU_REDUNDANCY: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_psu_redundancy_max_index, + ipmi_sensor_type_oem_fujitsu_psu_redundancy)); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_FLASH: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_flash_max_index, + ipmi_sensor_type_oem_fujitsu_flash)); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_CONFIG_BACKUP: + return (get_array_message (offset, + ipmi_sensor_type_oem_fujitsu_config_backup_max_index, + ipmi_sensor_type_oem_fujitsu_config_backup)); + /* These are reserved */ + case IPMI_SENSOR_TYPE_OEM_FUJITSU_COMMUNICATION: + case IPMI_SENSOR_TYPE_OEM_FUJITSU_EVENT: + default: + break; + } + return(pstr); +} + + +static char *get_oem_sensor_type_string (uint8_t sensor_type) +{ + switch (sensor_type) { + case IPMI_SENSOR_TYPE_OEM_FUJITSU_I2C_BUS : return ("OEM I2C Bus"); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_SYSTEM_POWER_CONSUMPTION: return ("OEM Power Consumption"); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_MEMORY_STATUS : return ("OEM Memory Status"); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_MEMORY_CONFIG : return ("OEM Memory Config"); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_MEMORY : return ("OEM Memory"); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_FAN_STATUS : return ("OEM Fan Status"); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_PSU_STATUS : return ("OEM PSU Status"); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_PSU_REDUNDANCY: return ("OEM PSU Redundancy"); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_COMMUNICATION : return ("OEM Communication"); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_FLASH : return ("OEM Flash"); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_EVENT : return ("OEM Event"); + case IPMI_SENSOR_TYPE_OEM_FUJITSU_CONFIG_BACKUP : return ("OEM Config Backup"); + default : break; /* fall into generic case below */ + } + return (""); +} + + +int decode_sensor_fujitsu(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + char *typestr = NULL; + char *readstr = NULL; + uchar stype; + int vend_id, prod_id; + + /* Only get here if vend_id == VENDOR_FUJITSU */ + if (sdr == NULL || reading == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + stype = sdr[12]; + typestr = get_oem_sensor_type_string(stype); + + get_mfgid(&vend_id,&prod_id); + if (vend_id == IPMI_IANA_ENTERPRISE_ID_FUJITSU + && (prod_id >= IPMI_FUJITSU_PRODUCT_ID_MIN + && prod_id <= IPMI_FUJITSU_PRODUCT_ID_MAX)) { + readstr = get_oem_reading_string(stype,reading[2]); + if (readstr != NULL && (readstr[0] != 0)) rv = 0; + } else readstr = ""; + snprintf (pstring, slen, "%s = %s",typestr,readstr); + return(rv); +} + +/* end oem_fujitsu.c */ diff --git a/util/oem_fujitsu.h b/util/oem_fujitsu.h new file mode 100644 index 0000000..defc6ac --- /dev/null +++ b/util/oem_fujitsu.h @@ -0,0 +1,130 @@ +/* + * oem_fujitsu.h + * + * Authors: Andy Cress arcress at users.sourceforge.net, and + * Dan Lukes dan at obluda.cz + * + * 08/27/10 Andy Cress - added with source input from Dan Lukes + */ +/*M* +The BSD 2.0 License + +Copyright (c) 2009 Kontron America, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron, nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ + +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int + +#define IPMI_OEM_MAX_BYTES 100 +#define IPMI_IANA_ENTERPRISE_ID_FUJITSU 10368 +#define IPMI_NET_FN_OEM_GROUP_RQ 0x2E +#define IPMI_CMD_OEM_FUJITSU_SYSTEM 0xF5 +#define IPMI_OEM_FUJITSU_COMMAND_SPECIFIER_GET_SEL_ENTRY_LONG_TEXT 0x43 + +#define IPMI_FUJITSU_PRODUCT_ID_MIN 0x0200 +#define IPMI_FUJITSU_PRODUCT_ID_MAX 0x03FF +// iRMC-S1 based systems +#define IPMI_FUJITSU_PRODUCT_ID_TX200S3 0x0200 +#define IPMI_FUJITSU_PRODUCT_ID_TX300S3 0x0201 +#define IPMI_FUJITSU_PRODUCT_ID_RX200S3 0x0202 +#define IPMI_FUJITSU_PRODUCT_ID_RX300S3 0x0203 +#define IPMI_FUJITSU_PRODUCT_ID_UNUSEDS3 0x0204 +#define IPMI_FUJITSU_PRODUCT_ID_RX100S4 0x0205 +#define IPMI_FUJITSU_PRODUCT_ID_TX150S5 0x0206 +#define IPMI_FUJITSU_PRODUCT_ID_TX120S1 0x0207 +#define IPMI_FUJITSU_PRODUCT_ID_BX630S2 0x0208 +#define IPMI_FUJITSU_PRODUCT_ID_RX330S1 0x0209 +#define IPMI_FUJITSU_PRODUCT_ID_E230RN1 0x0210 +#define IPMI_FUJITSU_PRODUCT_ID_E230RSL 0x0211 +#define IPMI_FUJITSU_PRODUCT_ID_RX330S1_SHA 0x0212 +#define IPMI_FUJITSU_PRODUCT_ID_BX630S2_SHA 0x0213 + +#define FUJITSU_PRODUCT_IS_iRMC_S1(_product_id_) \ + ((_product_id_) == IPMI_FUJITSU_PRODUCT_ID_TX200S3 \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_TX300S3 \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_RX200S3 \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_RX300S3 \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_UNUSEDS3 \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_RX100S4 \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_TX150S5 \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_TX120S1 \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_BX630S2 \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_RX330S1 \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_E230RN1 \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_E230RSL \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_RX330S1_SHA \ + || (_product_id_) == IPMI_FUJITSU_PRODUCT_ID_BX630S2_SHA) + +// iRMC-S2 based systems +#define IPMI_FUJITSU_PRODUCT_ID_RX600S4 0x0218 +#define IPMI_FUJITSU_PRODUCT_ID_TX200S4 0x0220 +#define IPMI_FUJITSU_PRODUCT_ID_TX300S4 0x0221 +#define IPMI_FUJITSU_PRODUCT_ID_RX200S4 0x0222 +#define IPMI_FUJITSU_PRODUCT_ID_RX300S4 0x0223 +#define IPMI_FUJITSU_PRODUCT_ID_UNUSEDS4 0x0224 +#define IPMI_FUJITSU_PRODUCT_ID_RX100S5 0x0225 +#define IPMI_FUJITSU_PRODUCT_ID_TX150S6 0x0226 +#define IPMI_FUJITSU_PRODUCT_ID_TX120S2 0x0227 +#define IPMI_FUJITSU_PRODUCT_ID_TX150S6_64K 0x0233 +#define IPMI_FUJITSU_PRODUCT_ID_TX200S4_64K 0x0234 +#define IPMI_FUJITSU_PRODUCT_ID_TX300S4_64K 0x0235 +#define IPMI_FUJITSU_PRODUCT_ID_TX200S5 0x0240 +#define IPMI_FUJITSU_PRODUCT_ID_TX300S5 0x0241 +#define IPMI_FUJITSU_PRODUCT_ID_RX200S5 0x0242 +#define IPMI_FUJITSU_PRODUCT_ID_RX300S5 0x0243 +#define IPMI_FUJITSU_PRODUCT_ID_BX620S5 0x0244 +#define IPMI_FUJITSU_PRODUCT_ID_RX100S6 0x0245 +#define IPMI_FUJITSU_PRODUCT_ID_TX150S7 0x0246 +#define IPMI_FUJITSU_PRODUCT_ID_BX960S1 0x0254 +#define IPMI_FUJITSU_PRODUCT_ID_BX924S1 0x0255 +#define IPMI_FUJITSU_PRODUCT_ID_BX920S1 0x0256 +#define IPMI_FUJITSU_PRODUCT_ID_BX922S1 0x0257 +#define IPMI_FUJITSU_PRODUCT_ID_RX600S5 0x0258 +#define IPMI_FUJITSU_PRODUCT_ID_TX200S6 0x0260 +#define IPMI_FUJITSU_PRODUCT_ID_TX300S6 0x0261 +#define IPMI_FUJITSU_PRODUCT_ID_RX200S6 0x0262 +#define IPMI_FUJITSU_PRODUCT_ID_RX300S6 0x0263 + +/******************************************* ++ * Fujitsu Siemens Computers * ++ * Fujitsu Technology Solutions * ++ * iRMC S1 / iRMC S2 * ++ *******************************************/ +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_I2C_BUS 0xC0 +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_SYSTEM_POWER_CONSUMPTION 0xDD //Events only +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_MEMORY_STATUS 0xDE +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_MEMORY_CONFIG 0xDF +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_MEMORY 0xE1 // Events only +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_HW_ERROR 0xE3 // Events only +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_SYS_ERROR 0xE4 // Events only +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_FAN_STATUS 0xE6 +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_PSU_STATUS 0xE8 +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_PSU_REDUNDANCY 0xE9 +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_COMMUNICATION 0xEA // Reserved +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_FLASH 0xEC // Events only +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_EVENT 0xEE // Reserved +#define IPMI_SENSOR_TYPE_OEM_FUJITSU_CONFIG_BACKUP 0xEF diff --git a/util/oem_hp.c b/util/oem_hp.c new file mode 100644 index 0000000..29a813f --- /dev/null +++ b/util/oem_hp.c @@ -0,0 +1,149 @@ +/* + * oem_hp.c + * Handle HP OEM command functions + * + * Change history: + * 02/23/2012 ARCress - included in source tree + * + *--------------------------------------------------------------------- + */ +/*M* +Copyright (c) 2012 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#endif +#include <stdio.h> +#include <string.h> +#include <time.h> +#include "ipmicmd.h" +#include "ievents.h" +#include "isensor.h" + +static char *redund_str(uchar b) +{ + char *pstr; + if (b == 0x00) pstr = "Disabled"; + else if (b == 0x01) pstr = "Fully Redundant"; + else if (b == 0x02) pstr = "Redundancy Lost"; + else if (b == 0x0b) pstr = "AC Lost"; + else pstr = "Redundancy Degraded"; + return(pstr); +} + +/* + * decode_sensor_hp + * inputs: + * sdr = the SDR buffer + * reading = the 3 or 4 bytes of data from GetSensorReading + * pstring = points to the output string buffer + * slen = size of the output buffer + * outputs: + * rv = 0 if this sensor was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * pstring = contains the sensor reading interpretation string (if rv==0) + */ +int decode_sensor_hp(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + char *pstr = NULL; + uchar stype, evtype, b; + ushort v; + + if (sdr == NULL || reading == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + /* sdr[3] is SDR type 1=full, 2=compact */ + stype = sdr[12]; /*sensor type*/ + evtype = sdr[13]; /*event type */ + if (stype == 0xC0) { /* HP OEM Sensor, no sensor reading */ + strncpy(pstring,"na",slen); /*oem*/ + rv = 0; + } else { + if ((reading[2] & 0x40) == 0x40) { /*Init/Unavail state*/ + strncpy(pstring,"Init",slen); + rv = 0; + } else if ((sdr[20] & 0xC0) == 0xC0) { /*unit1==discrete*/ + b = reading[2] & 0x3f; + pstr = "DiscreteUnit"; + if (evtype == 0x0b) pstr = redund_str(b); + snprintf(pstring,slen,"%02x%02x %s",reading[3],reading[2],pstr); + rv = 0; + } else if (evtype == 0x6f) { /*evtype==0x6f special*/ + pstr = "DiscreteEvt"; + if (stype == 0x08) { /*Power Supply presence*/ + if (reading[2] & 0x01) pstr = "Present"; + else pstr = "Absent"; + } + snprintf(pstring,slen,"%02x%02x %s",reading[3],reading[2],pstr); + rv = 0; + } else if (evtype == 0x0B) { /*Redundancy*/ + b = reading[2] & 0x3f; + pstr = "DiscretePS"; /*Power Supplies*/ + if (evtype == 0x0b) pstr = redund_str(b); + snprintf(pstring,slen,"%02x%02x %s",reading[3],reading[2],pstr); + rv = 0; + } else if (evtype == 0x0A) { /*Discrete Fan*/ + v = reading[2] + (reading[3] & 0x3f); + if (v & 0x001) pstr = "Transition to Running"; + else if (v & 0x002) pstr = "Transition to In Test"; + else if (v & 0x004) pstr = "Transition to Power Off"; + else if (v & 0x008) pstr = "Transition to On Line"; + else if (v & 0x010) pstr = "Transition to Off Line"; + else if (v & 0x020) pstr = "Transition to Off Duty"; + else if (v & 0x040) pstr = "Transition to Degraded"; + else if (v & 0x080) pstr = "Transition to Power"; + else if (v & 0x100) pstr = "Install Error"; + else pstr = "Unknown"; + snprintf(pstring,slen,"%02x%02x %s",reading[3],reading[2],pstr); + rv = 0; + } else if (evtype == 0x09) { /* stype==0x03 Power Meter */ + b = reading[2] & 0x3f; + if (b & 0x01) pstr = "Disabled"; + else if (b & 0x02) pstr = "Enabled"; + else pstr = "Unknown"; + snprintf(pstring,slen,"%02x%02x %s",reading[3],reading[2],pstr); + rv = 0; + } + } + return(rv); +} + +void show_oemsdr_hp(uchar *sdr) +{ + int len, i; + + len = sdr[4] + 5; + if (sdr[8] == 0x02) len = 18; + printf("HP: "); + for (i = 8; i < len; i++) + printf("%02x ",sdr[i]); + if (sdr[8] == 0x02) printf("%s",&sdr[18]); + printf("\n"); + return; +} + +/* end oem_hp.c */ diff --git a/util/oem_intel.c b/util/oem_intel.c new file mode 100644 index 0000000..f568300 --- /dev/null +++ b/util/oem_intel.c @@ -0,0 +1,1842 @@ +/* + * oem_intel.c + * + * This module handles code specific to Intel platforms, + * including the Intel/Kontron Telco Alarms panel. + * + * Note that the Intel BMC TAM will set these alarms + * based on firmware-detected thresholds and events. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2005 Intel Corporation + * Copyright (c) 2010 Kontron America, Inc. + * + * Compile flags for oem_intel.c: + * NO_CMD would be defined if linking with ievents.c only (no ipmicmd code) + * NO_EVENTS would be defined if linking with ialarms.c (no ievents code) + * + * 09/02/10 Andy Cress - separated from ialarms.c + */ +/*M* +Copyright (c) 2005 Intel Corporation +Copyright (c) 2010 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#if defined(DOS) +#include <dos.h> +#endif +#include "ipmicmd.h" +#include "oem_intel.h" + +#ifdef METACOMMAND +#include "ievents.h" +extern char fsm_debug; /*mem_if.c*/ +extern int sens_verbose; /*isensor.c*/ +extern int get_sensdesc(uchar sa, int snum, char *sdesc, int *pstyp, int *pidx); +extern int get_MemDesc(int array, int dimm, char *desc, int *psz); /*mem_if.c*/ +#else +static char fsm_debug = 0; +static int sens_verbose = 0; +static int get_MemDesc(int array, int dimm, char *desc, int *psz) { return -1;} +#if !defined(NO_CMD) +int get_sensdesc(uchar sa, int snum, char *sensdesc, int *pstyp, int *pidx) +{ return(-1); } +#endif +static char *get_sensor_type_desc(uchar stype) +{ + static char tstr[12]; + sprintf(tstr,"%02x",stype); + return(tstr); +} +#endif +extern char fdebug; /*ipmicmd.c*/ + +/* + * Global variables + */ +static char fRelayBits = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + +#ifdef OLD +#ifdef WIN32 +/* Windows tamutil is installed by the ipmirastools package from Kontron. */ +static char *tam1cmd = "\"\"%ProgramFiles%\"\\Intel\\ipmirastools\\tamutil\" >NUL: 2>NUL:"; +static char *tam2cmd = "\"\"%ProgramFiles%\"\\Intel\\ipmirastools\\tamutil\" |findstr TAM.Status >NUL:"; +//static char * tam3cmd = "ipmiutil sensor |findstr BMC_TAM >NUL:"; +//static char * tambcmd = "bmcTamActive"; /*old*/ +#define RET_NOT_FOUND 1 /*command not found (%ERRORLEVE%=9009)*/ +#else +/* Linux tamutil is installed by the ipmimisc package from Kontron. */ +static char *tam1cmd = "/usr/share/ipmimisc/tamutil >/dev/null 2>&1"; +static char *tam2cmd = "/usr/share/ipmimisc/tamutil 2>/dev/null |grep TAM.Status >/dev/null"; +//static char * tam3cmd = "ipmiutil sensor |grep BMC_TAM >/dev/null"; +//static char * tambcmd = "/usr/local/tam/bin/bmcTamActive 2>/dev/null"; /*old*/ +//#define RET_TAMB_ACTIVE 256 /*from bmcTamActive, if BMC TAM is enabled*/ +#define RET_NOT_FOUND 32512 /*command not found ($?=127 if shell)*/ +#endif +#endif + +#ifdef NOT +#define PRIVATE_BUS_ID 0x03 // w Sahalee, the 8574 is on Private Bus 1 +#define PRIVATE_BUS_ID5 0x05 // for Intel TIGI2U +#define PRIVATE_BUS_ID7 0x07 // for Intel S5000 +#define PERIPHERAL_BUS_ID 0x24 // w mBMC, the 8574 is on the Peripheral Bus +#define ALARMS_PANEL_WRITE 0x40 +#define ALARMS_PANEL_READ 0x41 +#define DISK_LED_WRITE 0x44 // only used for Chesnee mBMC +#define DISK_LED_READ 0x45 // only used for Chesnee mBMC +#endif + +#if defined(NO_CMD) +const char * val2str(ushort val, const struct valstr *vs) +{ + static char un_str[32]; + int i; + for (i = 0; vs[i].str != NULL; i++) + if (vs[i].val == val) return vs[i].str; + memset(un_str, 0, 32); + snprintf(un_str, 32, "Unknown (0x%x)", val); + return un_str; +} +#else +uchar get_nsc_diskleds(uchar busid) +{ + uchar inputData[4]; + uchar rdata[16]; + int responseLength = 4; + uchar completionCode; + int ret; + + inputData[0] = busid; + inputData[1] = DISK_LED_READ; + inputData[2] = 0x1; // return one byte of LED data + inputData[3] = 0x00; // init data to zero + ret = ipmi_cmd(MASTER_WRITE_READ, inputData, 3, rdata, + &responseLength, &completionCode, fdebug); + if (ret != 0) { + printf("get_nsc_diskleds: ret = %d, ccode %02x, leds = %02x\n", + ret, completionCode, rdata[0]); + return(0); + } + return(rdata[0]); +} /*end get_nsc_diskleds()*/ + +int set_nsc_diskleds(uchar val, uchar busid) +{ + uchar inputData[4]; + uchar rdata[16]; + int responseLength = 4; + uchar completionCode; + int ret; + + inputData[0] = busid; + inputData[1] = DISK_LED_WRITE; + inputData[2] = 0x01; // len = one byte of LED data + inputData[3] = val; + ret = ipmi_cmd(MASTER_WRITE_READ, inputData, 4, rdata, + &responseLength, &completionCode, fdebug); + if (ret != 0) { + printf("set_nsc_diskleds: ret = %d, ccode %02x, leds = %02x\n", + ret, completionCode, val); + return(0); + } + return(ret); +} /*end set_nsc_diskleds()*/ + +void show_nsc_diskleds(uchar val) +{ + if (fdebug) printf("diskled = %02x\n",val); + printf("disk A: "); + if ((val & 0x20) == 0) printf("present"); + else printf("not present"); + if ((val & 0x02) == 0) printf("/faulted "); + printf("\ndisk B: "); + if ((val & 0x10) == 0) printf("present"); + else printf("not present"); + if ((val & 0x01) == 0) printf("/faulted "); + printf("\n"); +} + +uchar get_alarms_intel(uchar busid) +{ + uchar inputData[4]; + uchar rdata[16]; + int responseLength = 4; + uchar completionCode; + int ret; + + inputData[0] = busid; + inputData[1] = ALARMS_PANEL_READ; + inputData[2] = 0x1; // return one byte of alarms data + inputData[3] = 0x00; // init data to zero + ret = ipmi_cmd(MASTER_WRITE_READ, inputData, 3, rdata, + &responseLength, &completionCode, fdebug); + if (ret != 0 || completionCode != 0) { + printf("get_alarms: ret = %d, ccode %02x, alarms = %02x\n", + ret, completionCode, rdata[0]); + return(0); + } + return(rdata[0]); +} /*end get_alarms()*/ + +int set_alarms_intel(uchar val, uchar busid) +{ + uchar inputData[4]; + uchar rdata[16]; + int responseLength = 4; + uchar completionCode; + int ret; + + inputData[0] = busid; + inputData[1] = ALARMS_PANEL_WRITE; + inputData[2] = 0x1; // one byte of alarms data + inputData[3] = val; + ret = ipmi_cmd(MASTER_WRITE_READ, inputData, 4, rdata, + &responseLength, &completionCode, fdebug); + if (ret != 0) { + printf("set_alarms: ret = %d, ccode %02x, value = %02x\n", + ret, completionCode, val); + return(ret); + } + if (completionCode != 0) ret = completionCode; + return(ret); +} /*end set_alarms()*/ + +/* + * show_alarms + * + * The alarm control/status byte is decoded as follows: + * bit + * 7 = reserved, always write 1 + * 6 = LED colors, 1 = amber (default), 0 = red + * Colors were added in some later firmware versions, but + * not for all platforms. + * 5 = Minor Relay bit, 0 = on, 1 = off, always write 1 + * 4 = Major Relay bit, 0 = on, 1 = off, always write 1 + * 3 = Minor LED bit, 0 = on, 1 = off + * 2 = Major LED bit, 0 = on, 1 = off + * 1 = Critical LED bit, 0 = on, 1 = off + * 0 = Power LED bit, 0 = on, 1 = off + * + * Note that the Power LED is also wired to the System Fault LED + * in the back of the system, so this state may be off for Power, + * but the LED could be lit for a System Fault reason instead. + */ +void show_alarms_intel(uchar val) +{ + char *scrit = "ON "; + char *smaj = "ON "; + char *smin = "ON "; + char *spow = "ON "; + char *rmaj = "ON"; + char *rmin = "ON"; + if (fdebug) printf("alarms = %02x\n",val); + + if (val & 0x01) spow = "off"; + if (val & 0x02) scrit = "off"; + if (val & 0x04) smaj = "off"; + if (val & 0x08) smin = "off"; + printf("Alarm LEDs: critical = %s major = %s minor = %s power = %s\n", + scrit,smaj,smin,spow); + if (fRelayBits == 1) { /*CG2100 platforms have Relay bits reversed*/ + if (val & 0x10) rmin = "off "; + if (val & 0x20) rmaj = "off "; + } else { + if (val & 0x10) rmaj = "off "; + if (val & 0x20) rmin = "off "; + } + printf("Alarm Relays: major = %s minor = %s\n", rmaj, rmin); +} + +/* + * get_led_status_intel + * uses Intel OEM command to get the status of the ID LED. + * if success, rv=0, pstate: 0=off, 1=on, 2=blinking + */ +int get_led_status_intel(uchar *pstate) +{ + uchar rdata[64]; + int rv, rlen; + uchar cc, b_leds, bstate; + + /* This command is only supported on Intel S5000 motherboards */ + rlen = sizeof(rdata); + rv = ipmi_cmdraw(0x40,0x32, g_sa,g_bus,g_lun, + NULL, 0, rdata, &rlen, &cc, fdebug); + if (fdebug) printf("get_led_status_intel: rv = %d, cc=%02x\n", rv,cc); + if (rv == 0 && cc != 0) rv = cc; + if (rv == 0) { + b_leds = rdata[0]; + bstate = 0; /*off*/ + if (b_leds & 0x80) { bstate = 1; /*on*/ } + else if (b_leds & 0x40) { bstate = 2; /*blink*/ } + if (pstate != NULL) *pstate = bstate; + } + return(rv); +} + + +int detect_capab_intel(int vend_id,int prod_id, int *cap, int *ndisk,char fdbg) +{ + int busid = PRIVATE_BUS_ID; + int f = 0; + char fbmctam = 0; + char fHasAlarms = 0; + char fHasEnc = 0; + char fpicmg = 0; + char fChesnee = 0; + int styp, idx, rv; + char desc[20]; + + fdebug = fdbg; + if (vend_id == VENDOR_NSC) { /*NSC mBMC, Chesnee*/ + busid = PERIPHERAL_BUS_ID; + fHasAlarms = 1; + fChesnee = 1; + } else if (vend_id == VENDOR_INTEL) { /*Intel BMC*/ + switch (prod_id) { + case 0x0022: + busid = PRIVATE_BUS_ID5; /* Intel TIGI2U */ + fbmctam = 1; /* Intel TIGI2U may have bmc tam */ + fHasAlarms = 1; + fHasEnc = 2; + break; + case 0x000C: /* TSRLT2 or TSRMT2 */ + busid = PRIVATE_BUS_ID; + fbmctam = 0; /* no BMC TAM */ + fHasAlarms = 1; + fHasEnc = 0; + break; + case 0x001B: + busid = PRIVATE_BUS_ID; + fbmctam = 1; /* Intel TIGPR2U may have bmc tam */ + fHasAlarms = 1; + break; + case 0x0808: + case 0x0841: + fpicmg = 1; /* Intel ATCA platform, supports PICMG */ + fHasAlarms = 1; + break; + case 0x4311: + busid = PERIPHERAL_BUS_ID; /* SJR2 (NSI2U) mBMC */ + break; + case 0x0026: /*BridgePort*/ + case 0x0028: /*S5000PAL*/ + case 0x0029: /*S5000PSL*/ + case 0x0811: /*S5000PHB*/ + busid = PRIVATE_BUS_ID7; /* Intel Harbision (TIGW1U/NSW1U) */ + /* Check for SAS Drv Pres sensor on HSC, if TIGW1U */ + rv = get_sensdesc(0xC0,0x09,desc,&styp, &idx); + if (fdebug) printf("get_sensdesc rv = %d\n",rv); + if (rv == ERR_NOT_FOUND) { /* NSW1U does not have alarm panel*/ + fHasAlarms = 0; + fHasEnc = 0; + } else { /* has HSC, like TIGW1U */ + fbmctam = 1; /* TIGW1U may have bmc tam */ + fHasAlarms = 1; + if (prod_id == 0x0811) fHasEnc = 3; + else fHasEnc = 6; + } + break; + case 0x003E: /*S5520UR*/ + busid = PRIVATE_BUS_ID; + fbmctam = 1; /* CG2100 has bmc tam */ + fHasAlarms = 1; + fHasEnc = 8; /* CG2100 has 8 disks */ + fRelayBits = 1; + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + break; + case 0x005D: /* Copper Pass, CG2200*/ + busid = PRIVATE_BUS_ID; + fbmctam = 1; /* CG2200 has bmc tam */ + fHasAlarms = 1; + fRelayBits = 1; + fHasEnc = 6; /* 6 disks */ + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + break; + case 0x0051: /* Eagle Pass */ + busid = PRIVATE_BUS_ID; + fbmctam = 1; /* CG1200 has bmc tam */ + fHasAlarms = 1; + fRelayBits = 1; + fHasEnc = 4; /* 4 disks */ + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + break; + case 0x0048: /* "(S1200BT)" *BearTooth Pass*/ + case 0x004A: /* "(S2600CP)" *Canoe Pass*/ + case 0x0055: /* Iron Pass */ + case 0x005C: /* Lizard Head Pass */ + fHasEnc = 8; + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + break; + default: + busid = PRIVATE_BUS_ID; + fHasEnc = 8; + break; + } + } + if (fHasAlarms) f |= HAS_ALARMS_MASK; + if (fbmctam) f |= HAS_BMCTAM_MASK; + if (fHasEnc > 0) { + f |= HAS_ENCL_MASK; + if (ndisk != NULL) *ndisk = fHasEnc; + } + if (fpicmg) f |= HAS_PICMG_MASK; + if (fChesnee) f |= HAS_NSC_MASK; + if (is_romley(vend_id,prod_id)) { + if (prod_id == 0x005D) fHasEnc = 6; /*CG2200*/ + fHasEnc = 8; + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + f |= HAS_ROMLEY_MASK; + } + *cap = f; + return(busid); +} + +int check_bmctam_intel(void) +{ + int ret, rlen; + uchar rdata[16]; + uchar cc; + + /* Check if BMC TAM is enabled */ + rlen = sizeof(rdata); + ret = ipmi_cmdraw(0x00, 0x36, g_sa,g_bus,g_lun, + NULL, 0, rdata, &rlen, &cc, fdebug); + if ((ret == 0) && (cc == 0)) { + printf("Warning: BMC TAM is active and managing the LEDs.\n" + "Use tamutil (from ipmimisc rpm) to set alarms instead.\n"); + return(LAN_ERR_ABORT); + } else return(0); +#ifdef OLD + ret = system(tam1cmd); + if (fdebug) printf("%s ret = %d\n",tam1cmd,ret); + if (ret == RET_NOT_FOUND) { /*command not found, no such file*/ + /* Could also do "ipmiutil sensor |grep BMC_TAM" (tam3cmd), + * but this would take a while to complete. */ + printf("Warning: BMC TAM may be active and managing the LEDs.\n" + "If so, use tamutil to set the alarm LEDs instead.\n"); + } else if (ret == 0) { + /*the command was found, check if BMC TAM enabled*/ + ret = system(tam2cmd); + if (fdebug) printf("%s ret = %d\n",tam2cmd,ret); + if (ret == 0) { + /*If so, print warning, use Intel tamutil instead.*/ + printf("Warning: BMC TAM is active and managing the LEDs.\n" + "Use tamutil or the Intel TAM API to set alarms instead.\n" + "Aborting.\n"); + return(LAN_ERR_ABORT); + } + } + /* else tamutil was there but did not show BMC TAM active, so + * assume BMC TAM is not active and do nothing. */ + return(ret); +#endif +} + +int soft_reset_intel(uchar func) +{ + int ret, rlen; + uchar idata[16]; + uchar rdata[16]; + uchar cc; + + /* Do an Intel S5000 soft reset, via an OS bridge agent (ipmiutil_asy) */ + rlen = sizeof(rdata); + idata[0] = func; /* 0=read, 1=shutdown, 2=reset */ + ret = ipmi_cmdraw(0x70, 0x30, g_sa,g_bus,g_lun, + idata, 1, rdata, &rlen, &cc, fdebug); + if ((ret == 0) && (cc != 0)) ret = cc; + return(ret); +} + +int lan_failover_intel(uchar func, uchar *mode) +{ + int ret, rlen; + uchar idata[16]; + uchar rdata[16]; + uchar cc; + + /* Do an Intel S2600 LAN Failover command, where func is: + * 0x00=disable, + * 0x01=enable with leash monitor, + * 0x02=enable with ARP monitor if blade, + * 0xFF=no set, just get current mode + */ + rlen = sizeof(rdata); + idata[0] = func; /* 0=read, 1=shutdown, 2=reset */ + ret = ipmi_cmdraw(0x40, 0x3E, g_sa,g_bus,g_lun, + idata, 1, rdata, &rlen, &cc, fdebug); + if ((ret == 0) && (cc != 0)) ret = cc; + if (ret == 0 && mode != NULL) *mode = rdata[0]; + return(ret); +} + +int get_power_restore_delay_intel(int *delay) +{ + int ret, rlen; + uchar idata[16]; + uchar rdata[16]; + uchar cc; + + rlen = sizeof(rdata); + ret = ipmi_cmdraw(0x55, 0x30, g_sa,g_bus,g_lun, + idata, 0, rdata, &rlen, &cc, fdebug); + if ((ret == 0) && (cc != 0)) ret = cc; + if (ret == 0 && delay != NULL) + *delay = ( rdata[1] + ((rdata[0] & 0x07) << 8) ); + return(ret); +} + +/* end-else NO_CMD not defined */ +#endif + +#define NTAMSEV 8 +static char *tam_sev[] = { +/*0*/ "OFF", +/*1*/ "MNR", +/*2*/ "MNR+P", +/*3*/ "MJR", +/*4*/ "MJR+P", +/*5*/ "CRT", +/*6*/ "CRT+P", +/*7*/ "UNK" +}; + +int decode_sensor_intel_nm(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + uchar stype; + char mystr[60]; + uchar nm_sa, chan, lun; + + if (sdr == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + switch(sdr[3]) { /*SDR type*/ + case 0xC0: /*OEM sensor*/ + if (sdr[8] == 0x0D) { /* OEM NM Reference SDR, no reading */ + nm_sa = sdr[10]; + chan = (sdr[11] & 0xf0) >> 4; + lun = (sdr[11] & 0x0f); + /* show NM location and sensor numbers for NM sensors */ + sprintf(mystr,"NM(%x,%x,%x) health=%x excep=%x capab=%x thresh=%x", + chan,nm_sa,lun, sdr[12],sdr[13],sdr[14],sdr[15]); + strncpy(pstring, mystr, slen); + if ((int)strlen(mystr) > slen) pstring[slen-1] = 0; /*string*/ + rv = 0; + } + break; + case 0x02: /*compact sensor*/ + if (reading == NULL) return(rv); + stype = sdr[12]; /*sensor type*/ + if (stype == 0xDC) { /* NM Capabilities sensor, usu snum 0x1a (26.)*/ + mystr[0] = 0; + if (reading[2] == 0x00) strcat(mystr,"None"); + else { + if (reading[2] & 0x01) strcat(mystr,"Policy "); + if (reading[2] & 0x02) strcat(mystr,"Monitor "); + if (reading[2] & 0x04) strcat(mystr,"Power "); + } + strncpy(pstring, mystr, slen); + if ((int)strlen(mystr) > slen) pstring[slen-1] = 0; /*string*/ + rv = 0; + } + break; + default: + break; + } + return(rv); +} + +static void show_oem_hex(uchar *sdr, int slen) +{ + int i; + for (i = 8; i < slen; i++) + printf("%02x ",sdr[i]); + printf("\n"); +} + +void show_oemsdr_nm(uchar *sdr) +{ + int rv, len; + char mystr[60]; + + /* vendor id has already been shown */ + len = sdr[4] + 5; + rv = decode_sensor_intel_nm(sdr,NULL,mystr,sizeof(mystr)); + if (rv == 0) printf("%s\n",mystr); + else show_oem_hex(sdr, len); + return; +} + +/* + * show_oemsdr_intel + */ +void show_oemsdr_intel(uchar *sdr) +{ + uchar idx, len, c, i, n, j, k, t; + int vend; + + len = sdr[4] + 5; + /*double-check that this is an Intel OEM SDR*/ + vend = sdr[5] | (sdr[6] << 8) | (sdr[7] << 16); + if (vend != VENDOR_INTEL) { + if (fdebug) printf("show_oemsdr_intel: vendor %x != %x (Intel)\n", + vend,VENDOR_INTEL); + return; + } + printf("Intel: "); + switch(sdr[8]) { /*OEM subtype*/ + case 0x53: /* SDR version subtype (has ASCII) */ + for (i = 8; i < len; i++) { + c = sdr[i]; + if (c < 0x20 || c > 0x7f) printf("[%02x]",c); + else printf("%c",c); + } + printf("\n"); + break; + case 0x60: /* BMC TAM subtype */ + idx = (sdr[10] & 0xf0) >> 4; + n = (sdr[10] & 0x0f) + 1; /*number of TAM records*/ + printf("BMC_TAM%d ",idx); + for (i = 8; i < len; i++) + printf("%02x ",sdr[i]); + if (idx == 0) { + printf(" nrec=%d cfg=%02x",n,sdr[11]); + } + printf("\n"); + if (fdebug || sens_verbose) { + /* show decoded BMC_TAM rules */ + if (idx > 0) { + uchar map, off, sev, sa; + const char *tstr; + sa = sdr[12]; + for (i = 13; i < len; ) { + k = (sdr[i] & 0xf0) >> 4; + t = sdr[i+1]; + tstr = get_sensor_type_desc(t); + printf("\tBMC_TAM%d sa=%02x %s (",idx,sa,tstr); + for (j = 0; j < k; j++) { + map = sdr[i+3+j]; + off = (map & 0xf0) >> 4; + sev = map & 0x0f; + if (sev >= NTAMSEV) sev = NTAMSEV - 1; + printf("%d=%s ",off,tam_sev[sev]); + } + printf(")\n"); + i += 3 + k; + } + } + } + break; + case 0x0C: /* Fan Speed Control */ + printf("FanCtl "); + show_oem_hex(sdr, len); + break; + case 0x0D: /* ME NM Reference SDR */ + show_oemsdr_nm(sdr); + break; + case 0x02: /*S5500 Power Unit Redundancy subtype*/ + case 0x05: /*S5500 Fan Redundancy subtype*/ + case 0x06: /*S5000 System Information/Capab */ + case 0x09: /*S5500 Voltage sensor scaling*/ + case 0x0A: /*S5500 Fan sensor scaling*/ + case 0x0B: /*S5500 Thermal Profile data*/ + default: /* other subtypes 07,0e,15 etc. */ + show_oem_hex(sdr, len); + break; + } /*end switch*/ +} /*end show_oemsdr_intel*/ + +#ifdef NO_EVENTS +/* if not linking with ievents.c, need to skip decode_sel_intel because it + * would have unresolved externals for fmt_time, get_sev_str, get_sensor_tag */ +#else +/* + * decode_sel_intel + * inputs: + * evt = the 16-byte IPMI SEL event + * outbuf = points to the output string buffer + * outsz = size of the output buffer + * outputs: + * rv = 0 if this event was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * outbuf = will contain the interpreted event text string (if rv==0) + */ +int decode_sel_intel(uchar *evt, char *outbuf, int outsz, char fdesc, + char fdebug) +{ + int rv = -1; + ushort id; + uchar rectype; + ulong timestamp; + char mybuf[64]; + char oembuf[64]; + char *type_str = NULL; + char *pstr = NULL; + int sevid; + ushort genid; + uchar snum; + char *p1; + int d, f; + + sevid = SEV_INFO; + id = evt[0] + (evt[1] << 8); + rectype = evt[2]; + snum = evt[11]; + timestamp = evt[3] + (evt[4] << 8) + (evt[5] << 16) + (evt[6] << 24); + genid = evt[7] | (evt[8] << 8); + if (rectype == 0x00) { + if (snum == 0x0A && evt[12] == 0x03) rectype = 0x02; /*internal wdog*/ + } + if (rectype == 0x02) { + type_str = ""; + sprintf(mybuf,"%02x [%02x %02x %02x]", evt[12],evt[13],evt[14],evt[15]); + pstr = ""; /*default*/ + switch(evt[10]) { /*sensor type*/ + case 0x00: /* type undefined */ + // type_str = get_sensor_type_desc(0x28); + type_str = "Management Subsystem Health"; + if (snum == 0x0A && evt[12] == 0x03) { /*internal wd event*/ + pstr = "BMC wd restart"; + sevid = SEV_CRIT; + rv = 0; + } + break; + case 0x13: /* Critical Interrupt */ + type_str = "Critical Interrupt"; + if (evt[12] == 0x70) { /*event trigger/type = OEM AER events */ + /* AER doc uses 'Fatal' here, but they are not really fatal.*/ + pstr = &oembuf[0]; + switch(evt[13]) { /*data1/offset*/ + case 0xA0: p1 = "PCIe Data Link Protocol Error"; break; + case 0xA1: p1 = "PCIe Surprise Link Down"; break; + case 0xA2: p1 = "PCIe Unexpected Completion"; break; + case 0xA3: p1 = "PCIe Unsupported Request"; break; + case 0xA4: p1 = "PCIe Poisoned TLP"; break; + case 0xA5: p1 = "PCIe Flow Control Protocol"; break; + case 0xA6: p1 = "PCIe Completion Timeout"; break; + case 0xA7: p1 = "PCIe Completer Abort"; break; + case 0xA8: p1 = "PCIe Recv Buffer Overflow"; break; + case 0xA9: p1 = "PCIe ACS Violation"; break; + case 0xAA: p1 = "PCIe Malformed TLP"; break; + case 0xAB: p1 = "PCIe Recvd Fatal Message"; break; + case 0xAC: p1 = "PCIe Unexpected Completion Error"; break; + case 0xAD: p1 = "PCIe Recvd Warning Message"; break; + default: p1 = "PCIe Other AER"; break; + } + rv = 0; + sevid = SEV_MAJ; + /* also include the bus dev/func bytes (as shown by lspci) */ + d = (evt[15] & 0xF8) >> 3; + f = (evt[15] & 0x07); + snprintf(oembuf,sizeof(oembuf),"%s on (%02x:%02x.%d)", + p1,evt[14],d,f); + } + if (evt[12] == 0x71) { /*event trigger/type = OEM AER warnings */ + pstr = &oembuf[0]; + switch(evt[13]) { /*data1/offset*/ + case 0xA0: p1 = "PCIe Warn Receiver Error"; break; + case 0xA1: p1 = "PCIe Warn Bad DLLP"; break; + case 0xA2: p1 = "PCIe Warn Bad TLLP"; break; + case 0xA3: p1 = "PCIe Warn Replay Num Rollover"; break; + case 0xA4: p1 = "PCIe Warn Replay Timeout"; break; + case 0xA5: p1 = "PCIe Warn Advisory Non-Fatal"; break; + case 0xA6: p1 = "PCIe Warn Link BW Changed"; break; + default: p1 = "PCIe Warn Other AER"; break; + } + rv = 0; + sevid = SEV_MIN; + /* also include the bus dev/func bytes (as shown by lspci) */ + d = (evt[15] & 0xF8) >> 3; + f = (evt[15] & 0x07); + snprintf(oembuf,sizeof(oembuf),"%s on (%02x:%02x.%d)", + p1,evt[14],d,f); + } + break; + case 0x2B: /* Version Change */ + type_str = "Version Change"; + if (evt[12] == 0x70) { /*event trigger/type */ + switch(evt[13]) { /*data1/offset*/ + case 0x00: pstr = "Update started"; break; + case 0x01: pstr = "Update completed"; break; + case 0x02: pstr = "Update failed"; sevid = SEV_MIN; break; + default: pstr = "-"; break; + } + rv = 0; + } + break; + default: break; + } + if (rv == 0) { + format_event(id,timestamp, sevid, genid, type_str, + snum,NULL,pstr,mybuf,outbuf,outsz); + } + } + return rv; +} /*end decode_sel_intel*/ +#endif + +const struct valstr intel_mem_s2600[] = { + { 0, "DIMM_A1" }, + { 1, "DIMM_A2" }, + { 2, "DIMM_A3" }, + { 3, "DIMM_B1" }, + { 4, "DIMM_B2" }, + { 5, "DIMM_B3" }, + { 6, "DIMM_C1" }, + { 7, "DIMM_C2" }, + { 8, "DIMM_C3" }, + { 9, "DIMM_D1" }, + { 10, "DIMM_D2" }, + { 11, "DIMM_D3" }, + { 12, "DIMM_E1" }, + { 13, "DIMM_E2" }, + { 14, "DIMM_E3" }, + { 15, "DIMM_F1" }, + { 16, "DIMM_F2" }, + { 17, "DIMM_F3" }, + { 18, "DIMM_G1" }, + { 19, "DIMM_G2" }, + { 20, "DIMM_G3" }, + { 21, "DIMM_H1" }, + { 22, "DIMM_H2" }, + { 23, "DIMM_H3" }, + { 24, "DIMM_I1" }, + { 25, "DIMM_I2" }, + { 26, "DIMM_I3" }, + { 27, "DIMM_J1" }, + { 28, "DIMM_J2" }, + { 29, "DIMM_J3" }, + { 30, "DIMM_K1" }, + { 31, "DIMM_K2" }, + { 32, "DIMM_K3" }, + { 33 , NULL } /*end of list*/ +}; + +const struct valstr intel_mem_s5520ur[] = { + { 0, "DIMM_A1" }, + { 1, "DIMM_A2" }, + { 2, "DIMM_B1" }, + { 3, "DIMM_B2" }, + { 4, "DIMM_C1" }, + { 5, "DIMM_C2" }, + { 6, "DIMM_D1" }, + { 7, "DIMM_D2" }, + { 8, "DIMM_E1" }, + { 9, "DIMM_E2" }, + { 10, "DIMM_F1" }, + { 11, "DIMM_F2" }, + { 12 , NULL } /*end of list*/ +}; +const struct valstr intel_mem_s5000phb[] = { + { 0, "DIMM_A1" }, + { 1, "DIMM_A2" }, + { 2, "DIMM_A3" }, + { 3, "DIMM_B1" }, + { 4, "DIMM_B2" }, + { 5, "DIMM_B3" }, + { 6 , NULL } /*end of list*/ +}; +const struct valstr intel_mem_s5000pal[] = { + { 0, "DIMM_A1" }, + { 1, "DIMM_A2" }, + { 2, "DIMM_B1" }, + { 3, "DIMM_B2" }, + { 4, "DIMM_C1" }, + { 5, "DIMM_C2" }, + { 6, "DIMM_D1" }, + { 7, "DIMM_D2" }, + { 8 , NULL } /*end of list*/ +}; +const struct valstr intel_mem_tigi2u[] = { + { 0, "DIMM_1B" }, + { 1, "DIMM_1A" }, + { 2, "DIMM_2B" }, + { 3, "DIMM_2A" }, + { 4, "DIMM_3B" }, + { 5, "DIMM_3A" }, + { 6 , NULL } /*end of list*/ +}; + +#define LIDS 8 +ushort lan2i_ids[LIDS] = { /*Intel prod_ids that use lan2i, rest use lan2*/ + 0x0000, /*uninitialized */ + 0x0022, /*TIGI2U */ + 0x0026, /*Bridgeport */ + 0x0028, /*S5000PAL, Alcolu*/ + 0x0029, /*S5000PSL, StarLake*/ + 0x002B, /*S5000VSA */ + 0x002D, /*ClearBay*/ + 0x0811 /*S5000PHB, TIGW1U*/ }; + +#define RIDS 21 /* Intel Romley product ids: */ +struct { ushort id; char *desc; } romleys[RIDS] = { + { 0x0048, "S1200BT" }, /* S1200BT, BearTooth Pass */ + { 0x0049, "S2600GL" }, /* S2600GL, S2600GZ */ + { 0x004A, "S2600CP" }, /* S2600CP, Canoe Pass */ + { 0x004D, "S2600JF" }, /* S2600JF, Jefferson Pass, Appro 512X */ + { 0x004E, "S2600WP" }, /* S2600WP */ + { 0x004F, "S2400SC" }, /* S2400SC */ + { 0x0050, "S2400LP" }, /* S2400LP */ + { 0x0051, "S2400EP" }, /* S2400EP, Eagle Pass */ + { 0x0052, "S1400FP" }, /* S1400FP */ + { 0x0053, "S1400SP" }, /* S1400SP */ + { 0x0054, "S2600KI" }, /* S2600KI */ + { 0x0055, "S2600IP" }, /* S2600IP, Iron Pass */ + { 0x0056, "W2600CR" }, /* W2600CR */ + { 0x0057, "S2400GP" }, /* S2400GP */ + { 0x0058, "Badger Pass" }, /* Badger Pass */ + { 0x0059, "S2400BB" }, /* S2400BB */ + { 0x005A, "Taylor Pass" }, /* Taylor Pass */ + { 0x005B, "S1600JP" }, /* S1600JP */ + { 0x005C, "S4600LH" }, /* S4600LH, Lizard Head Pass */ + { 0x005D, "CG2200" }, /* S2600CO, Copper Pass, Kontron CG2200 */ + { 0x005E, "Big Ridge"} /* Big Ridge */ +}; + +#define TIDS 5 +ushort thurley_ids[TIDS] = { /* Intel Thurley product ids: */ + 0x003A, /* Snow Hill */ + 0x003B, /* Shoffner */ + 0x003D, /* Melstone */ + 0x003E, /* S5520UR, S5500WB, Kontron CG2100, Penguin Computing Relion 700 */ + 0x0040 }; /* Stoutland, Quanta QSSC-S4R/Appro GB812X-CN (Nehalem-EX) */ + +int is_romley(int vend, int prod) +{ + int ret = 0; + int i; + if (vend != VENDOR_INTEL) return(ret); + for (i = 0; i < RIDS; i++) + if ((ushort)prod == romleys[i].id) { ret = 1; break; } + return(ret); +} + +int intel_romley_desc(int vend, int prod, char **pdesc) +{ + int ret = -1; + int i; + if (vend != VENDOR_INTEL) return(ret); + if (pdesc == NULL) return(ret); + for (i = 0; i < RIDS; i++) { + if ((ushort)prod == romleys[i].id) { + *pdesc = romleys[i].desc; + ret = 0; + break; + } + } + return(ret); +} + +int is_thurley(int vend, int prod) +{ + int ret = 0; + int i; + if (vend != VENDOR_INTEL) return(ret); + for (i = 0; i < TIDS; i++) + if ((ushort)prod == thurley_ids[i]) { ret = 1; break; } + return(ret); +} + +int is_lan2intel(int vend, int prod) +{ + int ret = 0; + int i; + if (vend != VENDOR_INTEL) return(ret); + if (is_thurley(vend,prod) || is_romley(vend,prod)) + ret = 0; /*iBMC does not use lan2i*/ + else { + for (i = 0; i < LIDS; i++) + if ((ushort)prod == lan2i_ids[i]) { ret = 1; break; } + } + return(ret); +} + +int decode_mem_intel(int prod, uchar b2, uchar b3, char *desc, int *psz) +{ + const char *pstr = NULL; + int array, dimm; + int node, chan, sock, n; + int rv = -1; + uchar bdata; + int vend; + int iBMC = 0; + + if ((desc == NULL) || (psz == NULL)) return -1; + + vend = VENDOR_INTEL; + if (is_thurley(vend,prod)) iBMC = 1; + if (is_romley(vend,prod)) iBMC = 2; + if (iBMC != 0) { + /* custom DIMM decoding for iBMC on Intel S5500 and S2600 */ + // rank = (b2 & 0x03); /* psel->event_data2 & 0x03; */ + node = (b3 & 0xE0) >> 5; /*socket*/ + chan = (b3 & 0x18) >> 3; + sock = (b3 & 0x07); + array = 0; /* is 0 for Thurley & Romley currently, else see b2. */ + if (iBMC == 1) dimm = (node * 6) + (chan * 2) + sock; + else dimm = (node * 12) + (chan * 3) + sock; + if (fdebug) printf("iBMC DIMM (%d,%d,%d) = idx %d\n", + node,chan,sock,dimm); + } else { /* use straight DIMM index */ + /* for mini-BMC, data2 is dimm index, data3 is syndrome */ + if (prod == 0x4311) bdata = b2; /*mini-BMC*/ + else if (b3 == 0xff) bdata = b2; /*ff is reserved*/ + else bdata = b3; /* normal case */ + /* (data3 & 0xc0) = SMBIOS type 16 mem array */ + array = (bdata & 0xc0) >> 6; + /* (data3 & 0x3f) = SMBIOS type 17 dimm index */ + dimm = bdata & 0x3f; + } + + if (! is_remote()) { + fsm_debug = fdebug; + rv = get_MemDesc(array,dimm,desc,psz); + /* if (rv != 0) desc has "DIMM[%d}" */ + } + if (rv != 0) { + /* either remote, or get_MemDesc failed, use common product defaults*/ + switch(prod) { + case 0x0811: /*S5000PHB*/ + pstr = val2str(dimm,intel_mem_s5000phb); + break; + case 0x0028: /*S5000PAL*/ + pstr = val2str(dimm,intel_mem_s5000pal); + break; + case 0x0022: /*TIGI2U*/ + pstr = val2str(dimm,intel_mem_tigi2u); + break; + default: + if (iBMC == 1) pstr = val2str(dimm,intel_mem_s5520ur); + else if (iBMC == 2) pstr = val2str(dimm,intel_mem_s2600); + else rv = -2; /*do not guess, use raw index below*/ + break; + } + if (pstr != NULL) rv = 0; + if (rv == 0) { + /* These strings are usually 7 chars, desc is 80 chars */ + n = strlen_(pstr); + strncpy(desc, pstr, n+1); + } else { + n = sprintf(desc,"DIMM[%d]",dimm); + } + *psz = n; + } + return(rv); +} /*end decode_mem_intel*/ + +/* + * decode_sensor_intel + * inputs: + * sdr = the SDR buffer + * reading = the 3 or 4 bytes of data from GetSensorReading + * pstring = points to the output string buffer + * slen = size of the output buffer + * outputs: + * rv = 0 if this sensor was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * pstring = contains the sensor reading interpretation string (if rv==0) + */ +int decode_sensor_intel(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + uchar stype; + char *pstr = NULL; + + if (sdr == NULL || reading == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + if (sdr[3] == 0x02) { /*Compact SDR*/ + stype = sdr[12]; + switch(stype) { + case 0xC0: /* SMI State, NMI State */ + case 0xC7: /* FanBoost */ + case 0xCC: /* Debug Info */ + case 0xD8: /* BIST */ + case 0xF0: /* ATCA HotSwap, TODO: refine this */ + case 0xF3: /* SMI Timeout, etc. */ + case 0xF6: /* Sensor Failure */ + case 0xF7: /* FSB Mismatch */ + if (reading[2] & 0x01) pstr = "Asserted"; /*Asserted, error*/ + else pstr = "OK"; /*deasserted*/ + strncpy(pstring, pstr, slen); + rv = 0; + break; + case 0xDC: /* NM Capabilities sensor */ + rv = decode_sensor_intel_nm(sdr,reading,pstring,slen); + break; + default: + break; + } + } else if (sdr[3] == 0xC0) { /*OEM SDR*/ + rv = decode_sensor_intel_nm(sdr,reading,pstring,slen); + } + return(rv); +} + +const struct valstr intel_s5000_post[] = { /*from S5000 TPS*/ + { 0x0012, "CMOS date/time not set" }, + { 0x0048, "Password check failed" }, + { 0x004C, "Keyboard/interface error" }, + { 0x0108, "Keyboard locked error" }, + { 0x0109, "Keyboard stuck key error" }, + { 0x0113, "The SAS RAID firmware cannot run properly, reflash" }, + { 0x0140, "PCI PERR detected" }, + { 0x0141, "PCI resource conflict" }, + { 0x0146, "Insufficient memory to shadow PCI ROM" }, + { 0x0192, "L3 cache size mismatch" }, + { 0x0194, "CPUID, processor family are different" }, + { 0x0195, "Front side bus mismatch" }, + { 0x0197, "Processor speeds mismatched" }, + { 0x5220, "Configuration cleared by jumper" }, + { 0x5221, "Passwords cleared by jumper" }, + { 0x5223, "Configuration default loaded" }, + { 0x8110, "Proc1 internal error (IERR) on last boot" }, + { 0x8111, "Proc2 internal error (IERR) on last boot" }, + { 0x8120, "Proc1 thermal trip error on last boot" }, + { 0x8121, "Proc2 thermal trip error on last boot" }, + { 0x8130, "Proc1 disabled" }, + { 0x8131, "Proc2 disabled" }, + { 0x8160, "Proc1 unable to apply BIOS update" }, + { 0x8161, "Proc2 unable to apply BIOS update" }, + { 0x8170, "Proc1 failed Self Test (BIST)" }, + { 0x8171, "Proc2 failed Self Test (BIST)" }, + { 0x8180, "Proc1 BIOS does not support current CPU stepping" }, + { 0x8181, "Proc2 BIOS does not support current CPU stepping" }, + { 0x8190, "Watchdog timer failed on last boot" }, + { 0x8198, "OS boot watchdog timer expired on last boot" }, + { 0x8300, "Baseboard management controller failed self-test" }, + { 0x8306, "Front panel controller locked" }, + { 0x8305, "Hot swap controller failed" }, + { 0x84F2, "Baseboard management controller failed to respond" }, + { 0x84F3, "Baseboard management controller in update mode" }, + { 0x84F4, "Sensor data record empty" }, + { 0x84FF, "System event log full" }, + { 0x8500, "Memory could not be configured in the selected RAS mode" }, + { 0x8510, "Memory above 16GB maximum" }, /*S5000V only*/ + { 0x8520, "DIMM_A1 failed Self Test (BIST)" }, + { 0x8521, "DIMM_A2 failed Self Test (BIST)" }, + { 0x8522, "DIMM_A3 failed Self Test (BIST)" }, + { 0x8523, "DIMM_A4 failed Self Test (BIST)" }, + { 0x8524, "DIMM_B1 failed Self Test (BIST)" }, + { 0x8525, "DIMM_B2 failed Self Test (BIST)" }, + { 0x8526, "DIMM_B3 failed Self Test (BIST)" }, + { 0x8527, "DIMM_B4 failed Self Test (BIST)" }, + { 0x8528, "DIMM_C1 failed Self Test (BIST)" }, + { 0x8529, "DIMM_C2 failed Self Test (BIST)" }, + { 0x852A, "DIMM_C3 failed Self Test (BIST)" }, + { 0x852B, "DIMM_C4 failed Self Test (BIST)" }, + { 0x852C, "DIMM_D1 failed Self Test (BIST)" }, + { 0x852D, "DIMM_D2 failed Self Test (BIST)" }, + { 0x852E, "DIMM_D3 failed Self Test (BIST)" }, + { 0x852F, "DIMM_D4 failed Self Test (BIST)" }, + { 0x8540, "Memory lost redundancy during last boot" }, + { 0x8580, "DIMM_A1 Correctable ECC error" }, + { 0x8581, "DIMM_A2 Correctable ECC error" }, + { 0x8582, "DIMM_A3 Correctable ECC error" }, + { 0x8583, "DIMM_A4 Correctable ECC error" }, + { 0x8584, "DIMM_B1 Correctable ECC error" }, + { 0x8585, "DIMM_B2 Correctable ECC error" }, + { 0x8586, "DIMM_B3 Correctable ECC error" }, + { 0x8587, "DIMM_B4 Correctable ECC error" }, + { 0x8588, "DIMM_C1 Correctable ECC error" }, + { 0x8589, "DIMM_C2 Correctable ECC error" }, + { 0x858A, "DIMM_C3 Correctable ECC error" }, + { 0x858B, "DIMM_C4 Correctable ECC error" }, + { 0x858C, "DIMM_D1 Correctable ECC error" }, + { 0x858D, "DIMM_D2 Correctable ECC error" }, + { 0x858E, "DIMM_D3 Correctable ECC error" }, + { 0x858F, "DIMM_D4 Correctable ECC error" }, + { 0x8600, "Primary and secondary BIOS IDs do not match" }, + { 0x8601, "BIOS Bank Override jumper set to lower bank" }, + { 0x8602, "WatchDog timer expired (check secondary BIOS bank)" }, + { 0x8603, "Secondary BIOS checksum fail" }, + { 0xffff , NULL } /*end of list*/ +}; +const struct valstr intel_s5500_post[] = { /*from S5520UR TPS*/ + { 0x0012, "CMOS date/time not set" }, + { 0x0048, "Password check failed" }, + { 0x0108, "Keyboard locked error" }, + { 0x0109, "Keyboard stuck key error" }, + { 0x0113, "The SAS RAID firmware cannot run properly" }, + { 0x0140, "PCI PERR detected" }, + { 0x0141, "PCI resource conflict" }, + { 0x0146, "PCI out of resources error" }, + { 0x0192, "Processor cache size mismatch" }, + { 0x0194, "Processor family mismatch" }, + { 0x0195, "Processor QPI speed mismatch" }, + { 0x0196, "Processor Model mismatch" }, + { 0x0197, "Processor speeds mismatched" }, + { 0x0198, "Processor family is unsupported" }, + { 0x019F, "Processor/chipset stepping configuration is unsupported" }, + { 0x5220, "CMOS/NVRAM Configuration Cleared" }, + { 0x5221, "Passwords cleared by jumper" }, + { 0x5224, "Password clear jumper is Set" }, + { 0x8110, "Proc1 internal error (IERR) on last boot" }, /*not used*/ + { 0x8111, "Proc2 internal error (IERR) on last boot" }, /*not used*/ + { 0x8120, "Proc1 thermal trip error on last boot" }, /*not used*/ + { 0x8121, "Proc2 thermal trip error on last boot" }, /*not used*/ + { 0x8130, "Proc1 disabled" }, /*not used*/ + { 0x8131, "Proc2 disabled" }, /*not used*/ + { 0x8140, "Proc1 Failed FRB-3 Timer" }, /*not used*/ + { 0x8141, "Proc2 Failed FRB-3 Timer" }, /*not used*/ + { 0x8160, "Proc1 unable to apply microcode update" }, + { 0x8161, "Proc2 unable to apply microcode update" }, + { 0x8170, "Proc1 failed Self Test (BIST)" }, /*not used*/ + { 0x8171, "Proc2 failed Self Test (BIST)" }, /*not used*/ + { 0x8180, "Processor microcode update not found" }, + { 0x8190, "Watchdog timer failed on last boot" }, + { 0x8198, "OS boot watchdog timer expired on last boot" }, + { 0x8300, "iBMC failed self-test" }, + { 0x8305, "Hotswap controller failure" }, + { 0x84F2, "iBMC failed to respond" }, + { 0x84F3, "iBMC in update mode" }, + { 0x84F4, "Sensor data record empty" }, + { 0x84FF, "System event log full" }, + { 0x8500, "Memory could not be configured in the selected RAS mode" }, + { 0x8520, "DIMM_A1 failed Self Test (BIST)" }, + { 0x8521, "DIMM_A2 failed Self Test (BIST)" }, + { 0x8522, "DIMM_B1 failed Self Test (BIST)" }, + { 0x8523, "DIMM_B2 failed Self Test (BIST)" }, + { 0x8524, "DIMM_C1 failed Self Test (BIST)" }, + { 0x8525, "DIMM_C2 failed Self Test (BIST)" }, + { 0x8526, "DIMM_D1 failed Self Test (BIST)" }, + { 0x8527, "DIMM_D2 failed Self Test (BIST)" }, + { 0x8528, "DIMM_E1 failed Self Test (BIST)" }, + { 0x8529, "DIMM_E2 failed Self Test (BIST)" }, + { 0x852A, "DIMM_F1 failed Self Test (BIST)" }, + { 0x852B, "DIMM_F2 failed Self Test (BIST)" }, + { 0x8540, "DIMM_A1 Disabled" }, + { 0x8541, "DIMM_A2 Disabled" }, + { 0x8542, "DIMM_B1 Disabled" }, + { 0x8543, "DIMM_B2 Disabled" }, + { 0x8544, "DIMM_C1 Disabled" }, + { 0x8545, "DIMM_C2 Disabled" }, + { 0x8546, "DIMM_D1 Disabled" }, + { 0x8547, "DIMM_D2 Disabled" }, + { 0x8548, "DIMM_E1 Disabled" }, + { 0x8549, "DIMM_E2 Disabled" }, + { 0x854A, "DIMM_F1 Disabled" }, + { 0x854B, "DIMM_F2 Disabled" }, + { 0x8560, "DIMM_A1 SPD fail error." }, + { 0x8561, "DIMM_A2 SPD fail error" }, + { 0x8562, "DIMM_B1 SPD fail error" }, + { 0x8563, "DIMM_B2 SPD fail error" }, + { 0x8564, "DIMM_C1 SPD fail error" }, + { 0x8565, "DIMM_C2 SPD fail error" }, + { 0x8566, "DIMM_D1 SPD fail error" }, + { 0x8567, "DIMM_D2 SPD fail error" }, + { 0x8568, "DIMM_E1 SPD fail error" }, + { 0x8569, "DIMM_E2 SPD fail error" }, + { 0x856A, "DIMM_F1 SPD fail error" }, + { 0x856B, "DIMM_F2 SPD fail error" }, + { 0x8580, "DIMM_A1 Correctable ECC error" }, + { 0x8581, "DIMM_A2 Correctable ECC error" }, + { 0x8582, "DIMM_B1 Correctable ECC error" }, + { 0x8583, "DIMM_B2 Correctable ECC error" }, + { 0x8584, "DIMM_C1 Correctable ECC error" }, + { 0x8585, "DIMM_C2 Correctable ECC error" }, + { 0x8586, "DIMM_D1 Correctable ECC error" }, + { 0x8587, "DIMM_D2 Correctable ECC error" }, + { 0x8588, "DIMM_E1 Correctable ECC error" }, + { 0x8589, "DIMM_E2 Correctable ECC error" }, + { 0x858A, "DIMM_F1 Correctable ECC error" }, + { 0x858B, "DIMM_F2 Correctable ECC error" }, + { 0x85A0, "DIMM_A1 Uncorrectable ECC error" }, + { 0x85A1, "DIMM_A2 Uncorrectable ECC error" }, + { 0x85A2, "DIMM_B1 Uncorrectable ECC error" }, + { 0x85A3, "DIMM_B2 Uncorrectable ECC error" }, + { 0x85A4, "DIMM_C1 Uncorrectable ECC error" }, + { 0x85A5, "DIMM_C2 Uncorrectable ECC error" }, + { 0x85A6, "DIMM_D1 Uncorrectable ECC error" }, + { 0x85A7, "DIMM_D2 Uncorrectable ECC error" }, + { 0x85A8, "DIMM_E1 Uncorrectable ECC error" }, + { 0x85A9, "DIMM_E2 Uncorrectable ECC error" }, + { 0x85AA, "DIMM_F1 Uncorrectable ECC error" }, + { 0x85AB, "DIMM_F2 Uncorrectable ECC error" }, + { 0x8601, "BIOS Bank Override jumper set to lower bank" }, /*not used*/ + { 0x8602, "WatchDog timer expired (check secondary BIOS bank)" }, /*not used*/ + { 0x8603, "Secondary BIOS checksum fail" }, /*not used*/ + { 0x8604, "Chipset Reclaim of non critical variables complete" }, + { 0x9000, "Unspecified processor component error" }, + { 0x9223, "Keyboard was not detected" }, /*not used*/ + { 0x9226, "Keyboard controller error" }, + { 0x9243, "Mouse was not detected" }, + { 0x9246, "Mouse controller error" }, + { 0x9266, "Local Console controller error" }, + { 0x9268, "Local Console output error" }, + { 0x9269, "Local Console resource conflict error" }, + { 0x9286, "Remote Console controller error" }, + { 0x9287, "Remote Console input error" }, + { 0x9288, "Remote Console output error" }, + { 0x92A3, "Serial port was not detected" }, + { 0x92A9, "Serial port resource conflict error" }, + { 0x92C6, "Serial Port controller error" }, + { 0x92C7, "Serial Port input error" }, + { 0x92C8, "Serial Port output error" }, + { 0x94C6, "LPC controller error" }, + { 0x94C9, "LPC resource conflict error" }, + { 0x9506, "ATA/ATPI controller error" }, + { 0x95A6, "PCI controller error" }, + { 0x95A7, "PCI read error" }, + { 0x95A8, "PCI write error" }, + { 0x9609, "Unspecified software start error" }, + { 0x9641, "PEI Core load error" }, + { 0x9667, "PEI module Illegal software state error" }, + { 0x9687, "DXE core Illegal software state error" }, + { 0x96A7, "DXE driver Illegal software state error" }, + { 0x96AB, "DXE driver Invalid configuration" }, + { 0x96E7, "SMM driver Illegal software state error" }, + { 0xA000, "TPM device not detected" }, + { 0xA001, "TPM device missing" }, + { 0xA002, "TPM device failure" }, + { 0xA003, "TPM device failed self-test" }, + { 0xA022, "Processor mismatch error" }, + { 0xA027, "Processor low voltage error" }, + { 0xA028, "Processor high voltage error" }, + { 0xA421, "PCI SERR detected" }, + { 0xA500, "ATA/ATPI ATA bus SMART not supported" }, + { 0xA501, "ATA/ATPI ATA SMART is disabled" }, + { 0xA5A0, "PCI Express PERR" }, + { 0xA5A1, "PCI Express SERR" }, + { 0xA5A4, "PCI Express IBIST error" }, + { 0xA6A0, "DXE driver Not enough memory to shadow legacy OpROM" }, + { 0xB6A3, "DXE driver unrecognized" }, + { 0xffff , NULL } /*end of list*/ +}; +const struct valstr intel_s2600_post[] = { /*from S2600CP TPS*/ + { 0x0012, "CMOS date/time not set" }, + { 0x0048, "Password check failed" }, + { 0x0108, "Keyboard locked error" }, + { 0x0109, "Keyboard stuck key error" }, + { 0x0113, "The SAS RAID firmware cannot run properly" }, + { 0x0140, "PCI PERR detected" }, + { 0x0141, "PCI resource conflict" }, + { 0x0146, "PCI out of resources error" }, + { 0x0191, "Processor core/thread count mismatch" }, + { 0x0192, "Processor cache size mismatch" }, + { 0x0194, "Processor family mismatch" }, + { 0x0195, "Processor QPI speed mismatch" }, + { 0x0196, "Processor Model mismatch" }, + { 0x0197, "Processor speeds mismatched" }, + { 0x0198, "Processor family is unsupported" }, + { 0x019F, "Processor/chipset stepping configuration is unsupported" }, + { 0x5220, "CMOS/NVRAM Configuration Cleared" }, + { 0x5221, "Passwords cleared by jumper" }, + { 0x5224, "Password clear jumper is Set" }, + { 0x8110, "Proc1 internal error (IERR) on last boot" }, /*not used*/ + { 0x8111, "Proc2 internal error (IERR) on last boot" }, /*not used*/ + { 0x8120, "Proc1 thermal trip error on last boot" }, /*not used*/ + { 0x8121, "Proc2 thermal trip error on last boot" }, /*not used*/ + { 0x8130, "Proc1 disabled" }, /*not used*/ + { 0x8131, "Proc2 disabled" }, /*not used*/ + { 0x8140, "Proc1 Failed FRB-3 Timer" }, /*not used*/ + { 0x8141, "Proc2 Failed FRB-3 Timer" }, /*not used*/ + { 0x8160, "Proc1 unable to apply microcode update" }, + { 0x8161, "Proc2 unable to apply microcode update" }, + { 0x8170, "Proc1 failed Self Test (BIST)" }, /*not used*/ + { 0x8171, "Proc2 failed Self Test (BIST)" }, /*not used*/ + { 0x8180, "Processor microcode update not found" }, + { 0x8181, "Proc2 microcode update not found" }, + { 0x8190, "Watchdog timer failed on last boot" }, + { 0x8198, "OS boot watchdog timer expired on last boot" }, + { 0x8300, "iBMC failed self-test" }, + { 0x8305, "Hotswap controller failure" }, + { 0x84F2, "iBMC failed to respond" }, + { 0x84F3, "iBMC in update mode" }, + { 0x84F4, "Sensor data record empty" }, + { 0x84FF, "System event log full" }, + { 0x8500, "Memory could not be configured in the selected RAS mode" }, + { 0x8501, "DIMM Population Error" }, + { 0x8520, "DIMM_A1 failed test/initialization" }, + { 0x8521, "DIMM_A2 failed test/initialization" }, + { 0x8522, "DIMM_A3 failed test/initialization" }, + { 0x8523, "DIMM_B1 failed test/initialization" }, + { 0x8524, "DIMM_B2 failed test/initialization" }, + { 0x8525, "DIMM_B3 failed test/initialization" }, + { 0x8526, "DIMM_C1 failed test/initialization" }, + { 0x8527, "DIMM_C2 failed test/initialization" }, + { 0x8528, "DIMM_C3 failed test/initialization" }, + { 0x8529, "DIMM_D1 failed test/initialization" }, + { 0x852A, "DIMM_D2 failed test/initialization" }, + { 0x852B, "DIMM_D3 failed test/initialization" }, + { 0x852C, "DIMM_E1 failed test/initialization" }, + { 0x852D, "DIMM_E2 failed test/initialization" }, + { 0x852E, "DIMM_E3 failed test/initialization" }, + { 0x852F, "DIMM_F1 failed test/initialization" }, + { 0x8530, "DIMM_F2 failed test/initialization" }, + { 0x8531, "DIMM_F3 failed test/initialization" }, + { 0x8532, "DIMM_G1 failed test/initialization" }, + { 0x8533, "DIMM_G2 failed test/initialization" }, + { 0x8534, "DIMM_G3 failed test/initialization" }, + { 0x8535, "DIMM_H1 failed test/initialization" }, + { 0x8536, "DIMM_H2 failed test/initialization" }, + { 0x8537, "DIMM_H3 failed test/initialization" }, + { 0x8538, "DIMM_I1 failed test/initialization" }, + { 0x8539, "DIMM_I2 failed test/initialization" }, + { 0x853A, "DIMM_I3 failed test/initialization" }, + { 0x853B, "DIMM_J1 failed test/initialization" }, + { 0x853C, "DIMM_J2 failed test/initialization" }, + { 0x853D, "DIMM_J3 failed test/initialization" }, + { 0x853E, "DIMM_K1 failed test/initialization" }, + { 0x853F, "DIMM_K2 failed test/initialization" }, + { 0x8540, "DIMM_A1 Disabled" }, + { 0x8541, "DIMM_A2 Disabled" }, + { 0x8542, "DIMM_A3 Disabled" }, + { 0x8543, "DIMM_B1 Disabled" }, + { 0x8544, "DIMM_B2 Disabled" }, + { 0x8545, "DIMM_B3 Disabled" }, + { 0x8546, "DIMM_C1 Disabled" }, + { 0x8547, "DIMM_C2 Disabled" }, + { 0x8548, "DIMM_C3 Disabled" }, + { 0x8549, "DIMM_D1 Disabled" }, + { 0x854A, "DIMM_D2 Disabled" }, + { 0x854B, "DIMM_D3 Disabled" }, + { 0x854C, "DIMM_E1 Disabled" }, + { 0x854D, "DIMM_E2 Disabled" }, + { 0x854E, "DIMM_E3 Disabled" }, + { 0x854F, "DIMM_F1 Disabled" }, + { 0x8550, "DIMM_F2 Disabled" }, + { 0x8551, "DIMM_F3 Disabled" }, + { 0x8552, "DIMM_G1 Disabled" }, + { 0x8553, "DIMM_G2 Disabled" }, + { 0x8554, "DIMM_G3 Disabled" }, + { 0x8555, "DIMM_H1 Disabled" }, + { 0x8556, "DIMM_H1 Disabled" }, + { 0x8557, "DIMM_H1 Disabled" }, + { 0x8558, "DIMM_I1 Disabled" }, + { 0x8559, "DIMM_I2 Disabled" }, + { 0x855A, "DIMM_I3 Disabled" }, + { 0x855B, "DIMM_J1 Disabled" }, + { 0x855C, "DIMM_J2 Disabled" }, + { 0x855D, "DIMM_J3 Disabled" }, + { 0x855E, "DIMM_K1 Disabled" }, + { 0x855F, "DIMM_K2 Disabled" }, + { 0x8560, "DIMM_A1 SPD fail error" }, + { 0x8561, "DIMM_A2 SPD fail error" }, + { 0x8562, "DIMM_A3 SPD fail error" }, + { 0x8563, "DIMM_B1 SPD fail error" }, + { 0x8564, "DIMM_B2 SPD fail error" }, + { 0x8565, "DIMM_B3 SPD fail error" }, + { 0x8566, "DIMM_C1 SPD fail error" }, + { 0x8567, "DIMM_C2 SPD fail error" }, + { 0x8568, "DIMM_C3 SPD fail error" }, + { 0x8569, "DIMM_D1 SPD fail error" }, + { 0x856A, "DIMM_D2 SPD fail error" }, + { 0x856B, "DIMM_D3 SPD fail error" }, + { 0x856C, "DIMM_E1 SPD fail error" }, + { 0x856D, "DIMM_E2 SPD fail error" }, + { 0x856E, "DIMM_E3 SPD fail error" }, + { 0x856F, "DIMM_F1 SPD fail error" }, + { 0x8570, "DIMM_F2 SPD fail error" }, + { 0x8571, "DIMM_F3 SPD fail error" }, + { 0x8572, "DIMM_G1 SPD fail error" }, + { 0x8573, "DIMM_G2 SPD fail error" }, + { 0x8574, "DIMM_G3 SPD fail error" }, + { 0x8575, "DIMM_H1 SPD fail error" }, + { 0x8576, "DIMM_H1 SPD fail error" }, + { 0x8577, "DIMM_H1 SPD fail error" }, + { 0x8578, "DIMM_I1 SPD fail error" }, + { 0x8579, "DIMM_I2 SPD fail error" }, + { 0x857A, "DIMM_I3 SPD fail error" }, + { 0x857B, "DIMM_J1 SPD fail error" }, + { 0x857C, "DIMM_J2 SPD fail error" }, + { 0x857D, "DIMM_J3 SPD fail error" }, + { 0x857E, "DIMM_K1 SPD fail error" }, + { 0x857F, "DIMM_K2 SPD fail error" }, + /* some missing here for DIMM_K3 thru DIMM_P3 */ + { 0x8604, "Chipset Reclaim of non critical variables complete" }, + { 0x8605, "BIOS settings are corrupt" }, + { 0x92A3, "Serial port was not detected" }, + { 0x92A9, "Serial port resource conflict error" }, + { 0xA000, "TPM device not detected" }, + { 0xA001, "TPM device missing" }, + { 0xA002, "TPM device failure" }, + { 0xA003, "TPM device failed self-test" }, + { 0xA100, "BIOS ACM errord" }, + { 0xA421, "PCI SERR detected" }, + { 0xA5A0, "PCI Express PERR" }, + { 0xA5A1, "PCI Express SERR" }, + { 0xffff , NULL } /*end of list*/ +}; + +/* decode Intel POST codes for some platforms*/ +int decode_post_intel(int prod, ushort code, char *outbuf,int szbuf) +{ + int rv = -1; + const char *poststr = NULL; + if (is_thurley(VENDOR_INTEL,prod)) /* S5520UR/T5520UR (CG2100 or NSN2U)*/ + poststr = val2str(code,intel_s5500_post); + else if (is_romley(VENDOR_INTEL,prod)) /* S2600CO, CG2200 */ + poststr = val2str(code,intel_s2600_post); + else switch(prod) { + case 0x0028: /*S5000PAL*/ + case 0x0029: /*S5000PSL*/ + case 0x0811: /*S5000PHB*/ + poststr = val2str(code,intel_s5000_post); + break; + default: break; + } + if (poststr != NULL) { + strncpy(outbuf, poststr, szbuf); + rv = 0; + } + return(rv); +} + +#define ENC_LED_SLEEP 50000 +#define ENC_RCMD_SLEEP 500000 + +int get_hsbp_version_intel(uchar *maj, uchar *min) +{ + uchar idata[8]; + uchar rdata[4]; + int rv, rlen, i; + uchar cc; + + *maj = 0; + *min = 0; + /* For Romley/CG2200 get HSBP FW Version */ + for (i = 0; i < 3; i++) { + idata[0] = 0x0A; // 0x0A + idata[1] = 0xD0; + idata[2] = 0x01; // return one byte of LED data + idata[3] = 0x0A; // HSBP Major version + rlen = sizeof(rdata); + rv = ipmi_cmd(MASTER_WRITE_READ, idata, 4, rdata, &rlen, &cc, fdebug); + if (rv == 0 && cc != 0) rv = cc; + os_usleep(0,ENC_LED_SLEEP); /* wait before re-reading values */ + if (rv == 0) { + *maj = rdata[0]; + break; + } + /*else retry reading it*/ + } + for (i = 0; i < 3; i++) { + idata[0] = 0x0A; // 0x0A + idata[1] = 0xD0; + idata[2] = 0x01; // return one byte of LED data + idata[3] = 0x0B; // HSBP Minor version + rlen = sizeof(rdata); + rv = ipmi_cmd(MASTER_WRITE_READ, idata, 4, rdata, &rlen, &cc, fdebug); + if (rv == 0 && cc != 0) rv = cc; + os_usleep(0,ENC_LED_SLEEP); /* wait before re-reading values */ + if (rv == 0) { + *min = rdata[0]; + break; + } + /*else retry reading it*/ + } + return (rv); +} + +static uchar rdisk_led_method = 0; /* 0=initial, 1=rcmd, 2=i2c */ +static uchar rdisk_led_override = 0x00; /*override is off by default*/ + +static int get_enc_leds_i2c(uchar *val) +{ + uchar idata[8]; + uchar rdata[4]; + int rv, rv2, rlen, i; + uchar cc; + + *val = 0; /*make sure to initialize the reading*/ + for (i = 0; i < 3; i++) { + /* For Romley/Patsburg get disk fault LED status */ + idata[0] = 0x0A; // 0x0A + idata[1] = 0xD0; + idata[2] = 0x01; // return one byte of LED data + idata[3] = 0x0E; // LED_Status + rlen = sizeof(rdata); + rv = ipmi_cmd(MASTER_WRITE_READ, idata, 4, rdata, &rlen, &cc, fdebug); + if (rv == 0 && cc != 0) rv = cc; + os_usleep(0,ENC_LED_SLEEP); /* wait before re-reading values */ + if (rv == 0) { + *val = rdata[0]; + break; + } + /*else retry reading the LED Status*/ + } + + /* get & save the override status for use in show() */ + idata[0] = 0x0A; // 0x0A + idata[1] = 0xD0; + idata[2] = 0x01; // return one byte of LED data + idata[3] = 0x0D; // LED_Override + rlen = sizeof(rdata); + rv2 = ipmi_cmd(MASTER_WRITE_READ, idata, 4, rdata, &rlen, &cc, fdebug); + if (rv2 == 0 && cc != 0) rv2 = cc; + if (rv2 == 0) rdisk_led_override = rdata[0]; + + return (rv); +} + +static int set_enc_override_i2c(uchar val) +{ + uchar idata[8]; + uchar rdata[4]; + int rv, rlen, i; + uchar cc; + + if (val != 0) val = 1; + for (i = 0; i < 3; i++) { + /* Set LED Override to 0=off or 1=on */ + idata[0] = 0x0A; // 0x0A bus + idata[1] = 0xD0; + idata[2] = 0x00; // return no data + idata[3] = 0x0D; // LED_Override + idata[4] = val; /* turn on override */ + rlen = sizeof(rdata); + rv = ipmi_cmd(MASTER_WRITE_READ, idata, 5, rdata, &rlen, &cc, fdebug); + if (rv == 0 && cc != 0) rv = cc; + os_usleep(0,ENC_LED_SLEEP); /* wait before next LED cmd */ + if (rv == 0) break; + } + return(rv); +} + +static int set_enc_leds_i2c(uchar val) +{ + uchar idata[8]; + uchar rdata[4]; + int rv, rv2, rlen, i; + uchar cc; + + if ((val != 0) && (rdisk_led_override == 0)) { + /* setting some LED, so set disk led override*/ + rv2 = set_enc_override_i2c(1); + } + + for (i = 0; i < 3; i++) { + /* For Romley/Patsburg set disk fault LED status */ + idata[0] = 0x0A; // 0x0A bus + idata[1] = 0xD0; + idata[2] = 0x00; // return one byte of LED data + idata[3] = 0x0E; // LED_Status + idata[4] = val; + rlen = sizeof(rdata); + rv = ipmi_cmd(MASTER_WRITE_READ, idata, 5, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + os_usleep(0,ENC_LED_SLEEP); /* wait before next LED cmd */ + if (rv == 0) break; + } + + if (val == 0x00) { /* clear the disk led override */ + rv2 = set_enc_override_i2c(0); + } + return (rv); +} + +void show_enc_leds_i2c(uchar val, int numd) +{ + char *enc_pattn = "disk slot %d LED: %s %s\n"; + char *pstat; + char *pover; + uchar mask; + int i; + if (fdebug) printf("leds = %02x override = %02x\n",val,rdisk_led_override); + /* Some backplanes support 6 slots, but max is 8. */ + if (numd > 8) numd = 8; + mask = 0x01; + for (i = 0; i < numd; i++) { + if (val & mask) pstat = "ON"; + else pstat = "off"; + if (rdisk_led_override) pover = "(override)"; + else pover = ""; + printf(enc_pattn,i,pstat,pover); + mask = (mask << 1); + } +} + +static int set_enc_override_rcmd(uchar val) +{ + rdisk_led_override = val; + return(0); +} + +static int get_enc_leds_rcmd(uchar *val) +{ + uchar rdata[8]; + uchar slot[12]; + int rv, rlen, i; + uchar cc; + uchar v = 0; + + /* This command is only supported on Intel Romley w BMC >= 1.10 */ + for (i = 0; i < 12; i++) slot[i] = 0; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(0x65, 0x30, g_sa,g_bus,g_lun, + NULL, 0, rdata, &rlen, &cc, fdebug); + if (fdebug) printf("get_enc_leds_rcmd: rv = %d, cc=%02x\n", rv,cc); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) { + rdisk_led_override = (rdata[0] & 0x07); +/* +rdata[1]: Slot 1 to 4 status + [7:6]Slot4 status + 00-Off + 01-Locate (Amber 4HZ) + 10-Fail (Amber solid on) + 11-Rebuild (Amber 1HZ) + [5:4] Slot3 status + 00-Off + 01-Locate (Amber 4HZ) + 10-Fail (Amber solid on) + 11-Rebuild (Amber 1HZ) + [3:2] Slot2 status + 00-Off + 01-Locate (Amber 4HZ) + 10-Fail (Amber solid on) + 11-Rebuild (Amber 1HZ) + [1:0] Slot1 status + 00-Off + 01-Locate (Amber 4HZ) + 10-Fail (Amber solid on) + 11-Rebuild (Amber 1HZ) + */ + if (rdata[1] & 0x02) slot[0] = 1; + if (rdata[1] & 0x08) slot[1] = 1; + if (rdata[1] & 0x20) slot[2] = 1; + if (rdata[1] & 0x80) slot[3] = 1; + if (rdata[2] & 0x02) slot[4] = 1; + if (rdata[2] & 0x08) slot[5] = 1; + if (rdata[2] & 0x20) slot[6] = 1; + if (rdata[2] & 0x80) slot[7] = 1; + if (rdata[3] & 0x02) slot[8] = 1; + if (rdata[3] & 0x08) slot[9] = 1; + if (rdata[3] & 0x20) slot[10] = 1; + if (rdata[3] & 0x80) slot[11] = 1; + } + for (i = 0; i < 8; i++) { + if (slot[i] == 1) v |= (1 << i); + } + *val = v; + return(rv); +} + +static int set_enc_leds_rcmd(uchar val) +{ + uchar idata[8]; + uchar rdata[4]; + int rlen, rv; + uchar cc; + + if ((val != 0) && (rdisk_led_override == 0)) + set_enc_override_rcmd(1); + + /* This command is only supported on Intel Romley w BMC >= 1.10 */ + idata[0] = rdisk_led_override; + idata[1] = val; /*first 8 slots*/ + idata[2] = 0; + idata[3] = 0; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(0x64, 0x30, g_sa,g_bus,g_lun, + idata, 4, rdata, &rlen, &cc, fdebug); + if (fdebug) printf("set_enc_leds_rcmd: rv = %d, cc=%02x\n", rv,cc); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) os_usleep(0,ENC_RCMD_SLEEP); + + if ((rv == 0) && (val == 0)) { /*repeat with override off*/ + os_usleep(1,0); /* wait before next LED cmd */ + idata[0] = 0; + idata[1] = val; + idata[2] = 0; + idata[3] = 0; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(0x64, 0x30, g_sa,g_bus,g_lun, + idata, 4, rdata, &rlen, &cc, fdebug); + if (fdebug) printf("set_enc_leds_rcmd0: rv = %d, cc=%02x\n", rv,cc); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) os_usleep(0,ENC_RCMD_SLEEP); + set_enc_override_rcmd(0); + } + os_usleep(1,0); /* wait before next LED cmd */ + return(rv); +} + +static void show_enc_leds_rcmd(uchar val, int numd) +{ + char *enc_pattn = "disk slot %d LED: %s %s\n"; + char *pstat; + char *pover; + uchar mask; + int i; + if (fdebug) printf("leds = %02x override = %02x\n",val,rdisk_led_override); + /* Some backplanes support 6 slots, but max is 8. */ + if (numd > 8) numd = 8; + mask = 0x01; + for (i = 0; i < numd; i++) { + if (val & mask) pstat = "ON"; + else pstat = "off"; + if (rdisk_led_override) pover = "(override)"; + else pover = ""; + printf(enc_pattn,i,pstat,pover); + mask = (mask << 1); + } +} + +int set_enc_override_intel(uchar val) +{ + int rv; + if (rdisk_led_method == 1) rv = set_enc_override_rcmd(val); + else rv = set_enc_override_i2c(val); + return(rv); +} + +int get_enc_leds_intel(uchar *val) +{ + int rv = -1; + if (rdisk_led_method < 2) rv = get_enc_leds_rcmd(val); + if ((rv != 0) && (rdisk_led_method == 0)) rdisk_led_method = 2; + if (rdisk_led_method == 2) rv = get_enc_leds_i2c(val); + return(rv); +} + +int set_enc_leds_intel(uchar val) +{ + int rv = -1; + if (rdisk_led_method < 2) rv = set_enc_leds_rcmd(val); + if ((rv != 0) && (rdisk_led_method == 0)) rdisk_led_method = 2; + if (rdisk_led_method == 2) rv = set_enc_leds_i2c(val); + return(rv); +} + +void show_enc_leds_intel(uchar val, int numd) +{ + if (rdisk_led_method == 1) show_enc_leds_rcmd(val, numd); + else show_enc_leds_i2c(val, numd); +} + +/* end oem_intel.c */ diff --git a/util/oem_intel.h b/util/oem_intel.h new file mode 100644 index 0000000..79587d5 --- /dev/null +++ b/util/oem_intel.h @@ -0,0 +1,79 @@ +/* + * oem_intel.h + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2010 Kontron America, Inc. + * + * 09/02/10 Andy Cress - separated from ialaems.c + */ +/*M* +Copyright (c) 2010 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ + + +#define PRIVATE_BUS_ID 0x03 // w Sahalee, the 8574 is on Private Bus 1 +#define PRIVATE_BUS_ID5 0x05 // for Intel TIGI2U +#define PRIVATE_BUS_ID7 0x07 // for Intel S5000 +#define PERIPHERAL_BUS_ID 0x24 // w mBMC, the 8574 is on the Peripheral Bus +#define ALARMS_PANEL_WRITE 0x40 +#define ALARMS_PANEL_READ 0x41 +#define DISK_LED_WRITE 0x44 // only used for Chesnee mBMC +#define DISK_LED_READ 0x45 // only used for Chesnee mBMC + +#define HAS_ALARMS_MASK 0x0001 +#define HAS_BMCTAM_MASK 0x0002 +#define HAS_ENCL_MASK 0x0004 +#define HAS_PICMG_MASK 0x0008 +#define HAS_NSC_MASK 0x0010 +#define HAS_ROMLEY_MASK 0x0020 + +uchar get_nsc_diskleds(uchar busid); +int set_nsc_diskleds(uchar val, uchar busid); +void show_nsc_diskleds(uchar val); + +uchar get_alarms_intel(uchar busid); +int set_alarms_intel(uchar val, uchar busid); +void show_alarms_intel(uchar val); +int check_bmctam_intel(void); +int detect_capab_intel(int vend_id,int prod_id, int *cap, int *ndsk,char fdbg); +int get_led_status_intel(uchar *pstate); +int is_lan2intel(int vend, int prod); +int decode_sensor_intel(uchar *sdr,uchar *reading,char *pstring, int slen); +int decode_sensor_intel_nm(uchar *sdr,uchar *reading,char *pstring, int slen); +void show_oemsdr_intel(uchar *sdr); +void show_oemsdr_nm(uchar *sdr); +int is_romley(int vend, int prod); +int is_thurley(int vend, int prod); +int get_enc_leds_intel(uchar *val); +int set_enc_leds_intel(uchar val); +void show_enc_leds_intel(uchar val, int numd); +int lan_failover_intel(uchar func, uchar *mode); +int intel_romley_desc(int vend, int prod, char **pdesc); +int get_power_restore_delay_intel(int *delay); +int get_hsbp_version_intel(uchar *maj, uchar *min); + +/* end oem_intel.h */ diff --git a/util/oem_kontron.c b/util/oem_kontron.c new file mode 100644 index 0000000..263560f --- /dev/null +++ b/util/oem_kontron.c @@ -0,0 +1,1107 @@ +/* + * oem_kontron.c + * This code implements Kontron OEM proprietary commands. + * + * Change history: + * 08/25/2010 ARCress - included in source tree + * + *--------------------------------------------------------------------- + */ +/* + * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved. + * + * Base on code from + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Tue Mar 7 14:36:12 2006 + * <stephane.filion@ca.kontron.com> + * + * This code implements an Kontron OEM proprietary commands. + */ + +#ifdef WIN32 +#include <windows.h> +#include <winsock.h> +#include <time.h> +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +typedef uint32_t socklen_t; +#else +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <netinet/in.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "ipmicmd.h" +#include "ievents.h" +#include "oem_kontron.h" + +#define FRU_TYPE_COMPONENT 0x01 +#define FRU_TYPE_BASEBOARD 0x07 + +const struct valstr ktc5520_post[] = { /*from EAS*/ + { 0x0003, "Start POST Init" }, + { 0x0004, "Check CMOS" }, + { 0x0005, "Init interrupt HW" }, + { 0x0006, "Init INT1Ch" }, + { 0x0008, "Init CPUs" }, + { 0x000A, "Init 8042 Keyboard" }, + { 0x000B, "Detect PS2 Mouse" }, + { 0x000C, "Detect KBC Keyboard" }, + { 0x000E, "Test Input Devices" }, + { 0x0013, "PreInit chipset regs" }, + { 0x0024, "Init platform modules" }, + { 0x002A, "Init PCI devices" }, + { 0x002C, "Init Video" }, + { 0x002E, "Init Output devices" }, + { 0x0030, "Init SMI" }, + { 0x0031, "Init ADM module" }, + { 0x0033, "Init Silent boot" }, + { 0x0037, "Show first message" }, + { 0x0038, "Init Buses" }, + { 0x0039, "Init DMAC" }, + { 0x003A, "Init RTC" }, + { 0x003B, "Memory Test" }, + { 0x003C, "MidInit chipset regs" }, + { 0x0040, "Detect Ports" }, + { 0x0050, "Adjust RAM size" }, + { 0x0052, "Update CMOS size" }, + { 0x0060, "Init Kbd Numlock" }, + { 0x0075, "Init Int13" }, + { 0x0078, "Init IPL" }, + { 0x007A, "Init OpRoms" }, + { 0x007C, "Write ESCD to NV" }, + { 0x0084, "Log errors" }, + { 0x0085, "Display errors" }, + { 0x0087, "Run BIOS Setup" }, + { 0x008C, "LateInit chipset regs" }, + { 0x008D, "Build ACPI Tables" }, + { 0x008E, "Program peripherals" }, + { 0x0090, "LateInit SMI" }, + { 0x00A0, "Check Boot password" }, + { 0x00A1, "PreBoot Cleanup" }, + { 0x00A2, "Init Runtime image" }, + { 0x00A4, "Init Runtime lang" }, + { 0x00A7, "Show Config, Init MTRR" }, + { 0x00A8, "Prep CPU for OS boot" }, + { 0x00A9, "Wait for input" }, + { 0x00AA, "Deinit ADM, Int1C" }, + { 0x00AB, "Prepare BBS" }, + { 0x00AC, "EndInit chipse regs" }, + { 0x00B1, "Save context for ACPI" }, + { 0x00C0, "EarlyCPU Init APIC" }, + { 0x00C1, "Setup BSP info" }, + { 0x00C2, "Setup BSP for POST" }, + { 0x00C5, "Setup App Processors" }, + { 0x00C6, "Setup BSP cache" }, + { 0x00C7, "EarlyCPU Init exit" }, + { 0x0000, "OS Loader" }, + { 0xffff , NULL } /*end of list*/ +}; +/* +61-70, OEM POST Error. This range is reserved for chipset vendors & system manufacturers. The error associated with this value may be different from one platform to the next. +DD-DE, OEM PCI init debug POST code during DIMM init, See DIM Code Checkpoints section of document for more information. +DD-DE, OEM PCI init debug POST code during DIMM init. DEh during BUS number +*/ + +extern int verbose; /*ipmilanplus.c*/ +#ifdef METACOMMAND +extern int load_fru(uchar sa, uchar frudev, uchar frutype, uchar **pfrubuf); +extern int write_fru_data(uchar id, ushort offset, uchar *data, int dlen, + char fdebug); /*ifru.c*/ +#endif + +/* local function prototypes */ +static void ipmi_kontron_help(void); +static int ipmi_kontron_set_serial_number(void * intf); +static int ipmi_kontron_set_mfg_date (void * intf); + +static void print_buf( uint8_t * buf, int len, char * desc) +{ + dump_buf(desc,buf,len,0); +} + +#ifdef METACOMMAND +/* get_fru_area_str - Parse FRU area string from raw data + * @data: raw FRU data + * @offset: offset into data for area + * returns pointer to FRU area string + */ +static char * get_fru_area_str(uint8_t * data, uint32_t * offset) +{ + static const char bcd_plus[] = "0123456789 -.:,_"; + char * str; + int len, off, size, i, j, k, typecode; + union { + uint32_t bits; + char chars[4]; + } u; + + size = 0; + off = *offset; + /* bits 6:7 contain format */ + typecode = ((data[off] & 0xC0) >> 6); + + /* bits 0:5 contain length */ + len = data[off++]; + len &= 0x3f; + + switch (typecode) { + case 0: /* 00b: binary/unspecified */ + /* hex dump -> 2x length */ + size = (len*2); + break; + case 2: /* 10b: 6-bit ASCII */ + /* 4 chars per group of 1-3 bytes */ + size = ((((len+2)*4)/3) & ~3); + break; + case 3: /* 11b: 8-bit ASCII */ + case 1: /* 01b: BCD plus */ + /* no length adjustment */ + size = len; + break; + } + + if (size < 1) { + *offset = off; + return NULL; + } + str = malloc(size+1); + if (str == NULL) + return NULL; + memset(str, 0, size+1); + + if (len == 0) { + str[0] = '\0'; + *offset = off; + return str; + } + + switch (typecode) { + case 0: /* Binary */ + strncpy(str, buf2str(&data[off], len), len*2); + break; + + case 1: /* BCD plus */ + for (k=0; k<len; k++) + str[k] = bcd_plus[(data[off+k] & 0x0f)]; + str[k] = '\0'; + break; + + case 2: /* 6-bit ASCII */ + for (i=j=0; i<len; i+=3) { + u.bits = 0; + k = ((len-i) < 3 ? (len-i) : 3); +#if WORDS_BIGENDIAN + u.chars[3] = data[off+i]; + u.chars[2] = (k > 1 ? data[off+i+1] : 0); + u.chars[1] = (k > 2 ? data[off+i+2] : 0); +#define CHAR_IDX 3 +#else + memcpy((void *)&u.bits, &data[off+i], k); +#define CHAR_IDX 0 +#endif + for (k=0; k<4; k++) { + str[j++] = ((u.chars[CHAR_IDX] & 0x3f) + 0x20); + u.bits >>= 6; + } + } + str[j] = '\0'; + break; + + case 3: + memcpy(str, &data[off], len); + str[len] = '\0'; + break; + } + + off += len; + *offset = off; + + return str; +} +#endif + +static char *bootdev[] = {"BIOS", "FDD", "HDD", "CDROM", "network", 0}; + +static void +ipmi_kontron_nextboot_help(void) +{ + int i; + printf("nextboot <device>\n" + "Supported devices:\n"); + for (i = 0; bootdev[i] != 0; i++) { + printf("- %s\n", bootdev[i]); + } +} + +/* ipmi_kontron_next_boot_set - Select the next boot order on CP6012 + * + * @intf: ipmi interface + * @id: fru id + * + * returns -1 on error + * returns 1 if successful + */ +static int +ipmi_kontron_nextboot_set(void * intf, int argc, char **argv) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + uint8_t msg_data[8]; + int i; + + memset(msg_data, 0, sizeof(msg_data)); + msg_data[0] = 0xb4; + msg_data[1] = 0x90; + msg_data[2] = 0x91; + msg_data[3] = 0x8b; + msg_data[4] = 0x9d; + msg_data[5] = 0xFF; + msg_data[6] = 0xFF; /* any */ + + for (i = 0; bootdev[i] != 0; i++) { + if (strcmp(argv[0], bootdev[i]) == 0) { + msg_data[5] = (uchar)i; + break; + } + } + + /* Invalid device selected? */ + if (msg_data[5] == 0xFF) { + printf("Unknown boot device: %s\n", argv[0]); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x3E; + req.msg.cmd = 0x02; + req.msg.data = msg_data; + req.msg.data_len = 7; + + /* Set Lun temporary, necessary for this oem command */ + req.msg.lun = 0x03; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf(" Device not present (No Response)\n"); + return (rv); + } + if (rv > 0) { + printf(" NextBoot Device error (%s)\n",decode_cc(0,rv)); + return(rv); + } + return (rv); +} + +#ifdef METACOMMAND +int +ipmi_kontronoem_main(void * intf, int argc, char ** argv) +{ + int rc = 0; + + if (argc == 0) + ipmi_kontron_help(); + else if (strncmp(argv[0], "help", 4) == 0) + ipmi_kontron_help(); + + else if(!strncmp(argv[0], "setsn", 5)) + { + if(argc >= 1) + { + rc = ipmi_kontron_set_serial_number(intf); + if(rc == 0) { + printf("FRU serial number set successfully\n"); + } else { + printf("FRU serial number set failed\n"); + } + } + else + { + printf("fru setsn\n"); + } + } + else if(!strncmp(argv[0], "setmfgdate", 5)) + { + if(argc >= 1) + { + rc = ipmi_kontron_set_mfg_date(intf); + if (rc == 0) { + printf("FRU manufacturing date set successfully\n"); + } else { + printf("FRU manufacturing date set failed\n"); + } + } + else + { + printf("fru setmfgdate\n"); + } + + } + else if (!strncmp(argv[0], "nextboot", sizeof("nextboot")-1)) + { + if (argc > 1) + { + if ((rc = ipmi_kontron_nextboot_set(intf, argc-1, argv+1)) == 0) + { + printf("Nextboot set successfully\n"); + } else { + printf("Nextboot set failed\n"); + } + } else { + ipmi_kontron_nextboot_help(); + } + } + + else + { + printf("Invalid Kontron command: %s", argv[0]); + ipmi_kontron_help(); + rc = ERR_USAGE; + } + + return rc; +} + +static void ipmi_kontron_help(void) +{ + printf("Kontron Commands: setsn setmfgdate nextboot\n"); +} + +/* ipmi_fru_set_serial_number - Set the Serial Number in FRU + * + * @intf: ipmi interface + * @id: fru id + * + * returns -1 on error + * returns 1 if successful + */ +static int +ipmi_kontron_set_serial_number(void * intf) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct fru_info fru; + struct fru_header header; + uint8_t msg_data[4]; + char *sn; + uint8_t sn_size, checksum; + uint8_t *fru_data; + char *fru_area; + uint32_t fru_data_offset, fru_data_offset_tmp, board_sec_len, prod_sec_len, i; + uint8_t bus, sa, lun, mtype; + + sn = NULL; + fru_data = NULL; + + ipmi_get_mc(&bus, &sa, &lun, &mtype); + + memset(msg_data, 0, 4); + msg_data[0] = 0xb4; + msg_data[1] = 0x90; + msg_data[2] = 0x91; + msg_data[3] = 0x8b; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x3E; + req.msg.cmd = 0x0C; + req.msg.data = msg_data; + req.msg.data_len = 4; + + /* Set Lun, necessary for this oem command */ + req.msg.lun = 0x03; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf(" Device not present (No Response)\n"); + return (rv); + } + + if (rv > 0) + { + if (verbose) printf("sernum cmd ccode = %02x\n",rv); + printf(" This option is not implemented for this board\n"); +#ifdef TEST + strcpy(rsp,"serialnumber"); + rsp_len = 12; +#else + return (rv); +#endif + } + + sn_size = (uchar)rsp_len; + if (sn_size < 1) + { + printf(" Original serial number is zero length, was cleared.\n"); + return(ERR_BAD_LENGTH); + } + sn = malloc(sn_size + 1); + if(sn == NULL) + { + printf("Out of memory!"); + return(-1); + } + + memset(sn, 0, sn_size + 1); + memcpy(sn, rsp, sn_size); + + if(verbose >= 1) + { + printf("Original serial number is : [%s]\n", sn); + } + + memset(msg_data, 0, 4); + msg_data[0] = 0; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_INFO; + req.msg.data = msg_data; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) { + printf(" Device not present (No Response)\n"); + free(sn); + return (rv); + } + if (rv > 0) { + printf(" Device not present (%s)\n",decode_cc(0,rv)); + free(sn); + return (rv); + } + + fru.size = (rsp[1] << 8) | rsp[0]; + fru.access = rsp[2] & 0x1; + + if (fru.size < 1) { + printf(" Invalid FRU size %d", fru.size); + free(sn); + return(ERR_BAD_LENGTH); + } + + /* + * retrieve the FRU header + */ + msg_data[0] = 0; + msg_data[1] = 0; + msg_data[2] = 0; + msg_data[3] = 8; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_DATA; + req.msg.data = msg_data; + req.msg.data_len = 4; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf(" Device not present (No Response)\n"); + free(sn); + return(rv); + } + if (rv > 0) + { + printf(" Device not present (%s)\n",decode_cc(0,rv)); + free(sn); + return(rv); + } + + if (verbose >= 1) + print_buf(rsp, rsp_len, "FRU DATA"); + + memcpy(&header, rsp + 1, 8); + + if (header.version != 1) + { + printf(" Unknown FRU header version 0x%02x\n", header.version); + free(sn); + return(-1); + } + + /* Set the Board Section */ + board_sec_len = (header.offset.product * 8) - (header.offset.board * 8); + + rv = load_fru(sa,0, FRU_TYPE_BASEBOARD, &fru_data); + if (rv != 0) + { + printf(" Cannot Read FRU, error %d\n",rv); + free(sn); + if (fru_data != NULL) free(fru_data); + return(rv); + } + + if (verbose >= 1) + print_buf(fru_data, fru.size, "FRU BUFFER"); + + /*Position at Board Manufacturer*/ + fru_data_offset = (header.offset.board * 8) + 6; + fru_area = &fru_data[fru_data_offset]; + if (verbose) + printf("board_area: offset=0x%x len=%d\n",fru_data_offset,board_sec_len); + + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Board Product Name*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + fru_data_offset_tmp = fru_data_offset; + + /*Position at Serial Number*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); + if (fru_area == NULL) { + printf("Bad FRU area data read.\n"); + free(sn); + free(fru_data); + return(-1); + } + + fru_data_offset ++; + if (verbose) + printf("%x: Old board sernum [%s], New board sernum [%s]\n", + fru_data_offset,fru_area,sn); + + if (strlen(fru_area) != sn_size) + { + printf("The length of the serial number in the FRU Board Area is wrong.\n"); + free(sn); + free(fru_data); + return(ERR_BAD_LENGTH); + } + + /* Copy the new serial number in the board section saved in memory*/ + memcpy(fru_data + fru_data_offset, sn, sn_size); + + /* Calculate Header Checksum */ + checksum = 0; + for( i = (header.offset.board * 8); i < (((header.offset.board * 8)+board_sec_len) - 2) ; i ++ ) + { + checksum += fru_data[i]; + } + checksum = (~checksum) + 1; + fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum; + +#ifdef TEST + if (verbose >= 1) + print_buf(fru_data, fru.size, "FRU BUFFER, New"); + + /* Write the new FRU Board section */ + rv = write_fru_data(0, 0, fru_data, fru.size, verbose); + // if(write_fru_area(intf, &fru, 0, (header.offset.board * 8), (header.offset.board * 8), board_sec_len, fru_data) < 0) + if ( rv != 0 ) + { + printf(" Cannot Write FRU, error %d\n",rv); + free(sn); + free(fru_data); + return(rv); + } + + if (fru_data != NULL) { free(fru_data); fru_data = NULL; } + rv = load_fru(sa,0, FRU_TYPE_BASEBOARD, &fru_data); + if (rv != 0) + { + printf(" Cannot Read FRU, error %d\n",rv); + free(sn); + if (fru_data != NULL) free(fru_data); + return(rv); + } +#endif + + /* Set the Product Section */ + prod_sec_len = (header.offset.multi * 8) - (header.offset.product * 8); + + /*Position at Product Manufacturer*/ + fru_data_offset = (header.offset.product * 8) + 3; + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Product Name*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Product Part*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Product Version*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + + + fru_data_offset_tmp = fru_data_offset; + + /*Position at Serial Number*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); + + fru_data_offset ++; + if (verbose) + printf("%x: Old product sernum [%s], New product sernum [%s]\n", + fru_data_offset,fru_area,sn); + + if(strlen(fru_area) != sn_size) + { + free(sn); + free(fru_data); + printf("The length of the serial number in the FRU Product Area is wrong.\n"); + return(ERR_BAD_LENGTH); + } + + /* Copy the new serial number in the product section saved in memory*/ + memcpy(fru_data + fru_data_offset, sn, sn_size); + + /* Calculate Header Checksum */ + checksum = 0; + for( i = (header.offset.product * 8); i < (((header.offset.product * 8)+prod_sec_len) - 2) ; i ++ ) + { + checksum += fru_data[i]; + } + checksum = (~checksum) + 1; + fru_data[(header.offset.product * 8)+prod_sec_len - 1] = checksum; + + if (verbose >= 1) + print_buf(fru_data, fru.size, "FRU BUFFER, New"); + + /* Write the new FRU Board section */ + rv = write_fru_data(0, 0, fru_data, fru.size, (char)verbose); + if ( rv != 0 ) + { + printf(" Cannot Write FRU, error %d\n",rv); + /* fall through and free(sn); free(fru_data); return(rv); */ + } + + free(sn); + free(fru_data); + return(rv); +} + + +/* ipmi_fru_set_mfg_date - Set the Manufacturing Date in FRU + * + * @intf: ipmi interface + * @id: fru id + * + * returns -1 on error + * returns 1 if successful + */ +static int +ipmi_kontron_set_mfg_date (void * intf) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct fru_info fru; + struct fru_header header; + uint8_t msg_data[4]; + uint8_t mfg_date[3]; + + uint32_t board_sec_len, i; + uint8_t *fru_data, checksum; + uint8_t bus, sa, lun, mtype; + + ipmi_get_mc(&bus, &sa, &lun, &mtype); + + memset(msg_data, 0, 4); + msg_data[0] = 0xb4; + msg_data[1] = 0x90; + msg_data[2] = 0x91; + msg_data[3] = 0x8b; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x3E; + req.msg.cmd = 0x0E; + req.msg.data = msg_data; + req.msg.data_len = 4; + + /* Set Lun temporary, necessary for this oem command */ + req.msg.lun = 0x03; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf("Device not present (No Response)\n"); + return(rv); + } + + if (rv > 0) + { + printf("This option is not implemented for this board\n"); + return(rv); + } + + if(rsp_len != 3) + { + printf("Invalid response for the Manufacturing date\n"); + return(ERR_BAD_LENGTH); + } + if(rsp[0] == 0 && rsp[1] == 0 && rsp[2] == 0) + { + printf("Manufacturing date is zero, has been cleared\n"); + return(ERR_BAD_FORMAT); + } + + memset(mfg_date, 0, 3); + memcpy(mfg_date, rsp, 3); + + memset(msg_data, 0, 4); + msg_data[0] = 0; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_INFO; + req.msg.data = msg_data; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) { + printf(" Device not present (No Response)\n"); + return(rv); + } + if (rv > 0) { + printf(" Device not present (%s)\n",decode_cc(0,rv)); + return(rv); + } + + fru.size = (rsp[1] << 8) | rsp[0]; + fru.access = rsp[2] & 0x1; + + if (fru.size < 1) { + printf(" Invalid FRU size %d", fru.size); + return(ERR_BAD_LENGTH); + } + + /* + * retrieve the FRU header + */ + msg_data[0] = 0; + msg_data[1] = 0; + msg_data[2] = 0; + msg_data[3] = 8; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_DATA; + req.msg.data = msg_data; + req.msg.data_len = 4; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf(" Device not present (No Response)\n"); + return(rv); + } + if (rv > 0) + { + printf(" Device not present (%s)\n",decode_cc(0,rv)); + return(rv); + } + + if (verbose > 1) + print_buf(rsp, rsp_len, "FRU DATA"); + + memcpy(&header, &rsp[1], 8); + + if (header.version != 1) + { + printf(" Unknown FRU header version 0x%02x", + header.version); + return(ERR_BAD_FORMAT); + } + + + board_sec_len = (header.offset.product * 8) - (header.offset.board * 8); + + rv = load_fru(sa,0, FRU_TYPE_BASEBOARD, &fru_data); + if (rv != 0) +#ifdef NOT + /* do not re-read the same fru buffer */ + fru_data = malloc( fru.size); + if(fru_data == NULL) + { + printf("Out of memory!"); + return(-1); + } + + memset(fru_data, 0, fru.size); + rv = read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8) ,board_sec_len , fru_data); + if(rv < 0) +#endif + { + if (fru_data != NULL) free(fru_data); + return(rv); + } + + /* Copy the new manufacturing date in the board section saved in memory*/ + memcpy(fru_data + (header.offset.board * 8) + 3, mfg_date, 3); + + checksum = 0; + /* Calculate Header Checksum */ + for( i = (header.offset.board * 8); i < (((header.offset.board * 8)+board_sec_len) - 2) ; i ++ ) + { + checksum += fru_data[i]; + } + checksum = (~checksum) + 1; + + fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum; + + /* Write the new FRU Board section */ +#ifdef NOT + if(write_fru_area(intf, &fru, 0, (header.offset.board * 8), (header.offset.board * 8), board_sec_len, fru_data) < 0) +#endif + rv = write_fru_data(0, 0, fru_data, fru.size, (char)verbose); + if ( rv != 0 ) + { + printf(" Cannot Write FRU, error %d\n",rv); + /* fall through and free(fru_data); return(rv); */ + } + + free(fru_data); + return(rv); +} +#endif + +static char *assert_str(uchar val) +{ + char *pstr; + if ((val & 0x0f) == 0) pstr = "Deasserted"; + else pstr = "Asserted"; + return(pstr); +} + +/* + * decode_sel_kontron + * inputs: + * evt = the 16-byte IPMI SEL event + * outbuf = points to the output string buffer + * outsz = size of the output buffer + * outputs: + * rv = 0 if this event was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * outbuf = will contain the interpreted event text string (if rv==0) + */ +int decode_sel_kontron(uint8_t *evt, char *outbuf, int outsz, char fdesc, + char fdebug) +{ + int rv = -1; + uint16_t id; + uint8_t rectype; + int oemid; + uint32_t timestamp; + char timestr[40]; + char mybuf[64]; + char oembuf[64]; + char *type_str = NULL; + char *gstr = NULL; + char *pstr = NULL; + int sevid; + ushort genid; + uchar snum; + int isdr = 0; + char *p1, *p2; + + sevid = SEV_INFO; + id = evt[0] + (evt[1] << 8); + /* instead try to decode some events manually */ + rectype = evt[2]; + timestamp = evt[3] + (evt[4] << 8) + (evt[5] << 16) + (evt[6] << 24); + genid = evt[7] | (evt[8] << 8); + snum = evt[11]; + if (rectype == 0xc1) { /* OEM type C1 */ + oemid = evt[7] + (evt[8] << 8) + (evt[9] << 16); + if (oemid == VENDOR_KONTRON) { + fmt_time(timestamp, timestr, sizeof(timestr)); + type_str = "Kontron"; + gstr = "BMC "; + switch(evt[10]) { + case 0x01: + default: + sprintf(mybuf,"OEM Event %02x %02x %02x %02x %02x %02x", + evt[10], evt[11], evt[12], evt[13], evt[14], evt[15]); + break; + } + snprintf(outbuf, outsz, "%04x %s %s %s %s %s\n", + id,timestr,get_sev_str(sevid), gstr, type_str, mybuf); + rv = 0; + } /*endif kontron*/ + } else if (rectype == 0x02) { + type_str = ""; + gstr = "BMC "; + sprintf(mybuf,"%02x [%02x %02x %02x]", evt[12],evt[13],evt[14],evt[15]); + switch(evt[10]) { /*sensor type*/ + /* TODO: 0xC0, 0xC2, 0xC6 */ + case 0xCF: /* Board Reset */ + type_str = "Board Reset"; + if (evt[12] == 0x03) { /*event trigger/type = discrete [de]assert */ + pstr = ""; /*default*/ + switch(evt[13]) { /*data1/offset*/ + case 0x01: + pstr = "Asserted"; + break; + case 0xa1: /*data2,3 bytes have meaning*/ + /* data2: usually 0x01 */ + /* data3: 05, 08, ff */ + switch(evt[14]) { /*data2*/ + case 0x00: p1 = "warm reset"; break; + case 0x01: p1 = "cold reset"; break; + case 0x02: p1 = "forced cold"; break; + case 0x03: p1 = "soft reset"; break; + case 0x04: p1 = "hard reset"; break; + case 0x05: p1 = "forced hard"; break; + default: p1 = "other"; break; + } + switch(evt[15]) { /*data3*/ + case 0x00: p2 = "IPMI watchdog"; break; + case 0x01: p2 = "IPMI command"; break; + case 0x02: p2 = "Proc check stop"; break; /*internal*/ + case 0x03: p2 = "Proc reset request"; break; /*internal*/ + case 0x04: p2 = "Reset button"; break; + case 0x05: p2 = "Power up"; break; + case 0x06: p2 = "Legacy int watchdog"; break; /*internal*/ + case 0x07: p2 = "Legacy prg watchdog"; break; /*programmable*/ + case 0x08: p2 = "Software initiated"; break; + case 0x09: p2 = "Setup reset"; break; + case 0x0a: p2 = "Power cycle"; break; + default: p2 = "Other"; break; + } + sprintf(oembuf,"%s/%s",p1,p2); + pstr = oembuf; + break; + default: break; + } + rv = 0; + } + break; + case 0x12: /* System Event */ + /* snum 38, 6f 00, or ef 00 */ + /* if (snum == 0x38) */ + type_str = "System Event"; + if (evt[12] == 0x6f) pstr = assert_str(1); /*asserted*/ + else pstr = assert_str(0); /*0xef means deasserted*/ + rv = 0; + break; + case 0x24: /* Platform Alert */ + /* usu 03 01 */ + type_str = "Platform Alert"; + pstr = assert_str(evt[13]); /*data1*/ + rv = 0; + break; + case 0x2B: /* Version Change */ + /* 6f c1 02 ff */ + type_str = "Version Change"; + if ((evt[13] & 0x80) == 0) pstr = ""; + else switch(evt[14]) { /*data2*/ + case 0x01: pstr = "HW Changed"; break; + case 0x02: pstr = "SW Changed"; break; + case 0x03: pstr = "HW incompatible"; break; + default: pstr = "Change failed"; break; /*TODO: add detail here*/ + } + rv = 0; + break; + case 0x70: + type_str = "OEM Firmware Info 1"; + pstr = assert_str(evt[13]); /*data1*/ + rv = 0; + break; + case 0x71: + type_str = "OEM Firmware Info 2"; + pstr = assert_str(evt[13]); /*data1*/ + rv = 0; + break; + default: break; + } + if (rv == 0) { + format_event(id,timestamp, sevid, genid, type_str, + snum,NULL,pstr,mybuf,outbuf,outsz); + } + } + return rv; +} /*end decode_sel_kontron*/ + +int decode_sensor_kontron(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + uchar stype; + char *pstr = NULL; + int rdval; + + if (sdr == NULL || reading == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + if (sdr[3] != 0x02) return(rv); /*skip if not compact sensor*/ + stype = sdr[12]; + rdval = reading[2] | ((reading[3] & 0x7f) << 8); + /* usually reading3 == 0x80 */ + switch(stype) { + case 0x08: /* Power Supply or PwrGood ... */ + if (sdr[14] == 0x02) { + if (reading[2] & 0x02) pstr = "Failed"; + else pstr = "OK"; + rv = 0; + } + break; + case 0xC0: /* IPMI Info-N */ + if (reading[2] == 0) pstr = "OK"; + else pstr = "Asserted"; + rv = 0; + break; + case 0xC2: /* IniAgent Err */ + if ((reading[2] & 0x01) == 1) pstr = "OK"; + else pstr = "Error"; /*could be 0x02*/ + rv = 0; + break; + case 0xC6: /* POST Value */ + pstr = (char *)val2str((ushort)rdval,ktc5520_post); + if (pstr == NULL) { + if (rdval >= 0x61 && rdval <= 0x71) pstr = "Error"; + else if (rdval >= 0xDD && rdval <= 0xDE) pstr = "DIMM Debug"; + else pstr = "Other"; + } + rv = 0; + break; + case 0xCF: /* Board Reset */ + if ((reading[2] & 0x01) == 1) pstr = "OK"; + else pstr = "Asserted"; + rv = 0; + break; + default: + break; + } + if (rv == 0) strncpy(pstring, pstr, slen); + return(rv); +} + +/* end oem_kontron.c */ diff --git a/util/oem_kontron.h b/util/oem_kontron.h new file mode 100644 index 0000000..b95e6a6 --- /dev/null +++ b/util/oem_kontron.h @@ -0,0 +1,80 @@ +/*
+ * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved.
+ *
+ * Base on code from
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef IPMI_KONTRONOEM_H
+#define IPMI_KONTRONOEM_H
+
+
+#define IPMI_BUF_SIZE 1024
+#ifdef HAVE_LANPLUS
+#include "../lib/lanplus/lanplus_defs.h"
+#endif
+
+#define TRUE 1
+#define FALSE 0
+
+#define IPMI_NETFN_APP 0x06
+#define IPMI_NETFN_STORAGE 0x0a
+#define IPMI_NETFN_PICMG 0x2C
+
+#define IPMI_BMC_SLAVE_ADDR 0x20
+
+#define BMC_GET_DEVICE_ID 0x1
+#define GET_FRU_INFO 0x10
+#define GET_FRU_DATA 0x11
+
+#pragma pack(1)
+struct fru_info {
+ uint16_t size;
+ uint8_t access:1;
+};
+struct fru_header {
+ uint8_t version;
+ struct {
+ uint8_t internal;
+ uint8_t chassis;
+ uint8_t board;
+ uint8_t product;
+ uint8_t multi;
+ } offset;
+ uint8_t pad;
+ uint8_t checksum;
+};
+#pragma pack()
+
+/* the ERRs are defined in ipmicmd.h */
+int ipmi_kontronoem_main(void *intf, int argc, char **argv);
+
+#endif /* IPMI_KONTRONOEM_H */
diff --git a/util/oem_newisys.c b/util/oem_newisys.c new file mode 100644 index 0000000..7b78532 --- /dev/null +++ b/util/oem_newisys.c @@ -0,0 +1,129 @@ +/* + * oem_newisys.c + * + * This module handles OEM-specific functions for newisys firmware. + * + * Copyright (c) 2012 Kontron America, Inc. + * + * 04/05/12 Andy Cress v1.0 new, with input from ipmitool + */ +/*M* +Copyright (c) 2012 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#endif +#include <stdio.h> +#include <string.h> +#include <time.h> +#include "ipmicmd.h" +#include "ievents.h" + +static char fdebug = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + +#define DESC_MAX 200 +/* + * decode_sel_newisys + * inputs: + * evt = the 16-byte IPMI SEL event + * outbuf = points to the output string buffer + * outsz = size of the output buffer + * outputs: + * rv = 0 if this event was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * outbuf = will contain the interpreted event text string (if rv==0) + */ +int decode_sel_newisys(uchar *evt, char *outbuf, int outsz, char fdesc, + char fdbg) +{ + int rv = -1; + ushort id, genid; + ulong timestamp; + char *type_str = NULL; + char *gstr = NULL; + char *pstr = NULL; + int sevid; + char description[DESC_MAX]; + int rlen, i; + uchar idata[16]; + uchar rdata[DESC_MAX]; + uchar cc; + uchar snum, stype, rectype; + + fdebug = fdbg; + id = evt[0] + (evt[1] << 8); + rectype = evt[2]; + timestamp = evt[3] + (evt[4] << 8) + (evt[5] << 16) + (evt[6] << 24); + genid = evt[7] | (evt[8] << 8); + stype = evt[10]; + snum = evt[11]; + gstr = "BMC "; + if (genid == 0x0033) gstr = "Bios"; + type_str = ""; + if (rectype == 0x02) type_str = get_sensor_type_desc(stype); + sevid = SEV_INFO; + + idata[0] = 0x15; /* IANA LSB */ + idata[1] = 0x24; /* IANA */ + idata[2] = 0x00; /* IANA MSB */ + idata[3] = 0x01; /* Subcommand */ + idata[4] = id & 0x00FF; /* SEL Record ID LSB */ + idata[5] = (id & 0xFF00) >> 8; /* SEL Record ID MSB */ + rlen = sizeof(rdata); + rv = ipmi_cmdraw(0x01, 0x2E, g_sa,g_bus,g_lun, + idata, 6, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + + if (rv == 0) { + if (rlen < 5) { + printf("Newisys OEM response too short"); + return LAN_ERR_TOO_SHORT; + } else if (rlen != (4 + rdata[3])) { + printf("Newisys OEM response has unexpected length"); + return LAN_ERR_TOO_SHORT; + } + + /* copy the description */ + i = rdata[3]; + if (i >= DESC_MAX) i = DESC_MAX - 1; + if (i > (rlen-4)) i = rlen - 4; + memcpy(description, &rdata[4], i); + description[i] = 0;; + pstr = description; + /*TODO: parse for severity, setting sevid */ + + format_event(id,timestamp, sevid, genid, type_str, + snum,NULL,pstr,NULL,outbuf,outsz); + } + return rv; +} + +/* end oem_newisys.c */ diff --git a/util/oem_quanta.c b/util/oem_quanta.c new file mode 100644 index 0000000..a0ee3bb --- /dev/null +++ b/util/oem_quanta.c @@ -0,0 +1,142 @@ +/* + * oem_quanta.c + * Handle Quanta OEM command functions + * + * Change history: + * 01/11/2012 ARCress - included in source tree + * + *--------------------------------------------------------------------- + */ +/*M* +Copyright (c) 2010 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#endif +#include <stdio.h> +#include <string.h> +#include <time.h> +#include "ipmicmd.h" +#include "ievents.h" + +extern int decode_sensor_intel_nm(uchar *sdr,uchar *reading, + char *pstring,int slen); /*oem_intel.c*/ +static char fdbg = 0; + +/* + * decode_sensor_quanta + * inputs: + * sdr = the SDR buffer + * reading = the 3 or 4 bytes of data from GetSensorReading + * pstring = points to the output string buffer + * slen = size of the output buffer + * outputs: + * rv = 0 if this sensor was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * pstring = contains the sensor reading interpretation string (if rv==0) + */ +int decode_sensor_quanta(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + int vend, prod; + + if (sdr == NULL || reading == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + get_mfgid(&vend,&prod); /*saved from ipmi_getdeviceid */ + if (vend != VENDOR_QUANTA) return(rv); + if (prod != PRODUCT_QUANTA_S99Q) return(rv); /*only handle S99Q product*/ + if (sdr[3] != 0x02) return(rv); /*skip if not compact sensor*/ + + /* OEM SDR for Intel Node Manager */ + rv = decode_sensor_intel_nm(sdr,reading,pstring,slen); + return(rv); +} + +/* + * decode_sel_quanta + * inputs: + * evt = the 16-byte IPMI SEL event + * outbuf = points to the output string buffer + * outsz = size of the output buffer + * outputs: + * rv = 0 if this event was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * outbuf = will contain the interpreted event text string (if rv==0) + * + * Also case 7 was added to mem_str() in ievents.c for Quanta QSSC-S4R. + */ +int decode_sel_quanta(uchar *evt, char *outbuf, int outsz, char fdesc, + char fdebug) +{ + int rv = -1; + ushort id; + uchar rectype; + ulong timestamp; + char mybuf[64]; + char *type_str = ""; + char *gstr = NULL; + char *pstr = NULL; + int sevid; + ushort genid; + uchar snum; + int vend, prod; + + fdbg = fdebug; + get_mfgid(&vend,&prod); /*saved from ipmi_getdeviceid */ + if (vend != VENDOR_QUANTA) return(rv); + if (prod != PRODUCT_QUANTA_S99Q) return(rv); /*only handle S99Q product*/ + + sevid = SEV_INFO; + id = evt[0] + (evt[1] << 8); + rectype = evt[2]; + snum = evt[11]; + timestamp = evt[3] + (evt[4] << 8) + (evt[5] << 16) + (evt[6] << 24); + genid = evt[7] | (evt[8] << 8); + if (genid == 0x0033) gstr = "Bios"; + else gstr = "BMC "; + if (rectype == 0x02) { + sprintf(mybuf,"%02x [%02x %02x %02x]", evt[12],evt[13],evt[14],evt[15]); + switch(evt[10]) { /*sensor type*/ + case 0xC0: /* CPU Temp Sensor, EvTyp=0x70 */ + switch(evt[13]) { /*offset/data1*/ + case 0x02: pstr = "Overheat"; sevid = SEV_MAJ; rv = 0; break; + default: break; + } + break; + default: + break; + } + } + if (rv == 0) { + format_event(id,timestamp, sevid, genid, type_str, + snum,NULL,pstr,mybuf,outbuf,outsz); + } + + return(rv); +} + +/* end oem_quanta.c */ diff --git a/util/oem_sun.c b/util/oem_sun.c new file mode 100644 index 0000000..da413a8 --- /dev/null +++ b/util/oem_sun.c @@ -0,0 +1,1058 @@ +/* + * oem_sun.c + * Handle Sun OEM command functions + * + * Change history: + * 09/02/2010 ARCress - included in source tree + * + *--------------------------------------------------------------------- + */ +/* + * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#ifdef WIN32 +#include <windows.h> +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +#include "getopt.h" +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <ctype.h> +#include <limits.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#include <stdint.h> +#else +#include <getopt.h> +#endif +#endif + +#ifndef ULONG_MAX +/*needed for WIN32*/ +#define ULONG_MAX 4294967295UL +#define UCHAR_MAX 255 +#endif + +#include "ipmicmd.h" +#include "isensor.h" +#include "oem_sun.h" + +extern int verbose; /*ipmilanplus.c*/ +extern void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/ +extern void set_loglevel(int level); + +static const struct valstr sunoem_led_type_vals[] = { + { 0, "OK2RM" }, + { 1, "SERVICE" }, + { 2, "ACT" }, + { 3, "LOCATE" }, + { 0xFF, NULL } +}; + +static const struct valstr sunoem_led_mode_vals[] = { + { 0, "OFF" }, + { 1, "ON" }, + { 2, "STANDBY" }, + { 3, "SLOW" }, + { 4, "FAST" }, + { 0xFF, NULL } +}; +static const struct valstr sunoem_led_mode_optvals[] = { + { 0, "STEADY_OFF" }, + { 1, "STEADY_ON" }, + { 2, "STANDBY_BLINK" }, + { 3, "SLOW_BLINK" }, + { 4, "FAST_BLINK" }, + { 0xFF, NULL } +}; + +/* global variables */ +static char * progname = "isunoem"; +static char * progver = "2.93"; +static char fdebug = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static int is_sbcmd = 0; +static int csv_output = 0; +static uchar *sdrcache = NULL; +static int vend_id = 0; +static int prod_id = 0; + +static void +ipmi_sunoem_usage(void) +{ + lprintf(LOG_NOTICE, "usage: sunoem <command> [option...]"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " fan speed <0-100>"); + lprintf(LOG_NOTICE, " Set system fan speed (PWM duty cycle)"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " sshkey set <userid> <id_rsa.pub>"); + lprintf(LOG_NOTICE, " Set ssh key for a userid into authorized_keys,"); + lprintf(LOG_NOTICE, " view users with 'user list' command."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " sshkey del <userid>"); + lprintf(LOG_NOTICE, " Delete ssh key for userid from authorized_keys,"); + lprintf(LOG_NOTICE, " view users with 'user list' command."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " led get <sensorid> [ledtype]"); + lprintf(LOG_NOTICE, " Read status of LED found in Generic Device Locator."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " led set <sensorid> <ledmode> [ledtype]"); + lprintf(LOG_NOTICE, " Set mode of LED found in Generic Device Locator."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " sbled get <sensorid> [ledtype]"); + lprintf(LOG_NOTICE, " Read status of LED found in Generic Device Locator"); + lprintf(LOG_NOTICE, " for Sun Blade Modular Systems."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " sbled set <sensorid> <ledmode> [ledtype]"); + lprintf(LOG_NOTICE, " Set mode of LED found in Generic Device Locator"); + lprintf(LOG_NOTICE, " for Sun Blade Modular Systems."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " Use 'sdr list generic' command to get list of Generic"); + lprintf(LOG_NOTICE, " Devices that are controllable LEDs."); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " Required SIS LED Mode:"); + lprintf(LOG_NOTICE, " OFF Off"); + lprintf(LOG_NOTICE, " ON Steady On"); + lprintf(LOG_NOTICE, " STANDBY 100ms on 2900ms off blink rate"); + lprintf(LOG_NOTICE, " SLOW 1HZ blink rate"); + lprintf(LOG_NOTICE, " FAST 4HZ blink rate"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " Optional SIS LED Type:"); + lprintf(LOG_NOTICE, " OK2RM OK to Remove"); + lprintf(LOG_NOTICE, " SERVICE Service Required"); + lprintf(LOG_NOTICE, " ACT Activity"); + lprintf(LOG_NOTICE, " LOCATE Locate"); + lprintf(LOG_NOTICE, ""); +} + +/* + * IPMI Request Data: 1 byte + * + * [byte 0] FanSpeed Fan speed as percentage + */ +static int +ipmi_sunoem_fan_speed(void * intf, uint8_t speed) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + /* + * sunoem fan speed <percent> + */ + + if (speed > 100) { + lprintf(LOG_NOTICE, "Invalid fan speed: %d", speed); + return -1; + } + + req.msg.netfn = IPMI_NETFN_SUNOEM; + req.msg.cmd = IPMI_SUNOEM_SET_FAN_SPEED; + req.msg.data = &speed; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) { + lprintf(LOG_ERR, "Sun OEM Set Fan Speed command failed"); + return (rv); + } else if (rv > 0) { + lprintf(LOG_ERR, "Sun OEM Set Fan Speed command failed: %s", + decode_cc(0,rv)); + return (rv); + } + + printf("Set Fan speed to %d%%\n", speed); + + return rv; +} + + +static void +led_print(const char * name, uint8_t state) +{ + if (csv_output) + printf("%s,%s\n", name, val2str(state, sunoem_led_mode_vals)); + else + printf("%-16s | %s\n", name, val2str(state, sunoem_led_mode_vals)); +} + +int +sunoem_led_get(void * intf, uchar *sdr, uchar ledtype, uchar *prsp) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + uint8_t rqdata[7]; + int rqdata_len = 5; + struct sdr_record_generic_locator * dev; + + if (sdr == NULL) return -1; + dev = (struct sdr_record_generic_locator *)&sdr[5]; + + rqdata[0] = dev->dev_slave_addr; + if (ledtype == 0xFF) + rqdata[1] = dev->oem; + else + rqdata[1] = ledtype; + rqdata[2] = dev->dev_access_addr; + rqdata[3] = dev->oem; + if (is_sbcmd) { + rqdata[4] = dev->entity.id; + rqdata[5] = dev->entity.instance; + rqdata[6] = 0; + rqdata_len = 7; + } + else { + rqdata[4] = 0; + } + + req.msg.netfn = IPMI_NETFN_SUNOEM; + req.msg.cmd = IPMI_SUNOEM_LED_GET; + req.msg.lun = dev->lun; + req.msg.data = rqdata; + req.msg.data_len = (uchar)rqdata_len; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) { + lprintf(LOG_ERR, "Sun OEM Get LED command failed"); + return rv; + } + else if (rv > 0) { + lprintf(LOG_ERR, "Sun OEM Get LED command failed: %s", + decode_cc(0,rv)); + return rv; + } + if (prsp != NULL) memcpy(prsp,rsp,rsp_len); + if (rsp_len != 1) { + lprintf(LOG_ERR, "Sun OEM Get LED command error len=%d", + rsp_len); + return -1; + } + return rv; +} + +int +sunoem_led_set(void * intf, uchar *sdr, uchar ledtype, uchar ledmode) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + uint8_t rqdata[9]; + int rqdata_len = 7; + struct sdr_record_generic_locator * dev; + + if (sdr == NULL) return -1; + dev = (struct sdr_record_generic_locator *)&sdr[5]; + + rqdata[0] = dev->dev_slave_addr; + if (ledtype == 0xFF) + rqdata[1] = dev->oem; + else + rqdata[1] = ledtype; + rqdata[2] = dev->dev_access_addr; + rqdata[3] = dev->oem; + rqdata[4] = ledmode; + if (is_sbcmd) { + rqdata[5] = dev->entity.id; + rqdata[6] = dev->entity.instance; + rqdata[7] = 0; + rqdata[8] = 0; + rqdata_len = 9; + } + else { + rqdata[5] = 0; + rqdata[6] = 0; + } + + req.msg.netfn = IPMI_NETFN_SUNOEM; + req.msg.cmd = IPMI_SUNOEM_LED_SET; + req.msg.lun = dev->lun; + req.msg.data = rqdata; + req.msg.data_len = (uchar)rqdata_len; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) { + lprintf(LOG_ERR, "Sun OEM Set LED command failed"); + } else if (rv > 0) { + lprintf(LOG_ERR, "Sun OEM Set LED command failed: %s", + decode_cc(0,rv)); + } + return rv; +} + +static void +sunoem_led_get_byentity(void * intf, uchar entity_id, + uchar entity_inst, uchar ledtype) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rv; + uchar *elist; + struct entity_id entity; + struct sdr_record_generic_locator *dev; + uchar sdr[IPMI_RSPBUF_SIZE]; + ushort id; + + if (entity_id == 0) + return; + + /* lookup sdrs with this entity */ + memset(&entity, 0, sizeof(struct entity_id)); + entity.id = entity_id; + entity.instance = entity_inst; + + if (sdrcache == NULL) rv = get_sdr_cache(&elist); + else elist = sdrcache; + id = 0; + /* for each generic sensor set its led state */ + while(find_sdr_next(sdr,elist,id) == 0) { + id = sdr[0] + (sdr[1] << 8); + if (sdr[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) + continue; + dev = (struct sdr_record_generic_locator *)&sdr[5]; + if ((dev->entity.id == entity_id) && + (dev->entity.instance == entity_inst)) { + rv = sunoem_led_get(intf, sdr, ledtype, rsp); + if (rv == 0) { + led_print((const char *)dev->id_string, rsp[0]); + } + } + } + + if (sdrcache == NULL) free_sdr_cache(elist); +} + +static void +sunoem_led_set_byentity(void * intf, uchar entity_id, + uchar entity_inst, uchar ledtype, uchar ledmode) +{ + int rv; + uchar *elist; + struct entity_id entity; + struct sdr_record_generic_locator * dev; + uchar sdr[IPMI_RSPBUF_SIZE]; + ushort id; + + if (entity_id == 0) + return; + + /* lookup sdrs with this entity */ + memset(&entity, 0, sizeof(struct entity_id)); + entity.id = entity_id; + entity.instance = entity_inst; + + if (sdrcache == NULL) rv = get_sdr_cache(&elist); + else elist = sdrcache; + id = 0; + /* for each generic sensor set its led state */ + while(find_sdr_next(sdr,elist,id) == 0) { + id = sdr[0] + (sdr[1] << 8); + if (sdr[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) + continue; + /* match entity_id and entity_inst */ + dev = (struct sdr_record_generic_locator *)&sdr[5]; + if ((dev->entity.id == entity_id) && + (dev->entity.instance == entity_inst)) { + rv = sunoem_led_set(intf, sdr, ledtype, ledmode); + if (rv == 0) { + led_print((const char *)dev->id_string, ledmode); + } + } + } + + if (sdrcache == NULL) free_sdr_cache(elist); +} + +/* + * IPMI Request Data: 5 bytes + * + * [byte 0] devAddr Value from the "Device Slave Address" field in + * LED's Generic Device Locator record in the SDR + * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE + * [byte 2] ctrlrAddr Controller address; value from the "Device + * Access Address" field, 0x20 if the LED is local + * [byte 3] hwInfo The OEM field from the SDR record + * [byte 4] force 1 = directly access the device + * 0 = go thru its controller + * Ignored if LED is local + * + * The format below is for Sun Blade Modular systems only + * [byte 4] entityID The entityID field from the SDR record + * [byte 5] entityIns The entityIns field from the SDR record + * [byte 6] force 1 = directly access the device + * 0 = go thru its controller + * Ignored if LED is local + */ +static int +ipmi_sunoem_led_get(void * intf, int argc, char ** argv) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rv; + uchar *alist; + struct sdr_record_entity_assoc *assoc; + struct sdr_record_generic_locator * dev; + uchar sdr[IPMI_RSPBUF_SIZE]; + uchar sdr1[IPMI_RSPBUF_SIZE]; + ushort id; + uchar ledtype = 0xFF; + int i; + + /* + * sunoem led/sbled get <id> [type] + */ + + if (argc < 1 || strncmp(argv[0], "help", 4) == 0) { + ipmi_sunoem_usage(); + return 0; + } + + if (argc > 1) { + ledtype = (uchar)str2val(argv[1], sunoem_led_type_vals); + if (ledtype == 0xFF) + lprintf(LOG_ERR, "Unknown ledtype, will use data from the SDR oem field"); + } + + if (strncasecmp(argv[0], "all", 3) == 0) { + /* do all generic sensors */ + lprintf(LOG_NOTICE, "Fetching SDRs ..."); + rv = get_sdr_cache(&alist); + if (fdebug) lprintf(LOG_NOTICE, "get_sdr_cache rv = %d",rv); + id = 0; + rv = ERR_NOT_FOUND; + while(find_sdr_next(sdr,alist,id) == 0) { + id = sdr[0] + (sdr[1] << 8); + if (sdr[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) + continue; + dev = (struct sdr_record_generic_locator *)&sdr[5]; + if (dev->entity.logical) // (sdr[13] & 0x80 != 0) + continue; + rv = sunoem_led_get(intf, sdr, ledtype, rsp); + if (rv == 0) { + led_print((const char *)dev->id_string, rsp[0]); + } + } + free_sdr_cache(alist); + return rv; + } + + /* look up generic device locator record in SDR */ + id = (ushort)atoi(argv[0]); + lprintf(LOG_NOTICE, "Fetching SDRs ..."); + rv = get_sdr_cache(&alist); + if (fdebug) lprintf(LOG_NOTICE, "get_sdr_cache rv = %d",rv); + if (rv == 0) { + sdrcache = alist; + rv = find_sdr_next(sdr1,alist,id); + } + if (rv != 0) { + lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]); + free_sdr_cache(alist); + return (rv); + } + + if (sdr1[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) { + lprintf(LOG_ERR, "Invalid SDR type %d", sdr1[3]); + free_sdr_cache(alist); + return (-1); + } + + dev = (struct sdr_record_generic_locator *)&sdr1[5]; + if (!dev->entity.logical) { + /* + * handle physical entity + */ + rv = sunoem_led_get(intf, sdr1, ledtype, rsp); + if (rv == 0) { + led_print((const char *)dev->id_string, rsp[0]); + } + free_sdr_cache(alist); + return rv; + } + + /* + * handle logical entity for LED grouping + */ + + lprintf(LOG_INFO, "LED %s is logical device", argv[0]); + + /* get entity assoc records */ + // rv = get_sdr_cache(&alist); + id = 0; + while(find_sdr_next(sdr,alist,id) == 0) { + id = sdr[0] + (sdr[1] << 8); + if (sdr[3] != SDR_RECORD_TYPE_ENTITY_ASSOC) + continue; + assoc = (struct sdr_record_entity_assoc *)&sdr[5]; + if (assoc == NULL) continue; + /* check that the entity id/instance matches our generic record */ + if (assoc->entity.id != dev->entity.id || + assoc->entity.instance != dev->entity.instance) + continue; + + if (assoc->flags.isrange) { + /* + * handle ranged entity associations + * + * the test for non-zero entity id is handled in + * sunoem_led_get_byentity() + */ + + /* first range set - id 1 and 2 must be equal */ + if (assoc->entity_id_1 == assoc->entity_id_2) + for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++) + sunoem_led_get_byentity(intf, assoc->entity_id_1, (uchar)i, ledtype); + + /* second range set - id 3 and 4 must be equal */ + if (assoc->entity_id_3 == assoc->entity_id_4) + for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++) + sunoem_led_get_byentity(intf, assoc->entity_id_3, (uchar)i, ledtype); + } + else { + /* + * handle entity list + */ + sunoem_led_get_byentity(intf, assoc->entity_id_1, + assoc->entity_inst_1, ledtype); + sunoem_led_get_byentity(intf, assoc->entity_id_2, + assoc->entity_inst_2, ledtype); + sunoem_led_get_byentity(intf, assoc->entity_id_3, + assoc->entity_inst_3, ledtype); + sunoem_led_get_byentity(intf, assoc->entity_id_4, + assoc->entity_inst_4, ledtype); + } + } + + free_sdr_cache(alist); + sdrcache = NULL; + + return rv; +} + +/* + * IPMI Request Data: 7 bytes + * + * [byte 0] devAddr Value from the "Device Slave Address" field in + * LED's Generic Device Locator record in the SDR + * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE + * [byte 2] ctrlrAddr Controller address; value from the "Device + * Access Address" field, 0x20 if the LED is local + * [byte 3] hwInfo The OEM field from the SDR record + * [byte 4] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST + * [byte 5] force TRUE - directly access the device + * FALSE - go thru its controller + * Ignored if LED is local + * [byte 6] role Used by BMC for authorization purposes + * + * The format below is for Sun Blade Modular systems only + * [byte 5] entityID The entityID field from the SDR record + * [byte 6] entityIns The entityIns field from the SDR record + * [byte 7] force TRUE - directly access the device + * FALSE - go thru its controller + * Ignored if LED is local + * [byte 8] role Used by BMC for authorization purposes + * + * + * IPMI Response Data: 1 byte + * + * [byte 0] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST + */ + +static int +ipmi_sunoem_led_set(void * intf, int argc, char ** argv) +{ + int rv; + uchar *alist; + struct sdr_record_entity_assoc *assoc; + struct sdr_record_generic_locator * dev; + uchar sdr[IPMI_RSPBUF_SIZE]; + uchar sdr1[IPMI_RSPBUF_SIZE]; + ushort id; + uchar ledmode; + uchar ledtype = 0xFF; + int i; + + /* + * sunoem led/sbled set <id> <mode> [type] + */ + + if (argc < 2 || strncmp(argv[0], "help", 4) == 0) { + ipmi_sunoem_usage(); + return 0; + } + + i = str2val(argv[1], sunoem_led_mode_vals); + if (i == 0xFF) { + i = str2val(argv[1], sunoem_led_mode_optvals); + if (i == 0xFF) { + lprintf(LOG_NOTICE, "Invalid LED Mode: %s", argv[1]); + return -1; + } + } + ledmode = (uchar)i; + + if (argc > 3) { + ledtype = (uchar)str2val(argv[2], sunoem_led_type_vals); + if (ledtype == 0xFF) + lprintf(LOG_ERR, "Unknown ledtype, will use data from the SDR oem field"); + } + + if (strncasecmp(argv[0], "all", 3) == 0) { + /* do all generic sensors */ + lprintf(LOG_NOTICE, "Fetching SDRs ..."); + rv = get_sdr_cache(&alist); + if (fdebug) lprintf(LOG_NOTICE, "get_sdr_cache rv = %d",rv); + id = 0; + rv = ERR_NOT_FOUND; + while(find_sdr_next(sdr,alist,id) == 0) { + id = sdr[0] + (sdr[1] << 8); + if (sdr[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) + continue; + dev = (struct sdr_record_generic_locator *)&sdr[5]; + if ((sdr[13] & 0x80) != 0) /*logical entity*/ + continue; + rv = sunoem_led_set(intf, sdr, ledtype, ledmode); + if (rv == 0) { + led_print((const char *)dev->id_string, ledmode); + } + } + free_sdr_cache(alist); + return rv; + } + + /* look up generic device locator records in SDR */ + id = (ushort)atoi(argv[0]); + lprintf(LOG_NOTICE, "Fetching SDRs ..."); + rv = get_sdr_cache(&alist); + if (fdebug) lprintf(LOG_NOTICE, "get_sdr_cache rv = %d",rv); + if (rv == 0) { + sdrcache = alist; + rv = find_sdr_next(sdr1,alist,id); + } + if (rv != 0) { + lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]); + free_sdr_cache(alist); + return (rv); + } + + if (sdr1[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) { + lprintf(LOG_ERR, "Invalid SDR type %d", sdr1[3]); + free_sdr_cache(alist); + return -1; + } + dev = (struct sdr_record_generic_locator *)&sdr1[5]; + + if (!dev->entity.logical) { + /* + * handle physical entity + */ + rv = sunoem_led_set(intf, sdr, ledtype, ledmode); + if (rv == 0) { + led_print(argv[0], ledmode); + } + free_sdr_cache(alist); + return rv; + } + + /* + * handle logical entity for LED grouping + */ + + lprintf(LOG_INFO, "LED %s is logical device", argv[0]); + + /* get entity assoc records */ + id = 0; + while(find_sdr_next(sdr,alist,id) == 0) { + id = sdr[0] + (sdr[1] << 8); + if (sdr[3] != SDR_RECORD_TYPE_ENTITY_ASSOC) + continue; + assoc = (struct sdr_record_entity_assoc *)&sdr[5]; + if (assoc == NULL) continue; + + /* check that the entity id/instance matches our generic record */ + if (assoc->entity.id != dev->entity.id || + assoc->entity.instance != dev->entity.instance) + continue; + + if (assoc->flags.isrange) { + /* + * handle ranged entity associations + * + * the test for non-zero entity id is handled in + * sunoem_led_get_byentity() + */ + + /* first range set - id 1 and 2 must be equal */ + if (assoc->entity_id_1 == assoc->entity_id_2) + for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++) + sunoem_led_set_byentity(intf, assoc->entity_id_1, (uchar)i, ledtype, ledmode); + + /* second range set - id 3 and 4 must be equal */ + if (assoc->entity_id_3 == assoc->entity_id_4) + for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++) + sunoem_led_set_byentity(intf, assoc->entity_id_3, (uchar)i, ledtype, ledmode); + } + else { + /* + * handle entity list + */ + sunoem_led_set_byentity(intf, assoc->entity_id_1, + assoc->entity_inst_1, ledtype, ledmode); + sunoem_led_set_byentity(intf, assoc->entity_id_2, + assoc->entity_inst_2, ledtype, ledmode); + sunoem_led_set_byentity(intf, assoc->entity_id_3, + assoc->entity_inst_3, ledtype, ledmode); + sunoem_led_set_byentity(intf, assoc->entity_id_4, + assoc->entity_inst_4, ledtype, ledmode); + } + } + + free_sdr_cache(alist); + sdrcache = NULL; + + return rv; +} + +static int +ipmi_sunoem_sshkey_del(void * intf, uint8_t uid) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + memset(&req, 0, sizeof(struct ipmi_rq)); + req.msg.netfn = IPMI_NETFN_SUNOEM; + req.msg.cmd = IPMI_SUNOEM_DEL_SSH_KEY; + req.msg.data = &uid; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) { + lprintf(LOG_ERR, "Unable to delete ssh key for UID %d", uid); + return rv; + } + else if (rv > 0) { + lprintf(LOG_ERR, "Unable to delete ssh key for UID %d: %s", uid, + decode_cc(0,rv)); + return rv; + } + + printf("Deleted SSH key for user id %d\n", uid); + return rv; +} + +#define SSHKEY_BLOCK_SIZE 64 +static int +ipmi_sunoem_sshkey_set(void * intf, uint8_t uid, char * ifile) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv = -1; + struct ipmi_rq req; + FILE * fp; + size_t count; + uint16_t i_size, r, f_size; + uint8_t wbuf[SSHKEY_BLOCK_SIZE + 3]; + + if (ifile == NULL) { + lprintf(LOG_ERR, "Invalid or missing input filename"); + return -1; + } + + fp = fopen(ifile, "r"); + if (fp == NULL) { + lprintf(LOG_ERR, "Unable to open file %s for reading", ifile); + return -1; + } + + printf("Setting SSH key for user id %d...", uid); + + memset(&req, 0, sizeof(struct ipmi_rq)); + req.msg.netfn = IPMI_NETFN_SUNOEM; + req.msg.cmd = IPMI_SUNOEM_SET_SSH_KEY; + req.msg.data = wbuf; + + fseek(fp, 0, SEEK_END); + f_size = (uint16_t)ftell(fp); + fseek(fp, 0, SEEK_SET); + + for (r = 0; r < f_size; r += i_size) { + i_size = f_size - r; + if (i_size > SSHKEY_BLOCK_SIZE) + i_size = SSHKEY_BLOCK_SIZE; + + memset(wbuf, 0, SSHKEY_BLOCK_SIZE); + fseek(fp, r, SEEK_SET); + count = fread(wbuf+3, 1, i_size, fp); + if (count != i_size) { + lprintf(LOG_ERR, "Unable to read %d bytes from file %s", i_size, ifile); + fclose(fp); + return -1; + } + + printf("."); + fflush(stdout); + + wbuf[0] = uid; + if ((r + SSHKEY_BLOCK_SIZE) >= f_size) + wbuf[1] = 0xff; + else + wbuf[1] = (uint8_t)(r / SSHKEY_BLOCK_SIZE); + wbuf[2] = (uint8_t)i_size; + req.msg.data_len = i_size + 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) { + lprintf(LOG_ERR, "Unable to set ssh key for UID %d", uid); + break; + } + } + + printf("done\n"); + + fclose(fp); + return rv; +} + + +int +ipmi_sunoem_main(void * intf, int argc, char ** argv) +{ + int rc = 0; + + if (argc == 0 || strncmp(argv[0], "help", 4) == 0) { + ipmi_sunoem_usage(); + return 0; + } + + if (strncmp(argv[0], "fan", 3) == 0) { + uint8_t pct; + if (argc < 2) { + ipmi_sunoem_usage(); + return -1; + } + else if (strncmp(argv[1], "speed", 5) == 0) { + if (argc < 3) { + ipmi_sunoem_usage(); + return -1; + } + pct = atob(argv[2]); + rc = ipmi_sunoem_fan_speed(intf, pct); + } + else { + ipmi_sunoem_usage(); + return -1; + } + } + + if ((strncmp(argv[0], "led", 3) == 0) || (strncmp(argv[0], "sbled", 5) == 0)) { + if (argc < 2) { + ipmi_sunoem_usage(); + return -1; + } + if (strncmp(argv[0], "sbled", 5) == 0) { + is_sbcmd = 1; + } + if (strncmp(argv[1], "get", 3) == 0) { + if (argc < 3) { + char * arg[] = { "all" }; + rc = ipmi_sunoem_led_get(intf, 1, arg); + } else { + rc = ipmi_sunoem_led_get(intf, argc-2, &(argv[2])); + } + } + else if (strncmp(argv[1], "set", 3) == 0) { + if (argc < 4) { + ipmi_sunoem_usage(); + return -1; + } + rc = ipmi_sunoem_led_set(intf, argc-2, &(argv[2])); + } + else { + ipmi_sunoem_usage(); + return -1; + } + } + + if (strncmp(argv[0], "sshkey", 6) == 0) { + uint8_t uid = 0; + unsigned long l; + if (argc < 2) { + ipmi_sunoem_usage(); + return -1; + } + else if (strncmp(argv[1], "del", 3) == 0) { + if (argc < 3) { + ipmi_sunoem_usage(); + return -1; + } + l = strtoul(argv[2], NULL, 0); + if ((l == ULONG_MAX) || (l > UCHAR_MAX)) { + printf("param %s is out of bounds\n",argv[2]); + return -17; /*ERR_BAD_PARAM*/ + } + uid = (uint8_t)l; + rc = ipmi_sunoem_sshkey_del(intf, uid); + } + else if (strncmp(argv[1], "set", 3) == 0) { + if (argc < 4) { + ipmi_sunoem_usage(); + return -1; + } + l = strtoul(argv[2], NULL, 0); + if ((l == ULONG_MAX) || (l > UCHAR_MAX)) { + printf("param %s is out of bounds\n",argv[2]); + return -17; /*ERR_BAD_PARAM*/ + } + uid = (uint8_t)l; + rc = ipmi_sunoem_sshkey_set(intf, uid, argv[3]); + } + } + + return rc; +} + +int decode_sensor_sun(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + uchar stype; + char *pstr = NULL; + + if (sdr == NULL || reading == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + /* sdr[3] is the SDR type: 02=Compact, 01=Full) */ + /* Usually compact sensors here, but type 0xC0 is a full sensor */ + stype = sdr[12]; + switch(stype) { + case 0x15: /* Module/Board State sensor (e.g. BL0/STATE) */ + if ((reading[1] + reading[2]) == 0) pstr = "NotAvailable"; + else if (reading[2] & 0x01) pstr = "OK"; /*deasserted/OK*/ + else pstr = "Asserted"; /*Asserted, error*/ + rv = 0; + break; + case 0xC0: /* Blade Error sensor (e.g. BL0/ERR, a Full SDR) */ + if ((reading[1] + reading[2]) == 0) pstr = "NotAvailable"; + else if (reading[2] & 0x01) pstr = "OK"; /*deasserted/OK*/ + else pstr = "Asserted"; /*Asserted, error*/ + rv = 0; + break; + default: + break; + } + if (rv == 0) strncpy(pstring, pstr, slen); + return(rv); +} + +#ifdef METACOMMAND +int i_sunoem(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + void *intf = NULL; + int rc = 0; + int c, i; + char *s1; + uchar devrec[16]; + + printf("%s ver %s\n", progname,progver); + set_loglevel(LOG_NOTICE); + + while ( (c = getopt( argc, argv,"m:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'x': fdebug = 1; verbose = 1; + set_debug(); + break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + ipmi_sunoem_usage(); + return 0; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + rc = ipmi_getdeviceid( devrec, sizeof(devrec),fdebug); + if (rc == 0) { + char ipmi_maj, ipmi_min; + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + prod_id = devrec[9] + (devrec[10] << 8); + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + + rc = ipmi_sunoem_main(intf, argc, argv); + } + ipmi_close_(); + // show_outcome(progname,rc); + return rc; +} diff --git a/util/oem_sun.h b/util/oem_sun.h new file mode 100644 index 0000000..2f4f8c6 --- /dev/null +++ b/util/oem_sun.h @@ -0,0 +1,137 @@ +/* + * oem_sun.h + * Handle Sun OEM command functions + * + * Change history: + * 09/02/2010 ARCress - included in source tree + * + *--------------------------------------------------------------------- + */ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef IPMI_SUNOEM_H +#define IPMI_SUNOEM_H + + +#define IPMI_NETFN_SUNOEM 0x2e + +#define IPMI_SUNOEM_SET_SSH_KEY 0x01 +#define IPMI_SUNOEM_DEL_SSH_KEY 0x02 +#define IPMI_SUNOEM_GET_HEALTH_STATUS 0x10 +#define IPMI_SUNOEM_SET_FAN_SPEED 0x20 +#define IPMI_SUNOEM_LED_GET 0x21 +#define IPMI_SUNOEM_LED_SET 0x22 + +#define SDR_RECORD_TYPE_ENTITY_ASSOC 0x08 +#define SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR 0x10 + +//struct valstr { + //uint16_t val; + //const char * str; +//}; +// const char * val2str(ushort val, const struct valstr *vs); +ushort str2val(const char *str, const struct valstr *vs); + +#pragma pack(1) +struct entity_id { + uint8_t id; /* physical entity id */ +#if WORDS_BIGENDIAN + uint8_t logical : 1; /* physical/logical */ + uint8_t instance : 7; /* instance number */ +#else + uint8_t instance : 7; /* instance number */ + uint8_t logical : 1; /* physical/logical */ +#endif +}; // __attribute__ ((packed)); + +struct sdr_record_generic_locator { + uint8_t dev_access_addr; + uint8_t dev_slave_addr; +#if WORDS_BIGENDIAN + uint8_t channel_num:3; + uint8_t lun:2; + uint8_t bus:3; +#else + uint8_t bus:3; + uint8_t lun:2; + uint8_t channel_num:3; +#endif +#if WORDS_BIGENDIAN + uint8_t addr_span:3; + uint8_t __reserved1:5; +#else + uint8_t __reserved1:5; + uint8_t addr_span:3; +#endif + uint8_t __reserved2; + uint8_t dev_type; + uint8_t dev_type_modifier; + struct entity_id entity; + uint8_t oem; + uint8_t id_code; + uint8_t id_string[16]; +}; // __attribute__ ((packed)); + +struct sdr_record_entity_assoc { + struct entity_id entity; /* container entity ID and instance */ + struct { +#if WORDS_BIGENDIAN + uint8_t isrange:1; + uint8_t islinked:1; + uint8_t isaccessable:1; + uint8_t __reserved:5; +#else + uint8_t __reserved:5; + uint8_t isaccessable:1; + uint8_t islinked:1; + uint8_t isrange:1; +#endif + } flags; + uint8_t entity_id_1; /* entity ID 1 | range 1 entity */ + uint8_t entity_inst_1; /* entity inst 1 | range 1 first instance */ + uint8_t entity_id_2; /* entity ID 2 | range 1 entity */ + uint8_t entity_inst_2; /* entity inst 2 | range 1 last instance */ + uint8_t entity_id_3; /* entity ID 3 | range 2 entity */ + uint8_t entity_inst_3; /* entity inst 3 | range 2 first instance */ + uint8_t entity_id_4; /* entity ID 4 | range 2 entity */ + uint8_t entity_inst_4; /* entity inst 4 | range 2 last instance */ +}; // __attribute__ ((packed)); +#pragma pack() + +int ipmi_sunoem_main(void *, int, char **); +int sunoem_led_get(void * intf, uchar * dev, uchar ledtype, uchar *prsp); +int sunoem_led_set(void * intf, uchar * dev, uchar ledtype, uchar ledmode); +int decode_sensor_sun(uchar *sdr,uchar *reading,char *pstring, int slen); + +#endif /*IPMI_SUNOEM_H*/ + diff --git a/util/oem_supermicro.c b/util/oem_supermicro.c new file mode 100644 index 0000000..528e4f7 --- /dev/null +++ b/util/oem_supermicro.c @@ -0,0 +1,595 @@ +/* + * oem_supermicro.c + * Handle SuperMicro OEM command functions + * + * Change history: + * 12/06/2010 ARCress - included in source tree + * + *--------------------------------------------------------------------- + */ +/*M* +Copyright (c) 2010 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include "getopt.h" +#else +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#include <sys/time.h> +#else +#include <getopt.h> +#endif +#endif +#include <stdio.h> +#include <string.h> +#include <time.h> +#include "ipmicmd.h" +#include "ievents.h" +#include "oem_supermicro.h" + +#ifdef MOVED /*moved to oem_supermicro.h*/ +#define SUPER_NETFN_OEM 0x30 +#define SUPER_CMD_BMCSTATUS 0x70 +#define SUPER_CMD_RESET_INTRUSION 0x03 +#define SUPER_NETFN_OEMFW 0x3C +#define SUPER_CMD_OEMFWINFO 0x20 +#endif + +void set_loglevel(int level); /*prototype */ +extern char fsm_debug; /*mem_if.c*/ + +static char * progver = "2.93"; +static char * progname = "ismcoem"; +static int verbose = 0; +static char fdebug = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static int vend_id = 0; +static int prod_id = 0; + +int oem_supermicro_get_bmc_status(uchar *sts) +{ + int rv; + int rlen, ilen; + uchar rdata[16]; + uchar idata[16]; + uchar cc; + + if (sts == NULL) return(LAN_ERR_INVPARAM); + if ((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) { + /* subfunc 0xF0 is invalid for newer SMC systems */ + idata[0] = 0x02; /* action: get status */ + ilen = 1; + } else { + idata[0] = 0xF0; /* subfunction */ + idata[1] = 0x02; /* action: get status */ + // idata[2] = 0; + ilen = 2; + } + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_BMCSTATUS, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, ilen, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) { *sts = rdata[0]; } + return(rv); +} + +int oem_supermicro_set_bmc_status(uchar sts) +{ + int rv; + int rlen, ilen; + uchar rdata[16]; + uchar idata[16]; + uchar cc; + + if (sts > 1) sts = 1; /* actions: 0=disable, 1=enable, 2=status*/ + if ((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) { + idata[0] = sts; + ilen = 1; + } else { + idata[0] = 0xF0; /* subfunction */ + idata[1] = sts; + ilen = 2; + } + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_BMCSTATUS, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, ilen, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + return(rv); +} + +int oem_supermicro_get_lan_port(uchar *val) +{ + int rv; + int rlen, ilen; + uchar rdata[16]; + uchar idata[16]; + uchar cc; + + idata[0] = 0x0c; /* subfunction */ + idata[1] = 0x00; /* get */ + ilen = 2; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_BMCSTATUS, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, ilen, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) { *val = rdata[0]; } + return(rv); +} + +int oem_supermicro_set_lan_port(uchar val) +{ + int rv; + int rlen, ilen; + uchar rdata[16]; + uchar idata[16]; + uchar cc; + + idata[0] = 0x0c; /* subfunction */ + idata[1] = 0x01; /* set */ + idata[2] = val; + ilen = 3; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_BMCSTATUS, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, ilen, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + return(rv); +} + +char *oem_supermicro_lan_port_string(uchar val) +{ + char *p; + switch(val) { + case 0: p = "Dedicated"; break; + case 1: p = "Onboard_LAN1"; break; + case 2: p = "Failover"; break; + default: p = "unknown"; break; + } + return(p); +} + +static void oem_supermicro_show_lan_port(uchar val) +{ + printf("Current LAN interface is %s\n", + oem_supermicro_lan_port_string(val)); +} + +int oem_supermicro_get_health(char *pstr, int sz) +{ + int rv; + uchar bsts; + char *str; + + rv = oem_supermicro_get_bmc_status(&bsts); + if (rv == 0) { + if (bsts == 0x01) str = "BMC status = enabled"; + else str = "BMC status = disabled"; + strncpy(pstr, str, sz); + } + return(rv); +} + +/* + * oem_supermicro_get_firmware_info + * + * From post by ipmitool developer. + * http://sourceforge.net/mailarchive/message.php?msg_name=49ABCCC3.4040004%40cern.ch + * + * Request + * 0x3C - OEM network function + * 0x20 - OEM cmd (SUPER_CMD_OEMFWINFO) + * + * Response data: + * 4 bytes - firmware major version (LSB first) + * 4 bytes - firmware minor version (LSB first) + * 4 bytes - firmware sub version (LSB first) + * 4 bytes - firmware build number (LSB first) + * 1 byte - hardware ID + * ? bytes - firmware tag, null terminated string + */ +int oem_supermicro_get_firmware_info(uchar *info) +{ + int rv; + int rlen; + uchar rdata[32]; + uchar idata[16]; + uchar cc; + + if (info == NULL) return(LAN_ERR_INVPARAM); + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_OEMFWINFO, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, 0, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) { memcpy(info,rdata,rlen); } + return(rv); +} + +int oem_supermicro_get_firmware_str(char *pstr, int sz) +{ + int rv; + uchar info[32]; + uint32 fwmaj; + uint32 fwmin; + uint32 fwsub; + uint32 fwbld; + uchar hwid; + rv = oem_supermicro_get_firmware_info(info); + if (rv == 0) { + fwmaj = info[0] + (info[1] << 8) + (info[2] << 16) + (info[3] << 24); + fwmin = info[4] + (info[5] << 8) + (info[6] << 16) + (info[7] << 24); + fwsub = info[8] + (info[9] << 8) + (info[10] << 16) + (info[11] << 24); + fwbld = info[12] +(info[13] << 8) + (info[14] << 16) + (info[15] << 24); + hwid = info[16]; + /*info[17] = fw tag string */ + snprintf(pstr,sz,"Firmware %d.%d.%d.%d HW %d %s\n",fwmaj,fwmin,fwsub, + fwbld,hwid,&info[17]); + } + return(rv); +} + + +int oem_supermicro_reset_intrusion(void) +{ + int rv; + int rlen; + uchar rdata[32]; + uchar idata[16]; + uchar cc; + // if (state == NULL) return(LAN_ERR_INVPARAM); + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_RESET_INTRUSION, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, 0, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) { /* check rdata for more info */ } + return(rv); +} + +/* + * decode_sensor_supermicro + * inputs: + * sdr = the SDR buffer + * reading = the 3 or 4 bytes of data from GetSensorReading + * pstring = points to the output string buffer + * slen = size of the output buffer + * outputs: + * rv = 0 if this sensor was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * pstring = contains the sensor reading interpretation string (if rv==0) + */ +int decode_sensor_supermicro(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + uchar stype; + uchar bval; + char *pstr = NULL; + + if (sdr == NULL || reading == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + /* sdr[3] is 0x01 for Full, 0x02 for Compact */ + bval = reading[2]; + stype = sdr[12]; + switch(stype) { + case 0xC0: /* CPU Temp Sensor, EvTyp=0x70 (Full) */ + //if (dbg) printf("supermicro %x sensor reading %x\n",stype,reading); + rv = 0; + switch(bval) { + case 0x0000: pstr = "00 Low"; break; + case 0x0001: pstr = "01 Medium"; break; + case 0x0002: pstr = "02 High"; break; + case 0x0004: pstr = "04 Overheat"; break; + case 0x0007: pstr = "07 Not Installed"; break; + default: rv = -1; break; + } + break; + case 0x08: /* Power Supply Status (Full/Discrete) Table 42-3 */ + rv = 0; + switch(bval) { + case 0x00: pstr = "00 Absent"; break; /*bit 0*/ + case 0x01: pstr = "01 Present"; break; /*bit 0*/ + case 0x02: pstr = "02 Failure"; break; /*bit 1*/ + case 0x04: pstr = "04 Predict Fail"; break; /*bit 2*/ + case 0x08: pstr = "08 Input Lost"; break; /*bit 3*/ + default: rv = -1; break; + } + break; + default: + break; + } + if (rv == 0) strncpy(pstring, pstr, slen); + return(rv); +} + +int decode_mem_supermicro(int prod, uchar b2, uchar b3, char *desc, int *psz) +{ + int array, dimm, n; + int rv = -1; + uchar bdata; + if ((desc == NULL) || (psz == NULL)) return -1; + if (b2 == 0xff) bdata = b3; /*ff is reserved*/ + else bdata = b2; /* normal case */ + array = (bdata & 0xc0) >> 6; + dimm = bdata & 0x3f; + /* bdata = 0x10 (16.) means CPU 1, DIMM 6 */ + array = bdata / 10; + dimm = bdata % 10; + +#ifdef DMIOK + /* Use DMI if we get confirmation about array/dimm indices. */ + if (! is_remote()) { + fsm_debug = fdebug; + rv = get_MemDesc(array,dimm,desc,psz); + /* if (rv != 0) desc has "DIMM[%d}" */ + } +#endif + + if (rv != 0) { + n = sprintf(desc,"DIMM%d/CPU%d",dimm,array); + *psz = n; + rv = 0; + } + return(rv); +} /*end decode_mem_supermicro*/ + +/* + * decode_sel_supermicro + * inputs: + * evt = the 16-byte IPMI SEL event + * outbuf = points to the output string buffer + * outsz = size of the output buffer + * outputs: + * rv = 0 if this event was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * outbuf = will contain the interpreted event text string (if rv==0) + */ +int decode_sel_supermicro(uchar *evt, char *outbuf, int outsz, char fdesc, + char fdbg) +{ + int rv = -1; + ushort id; + uchar rectype; + ulong timestamp; + char mybuf[64]; + char *type_str = ""; + char *pstr = NULL; + int sevid; + ushort genid; + uchar snum; + + fdebug = fdbg; + sevid = SEV_INFO; + id = evt[0] + (evt[1] << 8); + rectype = evt[2]; + snum = evt[11]; + timestamp = evt[3] + (evt[4] << 8) + (evt[5] << 16) + (evt[6] << 24); + genid = evt[7] | (evt[8] << 8); + if (rectype == 0x02) + { + sprintf(mybuf,"%02x [%02x %02x %02x]", evt[12],evt[13],evt[14],evt[15]); + switch(evt[10]) { /*sensor type*/ + case 0xC0: /* CPU Temp Sensor */ + type_str = "OEM_CpuTemp"; + switch((evt[13] &0x0f)) { /*offset/data1 l.o. nibble*/ + case 0x02: /* CPU Temp Sensor Overheat event offset */ + if (evt[12] & 0x80) { /*EvTyp==0xF0 if deassert*/ + pstr = "CpuTemp Overheat OK"; sevid = SEV_INFO; + } else { /* EvTyp=0x70 assert */ + pstr = "CpuTemp Overheat "; sevid = SEV_MAJ; + } + rv = 0; + break; + default: pstr = "CpuTemp Event"; break; + } + break; + case 0xC2: /* CPLD Event */ + type_str = "OEM_CPLD"; + switch((evt[13] & 0x0f)) { /* data1 usu 0xa0*/ + case 0x00: + if (evt[14] == 0x1c) + { pstr = "CPLD CATERR Asserted"; sevid = SEV_CRIT; } + else { pstr = "CPLD Event Asserted"; sevid = SEV_MIN; } + rv = 0; + break; + default: pstr = "CPLD Event"; break; + } + break; + default: /*other sensor types*/ + break; + } + } + if (rv == 0) { + format_event(id,timestamp, sevid, genid, type_str, + snum,NULL,pstr,mybuf,outbuf,outsz); + } + return(rv); +} + +static void usage(void) +{ + printf("Usage: %s <command> [arg]\n",progname); + printf(" intrusion = reset chassis intrusion\n"); + printf(" bmcstatus [enable| disable] = get/set BMC status\n"); + printf(" firmware = get extra firmware info\n"); + printf(" lanport [dedicated| lan1| failover] = get/set IPMI LAN port\n"); + printf("These commands may not work on all SuperMicro systems\n"); +} + +static int ipmi_smcoem_main(int argc, char **argv) +{ + int rv = 0; + char msg[80]; + uchar val; + + if (strncmp(argv[0],"intrusion",9) == 0) { + printf("Clearing Chassis Intrusion ...\n"); + rv = oem_supermicro_reset_intrusion(); + } else if (strncmp(argv[0],"bmcstatus",9) == 0) { + printf("Getting BMC status ...\n"); + rv = oem_supermicro_get_health(msg, sizeof(msg)); + if (rv != 0) return(rv); + printf("%s\n",msg); + if (argv[1] != NULL) { + if (strncmp(argv[1],"disable",7) == 0) { + val = 0; + } else if (strncmp(argv[1],"enable",6) == 0) { + val = 1; + } else { + usage(); + return(ERR_USAGE); + } + printf("Setting BMC status to %s ...\n",argv[1]); + rv = oem_supermicro_set_bmc_status(val); + if (rv != 0) return(rv); + rv = oem_supermicro_get_health(msg, sizeof(msg)); + if (rv == 0) printf("%s\n",msg); + } + } else if (strncmp(argv[0],"firmware",8) == 0) { + printf("Getting SMC Firmare Information ...\n"); + rv = oem_supermicro_get_firmware_str(msg, sizeof(msg)); + if (rv == 0) printf("%s\n",msg); + } else if (strncmp(argv[0],"lanport",9) == 0) { + rv = oem_supermicro_get_lan_port(&val); + if (rv == 0) { + oem_supermicro_show_lan_port(val); + if (argv[1] != NULL) { + if (strncmp(argv[1],"dedicated",9) == 0) { + val = 0; + } else if (strncmp(argv[1],"lan1",4) == 0) { + val = 1; + } else if (strncmp(argv[1],"failover",8) == 0) { + val = 2; + } else { + usage(); + return(ERR_USAGE); + } + printf("Setting LAN interface to %s ...\n",argv[1]); + rv = oem_supermicro_set_lan_port(val); + if (rv != 0) return(rv); + rv = oem_supermicro_get_lan_port(&val); + if (rv == 0) oem_supermicro_show_lan_port(val); + } + } + } else { + usage(); + rv = ERR_USAGE; + } + return(rv); +} + +#ifdef METACOMMAND +int i_smcoem(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int rv = 0; + uchar devrec[16]; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + set_loglevel(LOG_NOTICE); + parse_lan_options('V',"4",0); /*default to admin priv*/ + + while ( (c = getopt( argc, argv,"m:xzEF:J:N:P:R:T:U:V:YZ:?")) != EOF ) + switch(c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'x': fdebug = 2; /* normal (dbglog if isol) */ + verbose = 1; + break; + case 'z': fdebug = 3; /*full debug (for isol)*/ + verbose = 1; + break; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + usage(); + return(ERR_USAGE); + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + if (argc == 0) { + usage(); + return(ERR_USAGE); + } + + rv = ipmi_getdeviceid(devrec,16,fdebug); + if (rv == 0) { + char ipmi_maj, ipmi_min; + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + prod_id = devrec[9] + (devrec[10] << 8); + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + } + + rv = ipmi_smcoem_main(argc, argv); + + ipmi_close_(); + return(rv); +} +/* end oem_supermicro.c */ diff --git a/util/oem_supermicro.h b/util/oem_supermicro.h new file mode 100644 index 0000000..daf08d6 --- /dev/null +++ b/util/oem_supermicro.h @@ -0,0 +1,56 @@ +/* + * oem_supermicro.h + * SuperMicro OEM command functions + * + *--------------------------------------------------------------------- + */ +/*M* +Copyright (c) 2013 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ + +#define SUPER_NETFN_OEM 0x30 +#define SUPER_CMD_BMCSTATUS 0x70 +#define SUPER_CMD_RESET_INTRUSION 0x03 +#define SUPER_NETFN_OEMFW 0x3C /*for SuperMicro/Peppercon*/ +#define SUPER_CMD_OEMFWINFO 0x20 + +int oem_supermicro_get_bmc_status(uchar *sts); +int oem_supermicro_set_bmc_status(uchar sts); +int oem_supermicro_get_health(char *pstr, int sz); +int oem_supermicro_get_firmware_info(uchar *info); +int oem_supermicro_get_firmware_str(char *pstr, int sz); +int oem_supermicro_reset_intrusion(void); +int oem_supermicro_get_lan_port(uchar *val); +int oem_supermicro_set_lan_port(uchar val); +char *oem_supermicro_lan_port_string(uchar val); + +int decode_sensor_supermicro(uchar *sdr,uchar *reading,char *pstring, int slen); +int decode_mem_supermicro(int prod, uchar b2, uchar b3, char *desc, int *psz); +int decode_sel_supermicro(uchar *evt, char *outbuf, int outsz, char fdesc, + char fdebug); + +/* end oem_supermicro.h */ diff --git a/util/subs.c b/util/subs.c new file mode 100644 index 0000000..9f11423 --- /dev/null +++ b/util/subs.c @@ -0,0 +1,848 @@ +/* + * subs.c + * + * Some common helper subroutines + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2010 Kontron America, Inc. + * + * 08/18/11 Andy Cress - created to consolidate subroutines + */ +/*M* +Copyright (c) 2010 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#ifdef WIN32 +#include <windows.h> +// #if !defined(LONG_MAX) +// # if __WORDSIZE == 64 +// # define LONG_MAX 9223372036854775807L +// # else +// # define LONG_MAX 2147483647L +// # endif +// # define LONG_MIN (-LONG_MAX - 1L) +// #endif + +#else +/* Linux */ +#include <unistd.h> +#include <syslog.h> +#include <errno.h> +#endif + +#include "ipmicmd.h" + +extern char fdebug; /*ipmicmd.c*/ +extern char fdbglog; /*ipmilanplus.c*/ +extern int verbose; /*ipmilanplus.c*/ +extern FILE *fpdbg; /*ipmicmd.c*/ +extern FILE *fplog; /*ipmicmd.c */ +extern char log_name[60]; /*log_name global, from ipmicmd.c*/ + +static int loglevel = LOG_WARN; +#ifdef WIN32 +#define SELMSG_ID 0x40000101 /* showselmsg.dll EventID 257. = 0x101 */ +static HANDLE hLog = NULL; +#endif + +/* decode_rv, decode_cc are in ipmicmd.c */ + +/* strlen_ wrapper for size_t/int warnings*/ +int strlen_(const char *s) +{ + return((int)strlen(s)); +} + +/* Need our own copy of strdup(), named strdup_(), since Windows does + * not have the same subroutine. */ +char * strdup_(const char *instr) +{ + char *newstr = NULL; + if (instr != NULL) { + newstr = malloc(strlen_(instr)+1); + if (newstr != NULL) strcpy(newstr,instr); + } + return (newstr); +} + +#ifdef WIN32 +int strncasecmp(const char *s1, const char *s2, int n) +{ + int i, val; + char c1, c2; + if (s1 == NULL || s2 == NULL) return (-1); + val = 0; + for (i = 0; i < n; i++) { + c1 = s1[i] & 0x5f; + c2 = s2[i] & 0x5f; + if (c1 < c2) { val = -1; break; } + if (c1 > c2) { val = 1; break; } + } + return(val); +} +#endif + +/* case insensitive string compare */ +int str_icmp(char *s1, char *s2) +{ + int n1, n2, val; + if (s1 == NULL || s2 == NULL) return (-1); + n1 = strlen_(s1); + n2 = strlen_(s2); + if (n1 != n2) return(-1); + val = strncasecmp(s1,s2,n1); + return(val); +} +void set_loglevel(int level) +{ + loglevel = level; +} + +void lprintf(int level, const char * format, ...) +{ + va_list vptr; + static char logtmp[LOG_MSG_LENGTH]; + FILE *fp = stderr; + if (!verbose && (level > loglevel)) return; + if (fdbglog && (fplog != NULL)) fp = fplog; +#ifdef WIN32 + va_start(vptr, format); + vfprintf(fp, format, vptr); + va_end(vptr); + fprintf(fp,"\r\n"); +#else + va_start(vptr, format); + vsnprintf(logtmp, LOG_MSG_LENGTH, format, vptr); + va_end(vptr); + fprintf(fp, "%s\r\n", logtmp); +#endif + return; +} + +void lperror(int level, const char * format, ...) +{ + va_list vptr; + FILE *fp; + if (level > loglevel) return; + fp = stderr; + if (fdbglog && verbose > 1) { + if (fplog != NULL) fp = fplog; + } + va_start(vptr, format); + vfprintf(fp, format, vptr); + va_end(vptr); + fprintf(fp,"\r\n"); + return; +} + +void printbuf(const uchar * buf, int len, const char * desc) +{ + int i; + FILE *fp = stderr; + + if (len <= 0) return; + if (verbose < 1) return; + if (fdbglog && (fplog != NULL)) fp = fplog; + fprintf(fp, "%s (%d bytes)\r\n", desc, len); + for (i=0; i<len; i++) { + if (((i%16) == 0) && (i != 0)) + fprintf(fp, "\r\n"); + fprintf(fp, " %2.2x", buf[i]); + } + fprintf(fp, "\r\n"); +} + +const char * buf2str(uchar * buf, int len) +{ + static char str[1024]; + int i; + if (len <= 0 || len > sizeof(str)) return NULL; + memset(str, 0, sizeof(str)); + for (i=0; i<len; i++) sprintf(str+i+i, "%2.2x", buf[i]); + str[len*2] = '\0'; + return (const char *)str; +} +ushort buf2short(uchar * buf) +{ + return (ushort)(buf[1] << 8 | buf[0]); +} +ulong buf2long(uchar * buf) +{ + return (ulong)(buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]); +} + +#define IPMI_OEM_PICMG 12634 +#define SZUN 32 +const char * oemval2str(ushort oem, uchar val, const struct oemvalstr *vs) +{ + static char un_str[SZUN]; + int i; + for (i = 0; vs[i].oem != 0x00 && vs[i].str != NULL; i++) { + if ( ( vs[i].oem == oem || vs[i].oem == IPMI_OEM_PICMG ) + && vs[i].val == val ) { + return vs[i].str; + } + } + memset(un_str, 0, SZUN); + snprintf(un_str, SZUN, "OEM reserved #%02x", val); + return un_str; +} +const char * val2str(ushort val, const struct valstr *vs) +{ + static char un_str[SZUN]; + int i; + for (i = 0; vs[i].str != NULL; i++) { + if (vs[i].val == val) return vs[i].str; + } + memset(un_str, 0, SZUN); + snprintf(un_str, SZUN, "Unknown (0x%x)", val); + return un_str; +} +ushort str2val( char *str, struct valstr *vs) +{ + int i, x, y; + for (i = 0; vs[i].str != NULL; i++) { + x = strlen_(str); + y = strlen_(vs[i].str); + if (strncasecmp(vs[i].str, str, (x > y)? x : y) == 0) + return vs[i].val; + } + return vs[i].val; +} + + +void dump_buf(char *tag, uchar *pbuf, int sz, char fshowascii) +{ + uchar line[17]; + uchar a; + int i, j; + char *stag; + FILE *fpdbg1; + + if (fpdbg != NULL) fpdbg1 = fpdbg; + else fpdbg1 = stdout; + if (tag == NULL) stag = "dump_buf"; /*safety valve*/ + else stag = tag; + fprintf(fpdbg1,"%s (len=%d): ", stag,sz); + line[0] = 0; line[16] = 0; + j = 0; + if (sz < 0) { fprintf(fpdbg1,"\n"); return; } /*safety valve*/ + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { + line[j] = 0; + j = 0; + fprintf(fpdbg1,"%s\n %04x: ",line,i); + } + if (fshowascii) { + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + } + fprintf(fpdbg1,"%02x ",pbuf[i]); + } + if (fshowascii) { + if ((j > 0) && (j < 16)) { + /* space over the remaining number of hex bytes */ + for (i = 0; i < (16-j); i++) fprintf(fpdbg1," "); + } + else j = 16; + line[j] = 0; + } + fprintf(fpdbg1,"%s\n",line); + return; +} + +void close_log(void) +{ + if ((fplog != NULL) && (fplog != stderr) && (fplog != stdout)) { + fclose(fplog); + fplog = NULL; + } +} + +FILE *open_log(char *mname) +{ + FILE *fp = NULL; + char *pname; + int len; + + /* log_name is global, for reuse */ + if (log_name[0] == 0) { + if (mname == NULL) { /*make a default name*/ + pname = "ipmiutil"; +#ifdef WIN32 + sprintf(log_name,"%s.log",pname); +#elif defined(DOS) + sprintf(log_name,"%s.log",pname); +#else + /*LINUX, SOLARIS, BSD */ + sprintf(log_name,"/var/log/%s.log",pname); +#endif + } else { /*use mname arg*/ + len = strlen_(mname); + if (len >= sizeof(log_name)) len = sizeof(log_name) - 1; + strncpy(log_name, mname, len); + } + } + close_log(); + if (log_name[0] != 0) + fp = fopen( log_name, "a+" ); + if (fp == NULL) { + fp = stdout; /*was stderr*/ + fprintf(fp,"cannot open log: %s\n",log_name); + } + fplog = fp; + return fp; +} + +void flush_log(void) +{ + if (fplog != NULL) fflush(fplog); +} + +void print_log( char *pattn, ... ) +{ + va_list arglist; + if (fplog == NULL) fplog = open_log(NULL); + /* if error, open_log sets fplog = stdout */ + va_start( arglist, pattn ); + vfprintf( fplog, pattn, arglist ); + va_end( arglist ); +} + +/* + * logmsg + * This does an open/close if no log is already open, but does not set fplog. + */ +void logmsg( char *pname, char *pattn, ... ) +{ + va_list arglist; + FILE *fp = NULL; + int opened = 0; + + if (fplog == NULL) { /*no log alread open, open temp fp*/ + fp = open_log(pname); + if (fp == NULL) return; + opened = 1; + } else fp = fplog; + va_start( arglist, pattn ); + vfprintf( fp, pattn, arglist ); + va_end( arglist ); + if ((opened) && (fp != stderr)) /*opened temp fp, so close it*/ + { fclose(fp); } +} + +void dump_log(FILE *fp, char *tag, uchar *pbuf, int sz, char fshowascii) +{ + FILE *fpsav; + fpsav = fpdbg; + if (fplog != NULL) fpdbg = fplog; + if (fp != NULL) fpdbg = fp; + dump_buf(tag, pbuf, sz, fshowascii); /*uses fpdbg*/ + fflush(fpdbg); + fpdbg = fpsav; +} + + +extern int lasterr; /*defined in ipmilan.c */ +extern void show_LastError(char *tag, int err); /*ipmilan.c */ + +#ifdef WIN32 +/* Windows stdlib.h: extern int * __cdecl _errno(void); */ +int get_errno(void) +{ + return(errno); +} +#else +extern int errno; /* Linux<errno.h has this also */ +int get_errno(void) +{ + return(errno); +} +#endif + + /* For a list of all IANA enterprise mfg vendor numbers, + * see http://www.iana.org/assignments/enterprise-numbers + * Product numbers are different for each mfg vendor. */ +#define N_MFG 43 +static struct { int val; char *pstr; } mfgs[N_MFG] = { + {0, " "}, + {0x0000BA, "Toshiba"}, + {0x000074, "Hitachi"}, + {0x00018F, "Hitachi"}, + {0x000175, "Tatung"}, + {0x000614, "Performance Technologies"}, + {0x000F85, "Aelita Software"}, /*3973. HP DL140*/ + {0x0028B2, "Avocent"}, + {0x002B5E, "OSA"}, + {0x0035AE, "Raritan"}, /*13742.*/ + {0x0051EE, "AMI"}, + { 94, "Nokia-Siemens"}, + { 107, "Bull"}, + { 4337, "Radisys"}, + { 4542, "ASF"}, + { 6569, "Inventec"}, + { 7154, "IPMI forum"}, + { 11129, "Google"}, + { 12634, "PICMG"}, + { 16394, "Pigeon Point"}, + { 20569, "Inventec ESC"}, + { 24673, "ServerEngines"}, + { 27768, "NAT"}, + {VENDOR_CISCO, "Cisco"}, /*=5771.*/ + {VENDOR_IBM, "IBM"}, /*0x000002*/ + {VENDOR_NEWISYS, "Newisys"}, /*=9237. */ + {VENDOR_XYRATEX, "Xyratex"}, /*=1993. */ + {VENDOR_QUANTA, "Quanta"}, /*=7244. */ + {VENDOR_MAGNUM, "Magnum Technologies"}, /*=5593. */ + {VENDOR_SUPERMICROX, "xSuperMicro"}, /* 47488. used by Winbond/SuperMicro*/ + {VENDOR_HP, "HP"}, /* 0x00000B for HP */ + {VENDOR_DELL, "Dell"}, /*0x0002A2*/ + {VENDOR_KONTRON, "Kontron"}, /*=0x003A98, 15000.*/ + {VENDOR_SUPERMICRO, "SuperMicro"}, /*=0x002A7C, 10876. used in AOC-SIMSO*/ + {VENDOR_FUJITSU, "Fujitsu-Siemens"}, /* 0x002880, 10368. */ + {VENDOR_PEPPERCON, "Peppercon"}, /* 0x0028C5, 10437. now w Raritan*/ + {VENDOR_MICROSOFT, "Microsoft"}, /*=0x000137, 311.*/ + {VENDOR_NEC, "NEC"}, /*=0x000077*/ + {VENDOR_NSC, "NSC"}, /*=0x000322*/ + {VENDOR_LMC, "LMC"}, /*=0x000878 with SuperMicro*/ + {VENDOR_TYAN, "Tyan"}, /*=0x0019FD*/ + {VENDOR_SUN, "Sun"}, /*=0x00002A*/ + {VENDOR_INTEL, "Intel"} /*=0x000157*/ +}; + +char * get_iana_str(int mfg) +{ + char *mfgstr = ""; + int i; + for (i = 0; i < N_MFG; i++) { + if (mfgs[i].val == mfg) { + mfgstr = mfgs[i].pstr; + break; + } + } + if (i >= N_MFG) mfgstr = mfgs[0].pstr; + return(mfgstr); +} + +/* + * str2uchar + * Convert string into unsigned char and check for overflows + * @str: (input) array of chars to parse from + * @uchr_ptr: (output) pointer to address where uint8_t will be stored + * returns 0 if successful, or -1,-2,-3 if error + */ +int str2uchar(char *str, uchar *uchr_ptr) +{ + ulong lval = 0; + char *end_ptr = NULL; + if (str == NULL || uchr_ptr == NULL) return -1; /*NULL pointer arg*/ + *uchr_ptr = 0; /*seed with default result*/ + errno = 0; + /* handle use of 08, 09 to avoid octal overflow */ + if (strncmp(str,"08",2) == 0) lval = 8; + else if (strncmp(str,"09",2) == 0) lval = 9; + else { /*else do strtoul*/ + lval = strtoul(str, &end_ptr, 0); + if ((end_ptr == NULL) || *end_ptr != '\0' || errno != 0) + return -2; /* invalid input given by user/overflow occurred */ + if (lval > 0xFF || lval == LONG_MIN || lval == LONG_MAX) + return -3; /* Argument is too big to fit unsigned char */ + } + *uchr_ptr = (uchar)lval; + return 0; +} + +/* atob is like atoi, but using str2uchar */ +uchar atob(char *str_in) +{ + uchar b = 0; + int rv; + rv = str2uchar(str_in,&b); + /* if error, show error, but use default. */ + switch (rv) { + case -1: + printf("atob error: input pointer is NULL\n"); + break; + case -2: + printf("atob error: string-to-number conversion overflow\n"); + break; + case -3: + printf("atob error: numeric argument is too big for one byte\n"); + break; + default: + break; + } + return(b); +} + +void atoip(uchar *array,char *instr) +{ + int i,j,n; + char *pi; + char tmpstr[16]; + /* converts ASCII input string into binary IP Address (array) */ + if (array == NULL || instr == NULL) { + if (fdebug) printf("atoip(%p,%p) NULL pointer error\n",array,instr); + return; + } + j = 0; + n = strlen_(instr); + n++; /*include the null char*/ + if (n > sizeof(tmpstr)) n = sizeof(tmpstr); + memcpy(tmpstr,instr,n); + pi = tmpstr; + for (i = 0; i < n; i++) { + if (tmpstr[i] == '.') { + tmpstr[i] = 0; + array[j++] = atob(pi); + pi = &tmpstr[i+1]; + } + else if (tmpstr[i] == 0) { + array[j++] = atob(pi); + } + } + if (fdebug) + printf("atoip: %d %d %d %d\n", array[0],array[1],array[2],array[3]); +} /*end atoip()*/ + +/* + * htoi + * Almost all of the utilities use this subroutine + * Input: a 2 character string of hex digits. + * Output: a hex byte. + */ +uchar htoi(char *inhex) +{ + // char rghex[16] = "0123456789ABCDEF"; + uchar val; + uchar c; + if (inhex[1] == 0) { /* short string, one char */ + c = inhex[0] & 0x5f; /* force cap */ + if (c > '9') c += 9; /* c >= 'A' */ + val = (c & 0x0f); + } else { + c = inhex[0] & 0x5f; /* force cap */ + if (c > '9') c += 9; /* c >= 'A' */ + val = (c & 0x0f) << 4; + c = inhex[1] & 0x5f; /* force cap */ + if (c > '9') c += 9; /* c >= 'A' */ + val += (c & 0x0f); + } + return(val); +} + + +void os_usleep(int s, int u) +{ +#ifdef WIN32 + if (s == 0) { + int i; + if (u >= 1000) Sleep(u/1000); + else for (i=0; i<u; i++) s = 0; /*spin for u loops*/ + } else { + Sleep(s * 1000); + } +#elif defined(DOS) + if (s == 0) delay(u); + else delay(s * 1000); +#else + if (s == 0) { + usleep(u); + } else { + sleep(s); + } +#endif +} + +#define SYS_INFO_MAX 64 + +static int sysinfo_has_len(uchar enc, int vendor) +{ + int rv = 1; + int vend; + if (enc > (uchar)2) return(0); /*encoding max is 2*/ + if (vendor == 0) get_mfgid(&vend, NULL); + else vend = vendor; + if (vend == VENDOR_INTEL) rv = 0; + if (vend == VENDOR_SUPERMICRO) rv = 0; + return(rv); +} + +int get_device_guid(char *pbuf, int *szbuf) +{ + int rv = -1; + //uchar idata[8]; + uchar rdata[32]; + int rlen, len; + uchar cc; + ushort cmdw; + + len = *szbuf; + *szbuf = 0; + cmdw = 0x08 | (NETFN_APP << 8); + rv = ipmi_cmd_mc(cmdw, NULL,0,rdata,&rlen,&cc,fdebug); + if (rv == 0 && cc != 0) rv = cc; + if (rv == 0) { + if (rlen > len) rlen = len; + memcpy(pbuf,rdata,rlen); + *szbuf = rlen; + } + return(rv); +} + +int get_sysinfo(uchar parm, uchar set, uchar block, uchar *pbuf, int *szbuf) +{ + uchar idata[8]; + uchar rdata[32]; + int rlen, j, len; + int rv = -1; + uchar cc; + ushort cmdw; + + if (pbuf == NULL || szbuf == NULL) return(rv); + len = 0; + idata[0] = 0; + idata[1] = parm; + idata[2] = set; + idata[3] = block; + rlen = sizeof(rdata); + cmdw = CMD_GET_SYSTEM_INFO | (NETFN_APP << 8); + rv = ipmi_cmd_mc(cmdw, idata,4,rdata,&rlen,&cc,fdebug); + if (rv == 0 && cc != 0) rv = cc; + if (rv == 0) { + j = 2; + if (set == 0) { /*NEW_FMT: first set includes type, len */ + if (sysinfo_has_len(rdata[2],0)) { /*but len not used if Intel*/ + j = 4; + len = rdata[3]; + } + } + rdata[rlen] = 0; /*stringify for debug below*/ + rlen -= j; + if (fdebug) printf("get_sysinfo(%d,%d) j=%d len=%d %s\n", + parm,set,j,rlen,&rdata[j]); + if (rlen > *szbuf) rlen = *szbuf; + memcpy(pbuf,&rdata[j],rlen); + *szbuf = rlen; + } + return(rv); +} + +int set_system_info(uchar parm, uchar *pbuf, int szbuf) +{ + uchar idata[32]; + uchar rdata[8]; + int rlen, ilen, i, j, n; + int rv = -1; + uchar cc, set; + ushort cmdw; + + if (pbuf == NULL) return(rv); + if (szbuf > SYS_INFO_MAX) szbuf = SYS_INFO_MAX; + n = 0; set = 0; + while ((n < szbuf) || (n == 0)) { + ilen = 16; + j = 2; + memset(idata,0,sizeof(idata)); + idata[0] = parm; + idata[1] = set; + if (set == 0) { /*NEW_FMT: first set includes type, len */ + if (sysinfo_has_len(0,0)) { /*but len not used if Intel*/ + j = 4; + idata[2] = 0; /*type = ASCII+Latin1*/ + idata[3] = szbuf; /*overall length*/ + } + } + i = ilen; + if (i > (szbuf - n)) i = (szbuf - n); + memcpy(&idata[j],&pbuf[n],i); + rlen = sizeof(rdata); + cmdw = CMD_SET_SYSTEM_INFO | (NETFN_APP << 8); + rv = ipmi_cmd_mc(cmdw, idata,(ilen+j),rdata,&rlen,&cc,fdebug); + if (rv == 0 && cc != 0) rv = cc; + if (fdebug) printf("set_system_info(%d,%d) rv=%d j=%d ilen=%d %s\n", + parm,set,rv,j,ilen,&pbuf[n]); + if (rv != 0) break; + else { + n += ilen; + set++; + } + } + return(rv); +} + +int get_system_info(uchar parm, char *pbuf, int *szbuf) +{ + int rv = -1; + int i, off, len, szchunk; + + off = 0; len = *szbuf; + /* SYS_INFO_MAX = 64 (4 * 16) */ + for (i = 0; i < 4; i++) { + szchunk = 16; + if ((off + szchunk) > *szbuf) break; + rv = get_sysinfo(parm,i,0,&pbuf[off],&szchunk); + if (rv != 0) break; + off += szchunk; + if (off >= len) break; + } + if (off < *szbuf) *szbuf = off; + return(rv); +} + +int ipmi_reserved_user(int vend, int userid) +{ + int ret = 0; + if (userid == 1) { + switch(vend) { + case VENDOR_INTEL: ret = 0; break; + case VENDOR_KONTRON: ret = 1; break; + case VENDOR_SUPERMICRO: ret = 1; break; + case VENDOR_SUPERMICROX: ret = 1; break; + default: ret = 0; break; + } + } + return(ret); +} + +#define NSEV 4 +static char *sev_str[NSEV] = { + /*0*/ "INF", + /*1*/ "MIN", + /*2*/ "MAJ", + /*3*/ "CRT" }; + +uchar find_msg_sev(char *msg) +{ + int i; + char *p; + uchar sev = SEV_INFO; + + if (msg == NULL) return(sev); + for (i = 0; i < NSEV; i++) { + p = strstr(msg,sev_str[i]); + if (p != NULL) { sev = (uchar)i; break; } + } + return(sev); +} + +int OpenSyslog(char *tag) +{ + int ret = -1; + if (tag == NULL) tag = "ipmiutil"; +#ifdef WIN32 + /* Requires showselmsg.dll and this Registry entry: + HKLM/SYSTEM/CurrentControlSet/Services/EventLog/Application/showsel + EventMessageFile REG_EXPAND_SZ "%SystemRoot%\system32\showselmsg.dll" + TypesSupported REG_DWORD 0x000000007 + */ + hLog = RegisterEventSource(NULL, "showsel"); + if (hLog == (void *)ERROR_INVALID_HANDLE) { hLog = NULL; } + if (hLog == NULL) + printf("RegisterEventSource error, %lx\n", GetLastError()); + else ret = 0; /*success*/ +#elif defined(DOS) + ret = LAN_ERR_NOTSUPPORT; +#else + // Open syslog + openlog( tag, LOG_CONS, LOG_KERN); + ret = 0; /* success if here */ +#endif + return(ret); +} + +void CloseSyslog(void) +{ +#ifdef WIN32 + DeregisterEventSource(hLog); +#elif defined(DOS) + ; +#else + // Close syslog + closelog(); +#endif +} + +void WriteSyslog(char *msgbuf) +{ + uchar sev; +#ifdef WIN32 + BOOL status; + char *rgstrings[2] = {NULL, NULL}; + WORD level; + rgstrings[0] = msgbuf; /*decoded SEL entry*/ + sev = find_msg_sev(msgbuf); + switch(sev) { + case SEV_MIN: level = EVENTLOG_WARNING_TYPE; break; + case SEV_MAJ: level = EVENTLOG_ERROR_TYPE; break; + case SEV_CRIT: level = EVENTLOG_ERROR_TYPE; break; + case SEV_INFO: + default: level = EVENTLOG_INFORMATION_TYPE; break; + } + if (hLog != NULL) { + status = ReportEvent(hLog,EVENTLOG_INFORMATION_TYPE, + 0, SELMSG_ID, NULL, 1,0, + rgstrings,NULL); + /* showsel eventid = 0x101. */ + if (fdebug || (status == 0)) { /*error or debug*/ + printf("ReportEvent status=%d, %lx\n", + status,GetLastError()); + } + } +#elif defined(DOS) + ; +#else + int level; + sev = find_msg_sev(msgbuf); + switch(sev) { + case SEV_MIN: level = LOG_WARNING; break; + case SEV_MAJ: level = LOG_ERR; break; + case SEV_CRIT: level = LOG_CRIT; break; + case SEV_INFO: + default: level = LOG_INFO; break; + } + syslog(level,"%s",msgbuf); +#endif +} /*end WriteSyslog*/ + +int write_syslog(char *msg) +{ /* not used in showsel, but used by getevent, hwreset */ + int rv; + rv = OpenSyslog("ipmiutil"); + if (rv == 0) { + WriteSyslog(msg); + CloseSyslog(); + } + return(rv); +} + +/* end subs.c */ |