summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-06 18:04:32 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-06 18:04:32 +0200
commita7f89980e5b3f4b9a74c70dbc5ffe8aabd28be28 (patch)
tree41c4deec1fdfbafd7821b4ca7a9772ac0abd92f5 /util
Imported Upstream version 2.9.3upstream/2.9.3
Diffstat (limited to 'util')
-rw-r--r--util/AnsiTerm.cpp1892
-rw-r--r--util/AnsiTerm.h316
-rw-r--r--util/Makefile.am200
-rw-r--r--util/Makefile.am-so241
-rw-r--r--util/Makefile.in766
-rw-r--r--util/Makefile.sample28
-rw-r--r--util/ialarms.c689
-rw-r--r--util/icmd.c366
-rw-r--r--util/iconfig.c2680
-rw-r--r--util/idcmi.c976
-rw-r--r--util/idcmi.h69
-rw-r--r--util/idiscover.c1055
-rw-r--r--util/iekanalyzer.c4131
-rw-r--r--util/iekanalyzer.h521
-rw-r--r--util/ievents.c2505
-rw-r--r--util/ievents.h64
-rw-r--r--util/ifirewall.c1154
-rw-r--r--util/ifirewall.h111
-rwxr-xr-xutil/ifru.c2123
-rw-r--r--util/ifru.h13
-rw-r--r--util/ifru_picmg.c486
-rw-r--r--util/ifruset.c1658
-rw-r--r--util/ifwum.c1697
-rw-r--r--util/ifwum.h76
-rw-r--r--util/igetevent.c1439
-rw-r--r--util/ihealth.c1153
-rw-r--r--util/ihpm.c4003
-rw-r--r--util/ihpm.h117
-rw-r--r--util/ilan.c5149
-rw-r--r--util/imb_api.h708
-rw-r--r--util/imbapi.c2594
-rw-r--r--util/ipicmg.c1911
-rw-r--r--util/ipicmg.h313
-rw-r--r--util/ipmi_port.c146
-rw-r--r--util/ipmi_sample.c312
-rw-r--r--util/ipmi_sample.mak57
-rw-r--r--util/ipmi_sample_evt.c445
-rw-r--r--util/ipmibmc.c231
-rw-r--r--util/ipmicmd.c1429
-rw-r--r--util/ipmicmd.h543
-rw-r--r--util/ipmidir.c1513
-rw-r--r--util/ipmidir.h301
-rw-r--r--util/ipmilan.c2430
-rw-r--r--util/ipmilan.h83
-rw-r--r--util/ipmilan2.c68
-rw-r--r--util/ipmilan2.h62
-rw-r--r--util/ipmilanplus.c790
-rw-r--r--util/ipmilanplus.h64
-rw-r--r--util/ipmild.c250
-rw-r--r--util/ipmilipmi.c182
-rw-r--r--util/ipmims.cpp638
-rw-r--r--util/ipmimv.c784
-rw-r--r--util/ipmiutil.c229
-rw-r--r--util/ipmiutil.h66
-rw-r--r--util/ipmiutil.mak424
-rw-r--r--util/ipmiutil2-64.mak425
-rw-r--r--util/ipmiutil2.mak425
-rw-r--r--util/ipmiutil64.mak423
-rw-r--r--util/ipmiutillib.def31
-rw-r--r--util/ireset.c751
-rw-r--r--util/isel.c884
-rw-r--r--util/iseltime.c260
-rw-r--r--util/isensor.c3680
-rw-r--r--util/isensor.h176
-rw-r--r--util/iserial.c1592
-rw-r--r--util/isol.c1347
-rw-r--r--util/isolwin.c293
-rw-r--r--util/itsol.c725
-rw-r--r--util/itsol.h66
-rw-r--r--util/iwdt.c415
-rw-r--r--util/md2.c99
-rw-r--r--util/md2.h269
-rw-r--r--util/md5.c413
-rw-r--r--util/mem_if.c900
-rw-r--r--util/mem_if_cpp.cpp5
-rw-r--r--util/oem_dell.c6095
-rw-r--r--util/oem_dell.h629
-rw-r--r--util/oem_fujitsu.c773
-rw-r--r--util/oem_fujitsu.h130
-rw-r--r--util/oem_hp.c149
-rw-r--r--util/oem_intel.c1842
-rw-r--r--util/oem_intel.h79
-rw-r--r--util/oem_kontron.c1107
-rw-r--r--util/oem_kontron.h80
-rw-r--r--util/oem_newisys.c129
-rw-r--r--util/oem_quanta.c142
-rw-r--r--util/oem_sun.c1058
-rw-r--r--util/oem_sun.h137
-rw-r--r--util/oem_supermicro.c595
-rw-r--r--util/oem_supermicro.h56
-rw-r--r--util/subs.c848
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, &notUsed);
+
+ }
+
+
+ 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, &notUsed);
+ }
+
+ 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(&ltime2);
+ 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(&ltime2);
+ 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(&ltime);
+ if (fsimple)
+ printf("%c %s",bdelim,ctime(&ltime)); /*ctime has '\n' */
+ else
+ printf("at %s",ctime(&ltime)); /*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(&ltime);
+ if (fsimple)
+ printf("%c %s",bdelim,ctime(&ltime)); /*ctime has '\n' */
+ else
+ printf("at %s",ctime(&ltime)); /*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 *)&ltime1);
+
+ 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 *)&ltime2);
+ 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 */