ipmi_dcmi.c 109 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882
  1. /*
  2. * Copyright (C) 2008 Intel Corporation.
  3. * All rights reserved
  4. *
  5. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  6. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  7. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  8. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  9. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  10. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  11. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  12. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  13. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  14. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  15. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. *
  17. */
  18. /* Theory of operation
  19. *
  20. * DCMI is the Data Center Management Interface which is a subset of IPMI v2.0.
  21. * DCMI incorporates the ability to locate a system with DCMI functionality,
  22. * its available temperature sensors, and power limiting control.
  23. *
  24. * All of the available DCMI commands are contained in a struct with a numeric
  25. * value and a string. When the user specifies a command the string is
  26. * compared to one of several structs and is then given a numeric value based
  27. * on the matched string. A case statement is used to select the desired
  28. * action from the user. If an invalid string is entered, or a string that is
  29. * not a command option is entered, the available commands are printed to the
  30. * screen. This allows the strings to be changed quickly with the DCMI spec.
  31. *
  32. * Each called function usually executes whichever command was requested to
  33. * keep the main() from being overly complicated.
  34. *
  35. * This code conforms to the 1.0 DCMI Specification
  36. * released by Hari Ramachandran of the Intel Corporation
  37. */
  38. #define _BSD_SOURCE
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <stdio.h>
  42. #include <math.h>
  43. #include <unistd.h>
  44. #include <sys/types.h>
  45. #include <time.h>
  46. #include <netdb.h>
  47. #include <ipmitool/ipmi_dcmi.h>
  48. #include <ipmitool/helper.h>
  49. #include <ipmitool/ipmi.h>
  50. #include <ipmitool/log.h>
  51. #include <ipmitool/ipmi_intf.h>
  52. #include <ipmitool/ipmi_strings.h>
  53. #include <ipmitool/ipmi_mc.h>
  54. #include <ipmitool/ipmi_entity.h>
  55. #include <ipmitool/ipmi_constants.h>
  56. #include <ipmitool/ipmi_sensor.h>
  57. #include "../src/plugins/lanplus/lanplus.h"
  58. #define IPMI_LAN_PORT 0x26f
  59. extern int verbose;
  60. extern int csv_output;
  61. static int ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id);
  62. /*******************************************************************************
  63. * The structs below are the DCMI command option strings. They are printed *
  64. * when the user does not issue enough options or the wrong ones. The reason *
  65. * that the DMCI command strings are in a struct is so that when the *
  66. * specification changes, the strings can be changed quickly with out having *
  67. * to change a lot of the code in the main(). *
  68. ******************************************************************************/
  69. /* Main set of DCMI commands */
  70. const struct dcmi_cmd dcmi_cmd_vals[] = {
  71. { 0x00, "discover", " Used to discover supported DCMI capabilities" },
  72. { 0x01, "power", " Platform power limit command options" },
  73. { 0x02, "sensors", " Prints the available DCMI sensors" },
  74. { 0x03, "asset_tag", " Prints the platform's asset tag" },
  75. { 0x04, "set_asset_tag", " Sets the platform's asset tag" },
  76. { 0x05, "get_mc_id_string", " Get management controller ID string" },
  77. { 0x06, "set_mc_id_string", " Set management controller ID string" },
  78. { 0x07, "thermalpolicy", " Thermal policy get/set" },
  79. { 0x08, "get_temp_reading", " Get Temperature Readings" },
  80. { 0x09, "get_conf_param", " Get DCMI Config Parameters" },
  81. { 0x0A, "set_conf_param", " Set DCMI Config Parameters" },
  82. { 0x0B, "oob_discover", " Ping/Pong Message for DCMI Discovery" },
  83. { 0xFF, NULL, NULL }
  84. };
  85. /* get capabilites */
  86. const struct dcmi_cmd dcmi_capable_vals[] = {
  87. { 0x01, "platform", " Lists the system capabilities" },
  88. { 0x02, "mandatory_attributes", "Lists SEL, identification and"
  89. "temperature attributes" },
  90. { 0x03, "optional_attributes", " Lists power capabilities" },
  91. { 0x04, "managebility access", " Lists OOB channel information" },
  92. { 0xFF, NULL, NULL }
  93. };
  94. /* platform capabilities
  95. * Since they are actually in two bytes, we need three structs to make this
  96. * human readable...
  97. */
  98. const struct dcmi_cmd dcmi_mandatory_platform_capabilities[] = {
  99. { 0x01, "Identification support available", "" },
  100. { 0x02, "SEL logging available", "" },
  101. { 0x03, "Chassis power available", "" },
  102. { 0x04, "Temperature monitor available", "" },
  103. { 0xFF, NULL, NULL }
  104. };
  105. /* optional capabilities */
  106. const struct dcmi_cmd dcmi_optional_platform_capabilities[] = {
  107. { 0x01, "Power management available", "" },
  108. { 0xFF, NULL, NULL }
  109. };
  110. /* access capabilties */
  111. const struct dcmi_cmd dcmi_management_access_capabilities[] = {
  112. { 0x01, "In-band KCS channel available", "" },
  113. { 0x02, "Out-of-band serial TMODE available", "" },
  114. { 0x03, "Out-of-band secondary LAN channel available", "" },
  115. { 0x04, "Out-of-band primary LAN channel available", "" },
  116. { 0x05, "SOL enabled", "" },
  117. { 0x06, "VLAN capable", "" },
  118. { 0xFF, NULL, NULL }
  119. };
  120. /* identification capabilities */
  121. const struct dcmi_cmd dcmi_id_capabilities_vals[] = {
  122. { 0x01, "GUID", "" },
  123. { 0x02, "DHCP hostname", "" },
  124. { 0x03, "Asset tag", "" },
  125. { 0xFF, NULL, NULL }
  126. };
  127. /* Configuration parameters*/
  128. const struct dcmi_cmd dcmi_conf_param_vals[] = {
  129. { 0x01, "activate_dhcp", "\tActivate DHCP"},
  130. { 0x02, "dhcp_config", "\tDHCP Configuration" },
  131. { 0x03, "init", "\t\tInitial timeout interval" },
  132. { 0x04, "timeout", "\t\tServer contact timeout interval" },
  133. { 0x05, "retry", "\t\tServer contact retry interval" },
  134. { 0xFF, NULL, NULL }
  135. };
  136. /* temperature monitoring capabilities */
  137. const struct dcmi_cmd dcmi_temp_monitoring_vals[] = {
  138. { 0x01, "inlet", " Inlet air temperature sensors" },
  139. { 0x02, "cpu", " CPU temperature sensors" },
  140. { 0x03, "baseboard", "Baseboard temperature sensors" },
  141. { 0xff, NULL, NULL }
  142. };
  143. /* These are not comands. These are the DCMI temp sensors and their numbers
  144. * If new sensors are added, they need to be added to this list with their
  145. * sensor number
  146. */
  147. const struct dcmi_cmd dcmi_discvry_snsr_vals[] = {
  148. { 0x40, "Inlet", " Inlet air temperature sensors" },
  149. { 0x41, "CPU", " CPU temperature sensors" },
  150. { 0x42, "Baseboard", "Baseboard temperature sensors" },
  151. { 0xff, NULL, NULL }
  152. };
  153. /* Temperature Readings */
  154. const struct dcmi_cmd dcmi_temp_read_vals[] = {
  155. { 0x40, "Inlet", "Inlet air temperature(40h) " },
  156. { 0x41, "CPU", "CPU temperature sensors(41h) " },
  157. { 0x42, "Baseboard", "Baseboard temperature sensors(42h) " },
  158. { 0xff, NULL, NULL }
  159. };
  160. /* power management/control commands */
  161. const struct dcmi_cmd dcmi_pwrmgmt_vals[] = {
  162. { 0x00, "reading", " Get power related readings from the system" },
  163. { 0x01, "get_limit", " Get the configured power limits" },
  164. { 0x02, "set_limit", " Set a power limit option" },
  165. { 0x03, "activate", " Activate the set power limit" },
  166. { 0x04, "deactivate", "Deactivate the set power limit" },
  167. { 0xFF, NULL, NULL }
  168. };
  169. /* set power limit commands */
  170. const struct dcmi_cmd dcmi_pwrmgmt_set_usage_vals[] = {
  171. { 0x00, "action", " <no_action | sel_logging | power_off>" },
  172. { 0x01, "limit", " <number in Watts>" },
  173. { 0x02, "correction", "<number in milliseconds>" },
  174. { 0x03, "sample", " <number in seconds>" },
  175. { 0xFF, NULL, NULL }
  176. };
  177. /* power management/get action commands */
  178. const struct dcmi_cmd dcmi_pwrmgmt_get_action_vals[] = {
  179. { 0x00, "No Action", ""},
  180. { 0x01, "Hard Power Off & Log Event to SEL", ""},
  181. { 0x02, "OEM reserved (02h)", ""},
  182. { 0x03, "OEM reserved (03h)", ""},
  183. { 0x04, "OEM reserved (04h)", ""},
  184. { 0x05, "OEM reserved (05h)", ""},
  185. { 0x06, "OEM reserved (06h)", ""},
  186. { 0x07, "OEM reserved (07h)", ""},
  187. { 0x08, "OEM reserved (08h)", ""},
  188. { 0x09, "OEM reserved (09h)", ""},
  189. { 0x0a, "OEM reserved (0ah)", ""},
  190. { 0x0b, "OEM reserved (0bh)", ""},
  191. { 0x0c, "OEM reserved (0ch)", ""},
  192. { 0x0d, "OEM reserved (0dh)", ""},
  193. { 0x0e, "OEM reserved (0eh)", ""},
  194. { 0x0f, "OEM reserved (0fh)", ""},
  195. { 0x10, "OEM reserved (10h)", ""},
  196. { 0x11, "Log Event to SEL", ""},
  197. { 0xFF, NULL, NULL }
  198. };
  199. /* power management/set action commands */
  200. const struct dcmi_cmd dcmi_pwrmgmt_action_vals[] = {
  201. { 0x00, "no_action", "No Action"},
  202. { 0x01, "power_off", "Hard Power Off & Log Event to SEL"},
  203. { 0x11, "sel_logging", "Log Event to SEL"},
  204. { 0x02, "oem_02", "OEM reserved (02h)"},
  205. { 0x03, "oem_03", "OEM reserved (03h)"},
  206. { 0x04, "oem_04", "OEM reserved (04h)"},
  207. { 0x05, "oem_05", "OEM reserved (05h)"},
  208. { 0x06, "oem_06", "OEM reserved (06h)"},
  209. { 0x07, "oem_07", "OEM reserved (07h)"},
  210. { 0x08, "oem_08", "OEM reserved (08h)"},
  211. { 0x09, "oem_09", "OEM reserved (09h)"},
  212. { 0x0a, "oem_0a", "OEM reserved (0ah)"},
  213. { 0x0b, "oem_0b", "OEM reserved (0bh)"},
  214. { 0x0c, "oem_0c", "OEM reserved (0ch)"},
  215. { 0x0d, "oem_0d", "OEM reserved (0dh)"},
  216. { 0x0e, "oem_0e", "OEM reserved (0eh)"},
  217. { 0x0f, "oem_0f", "OEM reserved (0fh)"},
  218. { 0x10, "oem_10", "OEM reserved (10h)"},
  219. { 0xFF, NULL, NULL }
  220. };
  221. /* thermal policy action commands */
  222. const struct dcmi_cmd dcmi_thermalpolicy_vals[] = {
  223. { 0x00, "get", "Get thermal policy" },
  224. { 0x01, "set", "Set thermal policy" },
  225. { 0xFF, NULL, NULL }
  226. };
  227. /* thermal policy action commands */
  228. const struct dcmi_cmd dcmi_confparameters_vals[] = {
  229. { 0x00, "get", "Get configuration parameters" },
  230. { 0x01, "set", "Set configuration parameters" },
  231. { 0xFF, NULL, NULL }
  232. };
  233. /* entityIDs used in thermap policy */
  234. const struct dcmi_cmd dcmi_thermalpolicy_set_parameters_vals[] = {
  235. { 0x00, "volatile", " Current Power Cycle" },
  236. { 0x01, "nonvolatile", "Set across power cycles" },
  237. { 0x01, "poweroff", " Hard Power Off system" },
  238. { 0x00, "nopoweroff", " No 'Hard Power Off' action" },
  239. { 0x01, "sel", " Log event to SEL" },
  240. { 0x00, "nosel", " No 'Log event to SEL' action" },
  241. { 0x00, "disabled", " Disabled" },
  242. { 0x00, NULL, NULL }
  243. };
  244. /* DCMI command specific completion code results per 1.0 spec
  245. * 80h - parameter not supported.
  246. * 81h - attempt to set the ‘set in progress’ value (in parameter #0) when not
  247. * in the ‘set complete’ state. (This completion code provides a way to
  248. * recognize that another party has already ‘claimed’ the parameters)
  249. * 82h - attempt to write read-only parameter
  250. * 82h - set not supported on selected channel (e.g. channel is session-less.)
  251. * 83h - access mode not supported
  252. * 84h – Power Limit out of range
  253. * 85h – Correction Time out of range
  254. * 89h – Statistics Reporting Period out of range
  255. */
  256. const struct valstr dcmi_ccode_vals[] = {
  257. { 0x80, "Parameter not supported" },
  258. { 0x81, "Something else has already claimed these parameters" },
  259. { 0x82, "Not supported or failed to write a read-only parameter" },
  260. { 0x83, "Access mode is not supported" },
  261. { 0x84, "Power/Thermal limit out of range" },
  262. { 0x85, "Correction/Exception time out of range" },
  263. { 0x89, "Sample/Statistics Reporting period out of range" },
  264. { 0x8A, "Power limit already active" },
  265. { 0xFF, NULL }
  266. };
  267. /*
  268. * Start of Node Manager Operations
  269. */
  270. const struct dcmi_cmd dcmi_sampling_vals[] = {
  271. { 0x05, "5_sec", "" },
  272. { 0x0f, "15_sec", "" },
  273. { 0x1E, "30_sec", "" },
  274. { 0x41, "1_min", "" },
  275. { 0x43, "3_min", "" },
  276. { 0x47, "7_min", "" },
  277. { 0x4F, "15_min", "" },
  278. { 0x5E, "30_min", "" },
  279. { 0x81, "1_hour", ""},
  280. { 0x00, NULL, NULL },
  281. };
  282. /* Primary Node Manager commands */
  283. const struct dcmi_cmd nm_cmd_vals[] = {
  284. { 0x00, "discover", "Discover Node Manager " },
  285. { 0x01, "capability", "Get Node Manager Capabilities" },
  286. { 0x02, "control", "Enable/Disable Policy Control" },
  287. { 0x03, "policy", "Add/Remove Policies" },
  288. { 0x04, "statistics", "Get Statistics" },
  289. { 0x05, "power", "Set Power Draw Range" },
  290. { 0x06, "suspend", "Set/Get Policy suspend periods" },
  291. { 0x07, "reset", "Reset Statistics" },
  292. { 0x08, "alert", "Set/Get/Clear Alert destination" },
  293. { 0x09, "threshold", "Set/Get Alert Thresholds" },
  294. { 0xFF, NULL, NULL },
  295. };
  296. const struct dcmi_cmd nm_ctl_cmds[] = {
  297. { 0x01, "enable", " <control scope>" },
  298. { 0x00, "disable", "<control scope>"},
  299. { 0xFF, NULL, NULL },
  300. };
  301. const struct dcmi_cmd nm_ctl_domain[] = {
  302. { 0x00, "global", "" },
  303. { 0x02, "per_domain", "<platform|CPU|Memory> (default is platform)" },
  304. { 0x04, "per_policy", "<0-7>" },
  305. { 0xFF, NULL, NULL },
  306. };
  307. /* Node Manager Domain codes */
  308. const struct dcmi_cmd nm_domain_vals[] = {
  309. { 0x00, "platform", "" },
  310. { 0x01, "CPU", "" },
  311. { 0x02, "Memory", "" },
  312. { 0x03, "protection", "" },
  313. { 0x04, "I/O", "" },
  314. { 0xFF, NULL, NULL },
  315. };
  316. const struct dcmi_cmd nm_version_vals[] = {
  317. { 0x01, "1.0", "" },
  318. { 0x02, "1.5", "" },
  319. { 0x03, "2.0", "" },
  320. { 0x04, "2.5", "" },
  321. { 0x05, "3.0", "" },
  322. { 0xFF, NULL, NULL },
  323. };
  324. const struct dcmi_cmd nm_capability_opts[] = {
  325. { 0x01, "domain", "<platform|CPU|Memory> (default is platform)" },
  326. { 0x02, "inlet", "Inlet temp trigger" },
  327. { 0x03, "missing", "Missing Power reading trigger" },
  328. { 0x04, "reset", "Time after Host reset trigger" },
  329. { 0x05, "boot", "Boot time policy" },
  330. { 0xFF, NULL, NULL },
  331. };
  332. const struct dcmi_cmd nm_policy_type_vals[] = {
  333. { 0x00, "No trigger, use Power Limit", "" },
  334. { 0x01, "Inlet temp trigger", "" },
  335. { 0x02, "Missing Power reading trigger", "" },
  336. { 0x03, "Time after Host reset trigger", "" },
  337. { 0x04, "number of cores to disable at boot time", "" },
  338. { 0xFF, NULL, NULL },
  339. };
  340. const struct dcmi_cmd nm_stats_opts[] = {
  341. { 0x01, "domain", "<platform|CPU|Memory> (default is platform)" },
  342. { 0x02, "policy_id", "<0-7>" },
  343. { 0xFF, NULL, NULL },
  344. };
  345. const struct dcmi_cmd nm_stats_mode[] = {
  346. { 0x01, "power", "global power" },
  347. { 0x02, "temps", "inlet temperature" },
  348. { 0x11, "policy_power", "per policy power" },
  349. { 0x12, "policy_temps", "per policy inlet temp" },
  350. { 0x13, "policy_throt", "per policy throttling stats" },
  351. { 0x1B, "requests", "unhandled requests" },
  352. { 0x1C, "response", "response time" },
  353. { 0x1D, "cpu_throttling", "CPU throttling" },
  354. { 0x1E, "mem_throttling", "memory throttling" },
  355. { 0x1F, "comm_fail", "host communication failures" },
  356. { 0xFF, NULL, NULL },
  357. };
  358. const struct dcmi_cmd nm_policy_action[] = {
  359. { 0x00, "get", "nm policy get policy_id <0-7> [domain <platform|CPU|Memory>]" },
  360. { 0x04, "add", "nm policy add policy_id <0-7> [domain <platform|CPU|Memory>] correction auto|soft|hard power <watts>|inlet <temp> trig_lim <param> stats <seconds> enable|disable" },
  361. { 0x05, "remove", "nm policy remove policy_id <0-7> [domain <platform|CPU|Memory>]" },
  362. { 0x06, "limiting", "nm policy limiting [domain <platform|CPU|Memory>]" },
  363. { 0xFF, NULL, NULL },
  364. };
  365. const struct dcmi_cmd nm_policy_options[] = {
  366. { 0x01, "enable", "" },
  367. { 0x02, "disable", "" },
  368. { 0x03, "domain", "" },
  369. { 0x04, "inlet", "inlet air temp full limiting (SCRAM)"},
  370. { 0x06, "correction", "auto, soft, hard" },
  371. { 0x08, "power", "power limit in watts" },
  372. { 0x09, "trig_lim", "time to send alert" },
  373. { 0x0A, "stats", "moving window averaging time" },
  374. { 0x0B, "policy_id", "policy number" },
  375. { 0x0C, "volatile", "save policy in volatiel memory" },
  376. { 0x0D, "cores_off", "at boot time, disable N cores" },
  377. { 0xFF, NULL, NULL },
  378. };
  379. /* if "trigger" command used from nm_policy_options */
  380. const struct dcmi_cmd nm_trigger[] = {
  381. { 0x00, "none", "" },
  382. { 0x01, "temp", "" },
  383. { 0x02, "reset", "" },
  384. { 0x03, "boot", "" },
  385. { 0xFF, NULL, NULL },
  386. };
  387. /* if "correction" used from nm_policy_options */
  388. const struct dcmi_cmd nm_correction[] = {
  389. { 0x00, "auto", "" },
  390. { 0x01, "soft", "" },
  391. { 0x02, "hard", "" },
  392. { 0xFF, NULL, NULL },
  393. };
  394. /* returned codes from get policy */
  395. const struct dcmi_cmd nm_correction_vals[] = {
  396. { 0x00, "no T-state use", "" },
  397. { 0x01, "no T-state use", "" },
  398. { 0x02, "use T-states", "" },
  399. { 0xFF, NULL, NULL },
  400. };
  401. /* if "exception" used from nm_policy_options */
  402. const struct dcmi_cmd nm_exception[] = {
  403. { 0x00, "none", "" },
  404. { 0x01, "alert", "" },
  405. { 0x02, "shutdown", "" },
  406. { 0xFF, NULL, NULL },
  407. };
  408. const struct dcmi_cmd nm_reset_mode[] = {
  409. { 0x00, "global", "" },
  410. { 0x01, "per_policy", "" },
  411. { 0x1B, "requests", "" },
  412. { 0x1C, "response", "" },
  413. { 0x1D, "throttling", "" },
  414. { 0x1E, "memory", "", },
  415. { 0x1F, "comm", "" },
  416. { 0xFF, NULL, NULL },
  417. };
  418. const struct dcmi_cmd nm_power_range[] = {
  419. { 0x01, "domain", "domain <platform|CPU|Memory> (default is platform)" },
  420. { 0x02, "min", " min <integer value>" },
  421. { 0x03, "max", "max <integer value>" },
  422. { 0xFF, NULL, NULL },
  423. };
  424. const struct dcmi_cmd nm_alert_opts[] = {
  425. { 0x01, "set", "nm alert set chan <chan> dest <dest> string <string>" },
  426. { 0x02, "get", "nm alert get" },
  427. { 0x03, "clear", "nm alert clear dest <dest>" },
  428. };
  429. const struct dcmi_cmd nm_set_alert_param[] = {
  430. { 0x01, "chan", "chan <channel>" },
  431. { 0x02, "dest", "dest <destination>" },
  432. { 0x03, "string", "string <string>" },
  433. };
  434. const struct dcmi_cmd nm_thresh_cmds[] = {
  435. { 0x01, "set", "nm thresh set [domain <platform|CPU|Memory>] policy_id <policy> thresh_array" },
  436. { 0x02, "get", "nm thresh get [domain <platform|CPU|Memory>] policy_id <policy>" },
  437. };
  438. const struct dcmi_cmd nm_thresh_param[] = {
  439. { 0x01, "domain", "<platform|CPU|Memory> (default is platform)" },
  440. { 0x02, "policy_id", "<0-7>" },
  441. { 0xFF, NULL, NULL },
  442. };
  443. const struct dcmi_cmd nm_suspend_cmds[] = {
  444. { 0x01, "set", "nm suspend set [domain <platform|CPU|Memory]> policy_id <policy> <start> <stop> <pattern>" },
  445. { 0x02, "get", "nm suspend get [domain <platform|CPU|Memory]> policy_id <policy>" },
  446. };
  447. const struct valstr nm_ccode_vals[] = {
  448. { 0x80, "Policy ID Invalid"},
  449. { 0x81, "Domain ID Invalid"},
  450. { 0x82, "Unknown policy trigger type"},
  451. { 0x84, "Power Limit out of range"},
  452. { 0x85, "Correction Time out of range"},
  453. { 0x86, "Policy Trigger value out of range"},
  454. { 0x88, "Invalid Mode"},
  455. { 0x89, "Statistics Reporting Period out of range"},
  456. { 0x8B, "Invalid value for Aggressive CPU correction field"},
  457. { 0xA1, "No policy is currently limiting for the specified domain ID"},
  458. { 0xC4, "No space available"},
  459. { 0xD4, "Insufficient privledge level due wrong responder LUN"},
  460. { 0xD5, "Policy exists and param unchangeable while enabled"},
  461. { 0xD6, "Command subfunction disabled or unavailable"},
  462. { 0xFF, NULL },
  463. };
  464. /* End strings */
  465. /* This was taken from print_valstr() from helper.c. It serves the same
  466. * purpose but with out the extra formatting. This function simply prints
  467. * the dcmi_cmd struct provided. verthorz specifies to print vertically or
  468. * horizontally. If the string is printed horizontally then a | will be
  469. * printed between each instance of vs[i].str until it is NULL
  470. *
  471. * @vs: value string list to print
  472. * @title: name of this value string list
  473. * @loglevel: what log level to print, -1 for stdout
  474. * @verthorz: printed vertically or horizontally, 0 or 1
  475. */
  476. void
  477. print_strs(const struct dcmi_cmd * vs, const char * title, int loglevel,
  478. int verthorz)
  479. {
  480. int i;
  481. if (vs == NULL)
  482. return;
  483. if (title != NULL) {
  484. if (loglevel < 0)
  485. printf("\n%s\n", title);
  486. else
  487. lprintf(loglevel, "\n%s", title);
  488. }
  489. for (i = 0; vs[i].str != NULL; i++) {
  490. if (loglevel < 0) {
  491. if (vs[i].val < 256)
  492. if (verthorz == 0)
  493. printf(" %s %s\n", vs[i].str, vs[i].desc);
  494. else
  495. printf("%s", vs[i].str);
  496. else if (verthorz == 0)
  497. printf(" %s %s\n", vs[i].str, vs[i].desc);
  498. else
  499. printf("%s", vs[i].str);
  500. } else {
  501. if (vs[i].val < 256)
  502. lprintf(loglevel, " %s %s", vs[i].str, vs[i].desc);
  503. else
  504. lprintf(loglevel, " %s %s", vs[i].str, vs[i].desc);
  505. }
  506. /* Check to see if this is NOT the last element in vs.str if true
  507. * print the | else don't print anything.
  508. */
  509. if ((verthorz == 1) && (vs[i+1].str != NULL))
  510. printf(" | ");
  511. }
  512. if (verthorz == 0) {
  513. if (loglevel < 0) {
  514. printf("\n");
  515. } else {
  516. lprintf(loglevel, "");
  517. }
  518. }
  519. }
  520. /* This was taken from str2val() from helper.c. It serves the same
  521. * purpose but with the addition of a desc field from the structure.
  522. * This function converts the str from the dcmi_cmd struct provided to the
  523. * value associated to the compared string in the struct.
  524. *
  525. * @str: string to compare against
  526. * @vs: dcmi_cmd structure
  527. */
  528. uint16_t
  529. str2val2(const char *str, const struct dcmi_cmd *vs)
  530. {
  531. int i;
  532. if (vs == NULL || str == NULL) {
  533. return 0;
  534. }
  535. for (i = 0; vs[i].str != NULL; i++) {
  536. if (strncasecmp(vs[i].str, str,
  537. __maxlen(str, vs[i].str)) == 0) {
  538. return vs[i].val;
  539. }
  540. }
  541. return vs[i].val;
  542. }
  543. /* This was taken from val2str() from helper.c. It serves the same
  544. * purpose but with the addition of a desc field from the structure.
  545. * This function converts the val and returns a string from the dcmi_cmd
  546. * struct provided in the struct.
  547. *
  548. * @val: value to compare against
  549. * @vs: dcmi_cmd structure
  550. */
  551. const char *
  552. val2str2(uint16_t val, const struct dcmi_cmd *vs)
  553. {
  554. static char un_str[32];
  555. int i;
  556. if (vs == NULL)
  557. return NULL;
  558. for (i = 0; vs[i].str != NULL; i++) {
  559. if (vs[i].val == val)
  560. return vs[i].str;
  561. }
  562. memset(un_str, 0, sizeof (un_str));
  563. snprintf(un_str, 32, "Unknown (0x%x)", val);
  564. return un_str;
  565. }
  566. /* check the DCMI response from the BMC
  567. * @rsp: Response data structure
  568. */
  569. static int
  570. chk_rsp(struct ipmi_rs * rsp)
  571. {
  572. /* if the response from the intf is NULL then the BMC is experiencing
  573. * some issue and cannot complete the command
  574. */
  575. if (rsp == NULL) {
  576. lprintf(LOG_ERR, "\n Unable to get DCMI information");
  577. return 1;
  578. }
  579. /* if the completion code is greater than zero there was an error. We'll
  580. * use val2str from helper.c to print the error from either the DCMI
  581. * completion code struct or the generic IPMI completion_code_vals struct
  582. */
  583. if ((rsp->ccode >= 0x80) && (rsp->ccode <= 0x8F)) {
  584. lprintf(LOG_ERR, "\n DCMI request failed because: %s (%x)",
  585. val2str(rsp->ccode, dcmi_ccode_vals), rsp->ccode);
  586. return 1;
  587. } else if (rsp->ccode > 0) {
  588. lprintf(LOG_ERR, "\n DCMI request failed because: %s (%x)",
  589. val2str(rsp->ccode, completion_code_vals), rsp->ccode);
  590. return 1;
  591. }
  592. /* check to make sure this is a DCMI firmware */
  593. if(rsp->data[0] != IPMI_DCMI) {
  594. printf("\n A valid DCMI command was not returned! (%x)", rsp->data[0]);
  595. return 1;
  596. }
  597. return 0;
  598. }
  599. /* check the Node Manager response from the BMC
  600. * @rsp: Response data structure
  601. */
  602. static int
  603. chk_nm_rsp(struct ipmi_rs * rsp)
  604. {
  605. /* if the response from the intf is NULL then the BMC is experiencing
  606. * some issue and cannot complete the command
  607. */
  608. if (rsp == NULL) {
  609. lprintf(LOG_ERR, "\n No response to NM request");
  610. return 1;
  611. }
  612. /* if the completion code is greater than zero there was an error. We'll
  613. * use val2str from helper.c to print the error from either the DCMI
  614. * completion code struct or the generic IPMI completion_code_vals struct
  615. */
  616. if ((rsp->ccode >= 0x80) && (rsp->ccode <= 0xD6)) {
  617. lprintf(LOG_ERR, "\n NM request failed because: %s (%x)",
  618. val2str(rsp->ccode, nm_ccode_vals), rsp->ccode);
  619. return 1;
  620. } else if (rsp->ccode > 0) {
  621. lprintf(LOG_ERR, "\n NM request failed because: %s (%x)",
  622. val2str(rsp->ccode, completion_code_vals), rsp->ccode);
  623. return 1;
  624. }
  625. /* check to make sure this is a DCMI firmware */
  626. if(rsp->data[0] != 0x57) {
  627. printf("\n A valid NM command was not returned! (%x)", rsp->data[0]);
  628. return 1;
  629. }
  630. return 0;
  631. }
  632. /* Get capabilities ipmi response
  633. *
  634. * This function returns the available capabilities of the platform.
  635. * The reason it returns in the rsp struct is so that it can be used for other
  636. * purposes.
  637. *
  638. * returns ipmi response structure
  639. *
  640. * @intf: ipmi interface handler
  641. * @selector: Parameter selector
  642. */
  643. struct ipmi_rs *
  644. ipmi_dcmi_getcapabilities(struct ipmi_intf * intf, uint8_t selector)
  645. {
  646. struct ipmi_rq req; /* request data to send to the BMC */
  647. uint8_t msg_data[2]; /* 'raw' data to be sent to the BMC */
  648. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  649. msg_data[1] = selector;
  650. memset(&req, 0, sizeof(req));
  651. req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.0 spec */
  652. req.msg.cmd = IPMI_DCMI_COMPAT; /* 0x01 per 1.0 spec */
  653. req.msg.data = msg_data; /* 0xDC 0x01 or the msg_data above */
  654. req.msg.data_len = 2; /* How many times does req.msg.data need to read */
  655. return intf->sendrecv(intf, &req);
  656. }
  657. /* end capabilities struct */
  658. /* Displays capabilities from structure
  659. * returns void
  660. *
  661. * @cmd: dcmi_cmd structure
  662. * @data_val: holds value of what to display
  663. */
  664. void
  665. display_capabilities_attributes(const struct dcmi_cmd *cmd, uint8_t data_val)
  666. {
  667. uint8_t i;
  668. for (i = 0x01; cmd[i-1].val != 0xFF; i++) {
  669. if (data_val & (1<<(i-1))) {
  670. printf(" %s\n", val2str2(i, cmd));
  671. }
  672. }
  673. }
  674. static int
  675. ipmi_dcmi_prnt_oobDiscover(struct ipmi_intf * intf)
  676. {
  677. # ifndef IPMI_INTF_LANPLUS
  678. lprintf(LOG_ERR,
  679. "DCMI Discovery is available only when LANplus(IPMI v2.0) is enabled.");
  680. return (-1);
  681. # else
  682. struct ipmi_session_params *p;
  683. if (intf->opened == 0 && intf->open != NULL) {
  684. if (intf->open(intf) < 0)
  685. return (-1);
  686. }
  687. if (intf == NULL || intf->session == NULL)
  688. return -1;
  689. p = &intf->ssn_params;
  690. if (p->port == 0)
  691. p->port = IPMI_LAN_PORT;
  692. if (p->privlvl == 0)
  693. p->privlvl = IPMI_SESSION_PRIV_ADMIN;
  694. if (p->timeout == 0)
  695. p->timeout = IPMI_LAN_TIMEOUT;
  696. if (p->retry == 0)
  697. p->retry = IPMI_LAN_RETRY;
  698. if (p->hostname == NULL || strlen((const char *)p->hostname) == 0) {
  699. lprintf(LOG_ERR, "No hostname specified!");
  700. return -1;
  701. }
  702. intf->abort = 1;
  703. intf->session->sol_data.sequence_number = 1;
  704. if (ipmi_intf_socket_connect (intf) == -1) {
  705. lprintf(LOG_ERR, "Could not open socket!");
  706. return -1;
  707. }
  708. if (intf->fd < 0) {
  709. lperror(LOG_ERR, "Connect to %s failed",
  710. p->hostname);
  711. intf->close(intf);
  712. return -1;
  713. }
  714. intf->opened = 1;
  715. /* Lets ping/pong */
  716. return ipmiv2_lan_ping(intf);
  717. # endif
  718. }
  719. /* This is the get DCMI Capabilities function to see what the BMC supports.
  720. *
  721. * returns 0 with out error -1 with any errors
  722. *
  723. * @intf: ipmi interface handler
  724. * @selector: selection parameter
  725. */
  726. static int
  727. ipmi_dcmi_prnt_getcapabilities(struct ipmi_intf * intf, uint8_t selector)
  728. {
  729. struct capabilities cape;
  730. struct ipmi_rs * rsp;
  731. uint8_t reply[16];
  732. rsp = ipmi_dcmi_getcapabilities(intf, selector);
  733. int j;
  734. if(chk_rsp(rsp))
  735. return -1;
  736. /* if there were no errors, the command worked! */
  737. memcpy(&cape, rsp->data, sizeof (cape));
  738. memcpy(&reply, rsp->data, sizeof (reply));
  739. /* check to make sure that this is a 1.0/1.1/1.5 command */
  740. if ((cape.conformance != IPMI_DCMI_CONFORM)
  741. && (cape.conformance != IPMI_DCMI_1_1_CONFORM)
  742. && (cape.conformance != IPMI_DCMI_1_5_CONFORM)) {
  743. lprintf(LOG_ERR,
  744. "ERROR! This command is not available on this platform");
  745. return -1;
  746. }
  747. /* check to make sure that this is a rev .01 or .02 */
  748. if (cape.revision != 0x01 && cape.revision != 0x02) {
  749. lprintf(LOG_ERR,
  750. "ERROR! This command is not compatible with this version");
  751. return -1;
  752. }
  753. /* 0x01 - platform capabilities
  754. * 0x02 - Manageability Access Capabilities
  755. * 0x03 - SEL Capability
  756. * 0x04 - Identification Capability
  757. * 0x05 - LAN Out-Of-Band Capability
  758. * 0x06 - Serial Out-Of-Band TMODE Capability
  759. */
  760. switch (selector) {
  761. case 0x01:
  762. printf(" Supported DCMI capabilities:\n");
  763. /* loop through each of the entries in the first byte from the
  764. * struct
  765. */
  766. printf("\n Mandatory platform capabilties\n");
  767. display_capabilities_attributes(
  768. dcmi_mandatory_platform_capabilities, cape.data_byte1);
  769. /* loop through each of the entries in the second byte from the
  770. * struct
  771. */
  772. printf("\n Optional platform capabilties\n");
  773. display_capabilities_attributes(
  774. dcmi_optional_platform_capabilities, cape.data_byte2);
  775. /* loop through each of the entries in the third byte from the
  776. * struct
  777. */
  778. printf("\n Managebility access capabilties\n");
  779. display_capabilities_attributes(
  780. dcmi_management_access_capabilities, cape.data_byte3);
  781. break;
  782. case 0x02:
  783. printf("\n Mandatory platform attributes:\n");
  784. /* byte 1 & 2 data */
  785. printf("\n SEL Attributes: ");
  786. printf("\n SEL automatic rollover is ");
  787. /* mask the 2nd byte of the data response with 10000000b or 0x80
  788. * because of the endian-ness the 15th bit is in the second byte
  789. */
  790. if ((cape.data_byte2 & 0x80))
  791. printf("enabled");
  792. else
  793. printf("not present");
  794. /* since the number of SEL entries is split across the two data
  795. * bytes we will need to bit shift and append them together again
  796. */
  797. /* cast cape.data_byte1 as 16 bits */
  798. uint16_t sel_entries = (uint16_t)cape.data_byte1;
  799. /* or sel_entries with byte 2 and shift it 8 places */
  800. sel_entries |= (uint16_t)cape.data_byte2 << 8;
  801. printf("\n %d SEL entries\n", sel_entries & 0xFFF);
  802. /* byte 3 data */
  803. printf("\n Identification Attributes: \n");
  804. display_capabilities_attributes(
  805. dcmi_id_capabilities_vals, cape.data_byte3);
  806. /* byte 4 data */
  807. printf("\n Temperature Monitoring Attributes: \n");
  808. display_capabilities_attributes(dcmi_temp_monitoring_vals,
  809. cape.data_byte4);
  810. break;
  811. case 0x03:
  812. printf("\n Optional Platform Attributes: \n");
  813. /* Power Management */
  814. printf("\n Power Management:\n");
  815. if (cape.data_byte1 == 0x40) {
  816. printf(" Slave address of device: 20h (BMC)\n" );
  817. } else {
  818. printf(" Slave address of device: %xh (8bits)"
  819. "(Satellite/External controller)\n",
  820. cape.data_byte1);
  821. }
  822. /* Controller channel number (4-7) bits */
  823. if ((cape.data_byte2>>4) == 0x00) {
  824. printf(" Channel number is 0h (Primary BMC)\n");
  825. } else {
  826. printf(" Channel number is %xh \n",
  827. (cape.data_byte2>>4));
  828. }
  829. /* Device revision (0-3) */
  830. printf(" Device revision is %d \n",
  831. cape.data_byte2 &0xf);
  832. break;
  833. case 0x04:
  834. /* LAN */
  835. printf("\n Manageability Access Attributes: \n");
  836. if (cape.data_byte1 == 0xFF) {
  837. printf(" Primary LAN channel is not available for OOB\n");
  838. } else {
  839. printf(" Primary LAN channel number: %d is available\n",
  840. cape.data_byte1);
  841. }
  842. if (cape.data_byte2 == 0xFF) {
  843. printf(" Secondary LAN channel is not available for OOB\n");
  844. } else {
  845. printf(" Secondary LAN channel number: %d is available\n",
  846. cape.data_byte2);
  847. }
  848. /* serial */
  849. if (cape.data_byte3 == 0xFF) {
  850. printf(" No serial channel is available\n");
  851. } else {
  852. printf(" Serial channel number: %d is available\n",
  853. cape.data_byte3);
  854. }
  855. break;
  856. case 0x05:
  857. /* Node Manager */
  858. printf("\n Node Manager Get DCMI Capability Info: \n");
  859. printf(" DCMI Specification %d.%d\n", reply[1], reply[2]);
  860. printf(" Rolling average time period options: %d\n", reply[4]);
  861. printf(" Sample time options: ");
  862. for (j = 1; dcmi_sampling_vals[j-1].str != NULL; j++)
  863. printf(" %s ", val2str2(reply[4+j],dcmi_sampling_vals));
  864. printf("\n");
  865. break;
  866. default:
  867. return -1;
  868. }
  869. return 0;
  870. /* return intf->sendrecv(intf, &req); */
  871. }
  872. /* This is the get asset tag command. This checks the length of the asset tag
  873. * with the first read, then reads n number of bytes thereafter to get the
  874. * complete asset tag.
  875. *
  876. * @intf: ipmi interface handler
  877. * @offset: where to start reading the asset tag
  878. * @length: how much to read
  879. *
  880. * returns ipmi_rs structure
  881. */
  882. struct ipmi_rs *
  883. ipmi_dcmi_getassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length)
  884. {
  885. struct ipmi_rq req; /* request data to send to the BMC */
  886. uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
  887. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  888. msg_data[1] = offset; /* offset 0 */
  889. msg_data[2] = length; /* read one byte */
  890. memset(&req, 0, sizeof(req));
  891. req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
  892. req.msg.cmd = IPMI_DCMI_GETASSET; /* 0x01 per 1.1 spec */
  893. req.msg.data = msg_data; /* msg_data above */
  894. req.msg.data_len = 3; /* How many times does req.msg.data need to read */
  895. return intf->sendrecv(intf, &req);
  896. }
  897. /* This is the get asset tag command. The function first checks to see if the
  898. * platform is capable of getting the asset tag by calling the getcapabilities
  899. * function and checking the response. Then it checks the length of the asset
  900. * tag with the first read, then x number of reads thereafter to get the asset
  901. * complete asset tag then print it.
  902. *
  903. * @intf: ipmi interface handler
  904. *
  905. * returns 0 if no failure, -1 with a failure
  906. */
  907. static int
  908. ipmi_dcmi_prnt_getassettag(struct ipmi_intf * intf)
  909. {
  910. struct ipmi_rs * rsp; /* ipmi response */
  911. uint8_t taglength = 0;
  912. uint8_t getlength = 0;
  913. uint8_t offset = 0;
  914. uint8_t i;
  915. /* now let's get the asset tag length */
  916. rsp = ipmi_dcmi_getassettag(intf, 0, 0);
  917. if (chk_rsp(rsp)) {
  918. return -1;
  919. }
  920. taglength = rsp->data[1];
  921. printf("\n Asset tag: ");
  922. while (taglength) {
  923. getlength = taglength / DCMI_MAX_BYTE_SIZE ?
  924. DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
  925. rsp = ipmi_dcmi_getassettag(intf, offset, getlength);
  926. /* macro has no effect here where can generate sig segv
  927. * if rsp occurs with null
  928. */
  929. if (rsp != NULL) {
  930. GOOD_ASSET_TAG_CCODE(rsp->ccode);
  931. }
  932. if (chk_rsp(rsp)) {
  933. return -1;
  934. }
  935. for (i=0; i<getlength; i++) {
  936. printf("%c", rsp->data[i+2]);
  937. }
  938. offset += getlength;
  939. taglength -= getlength;
  940. }
  941. printf("\n");
  942. return 0;
  943. }
  944. /* This is the set asset tag command. This checks the length of the asset tag
  945. * with the first read, then reads n number of bytes thereafter to set the
  946. * complete asset tag.
  947. *
  948. * @intf: ipmi interface handler
  949. * @offset: offset to write
  950. * @length: number of bytes to write (16 bytes maximum)
  951. * @data: data to write
  952. *
  953. * returns ipmi_rs structure
  954. */
  955. struct ipmi_rs *
  956. ipmi_dcmi_setassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length,
  957. uint8_t *data)
  958. {
  959. struct ipmi_rq req; /* request data to send to the BMC */
  960. uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */
  961. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  962. msg_data[1] = offset; /* offset 0 */
  963. msg_data[2] = length; /* read one byte */
  964. memset(&req, 0, sizeof(req));
  965. req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
  966. req.msg.cmd = IPMI_DCMI_SETASSET; /* 0x08 per 1.1 spec */
  967. req.msg.data = msg_data; /* msg_data above */
  968. /* How many times does req.msg.data need to read */
  969. req.msg.data_len = length + 3;
  970. memcpy(req.msg.data + 3, data, length);
  971. return intf->sendrecv(intf, &req);
  972. }
  973. static int
  974. ipmi_dcmi_prnt_setassettag(struct ipmi_intf * intf, uint8_t * data)
  975. {
  976. struct ipmi_rs * rsp; /* ipmi response */
  977. uint8_t tmpData[DCMI_MAX_BYTE_SIZE];
  978. int32_t taglength = 0;
  979. uint8_t getlength = 0;
  980. uint8_t offset = 0;
  981. uint8_t i;
  982. /* now let's get the asset tag length */
  983. taglength = strlen((char *)data);
  984. if (taglength > 64){
  985. lprintf(LOG_ERR, "\nValue is too long.");
  986. return -1;
  987. }
  988. printf("\n Set Asset Tag: ");
  989. while (taglength) {
  990. getlength = taglength / DCMI_MAX_BYTE_SIZE ?
  991. DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
  992. memcpy(tmpData, data + offset, getlength);
  993. rsp = ipmi_dcmi_setassettag(intf, offset, getlength, tmpData);
  994. if (chk_rsp(rsp)) {
  995. return -1;
  996. }
  997. for (i=0; i<getlength; i++) {
  998. printf("%c", tmpData[i]);
  999. }
  1000. offset += getlength;
  1001. taglength -= getlength;
  1002. }
  1003. printf("\n");
  1004. return 0;
  1005. }
  1006. /* Management Controller Identifier String is provided in order to accommodate
  1007. * the requirement for the management controllers to identify themselves.
  1008. *
  1009. * @intf: ipmi interface handler
  1010. * @offset: offset to read
  1011. * @length: number of bytes to read (16 bytes maximum)
  1012. *
  1013. * returns ipmi_rs structure
  1014. */
  1015. struct ipmi_rs *
  1016. ipmi_dcmi_getmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length)
  1017. {
  1018. struct ipmi_rq req; /* request data to send to the BMC */
  1019. uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
  1020. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  1021. msg_data[1] = offset; /* offset 0 */
  1022. msg_data[2] = length; /* read one byte */
  1023. memset(&req, 0, sizeof(req));
  1024. req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
  1025. req.msg.cmd = IPMI_DCMI_GETMNGCTRLIDS; /* 0x09 per 1.1 spec */
  1026. req.msg.data = msg_data; /* msg_data above */
  1027. /* How many times does req.msg.data need to read */
  1028. req.msg.data_len = 3;
  1029. return intf->sendrecv(intf, &req);
  1030. }
  1031. static int
  1032. ipmi_dcmi_prnt_getmngctrlids(struct ipmi_intf * intf)
  1033. {
  1034. struct ipmi_rs * rsp; /* ipmi response */
  1035. uint8_t taglength = 0;
  1036. uint8_t getlength = 0;
  1037. uint8_t offset = 0;
  1038. uint8_t i;
  1039. /* now let's get the asset tag length */
  1040. rsp = ipmi_dcmi_getmngctrlids(intf, 0, 1);
  1041. if (chk_rsp(rsp)) {
  1042. return -1;
  1043. }
  1044. taglength = rsp->data[1];
  1045. printf("\n Get Management Controller Identifier String: ");
  1046. while (taglength) {
  1047. getlength = taglength / DCMI_MAX_BYTE_SIZE ?
  1048. DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
  1049. rsp = ipmi_dcmi_getmngctrlids(intf, offset, getlength);
  1050. if (chk_rsp(rsp)) {
  1051. return -1;
  1052. }
  1053. for (i=0; i<getlength; i++) {
  1054. printf("%c", rsp->data[i+2]);
  1055. }
  1056. offset += getlength;
  1057. taglength -= getlength;
  1058. }
  1059. printf("\n");
  1060. return 0;
  1061. }
  1062. /* Management Controller Identifier String is provided in order to accommodate
  1063. * the requirement for the management controllers to identify themselves.
  1064. *
  1065. * @intf: ipmi interface handler
  1066. * @offset: offset to write
  1067. * @length: number of bytes to write (16 bytes maximum)
  1068. * @data: data to write
  1069. *
  1070. * returns ipmi_rs structure
  1071. */
  1072. struct ipmi_rs *
  1073. ipmi_dcmi_setmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length,
  1074. uint8_t *data)
  1075. {
  1076. struct ipmi_rq req; /* request data to send to the BMC */
  1077. uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */
  1078. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  1079. msg_data[1] = offset; /* offset 0 */
  1080. msg_data[2] = length; /* read one byte */
  1081. memset(&req, 0, sizeof(req));
  1082. req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
  1083. req.msg.cmd = IPMI_DCMI_SETMNGCTRLIDS; /* 0x0A per 1.1 spec */
  1084. req.msg.data = msg_data; /* msg_data above */
  1085. /* How many times does req.msg.data need to read */
  1086. req.msg.data_len = 3 + length;
  1087. memcpy(req.msg.data + 3, data, length);
  1088. return intf->sendrecv(intf, &req);
  1089. }
  1090. /* Set Asset Tag command provides ability for the management console to set the
  1091. * asset tag as appropriate. Management controller is not responsible for the
  1092. * data format used for the Asset Tag once modified by IPDC.
  1093. *
  1094. * @intf: ipmi interface handler
  1095. *
  1096. * returns 0 if no failure, -1 with a failure
  1097. */
  1098. static int
  1099. ipmi_dcmi_prnt_setmngctrlids(struct ipmi_intf * intf, uint8_t * data)
  1100. {
  1101. struct ipmi_rs * rsp; /* ipmi response */
  1102. uint8_t tmpData[DCMI_MAX_BYTE_SIZE];
  1103. uint8_t taglength = 0;
  1104. uint8_t getlength = 0;
  1105. uint8_t offset = 0;
  1106. uint8_t i;
  1107. data += '\0';
  1108. taglength = strlen((char *)data) +1;
  1109. if (taglength > 64) {
  1110. lprintf(LOG_ERR, "\nValue is too long.");
  1111. return -1;
  1112. }
  1113. printf("\n Set Management Controller Identifier String Command: ");
  1114. while (taglength) {
  1115. getlength = taglength / DCMI_MAX_BYTE_SIZE ?
  1116. DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
  1117. memcpy(tmpData, data + offset, getlength);
  1118. rsp = ipmi_dcmi_setmngctrlids(intf, offset, getlength, tmpData);
  1119. /* because after call "Set mc id string" RMCP+ will go down
  1120. * we have no "rsp"
  1121. */
  1122. if (strncmp(intf->name, "lanplus", 7)) {
  1123. if (chk_rsp(rsp)) {
  1124. return -1;
  1125. }
  1126. }
  1127. for (i=0; i<getlength; i++) {
  1128. printf("%c", tmpData[i]);
  1129. }
  1130. offset += getlength;
  1131. taglength -= getlength;
  1132. }
  1133. printf("\n");
  1134. return 0;
  1135. }
  1136. /* Issues a discovery command to see what sensors are available on the target.
  1137. * system.
  1138. *
  1139. * @intf: ipmi interface handler
  1140. * @isnsr: entity ID
  1141. * @offset: offset (Entity instace start)
  1142. *
  1143. * returns ipmi_rs structure
  1144. */
  1145. struct ipmi_rs *
  1146. ipmi_dcmi_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr, uint8_t offset)
  1147. {
  1148. struct ipmi_rq req; /* ipmi request struct */
  1149. uint8_t msg_data[5]; /* number of request data bytes */
  1150. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  1151. msg_data[1] = 0x01; /* Senser Type = Temp (01h) */
  1152. msg_data[2] = isnsr; /* Sensor Number */
  1153. msg_data[3] = 0x00; /* Entity Instance, set to read all instances */
  1154. msg_data[4] = offset; /* Entity instace start */
  1155. memset(&req, 0, sizeof(req));
  1156. req.msg.netfn = IPMI_NETFN_DCGRP;
  1157. req.msg.cmd = IPMI_DCMI_GETSNSR;
  1158. req.msg.data = msg_data; /* Contents above */
  1159. req.msg.data_len = 5; /* how many times does req.msg.data need to read */
  1160. return intf->sendrecv(intf, &req);
  1161. }
  1162. /* DCMI sensor discovery
  1163. * Uses the dcmi_discvry_snsr_vals struct to print its string and
  1164. * uses the numeric values to request the sensor sdr record id.
  1165. *
  1166. * @intf: ipmi interface handler
  1167. * @isnsr: entity ID
  1168. * @ient: sensor entity id
  1169. */
  1170. static int
  1171. ipmi_dcmi_prnt_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr)
  1172. {
  1173. int i = 0;
  1174. struct ipmi_rs * rsp; /* ipmi response */
  1175. uint8_t records = 0;
  1176. int8_t instances = 0;
  1177. uint8_t offset = 0;
  1178. uint16_t record_id = 0;
  1179. uint8_t id_buff[16]; /* enough for 8 record IDs */
  1180. rsp = ipmi_dcmi_discvry_snsr(intf, isnsr, 0);
  1181. if (chk_rsp(rsp)) {
  1182. return -1;
  1183. }
  1184. instances = rsp->data[1];
  1185. printf("\n%s: %d temperature sensor%s found:\n",
  1186. val2str2(isnsr, dcmi_discvry_snsr_vals),
  1187. instances,
  1188. (instances > 1) ? "s" : "");
  1189. while(instances > 0) {
  1190. ipmi_dcmi_discvry_snsr(intf, isnsr, offset);
  1191. if (chk_rsp(rsp)) {
  1192. return -1;
  1193. }
  1194. records = rsp->data[2];
  1195. /* cache the data since it may be destroyed by subsequent
  1196. * ipmi_xxx calls
  1197. */
  1198. memcpy(id_buff, &rsp->data[3], sizeof (id_buff));
  1199. for (i=0; i<records; i++) {
  1200. /* Record ID is in little endian format */
  1201. record_id = (id_buff[2*i + 1] << 8) + id_buff[2*i];
  1202. printf("Record ID 0x%04x: ", record_id);
  1203. ipmi_print_sensor_info(intf, record_id);
  1204. }
  1205. offset += 8;
  1206. instances -= records;
  1207. }
  1208. return 0;
  1209. }
  1210. /* end sensor discovery */
  1211. /* Power Management get power reading
  1212. *
  1213. * @intf: ipmi interface handler
  1214. */
  1215. static int
  1216. ipmi_dcmi_pwr_rd(struct ipmi_intf * intf, uint8_t sample_time)
  1217. {
  1218. struct ipmi_rs * rsp;
  1219. struct ipmi_rq req;
  1220. struct power_reading val;
  1221. struct tm tm_t;
  1222. time_t t;
  1223. uint8_t msg_data[4]; /* number of request data bytes */
  1224. memset(&tm_t, 0, sizeof(tm_t));
  1225. memset(&t, 0, sizeof(t));
  1226. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  1227. if (sample_time) {
  1228. msg_data[1] = 0x02; /* Enhanced Power Statistics */
  1229. msg_data[2] = sample_time;
  1230. } else {
  1231. msg_data[1] = 0x01; /* Mode Power Status */
  1232. msg_data[2] = 0x00; /* reserved */
  1233. }
  1234. msg_data[3] = 0x00; /* reserved */
  1235. memset(&req, 0, sizeof(req));
  1236. req.msg.netfn = IPMI_NETFN_DCGRP;
  1237. req.msg.cmd = IPMI_DCMI_GETRED; /* Get power reading */
  1238. req.msg.data = msg_data; /* msg_data above */
  1239. req.msg.data_len = 4; /* how many times does req.msg.data need to read */
  1240. rsp = intf->sendrecv(intf, &req);
  1241. if (chk_rsp(rsp)) {
  1242. return -1;
  1243. }
  1244. /* rsp->data[0] is equal to response data byte 2 in spec */
  1245. /* printf("Group Extension Identification: %02x\n", rsp->data[0]); */
  1246. memcpy(&val, rsp->data, sizeof (val));
  1247. t = val.time_stamp;
  1248. gmtime_r(&t, &tm_t);
  1249. printf("\n");
  1250. printf(" Instantaneous power reading: %8d Watts\n",
  1251. val.curr_pwr);
  1252. printf(" Minimum during sampling period: %8d Watts\n",
  1253. val.min_sample);
  1254. printf(" Maximum during sampling period: %8d Watts\n",
  1255. val.max_sample);
  1256. printf(" Average power reading over sample period: %8d Watts\n",
  1257. val.avg_pwr);
  1258. printf(" IPMI timestamp: %s",
  1259. asctime(&tm_t));
  1260. printf(" Sampling period: ");
  1261. if (sample_time)
  1262. printf("%s \n", val2str2(val.sample,dcmi_sampling_vals));
  1263. else
  1264. printf("%08u Seconds.\n", val.sample/1000);
  1265. printf(" Power reading state is: ");
  1266. /* mask the rsp->data so that we only care about bit 6 */
  1267. if((val.state & 0x40) == 0x40) {
  1268. printf("activated");
  1269. } else {
  1270. printf("deactivated");
  1271. }
  1272. printf("\n\n");
  1273. return 0;
  1274. }
  1275. /* end Power Management get reading */
  1276. /* This is the get thermalpolicy command.
  1277. *
  1278. * @intf: ipmi interface handler
  1279. */
  1280. int
  1281. ipmi_dcmi_getthermalpolicy(struct ipmi_intf * intf, uint8_t entityID,
  1282. uint8_t entityInstance)
  1283. {
  1284. struct ipmi_rs * rsp;
  1285. struct ipmi_rq req;
  1286. struct thermal_limit val;
  1287. uint8_t msg_data[3]; /* number of request data bytes */
  1288. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  1289. msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/
  1290. msg_data[2] = entityInstance; /* Entity Instance */
  1291. memset(&req, 0, sizeof(req));
  1292. req.msg.netfn = IPMI_NETFN_DCGRP;
  1293. req.msg.cmd = IPMI_DCMI_GETTERMALLIMIT; /* Get thermal policy reading */
  1294. req.msg.data = msg_data; /* msg_data above */
  1295. req.msg.data_len = 3; /* how many times does req.msg.data need to read */
  1296. rsp = intf->sendrecv(intf, &req);
  1297. if (chk_rsp(rsp)) {
  1298. return -1;
  1299. }
  1300. /* rsp->data[0] is equal to response data byte 2 in spec */
  1301. memcpy(&val, rsp->data, sizeof (val));
  1302. printf("\n");
  1303. printf(" Persistence flag is: %s\n",
  1304. ((val.exceptionActions & 0x80) ? "set" : "notset"));
  1305. printf(" Exception Actions, taken if the Temperature Limit exceeded:\n");
  1306. printf(" Hard Power Off system and log event: %s\n",
  1307. ((val.exceptionActions & 0x40) ? "active":"inactive"));
  1308. printf(" Log event to SEL only: %s\n",
  1309. ((val.exceptionActions & 0x20) ? "active":"inactive"));
  1310. printf(" Temperature Limit %d degrees\n",
  1311. val.tempLimit);
  1312. printf(" Exception Time %d seconds\n",
  1313. val.exceptionTime);
  1314. printf("\n\n");
  1315. return 0;
  1316. }
  1317. /* This is the set thermalpolicy command.
  1318. *
  1319. * @intf: ipmi interface handler
  1320. */
  1321. int
  1322. ipmi_dcmi_setthermalpolicy(struct ipmi_intf * intf,
  1323. uint8_t entityID,
  1324. uint8_t entityInst,
  1325. uint8_t persistanceFlag,
  1326. uint8_t actionHardPowerOff,
  1327. uint8_t actionLogToSEL,
  1328. uint8_t tempLimit,
  1329. uint8_t samplingTimeLSB,
  1330. uint8_t samplingTimeMSB)
  1331. {
  1332. struct ipmi_rs * rsp;
  1333. struct ipmi_rq req;
  1334. uint8_t msg_data[7]; /* number of request data bytes */
  1335. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  1336. msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/
  1337. msg_data[2] = entityInst; /* Entity Instance */
  1338. /* persistance and actions or disabled if no actions */
  1339. msg_data[3] = (((persistanceFlag ? 1 : 0) << 7) |
  1340. ((actionHardPowerOff? 1 : 0) << 6) |
  1341. ((actionLogToSEL ? 1 : 0) << 5));
  1342. msg_data[4] = tempLimit;
  1343. msg_data[5] = samplingTimeLSB;
  1344. msg_data[6] = samplingTimeMSB;
  1345. memset(&req, 0, sizeof(req));
  1346. req.msg.netfn = IPMI_NETFN_DCGRP;
  1347. /* Get thermal policy reading */
  1348. req.msg.cmd = IPMI_DCMI_SETTERMALLIMIT;
  1349. req.msg.data = msg_data; /* msg_data above */
  1350. /* how many times does req.msg.data need to read */
  1351. req.msg.data_len = 7;
  1352. rsp = intf->sendrecv(intf, &req);
  1353. if (chk_rsp(rsp)) {
  1354. return -1;
  1355. }
  1356. /* rsp->data[0] is equal to response data byte 2 in spec */
  1357. printf("\nThermal policy %d for %0Xh entity successfully set.\n\n",
  1358. entityInst, entityID);
  1359. return 0;
  1360. }
  1361. /* This is Get Temperature Readings Command
  1362. *
  1363. * returns ipmi response structure
  1364. *
  1365. * @intf: ipmi interface handler
  1366. */
  1367. struct ipmi_rs *
  1368. ipmi_dcmi_get_temp_readings(struct ipmi_intf * intf,
  1369. uint8_t entityID,
  1370. uint8_t entityInst,
  1371. uint8_t entityInstStart)
  1372. {
  1373. struct ipmi_rq req;
  1374. uint8_t msg_data[5]; /* number of request data bytes */
  1375. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  1376. msg_data[1] = 0x01; /* Sensor type */
  1377. msg_data[2] = entityID; /* Entity Instance */
  1378. msg_data[3] = entityInst;
  1379. msg_data[4] = entityInstStart;
  1380. memset(&req, 0, sizeof(req));
  1381. req.msg.netfn = IPMI_NETFN_DCGRP;
  1382. req.msg.cmd = IPMI_DCMI_GETTEMPRED; /* Get thermal policy reading */
  1383. req.msg.data = msg_data; /* msg_data above */
  1384. /* how many times does req.msg.data need to read */
  1385. req.msg.data_len = 5;
  1386. return intf->sendrecv(intf, &req);
  1387. }
  1388. static int
  1389. ipmi_dcmi_prnt_get_temp_readings(struct ipmi_intf * intf)
  1390. {
  1391. struct ipmi_rs * rsp;
  1392. int i,j, tota_inst, get_inst, offset = 0;
  1393. /* Print sensor description */
  1394. printf("\n\tEntity ID\t\t\tEntity Instance\t Temp. Readings");
  1395. for (i = 0; dcmi_temp_read_vals[i].str != NULL; i++) {
  1396. /* get all of the information about this sensor */
  1397. rsp = ipmi_dcmi_get_temp_readings(intf,
  1398. dcmi_temp_read_vals[i].val, 0, 0);
  1399. if (chk_rsp(rsp)) {
  1400. continue;
  1401. }
  1402. /* Total number of available instances for the Entity ID */
  1403. offset = 0;
  1404. tota_inst = rsp->data[1];
  1405. while (tota_inst > 0) {
  1406. get_inst = ((tota_inst / DCMI_MAX_BYTE_TEMP_READ_SIZE) ?
  1407. DCMI_MAX_BYTE_TEMP_READ_SIZE :
  1408. (tota_inst % DCMI_MAX_BYTE_TEMP_READ_SIZE));
  1409. rsp = ipmi_dcmi_get_temp_readings(intf,
  1410. dcmi_temp_read_vals[i].val, offset, 0);
  1411. if (chk_rsp(rsp)) {
  1412. continue;
  1413. }
  1414. /* Number of sets of Temperature Data in this
  1415. * response (Max 8 per response)
  1416. */
  1417. for (j=0; j < rsp->data[2]*2; j=j+2) {
  1418. /* Print Instance temperature info */
  1419. printf("\n%s",dcmi_temp_read_vals[i].desc);
  1420. printf("\t\t%i\t\t%c%i C", rsp->data[j+4],
  1421. ((rsp->data[j+3]) >> 7) ?
  1422. '-' : '+', (rsp->data[j+3] & 127));
  1423. }
  1424. offset += get_inst;
  1425. tota_inst -= get_inst;
  1426. }
  1427. }
  1428. return 0;
  1429. }
  1430. /* This is Get DCMI Config Parameters Command
  1431. *
  1432. * returns ipmi response structure
  1433. *
  1434. * @intf: ipmi interface handler
  1435. */
  1436. struct ipmi_rs *
  1437. ipmi_dcmi_getconfparam(struct ipmi_intf * intf, int param_selector)
  1438. {
  1439. struct ipmi_rq req;
  1440. uint8_t msg_data[3]; /* number of request data bytes */
  1441. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  1442. msg_data[1] = param_selector; /* Parameter selector */
  1443. /* Set Selector. Selects a given set of parameters under a given Parameter
  1444. * selector value. 00h if parameter doesn't use a Set Selector.
  1445. */
  1446. msg_data[2] = 0x00;
  1447. memset(&req, 0, sizeof(req));
  1448. req.msg.netfn = IPMI_NETFN_DCGRP;
  1449. req.msg.cmd = IPMI_DCMI_GETCONFPARAM; /* Get DCMI Config Parameters */
  1450. req.msg.data = msg_data; /* Contents above */
  1451. /* how many times does req.msg.data need to read */
  1452. req.msg.data_len = 3;
  1453. return intf->sendrecv(intf, &req);
  1454. }
  1455. static int
  1456. ipmi_dcmi_prnt_getconfparam(struct ipmi_intf * intf)
  1457. {
  1458. struct ipmi_rs * rsp;
  1459. const int dcmi_conf_params = 5;
  1460. int param_selector;
  1461. uint16_t tmp_value = 0;
  1462. /* We are not interested in parameter 1 which always will return 0 */
  1463. for (param_selector = 2 ; param_selector <= dcmi_conf_params;
  1464. param_selector++) {
  1465. rsp = ipmi_dcmi_getconfparam(intf, param_selector);
  1466. if (chk_rsp(rsp)) {
  1467. return -1;
  1468. }
  1469. /* Time to print what we have got */
  1470. switch(param_selector) {
  1471. case 2:
  1472. tmp_value = (rsp->data[4])& 1;
  1473. printf("\n\tDHCP Discovery method\t: ");
  1474. printf("\n\t\tManagement Controller ID String is %s",
  1475. tmp_value ? "enabled" : "disabled");
  1476. printf("\n\t\tVendor class identifier DCMI IANA and Vendor class-specific Informationa are %s",
  1477. ((rsp->data[4])& 2) ? "enabled" : "disabled" );
  1478. break;
  1479. case 3:
  1480. printf("\n\tInitial timeout interval\t: %i seconds",
  1481. rsp->data[4]);
  1482. break;
  1483. case 4:
  1484. printf("\n\tServer contact timeout interval\t: %i seconds",
  1485. rsp->data[4] + (rsp->data[5]<<8));
  1486. break;
  1487. case 5:
  1488. printf("\n\tServer contact retry interval\t: %i seconds",
  1489. rsp->data[4] + (rsp->data[5] << 8));
  1490. break;
  1491. default:
  1492. printf("\n\tConfiguration Parameter not supported.");
  1493. }
  1494. }
  1495. return 0;
  1496. }
  1497. /* This is Set DCMI Config Parameters Command
  1498. *
  1499. * returns ipmi response structure
  1500. *
  1501. * @intf: ipmi interface handler
  1502. */
  1503. struct ipmi_rs *
  1504. ipmi_dcmi_setconfparam(struct ipmi_intf * intf, uint8_t param_selector,
  1505. uint16_t value)
  1506. {
  1507. struct ipmi_rq req;
  1508. uint8_t msg_data[5]; /* number of request data bytes */
  1509. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  1510. msg_data[1] = param_selector; /* Parameter selector */
  1511. /* Set Selector (use 00h for parameters that only have one set). */
  1512. msg_data[2] = 0x00;
  1513. if (param_selector > 3) {
  1514. /* One bite more */
  1515. msg_data[3] = value & 0xFF;
  1516. msg_data[4] = value >> 8;
  1517. } else {
  1518. msg_data[3] = value;
  1519. }
  1520. memset(&req, 0, sizeof(req));
  1521. req.msg.netfn = IPMI_NETFN_DCGRP;
  1522. req.msg.cmd = IPMI_DCMI_SETCONFPARAM; /* Set DCMI Config Parameters */
  1523. req.msg.data = msg_data; /* Contents above */
  1524. if (param_selector > 3) {
  1525. /* One bite more */
  1526. /* how many times does req.msg.data need to read */
  1527. req.msg.data_len = 5;
  1528. } else {
  1529. /* how many times does req.msg.data need to read */
  1530. req.msg.data_len = 4;
  1531. }
  1532. return intf->sendrecv(intf, &req);
  1533. }
  1534. /* Power Management get limit ipmi response
  1535. *
  1536. * This function returns the currently set power management settings as an
  1537. * ipmi response structure. The reason it returns in the rsp struct is so
  1538. * that it can be used in the set limit [slimit()] function to populate
  1539. * un-changed or un-edited values.
  1540. *
  1541. * returns ipmi response structure
  1542. *
  1543. * @intf: ipmi interface handler
  1544. */
  1545. struct ipmi_rs * ipmi_dcmi_pwr_glimit(struct ipmi_intf * intf)
  1546. {
  1547. struct ipmi_rq req;
  1548. uint8_t msg_data[3]; /* number of request data bytes */
  1549. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  1550. msg_data[1] = 0x00; /* reserved */
  1551. msg_data[2] = 0x00; /* reserved */
  1552. memset(&req, 0, sizeof(req));
  1553. req.msg.netfn = IPMI_NETFN_DCGRP;
  1554. req.msg.cmd = IPMI_DCMI_GETLMT; /* Get power limit */
  1555. req.msg.data = msg_data; /* Contents above */
  1556. /* how many times does req.msg.data need to read */
  1557. req.msg.data_len = 3;
  1558. return intf->sendrecv(intf, &req);
  1559. }
  1560. /* end Power Management get limit response */
  1561. /* Power Management print the get limit command
  1562. *
  1563. * This function calls the get limit function that returns an ipmi response.
  1564. *
  1565. * returns 0 else 1 with error
  1566. * @intf: ipmi interface handler
  1567. */
  1568. static int
  1569. ipmi_dcmi_pwr_prnt_glimit(struct ipmi_intf * intf)
  1570. {
  1571. struct ipmi_rs * rsp;
  1572. struct power_limit val;
  1573. uint8_t realCc = 0xff;
  1574. rsp = ipmi_dcmi_pwr_glimit(intf);
  1575. /* rsp can be a null so check response before any operation
  1576. * on it to avoid sig segv
  1577. */
  1578. if (rsp != NULL) {
  1579. realCc = rsp->ccode;
  1580. GOOD_PWR_GLIMIT_CCODE(rsp->ccode);
  1581. }
  1582. if (chk_rsp(rsp)) {
  1583. return -1;
  1584. }
  1585. /* rsp->data[0] is equal to response data byte 2 in spec */
  1586. /* printf("Group Extension Identification: %02x\n", rsp->data[0]); */
  1587. memcpy(&val, rsp->data, sizeof (val));
  1588. printf("\n Current Limit State: %s\n",
  1589. (realCc == 0) ?
  1590. "Power Limit Active" : "No Active Power Limit");
  1591. printf(" Exception actions: %s\n",
  1592. val2str2(val.action, dcmi_pwrmgmt_get_action_vals));
  1593. printf(" Power Limit: %i Watts\n", val.limit);
  1594. printf(" Correction time: %i milliseconds\n", val.correction);
  1595. printf(" Sampling period: %i seconds\n", val.sample);
  1596. printf("\n");
  1597. return 0;
  1598. }
  1599. /* end print get limit */
  1600. /* Power Management set limit
  1601. *
  1602. * Undocumented bounds:
  1603. * Power limit: 0 - 0xFFFF
  1604. * Correction period 5750ms to 28751ms or 0x1676 to 0x704F
  1605. * sample period: 3 sec to 65 sec and 69+
  1606. *
  1607. * @intf: ipmi interface handler
  1608. * @option: Power option to change
  1609. * @value: Value of the desired change
  1610. */
  1611. static int
  1612. ipmi_dcmi_pwr_slimit(struct ipmi_intf * intf, const char * option,
  1613. const char * value)
  1614. {
  1615. struct ipmi_rs * rsp; /* ipmi response */
  1616. struct ipmi_rq req; /* ipmi request (to send) */
  1617. struct power_limit val;
  1618. uint8_t msg_data[15]; /* number of request data bytes */
  1619. uint32_t lvalue = 0;
  1620. rsp = ipmi_dcmi_pwr_glimit(intf); /* get the power limit settings */
  1621. /* rsp can be a null so check response before any operation on it to
  1622. * avoid sig segv
  1623. */
  1624. if (rsp != NULL) {
  1625. GOOD_PWR_GLIMIT_CCODE(rsp->ccode);
  1626. }
  1627. if (chk_rsp(rsp)) {
  1628. return -1;
  1629. }
  1630. memcpy(&val, rsp->data, sizeof (val));
  1631. /* same as above; sets the values of the val struct
  1632. * DCMI group ID *
  1633. * val.grp_id = rsp->data[0];
  1634. * exception action *
  1635. * val.action = rsp->data[3]; *
  1636. *
  1637. * power limit in Watts *
  1638. * store 16 bits of the rsp from the 4th entity *
  1639. * val.limit = *(uint16_t*)(&rsp->data[4]);
  1640. * correction period in mS *
  1641. * store 32 bits of the rsp from the 6th entity *
  1642. * val.correction = *(uint32_t*)(&rsp->data[6]);
  1643. * store 16 bits of the rsp from the 12th entity *
  1644. * sample period in seconds *
  1645. * val.sample = *(uint16_t*)(&rsp->data[12]);
  1646. */
  1647. lprintf(LOG_INFO,
  1648. "DCMI IN Limit=%d Correction=%d Action=%d Sample=%d\n",
  1649. val.limit, val.correction, val.action, val.sample);
  1650. switch (str2val2(option, dcmi_pwrmgmt_set_usage_vals)) {
  1651. case 0x00:
  1652. /* action */
  1653. switch (str2val2(value, dcmi_pwrmgmt_action_vals)) {
  1654. case 0x00:
  1655. /* no_action */
  1656. val.action = 0;
  1657. break;
  1658. case 0x01:
  1659. /* power_off */
  1660. val.action = 1;
  1661. break;
  1662. case 0x02:
  1663. /* OEM reserved action */
  1664. val.action = 0x02;
  1665. break;
  1666. case 0x03:
  1667. /* OEM reserved action */
  1668. val.action = 0x03;
  1669. break;
  1670. case 0x04:
  1671. /* OEM reserved action */
  1672. val.action = 0x04;
  1673. break;
  1674. case 0x05:
  1675. /* OEM reserved action */
  1676. val.action = 0x05;
  1677. break;
  1678. case 0x06:
  1679. /* OEM reserved action */
  1680. val.action = 0x06;
  1681. break;
  1682. case 0x07:
  1683. /* OEM reserved action */
  1684. val.action = 0x07;
  1685. break;
  1686. case 0x08:
  1687. /* OEM reserved action */
  1688. val.action = 0x08;
  1689. break;
  1690. case 0x09:
  1691. /* OEM reserved action */
  1692. val.action = 0x09;
  1693. break;
  1694. case 0x0a:
  1695. /* OEM reserved action */
  1696. val.action = 0x0a;
  1697. break;
  1698. case 0x0b:
  1699. /* OEM reserved action */
  1700. val.action = 0x0b;
  1701. break;
  1702. case 0x0c:
  1703. /* OEM reserved action */
  1704. val.action = 0x0c;
  1705. break;
  1706. case 0x0d:
  1707. /* OEM reserved action */
  1708. val.action = 0x0d;
  1709. break;
  1710. case 0x0e:
  1711. /* OEM reserved action */
  1712. val.action = 0x0e;
  1713. break;
  1714. case 0x0f:
  1715. /* OEM reserved action */
  1716. val.action = 0x0f;
  1717. break;
  1718. case 0x10:
  1719. /* OEM reserved action */
  1720. val.action = 0x10;
  1721. break;
  1722. case 0x11:
  1723. /* sel_logging*/
  1724. val.action = 0x11;
  1725. break;
  1726. case 0xFF:
  1727. /* error - not a string we knew what to do with */
  1728. lprintf(LOG_ERR, "Given %s '%s' is invalid.",
  1729. option, value);
  1730. return -1;
  1731. }
  1732. break;
  1733. case 0x01:
  1734. /* limit */
  1735. if (str2uint(value, &lvalue) != 0) {
  1736. lprintf(LOG_ERR, "Given %s '%s' is invalid.",
  1737. option, value);
  1738. return (-1);
  1739. }
  1740. val.limit = *(uint16_t*)(&lvalue);
  1741. break;
  1742. case 0x02:
  1743. /* correction */
  1744. if (str2uint(value, &lvalue) != 0) {
  1745. lprintf(LOG_ERR, "Given %s '%s' is invalid.",
  1746. option, value);
  1747. return (-1);
  1748. }
  1749. val.correction = *(uint32_t*)(&lvalue);
  1750. break;
  1751. case 0x03:
  1752. /* sample */
  1753. if (str2uint(value, &lvalue) != 0) {
  1754. lprintf(LOG_ERR, "Given %s '%s' is invalid.",
  1755. option, value);
  1756. return (-1);
  1757. }
  1758. val.sample = *(uint16_t*)(&lvalue);
  1759. break;
  1760. case 0xff:
  1761. /* no valid options */
  1762. return -1;
  1763. }
  1764. lprintf(LOG_INFO, "DCMI OUT Limit=%d Correction=%d Action=%d Sample=%d\n", val.limit, val.correction, val.action, val.sample);
  1765. msg_data[0] = val.grp_id; /* Group Extension Identification */
  1766. msg_data[1] = 0x00; /* reserved */
  1767. msg_data[2] = 0x00; /* reserved */
  1768. msg_data[3] = 0x00; /* reserved */
  1769. msg_data[4] = val.action; /* exception action; 0x00 disables it */
  1770. /* fill msg_data[5] with the first 16 bits of val.limit */
  1771. *(uint16_t*)(&msg_data[5]) = val.limit;
  1772. /* msg_data[5] = 0xFF;
  1773. * msg_data[6] = 0xFF;
  1774. */
  1775. /* fill msg_data[7] with the first 32 bits of val.correction */
  1776. *(uint32_t*)(&msg_data[7]) = val.correction;
  1777. /* msg_data[7] = 0x76;
  1778. * msg_data[8] = 0x16;
  1779. * msg_data[9] = 0x00;
  1780. * msg_data[10] = 0x00;
  1781. */
  1782. msg_data[11] = 0x00; /* reserved */
  1783. msg_data[12] = 0x00; /* reserved */
  1784. /* fill msg_data[13] with the first 16 bits of val.sample */
  1785. *(uint16_t*)(&msg_data[13]) = val.sample;
  1786. /* msg_data[13] = 0x03; */
  1787. memset(&req, 0, sizeof(req));
  1788. req.msg.netfn = IPMI_NETFN_DCGRP;
  1789. req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */
  1790. req.msg.data = msg_data; /* Contents above */
  1791. /* how many times does req.msg.data need to read */
  1792. req.msg.data_len = 15;
  1793. rsp = intf->sendrecv(intf, &req);
  1794. if (chk_rsp(rsp)) {
  1795. return -1;
  1796. }
  1797. return 0;
  1798. }
  1799. /* end Power Management set limit */
  1800. /* Power Management activate deactivate
  1801. *
  1802. * @intf: ipmi interface handler
  1803. * @option: uint8_t - 0 to deactivate or 1 to activate
  1804. */
  1805. static int
  1806. ipmi_dcmi_pwr_actdeact(struct ipmi_intf * intf, uint8_t option)
  1807. {
  1808. struct ipmi_rs * rsp;
  1809. struct ipmi_rq req;
  1810. uint8_t msg_data[4]; /* number of request data bytes */
  1811. msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
  1812. msg_data[1] = option; /* 0 = Deactivate 1 = Activate */
  1813. msg_data[2] = 0x00; /* reserved */
  1814. msg_data[3] = 0x00; /* reserved */
  1815. memset(&req, 0, sizeof(req));
  1816. req.msg.netfn = IPMI_NETFN_DCGRP;
  1817. req.msg.cmd = IPMI_DCMI_PWRACT; /* Act-deactivate power limit */
  1818. req.msg.data = msg_data; /* Contents above */
  1819. req.msg.data_len = 4; /* how mant times does req.msg.data need to read */
  1820. rsp = intf->sendrecv(intf, &req);
  1821. if (chk_rsp(rsp)) {
  1822. return -1;
  1823. }
  1824. printf("\n Power limit successfully ");
  1825. if (option == 0x00) {
  1826. printf("deactivated");
  1827. } else {
  1828. printf("activated");
  1829. }
  1830. printf("\n");
  1831. return 0;
  1832. }
  1833. /* end power management activate/deactivate */
  1834. /* Node Manager discover */
  1835. static int
  1836. _ipmi_nm_discover(struct ipmi_intf * intf, struct nm_discover *disc)
  1837. {
  1838. struct ipmi_rq req; /* request data to send to the BMC */
  1839. struct ipmi_rs *rsp;
  1840. uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
  1841. msg_data[0] = 0x57;
  1842. msg_data[1] = 1;
  1843. msg_data[2] = 0;
  1844. memset(&req, 0, sizeof(req));
  1845. req.msg.netfn = IPMI_NETFN_OEM;
  1846. req.msg.cmd = IPMI_NM_GET_VERSION;
  1847. req.msg.data = msg_data;
  1848. req.msg.data_len = 3;
  1849. rsp = intf->sendrecv(intf, &req);
  1850. if (chk_nm_rsp(rsp)) {
  1851. return -1;
  1852. }
  1853. memcpy(disc, rsp->data, sizeof (struct nm_discover));
  1854. return 0;
  1855. }
  1856. /* Get NM capabilities
  1857. *
  1858. * This function returns the available capabilities of the platform.
  1859. *
  1860. * returns success/failure
  1861. *
  1862. * @intf: ipmi interface handler
  1863. * @caps: fills in capability struct
  1864. */
  1865. static int
  1866. _ipmi_nm_getcapabilities(struct ipmi_intf * intf, uint8_t domain, uint8_t trigger, struct nm_capability *caps)
  1867. {
  1868. struct ipmi_rq req; /* request data to send to the BMC */
  1869. struct ipmi_rs *rsp;
  1870. uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
  1871. msg_data[0] = 0x57;
  1872. msg_data[1] = 1;
  1873. msg_data[2] = 0;
  1874. msg_data[3] = domain;
  1875. msg_data[4] = trigger; /* power control policy or trigger */
  1876. memset(&req, 0, sizeof(req));
  1877. req.msg.netfn = IPMI_NETFN_OEM;
  1878. req.msg.cmd = IPMI_NM_GET_CAP;
  1879. req.msg.data = msg_data;
  1880. req.msg.data_len = 5;
  1881. rsp = intf->sendrecv(intf, &req);
  1882. if (chk_nm_rsp(rsp)) {
  1883. return -1;
  1884. }
  1885. memcpy(caps, rsp->data, sizeof (struct nm_capability));
  1886. return 0;
  1887. }
  1888. static int
  1889. _ipmi_nm_get_policy(struct ipmi_intf * intf, uint8_t domain, uint8_t policy_id, struct nm_get_policy *policy)
  1890. {
  1891. struct ipmi_rq req; /* request data to send to the BMC */
  1892. struct ipmi_rs *rsp;
  1893. uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
  1894. msg_data[0] = 0x57;
  1895. msg_data[1] = 1;
  1896. msg_data[2] = 0;
  1897. msg_data[3] = domain;
  1898. msg_data[4] = policy_id;
  1899. memset(&req, 0, sizeof(req));
  1900. req.msg.netfn = IPMI_NETFN_OEM;
  1901. req.msg.cmd = IPMI_NM_GET_POLICY;
  1902. req.msg.data = msg_data;
  1903. req.msg.data_len = 5;
  1904. rsp = intf->sendrecv(intf, &req);
  1905. if (chk_nm_rsp(rsp)) {
  1906. return -1;
  1907. }
  1908. memcpy(policy, rsp->data, sizeof (struct nm_get_policy));
  1909. return 0;
  1910. }
  1911. static int
  1912. _ipmi_nm_set_policy(struct ipmi_intf * intf, struct nm_policy *policy)
  1913. {
  1914. struct ipmi_rq req; /* request data to send to the BMC */
  1915. struct ipmi_rs *rsp;
  1916. memset(&req, 0, sizeof(req));
  1917. req.msg.netfn = IPMI_NETFN_OEM;
  1918. req.msg.cmd = IPMI_NM_SET_POLICY;
  1919. req.msg.data = (uint8_t *)policy;
  1920. req.msg.data_len = sizeof(struct nm_policy);
  1921. policy->intel_id[0] = 0x57; policy->intel_id[1] =1; policy->intel_id[2] =0;
  1922. rsp = intf->sendrecv(intf, &req);
  1923. if (chk_nm_rsp(rsp)) {
  1924. return -1;
  1925. }
  1926. return 0;
  1927. }
  1928. static int
  1929. _ipmi_nm_policy_limiting(struct ipmi_intf * intf, uint8_t domain)
  1930. {
  1931. struct ipmi_rq req; /* request data to send to the BMC */
  1932. struct ipmi_rs *rsp;
  1933. uint8_t msg_data[4]; /* 'raw' data to be sent to the BMC */
  1934. memset(&req, 0, sizeof(req));
  1935. req.msg.netfn = IPMI_NETFN_OEM;
  1936. req.msg.cmd = IPMI_NM_LIMITING;
  1937. msg_data[0] = 0x57;
  1938. msg_data[1] = 1;
  1939. msg_data[2] = 0;
  1940. msg_data[3] = domain;
  1941. req.msg.data = msg_data;
  1942. req.msg.data_len = 4;
  1943. rsp = intf->sendrecv(intf, &req);
  1944. /* check for special case error of no policy is limiting */
  1945. if (rsp && (rsp->ccode == 0xA1))
  1946. return 0x80;
  1947. else if (chk_nm_rsp(rsp))
  1948. return -1;
  1949. return rsp->data[0];
  1950. }
  1951. static int
  1952. _ipmi_nm_control(struct ipmi_intf * intf, uint8_t scope, uint8_t domain, uint8_t policy_id)
  1953. {
  1954. struct ipmi_rq req; /* request data to send to the BMC */
  1955. struct ipmi_rs *rsp;
  1956. uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
  1957. msg_data[0] = 0x57;
  1958. msg_data[1] = 1;
  1959. msg_data[2] = 0;
  1960. msg_data[3] = scope;
  1961. msg_data[4] = domain;
  1962. msg_data[5] = policy_id;
  1963. memset(&req, 0, sizeof(req));
  1964. req.msg.netfn = IPMI_NETFN_OEM;
  1965. req.msg.cmd = IPMI_NM_POLICY_CTL;
  1966. req.msg.data = msg_data;
  1967. req.msg.data_len = 6;
  1968. rsp = intf->sendrecv(intf, &req);
  1969. if (chk_nm_rsp(rsp)) {
  1970. return -1;
  1971. }
  1972. return 0;
  1973. }
  1974. /* Get NM statistics
  1975. *
  1976. * This function returns the statistics
  1977. *
  1978. * returns success/failure
  1979. *
  1980. * @intf: ipmi interface handler
  1981. * @selector: Parameter selector
  1982. */
  1983. static int
  1984. _ipmi_nm_statistics(struct ipmi_intf * intf, uint8_t mode, uint8_t domain, uint8_t policy_id, struct nm_statistics *caps)
  1985. {
  1986. struct ipmi_rq req; /* request data to send to the BMC */
  1987. struct ipmi_rs *rsp;
  1988. uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
  1989. msg_data[0] = 0x57;
  1990. msg_data[1] = 1;
  1991. msg_data[2] = 0;
  1992. msg_data[3] = mode;
  1993. msg_data[4] = domain;
  1994. msg_data[5] = policy_id;
  1995. memset(&req, 0, sizeof(req));
  1996. req.msg.netfn = IPMI_NETFN_OEM;
  1997. req.msg.cmd = IPMI_NM_GET_STATS;
  1998. req.msg.data = msg_data;
  1999. req.msg.data_len = 6;
  2000. rsp = intf->sendrecv(intf, &req);
  2001. if (chk_nm_rsp(rsp)) {
  2002. return -1;
  2003. }
  2004. memcpy(caps, rsp->data, sizeof (struct nm_statistics));
  2005. return 0;
  2006. }
  2007. static int
  2008. _ipmi_nm_reset_stats(struct ipmi_intf * intf, uint8_t mode, uint8_t domain, uint8_t policy_id)
  2009. {
  2010. struct ipmi_rq req; /* request data to send to the BMC */
  2011. struct ipmi_rs *rsp;
  2012. uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
  2013. msg_data[0] = 0x57;
  2014. msg_data[1] = 1;
  2015. msg_data[2] = 0;
  2016. msg_data[3] = mode;
  2017. msg_data[4] = domain;
  2018. msg_data[5] = policy_id;
  2019. memset(&req, 0, sizeof(req));
  2020. req.msg.netfn = IPMI_NETFN_OEM;
  2021. req.msg.cmd = IPMI_NM_RESET_STATS;
  2022. req.msg.data = msg_data;
  2023. req.msg.data_len = 6;
  2024. rsp = intf->sendrecv(intf, &req);
  2025. if (chk_nm_rsp(rsp)) {
  2026. return -1;
  2027. }
  2028. return 0;
  2029. }
  2030. static int
  2031. _nm_set_range(struct ipmi_intf * intf, uint8_t domain, uint16_t minimum, uint16_t maximum)
  2032. {
  2033. struct ipmi_rq req; /* request data to send to the BMC */
  2034. struct ipmi_rs *rsp;
  2035. uint8_t msg_data[8]; /* 'raw' data to be sent to the BMC */
  2036. msg_data[0] = 0x57;
  2037. msg_data[1] = 1;
  2038. msg_data[2] = 0;
  2039. msg_data[3] = domain;
  2040. msg_data[4] = minimum & 0xFF;
  2041. msg_data[5] = minimum >> 8;
  2042. msg_data[6] = maximum & 0xFF;
  2043. msg_data[7] = maximum >> 8;
  2044. memset(&req, 0, sizeof(req));
  2045. req.msg.netfn = IPMI_NETFN_OEM;
  2046. req.msg.cmd = IPMI_NM_SET_POWER;
  2047. req.msg.data = msg_data;
  2048. req.msg.data_len = 8;
  2049. rsp = intf->sendrecv(intf, &req);
  2050. if (chk_nm_rsp(rsp)) {
  2051. return -1;
  2052. }
  2053. return 0;
  2054. }
  2055. static int
  2056. _ipmi_nm_get_alert(struct ipmi_intf * intf, struct nm_set_alert *alert)
  2057. {
  2058. struct ipmi_rq req; /* request data to send to the BMC */
  2059. struct ipmi_rs *rsp;
  2060. uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
  2061. msg_data[0] = 0x57;
  2062. msg_data[1] = 1;
  2063. msg_data[2] = 0;
  2064. memset(&req, 0, sizeof(req));
  2065. req.msg.netfn = IPMI_NETFN_OEM;
  2066. req.msg.cmd = IPMI_NM_GET_ALERT_DS;
  2067. req.msg.data = msg_data;
  2068. req.msg.data_len = 3;
  2069. rsp = intf->sendrecv(intf, &req);
  2070. if (chk_nm_rsp(rsp)) {
  2071. return -1;
  2072. }
  2073. memcpy(alert, rsp->data, sizeof (struct nm_set_alert));
  2074. return 0;
  2075. }
  2076. static int
  2077. _ipmi_nm_set_alert(struct ipmi_intf * intf, struct nm_set_alert *alert)
  2078. {
  2079. struct ipmi_rq req; /* request data to send to the BMC */
  2080. struct ipmi_rs *rsp;
  2081. uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
  2082. msg_data[0] = 0x57;
  2083. msg_data[1] = 1;
  2084. msg_data[2] = 0;
  2085. msg_data[3] = alert->chan;
  2086. msg_data[4] = alert->dest;
  2087. msg_data[5] = alert->string;
  2088. memset(&req, 0, sizeof(req));
  2089. req.msg.netfn = IPMI_NETFN_OEM;
  2090. req.msg.cmd = IPMI_NM_SET_ALERT_DS;
  2091. req.msg.data = msg_data;
  2092. req.msg.data_len = 6;
  2093. rsp = intf->sendrecv(intf, &req);
  2094. if (chk_nm_rsp(rsp)) {
  2095. return -1;
  2096. }
  2097. return 0;
  2098. }
  2099. /*
  2100. *
  2101. * get alert threshold values.
  2102. *
  2103. * the list pointer is assumed to point to an array of 16 short integers.
  2104. * This array is filled in for valid thresholds returned.
  2105. */
  2106. static int
  2107. _ipmi_nm_get_thresh(struct ipmi_intf * intf, uint8_t domain, uint8_t policy_id, uint16_t *list)
  2108. {
  2109. struct ipmi_rq req; /* request data to send to the BMC */
  2110. struct ipmi_rs *rsp;
  2111. uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
  2112. msg_data[0] = 0x57;
  2113. msg_data[1] = 1;
  2114. msg_data[2] = 0;
  2115. msg_data[3] = domain;
  2116. msg_data[4] = policy_id;
  2117. memset(&req, 0, sizeof(req));
  2118. req.msg.netfn = IPMI_NETFN_OEM;
  2119. req.msg.cmd = IPMI_NM_GET_ALERT_TH;
  2120. req.msg.data = msg_data;
  2121. req.msg.data_len = 5;
  2122. rsp = intf->sendrecv(intf, &req);
  2123. if (chk_nm_rsp(rsp)) {
  2124. return -1;
  2125. }
  2126. if (rsp->data[3] > 0)
  2127. *list++ = (rsp->data[5] << 8) | rsp->data[4];
  2128. if (rsp->data[3] > 1)
  2129. *list++ = (rsp->data[7] << 8) | rsp->data[6];
  2130. if (rsp->data[3] > 2)
  2131. *list = (rsp->data[9] << 8) | rsp->data[8];
  2132. return 0;
  2133. }
  2134. static int
  2135. _ipmi_nm_set_thresh(struct ipmi_intf * intf, struct nm_thresh * thresh)
  2136. {
  2137. struct ipmi_rq req; /* request data to send to the BMC */
  2138. struct ipmi_rs *rsp;
  2139. uint8_t msg_data[IPMI_NM_SET_THRESH_LEN]; /* 'raw' data to be sent to the BMC */
  2140. memset(&msg_data, 0, sizeof(msg_data));
  2141. msg_data[0] = 0x57;
  2142. msg_data[1] = 1;
  2143. msg_data[2] = 0;
  2144. msg_data[3] = thresh->domain;
  2145. msg_data[4] = thresh->policy_id;
  2146. msg_data[5] = thresh->count;
  2147. if (thresh->count > 0) {
  2148. msg_data[7] = thresh->thresholds[0] >> 8;
  2149. msg_data[6] = thresh->thresholds[0] & 0xFF;
  2150. }
  2151. if (thresh->count > 1) {
  2152. msg_data[9] = thresh->thresholds[1] >> 8;
  2153. msg_data[8] = thresh->thresholds[1] & 0xFF;
  2154. }
  2155. if (thresh->count > 2) {
  2156. msg_data[11] = thresh->thresholds[2] >> 8;
  2157. msg_data[10] = thresh->thresholds[2] & 0xFF;
  2158. }
  2159. memset(&req, 0, sizeof(req));
  2160. req.msg.netfn = IPMI_NETFN_OEM;
  2161. req.msg.cmd = IPMI_NM_SET_ALERT_TH;
  2162. req.msg.data = msg_data;
  2163. req.msg.data_len = 6 + (thresh->count * 2);
  2164. rsp = intf->sendrecv(intf, &req);
  2165. if (chk_nm_rsp(rsp)) {
  2166. return -1;
  2167. }
  2168. return 0;
  2169. }
  2170. /*
  2171. *
  2172. * get suspend periods
  2173. *
  2174. */
  2175. static int
  2176. _ipmi_nm_get_suspend(struct ipmi_intf * intf, uint8_t domain, uint8_t policy_id, int *count, struct nm_period *periods)
  2177. {
  2178. struct ipmi_rq req; /* request data to send to the BMC */
  2179. struct ipmi_rs *rsp;
  2180. uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
  2181. int i;
  2182. msg_data[0] = 0x57;
  2183. msg_data[1] = 1;
  2184. msg_data[2] = 0;
  2185. msg_data[3] = domain;
  2186. msg_data[4] = policy_id;
  2187. memset(&req, 0, sizeof(req));
  2188. req.msg.netfn = IPMI_NETFN_OEM;
  2189. req.msg.cmd = IPMI_NM_GET_SUSPEND;
  2190. req.msg.data = msg_data;
  2191. req.msg.data_len = 5;
  2192. rsp = intf->sendrecv(intf, &req);
  2193. if (chk_nm_rsp(rsp)) {
  2194. return -1;
  2195. }
  2196. *count = rsp->data[3];
  2197. for (i = 0; i < rsp->data[3]; i += 3, periods++) {
  2198. periods->start = rsp->data[4+i];
  2199. periods->stop = rsp->data[5+i];
  2200. periods->repeat = rsp->data[6+i];
  2201. }
  2202. return 0;
  2203. }
  2204. static int
  2205. _ipmi_nm_set_suspend(struct ipmi_intf * intf, struct nm_suspend *suspend)
  2206. {
  2207. struct ipmi_rq req; /* request data to send to the BMC */
  2208. struct ipmi_rs *rsp;
  2209. uint8_t msg_data[21]; /* 6 control bytes + 5 suspend periods, 3 bytes per period */
  2210. struct nm_period *periods;
  2211. int i;
  2212. msg_data[0] = 0x57;
  2213. msg_data[1] = 1;
  2214. msg_data[2] = 0;
  2215. msg_data[3] = suspend->domain;
  2216. msg_data[4] = suspend->policy_id;
  2217. msg_data[5] = suspend->count;
  2218. for (i = 0, periods = &suspend->period[0]; i < (suspend->count*3); i += 3, periods++) {
  2219. msg_data[6+i] = periods->start;
  2220. msg_data[7+i] = periods->stop;
  2221. msg_data[8+i] = periods->repeat;
  2222. }
  2223. memset(&req, 0, sizeof(req));
  2224. req.msg.data_len = 6 + (suspend->count*3);
  2225. req.msg.netfn = IPMI_NETFN_OEM;
  2226. req.msg.cmd = IPMI_NM_SET_SUSPEND;
  2227. req.msg.data = msg_data;
  2228. rsp = intf->sendrecv(intf, &req);
  2229. if (chk_nm_rsp(rsp)) {
  2230. return -1;
  2231. }
  2232. return 0;
  2233. }
  2234. static int
  2235. ipmi_nm_getcapabilities(struct ipmi_intf * intf, int argc, char **argv)
  2236. {
  2237. uint8_t option;
  2238. uint8_t domain = 0; /* default domain of platform */
  2239. uint8_t trigger = 0; /* default power policy (no trigger) */
  2240. struct nm_capability caps;
  2241. while (--argc > 0) {
  2242. argv++;
  2243. if (argv[0] == NULL) break;
  2244. if ((option = str2val2(argv[0], nm_capability_opts)) == 0xFF) {
  2245. print_strs(nm_capability_opts, "Capability commands", LOG_ERR, 0);
  2246. return -1;
  2247. }
  2248. switch (option) {
  2249. case 0x01: /* get domain scope */
  2250. if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
  2251. print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
  2252. return -1;
  2253. }
  2254. break;
  2255. case 0x02: /* Inlet */
  2256. trigger = 1;
  2257. break;
  2258. case 0x03: /* Missing power reading */
  2259. trigger = 2;
  2260. break;
  2261. case 0x04: /* Time after host reset */
  2262. trigger = 3;
  2263. break;
  2264. case 0x05: /* Boot time policy */
  2265. trigger = 4;
  2266. break;
  2267. default:
  2268. break;
  2269. }
  2270. argc--;
  2271. argv++;
  2272. }
  2273. trigger |= 0x10;
  2274. memset(&caps, 0, sizeof(caps));
  2275. if (_ipmi_nm_getcapabilities(intf, domain, trigger, &caps))
  2276. return -1;
  2277. if (csv_output) {
  2278. printf("%d,%u,%u,%u,%u,%u,%u,%s\n",
  2279. caps.max_settings, caps.max_value,caps.min_value,
  2280. caps.min_corr/1000, caps.max_corr/1000,
  2281. caps.min_stats, caps.max_stats,
  2282. val2str2(caps.scope&0xF, nm_domain_vals));
  2283. return 0;
  2284. }
  2285. printf(" power policies:\t\t%d\n", caps.max_settings);
  2286. switch (trigger&0xF) {
  2287. case 0: /* power */
  2288. printf(" max_power\t\t%7u Watts\n min_power\t\t%7u Watts\n",
  2289. caps.max_value, caps.min_value);
  2290. break;
  2291. case 1: /* Inlet */
  2292. printf(" max_temp\t\t%7u C\n min_temp\t\t%7u C\n",
  2293. caps.max_value, caps.min_value);
  2294. break;
  2295. case 2: /* Missing reading time */
  2296. case 3: /* Time after host reset */
  2297. printf(" max_time\t\t%7u Secs\n min_time\t\t%7u Secs\n",
  2298. caps.max_value/10, caps.min_value/10);
  2299. break;
  2300. case 4: /* boot time policy does not use these values */
  2301. default:
  2302. break;
  2303. }
  2304. printf(" min_corr\t\t%7u secs\n max_corr\t\t%7u secs\n",
  2305. caps.min_corr/1000, caps.max_corr/1000);
  2306. printf(" min_stats\t\t%7u secs\n max_stats\t\t%7u secs\n",
  2307. caps.min_stats, caps.max_stats);
  2308. printf(" domain scope:\t%s\n", val2str2(caps.scope&0xF, nm_domain_vals));
  2309. return 0;
  2310. }
  2311. static int
  2312. ipmi_nm_get_policy(struct ipmi_intf * intf, int argc, char **argv)
  2313. {
  2314. uint8_t option;
  2315. uint8_t domain = 0; /* default domain of platform */
  2316. uint8_t policy_id = -1;
  2317. struct nm_get_policy policy;
  2318. memset(&policy, 0, sizeof(policy));
  2319. while (--argc) {
  2320. argv++;
  2321. if (argv[0] == NULL) break;
  2322. if ((option = str2val2(argv[0], nm_policy_options)) == 0xFF) {
  2323. print_strs(nm_policy_options, "Get Policy commands", LOG_ERR, 0);
  2324. return -1;
  2325. }
  2326. switch (option) {
  2327. case 0x03: /* get domain scope */
  2328. if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
  2329. print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
  2330. return -1;
  2331. }
  2332. policy.domain |= domain & 0xF;
  2333. break;
  2334. case 0x0B: /* policy id */
  2335. if (str2uchar(argv[1], &policy_id) < 0) {
  2336. lprintf(LOG_ERR," Policy ID must be a positive integer 0-7.\n");
  2337. return -1;
  2338. }
  2339. break;
  2340. default:
  2341. printf(" Unknown command 0x%x, skipping.\n", option);
  2342. break;
  2343. }
  2344. argc--;
  2345. argv++;
  2346. }
  2347. if (policy_id == 0xFF) {
  2348. print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
  2349. return -1;
  2350. }
  2351. if (_ipmi_nm_get_policy(intf, policy.domain, policy_id, &policy))
  2352. return -1;
  2353. if (csv_output) {
  2354. printf("%s,0x%x,%s,%s,%s,%u,%u,%u,%u,%s\n",
  2355. val2str2(policy.domain&0xF, nm_domain_vals),
  2356. policy.domain,
  2357. (policy.policy_type & 0x10) ? "power" : "nopower ",
  2358. val2str2(policy.policy_type & 0xF, nm_policy_type_vals),
  2359. val2str2(policy.policy_exception, nm_exception),
  2360. policy.policy_limits,
  2361. policy.corr_time,
  2362. policy.trigger_limit,
  2363. policy.stats_period,
  2364. policy.policy_type & 0x80 ? "volatile" : "non-volatile");
  2365. return 0;
  2366. }
  2367. printf(" Power domain: %s\n",
  2368. val2str2(policy.domain&0xF, nm_domain_vals));
  2369. printf(" Policy is %s %s%s%s\n",
  2370. policy.domain&0x10 ? "enabled" : "not enabled",
  2371. policy.domain&0x20 ? "per Domain " : "",
  2372. policy.domain&0x40 ? "Globally " : "",
  2373. policy.domain&0x80 ? "via DCMI api " : "");
  2374. printf(" Policy is %sa power control type.\n", (policy.policy_type & 0x10) ? "" : "not ");
  2375. printf(" Policy Trigger Type: %s\n",
  2376. val2str2(policy.policy_type & 0xF, nm_policy_type_vals));
  2377. printf(" Correction Aggressiveness: %s\n",
  2378. val2str2((policy.policy_type>> 5) & 0x3, nm_correction_vals));
  2379. printf(" Policy Exception Actions: %s\n",
  2380. val2str2(policy.policy_exception, nm_exception));
  2381. printf(" Power Limit: %u Watts\n",
  2382. policy.policy_limits);
  2383. printf(" Correction Time Limit: %u milliseconds\n",
  2384. policy.corr_time);
  2385. printf(" Trigger Limit: %u units\n",
  2386. policy.trigger_limit);
  2387. printf(" Statistics Reporting Period: %u seconds\n",
  2388. policy.stats_period);
  2389. printf(" Policy retention: %s\n",
  2390. policy.policy_type & 0x80 ? "volatile" : "non-volatile");
  2391. if ( (policy_id == 0) && ((policy.domain & 0xf) == 0x3) )
  2392. printf(" HW Prot Power domain: %s\n",
  2393. policy.policy_type & 0x80 ? "Secondary" : "Primary");
  2394. return 0;
  2395. }
  2396. static int
  2397. ipmi_nm_policy(struct ipmi_intf * intf, int argc, char **argv)
  2398. {
  2399. uint8_t action;
  2400. uint8_t option;
  2401. uint8_t correction;
  2402. uint8_t domain = 0; /* default domain of platform */
  2403. uint8_t policy_id = -1;
  2404. uint16_t power, period, inlet;
  2405. uint16_t cores;
  2406. uint32_t limit;
  2407. struct nm_policy policy;
  2408. argv++;
  2409. argc--;
  2410. if ((argv[0] == NULL) ||
  2411. ((action = str2val2(argv[0], nm_policy_action)) == 0xFF)) {
  2412. print_strs(nm_policy_action, "Policy commands", LOG_ERR, 0);
  2413. return -1;
  2414. }
  2415. if (action == 0) /* get */
  2416. return (ipmi_nm_get_policy(intf, argc, argv));
  2417. memset(&policy, 0, sizeof(policy));
  2418. /*
  2419. * nm policy add [domain <param>] enable|disable policy_id <param> correction <opt> power <watts> limit <param> period <param>
  2420. * nm policy remove [domain <param>] policy_id <param>
  2421. * nm policy limiting {domain <param>]
  2422. */
  2423. while (--argc > 0) {
  2424. argv++;
  2425. if (argv[0] == NULL) break;
  2426. if ((option = str2val2(argv[0], nm_policy_options)) == 0xFF) {
  2427. print_strs(nm_policy_options, "Policy options", LOG_ERR, 0);
  2428. return -1;
  2429. }
  2430. switch (option) {
  2431. case 0x01: /* policy enable */
  2432. policy.domain |= IPMI_NM_POLICY_ENABLE;
  2433. break;
  2434. case 0x02: /* policy disable */
  2435. break; /* value is initialized to zero already */
  2436. case 0x03: /* get domain scope */
  2437. if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
  2438. print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
  2439. return -1;
  2440. }
  2441. policy.domain |= domain & 0xF;
  2442. break;
  2443. case 0x04: /* inlet */
  2444. if (str2ushort(argv[1], &inlet) < 0) {
  2445. printf("Inlet Temp value must be 20-45.\n");
  2446. return -1;
  2447. }
  2448. policy.policy_type |= 1;
  2449. policy.policy_limits = 0;
  2450. policy.trigger_limit = inlet;
  2451. break;
  2452. case 0x06: /* get correction action */
  2453. if (action == 0x5) break; /* skip if this is a remove */
  2454. if ((correction = str2val2(argv[1], nm_correction)) == 0xFF) {
  2455. print_strs(nm_correction, "Correction Actions", LOG_ERR, 0);
  2456. return -1;
  2457. }
  2458. policy.policy_type |= (correction << 5);
  2459. break;
  2460. case 0x07: /* not implemented */
  2461. break;
  2462. case 0x08: /* power */
  2463. if (str2ushort(argv[1], &power) < 0) {
  2464. printf("Power limit value must be 0-500.\n");
  2465. return -1;
  2466. }
  2467. policy.policy_limits = power;
  2468. break;
  2469. case 0x09: /* trigger limit */
  2470. if (str2uint(argv[1], &limit) < 0) {
  2471. printf("Trigger Limit value must be positive integer.\n");
  2472. return -1;
  2473. }
  2474. policy.corr_time = limit;
  2475. break;
  2476. case 0x0A: /* statistics period */
  2477. if (str2ushort(argv[1], &period) < 0) {
  2478. printf("Statistics Reporting Period must be positive integer.\n");
  2479. return -1;
  2480. }
  2481. policy.stats_period = period;
  2482. break;
  2483. case 0x0B: /* policy ID */
  2484. if (str2uchar(argv[1], &policy_id) < 0) {
  2485. printf("Policy ID must be a positive integer 0-7.\n");
  2486. return -1;
  2487. }
  2488. policy.policy_id = policy_id;
  2489. break;
  2490. case 0x0C: /* volatile */
  2491. policy.policy_type |= 0x80;
  2492. break;
  2493. case 0x0D: /* cores_off, number of cores to disable at boot time */
  2494. policy.policy_type |= 4;
  2495. if (str2ushort(argv[1], &cores) < 0) {
  2496. printf("number of cores disabled must be 1-127.\n");
  2497. return -1;
  2498. }
  2499. if ((cores < 1) || (cores > 127)) {
  2500. printf("number of cores disabled must be 1-127.\n");
  2501. return -1;
  2502. }
  2503. policy.policy_type |= 4;
  2504. policy.policy_limits = cores << 1;
  2505. break;
  2506. default:
  2507. break;
  2508. }
  2509. argc--;
  2510. argv++;
  2511. }
  2512. if (action == 0x06) { /* limiting */
  2513. if ((limit = _ipmi_nm_policy_limiting(intf, domain) == -1))
  2514. return -1;
  2515. printf("limit %x\n", limit);
  2516. return 0;
  2517. }
  2518. if (policy_id == 0xFF) {
  2519. print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
  2520. return -1;
  2521. }
  2522. if (action == 0x04) /* add */
  2523. policy.policy_type |= 0x10;
  2524. if (_ipmi_nm_set_policy(intf, &policy))
  2525. return -1;
  2526. return 0;
  2527. }
  2528. /* end policy */
  2529. static int
  2530. ipmi_nm_control(struct ipmi_intf * intf, int argc, char **argv)
  2531. {
  2532. uint8_t action;
  2533. uint8_t scope = 0; /* default control scope of global */
  2534. uint8_t domain = 0; /* default domain of platform */
  2535. uint8_t policy_id = -1;
  2536. argv++;
  2537. argc--;
  2538. /* nm_ctl_cmds returns 0 for disable, 1 for enable */
  2539. if ((argv[0] == NULL) ||
  2540. ((action = str2val2(argv[0], nm_ctl_cmds)) == 0xFF)) {
  2541. print_strs(nm_ctl_cmds, "Control parameters:", LOG_ERR, 0);
  2542. print_strs(nm_ctl_domain, "control Scope (required):", LOG_ERR, 0);
  2543. return -1;
  2544. }
  2545. argv++;
  2546. while (--argc) {
  2547. /* nm_ctl_domain returns correct bit field except for action */
  2548. if ((argv[0] == NULL) ||
  2549. ((scope = str2val2(argv[0], nm_ctl_domain)) == 0xFF)) {
  2550. print_strs(nm_ctl_domain, "Control Scope (required):", LOG_ERR, 0);
  2551. return -1;
  2552. }
  2553. argv++;
  2554. if (argv[0] == NULL) break;
  2555. if (scope == 0x02) { /* domain */
  2556. if ((domain = str2val2(argv[0], nm_domain_vals)) == 0xFF) {
  2557. print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
  2558. return -1;
  2559. }
  2560. } else if (scope == 0x04) { /* per_policy */
  2561. if (str2uchar(argv[0], &policy_id) < 0) {
  2562. lprintf(LOG_ERR,"Policy ID must be a positive integer.\n");
  2563. return -1;
  2564. }
  2565. break;
  2566. }
  2567. argc--;
  2568. argv++;
  2569. }
  2570. if ((scope == 0x04) && (policy_id == 0xFF)) {
  2571. print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
  2572. return -1;
  2573. }
  2574. if (_ipmi_nm_control(intf, scope|(action&1), domain, policy_id) < 0 )
  2575. return -1;
  2576. return 0;
  2577. }
  2578. static int
  2579. ipmi_nm_get_statistics(struct ipmi_intf * intf, int argc, char **argv)
  2580. {
  2581. uint8_t mode = 0;
  2582. uint8_t option;
  2583. uint8_t domain = 0; /* default domain of platform */
  2584. uint8_t policy_id = -1;
  2585. int policy_mode = 0;
  2586. int cut;
  2587. char *units = "";
  2588. char datebuf[27];
  2589. struct nm_statistics stats;
  2590. struct tm tm_t;
  2591. time_t t;
  2592. argv++;
  2593. if ((argv[0] == NULL) ||
  2594. ((mode = str2val2(argv[0], nm_stats_mode)) == 0xFF)) {
  2595. print_strs(nm_stats_mode, "Statistics commands", LOG_ERR, 0);
  2596. return -1;
  2597. }
  2598. while (--argc) {
  2599. argv++;
  2600. if (argv[0] == NULL) break;
  2601. if ((option = str2val2(argv[0], nm_stats_opts)) == 0xFF) {
  2602. print_strs(nm_stats_opts, "Control Scope options", LOG_ERR, 0);
  2603. return -1;
  2604. }
  2605. switch (option) {
  2606. case 0x01: /* get domain scope */
  2607. if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
  2608. print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
  2609. return -1;
  2610. }
  2611. break;
  2612. case 0x02: /* policy ID */
  2613. if (str2uchar(argv[1], &policy_id) < 0) {
  2614. lprintf(LOG_ERR,"Policy ID must be a positive integer.\n");
  2615. return -1;
  2616. }
  2617. break;
  2618. default:
  2619. break;
  2620. }
  2621. argc--;
  2622. argv++;
  2623. }
  2624. switch (mode) {
  2625. case 0x01:
  2626. units = "Watts";
  2627. break;
  2628. case 0x02:
  2629. units = "Celsius";
  2630. break;
  2631. case 0x03:
  2632. units = "%";
  2633. break;
  2634. case 0x11:
  2635. case 0x12:
  2636. case 0x13:
  2637. policy_mode = 1;
  2638. units = (mode == 0x11) ? "Watts" : (mode == 0x12) ? "Celsius" : " %";
  2639. if (policy_id == 0xFF) {
  2640. print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
  2641. return -1;
  2642. }
  2643. break;
  2644. default:
  2645. break;
  2646. }
  2647. if (_ipmi_nm_statistics(intf, mode, domain, policy_id, &stats))
  2648. return -1;
  2649. t = stats.time_stamp;
  2650. gmtime_r(&t, &tm_t);
  2651. sprintf(datebuf, "%s", asctime(&tm_t));
  2652. cut = strlen(datebuf) -1;
  2653. datebuf[cut] = 0;
  2654. if (csv_output) {
  2655. printf("%s,%s,%s,%s,%s,%d,%d,%d,%d,%s,%d\n",
  2656. val2str2(stats.id_state & 0xF, nm_domain_vals),
  2657. ((stats.id_state >> 4) & 1) ? (policy_mode ? "Policy Enabled" : "Globally Enabled") : "Disabled" ,
  2658. ((stats.id_state >> 5) & 1) ? "active" : "suspended",
  2659. ((stats.id_state >> 6) & 1) ? "in progress" : "suspended",
  2660. ((stats.id_state >> 7) & 1) ? "triggered" : "not triggered",
  2661. stats.curr_value,
  2662. stats.min_value,
  2663. stats.max_value,
  2664. stats.ave_value,
  2665. datebuf,
  2666. stats.stat_period);
  2667. return 0;
  2668. }
  2669. printf(" Power domain: %s\n",
  2670. val2str2(stats.id_state & 0xF, nm_domain_vals));
  2671. printf(" Policy/Global Admin state %s\n",
  2672. ((stats.id_state >> 4) & 1) ? (policy_mode ? "Policy Enabled" : "Globally Enabled") : "Disabled" );
  2673. printf(" Policy/Global Operational state %s\n",
  2674. ((stats.id_state >> 5) & 1) ? "active" : "suspended");
  2675. printf(" Policy/Global Measurement state %s\n",
  2676. ((stats.id_state >> 6) & 1) ? "in progress" : "suspended");
  2677. printf(" Policy Activation state %s\n",
  2678. ((stats.id_state >> 7) & 1) ? "triggered" : "not triggered");
  2679. printf(" Instantaneous reading: %8d %s\n",
  2680. stats.curr_value, units);
  2681. printf(" Minimum during sampling period: %8d %s\n",
  2682. stats.min_value, units);
  2683. printf(" Maximum during sampling period: %8d %s\n",
  2684. stats.max_value, units);
  2685. printf(" Average reading over sample period: %8d %s\n",
  2686. stats.ave_value, units);
  2687. printf(" IPMI timestamp: %s\n",
  2688. datebuf);
  2689. printf(" Sampling period: %08d Seconds.\n", stats.stat_period);
  2690. printf("\n");
  2691. return 0;
  2692. }
  2693. static int
  2694. ipmi_nm_reset_statistics(struct ipmi_intf * intf, int argc, char **argv)
  2695. {
  2696. uint8_t mode;
  2697. uint8_t option;
  2698. uint8_t domain = 0; /* default domain of platform */
  2699. uint8_t policy_id = -1;
  2700. argv++;
  2701. if ((argv[0] == NULL) ||
  2702. ((mode = str2val2(argv[0], nm_reset_mode)) == 0xFF)) {
  2703. print_strs(nm_reset_mode, "Reset Statistics Modes:", LOG_ERR, 0);
  2704. return -1;
  2705. }
  2706. while (--argc) {
  2707. argv++;
  2708. if (argv[0] == NULL) break;
  2709. if ((option = str2val2(argv[0], nm_stats_opts)) == 0xFF) {
  2710. print_strs(nm_stats_opts, "Reset Scope options", LOG_ERR, 0);
  2711. return -1;
  2712. }
  2713. switch (option) {
  2714. case 0x01: /* get domain scope */
  2715. if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
  2716. print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
  2717. return -1;
  2718. }
  2719. break;
  2720. case 0x02: /* policy ID */
  2721. if (str2uchar(argv[1], &policy_id) < 0) {
  2722. lprintf(LOG_ERR,"Policy ID must be a positive integer.\n");
  2723. return -1;
  2724. }
  2725. break;
  2726. default:
  2727. break;
  2728. }
  2729. argc--;
  2730. argv++;
  2731. }
  2732. if (mode && (policy_id == 0xFF)) {
  2733. print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
  2734. return -1;
  2735. }
  2736. if (_ipmi_nm_reset_stats(intf, mode, domain, policy_id) < 0)
  2737. return -1;
  2738. return 0;
  2739. }
  2740. static int
  2741. ipmi_nm_set_range(struct ipmi_intf * intf, int argc, char **argv)
  2742. {
  2743. uint8_t domain = 0;
  2744. uint8_t param;
  2745. uint16_t minimum = -1;
  2746. uint16_t maximum = -1;
  2747. while (--argc) {
  2748. argv++;
  2749. if (argv[0] == NULL) break;
  2750. if ((param = str2val2(argv[0], nm_power_range)) == 0xFF) {
  2751. print_strs(nm_power_range, "power range parameters:", LOG_ERR, 0);
  2752. return -1;
  2753. }
  2754. switch (param) {
  2755. case 0x01: /* get domain scope */
  2756. if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
  2757. print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
  2758. return -1;
  2759. }
  2760. break;
  2761. case 0x02: /* min */
  2762. if (str2ushort(argv[1], &minimum) < 0) {
  2763. lprintf(LOG_ERR,"Power minimum must be a positive integer.\n");
  2764. return -1;
  2765. }
  2766. break;
  2767. case 0x03: /* max */
  2768. if (str2ushort(argv[1], &maximum) < 0) {
  2769. lprintf(LOG_ERR,"Power maximum must be a positive integer.\n");
  2770. return -1;
  2771. }
  2772. break;
  2773. default:
  2774. break;
  2775. }
  2776. argc--;
  2777. argv++;
  2778. }
  2779. if ((minimum == 0xFFFF) || (maximum == 0xFFFF)) {
  2780. lprintf(LOG_ERR,"Missing parameters: nm power range min <minimum> max <maximum>.\n");
  2781. return -1;
  2782. }
  2783. if (_nm_set_range(intf, domain, minimum, maximum) < 0)
  2784. return -1;
  2785. return 0;
  2786. }
  2787. static int
  2788. ipmi_nm_get_alert(struct ipmi_intf * intf)
  2789. {
  2790. struct nm_set_alert alert;
  2791. memset(&alert, 0, sizeof(alert));
  2792. if (_ipmi_nm_get_alert(intf, &alert))
  2793. return -1;
  2794. if (csv_output) {
  2795. printf("%d,%s,0x%x,%s,0x%x\n",
  2796. alert.chan&0xF,
  2797. (alert.chan >> 7) ? "not registered" : "registered",
  2798. alert.dest,
  2799. (alert.string >> 7) ? "yes" : "no",
  2800. alert.string & 0x7F);
  2801. return 0;
  2802. }
  2803. printf(" Alert Chan: %d\n",
  2804. alert.chan&0xF);
  2805. printf(" Alert Receiver: %s\n",
  2806. (alert.chan >> 7) ? "not registered" : "registered");
  2807. printf(" Alert Lan Destination: 0x%x\n",
  2808. alert.dest);
  2809. printf(" Use Alert String: %s\n",
  2810. (alert.string >> 7) ? "yes" : "no");
  2811. printf(" Alert String Selector: 0x%x\n",
  2812. alert.string & 0x7F);
  2813. return 0;
  2814. }
  2815. static int
  2816. ipmi_nm_alert(struct ipmi_intf * intf, int argc, char **argv)
  2817. {
  2818. uint8_t param;
  2819. uint8_t action;
  2820. uint8_t chan = -1;
  2821. uint8_t dest = -1;
  2822. uint8_t string = -1;
  2823. struct nm_set_alert alert;
  2824. argv++;
  2825. argc--;
  2826. if ((argv[0] == NULL) ||
  2827. ((action = str2val2(argv[0], nm_alert_opts)) == 0xFF)) {
  2828. print_strs(nm_alert_opts, "Alert commands", LOG_ERR, 0);
  2829. return -1;
  2830. }
  2831. if (action == 0x02) /* get */
  2832. return (ipmi_nm_get_alert(intf));
  2833. /* set */
  2834. memset(&alert, 0, sizeof(alert));
  2835. while (--argc) {
  2836. argv++;
  2837. if (argv[0] == NULL) break;
  2838. if ((param = str2val2(argv[0], nm_set_alert_param)) == 0xFF) {
  2839. print_strs(nm_set_alert_param, "Set alert Parameters:", LOG_ERR, 0);
  2840. return -1;
  2841. }
  2842. switch (param) {
  2843. case 0x01: /* channnel */
  2844. if (str2uchar(argv[1], &chan) < 0) {
  2845. lprintf(LOG_ERR,"Alert Lan chan must be a positive integer.\n");
  2846. return -1;
  2847. }
  2848. if (action == 0x03) /* Clear */
  2849. chan |= 0x80; /* deactivate alert reciever */
  2850. break;
  2851. case 0x02: /* dest */
  2852. if (str2uchar(argv[1], &dest) < 0) {
  2853. lprintf(LOG_ERR,"Alert Destination must be a positive integer.\n");
  2854. return -1;
  2855. }
  2856. break;
  2857. case 0x03: /* string number */
  2858. if (str2uchar(argv[1], &string) < 0) {
  2859. lprintf(LOG_ERR,"Alert String # must be a positive integer.\n");
  2860. return -1;
  2861. }
  2862. string |= 0x80; /* set string select flag */
  2863. break;
  2864. }
  2865. argc--;
  2866. argv++;
  2867. }
  2868. if ((chan == 0xFF) || (dest == 0xFF)) {
  2869. print_strs(nm_set_alert_param, "Must set alert chan and dest params.", LOG_ERR, 0);
  2870. return -1;
  2871. }
  2872. if (string == 0xFF) string = 0;
  2873. alert.chan = chan;
  2874. alert.dest = dest;
  2875. alert.string = string;
  2876. if (_ipmi_nm_set_alert(intf, &alert))
  2877. return -1;
  2878. return 0;
  2879. }
  2880. static int
  2881. ipmi_nm_get_thresh(struct ipmi_intf *intf, uint8_t domain, uint8_t policy_id)
  2882. {
  2883. uint16_t list[3];
  2884. memset(list, 0, sizeof(list));
  2885. if (_ipmi_nm_get_thresh(intf, domain, policy_id, &list[0]))
  2886. return -1;
  2887. printf(" Alert Threshold domain: %s\n",
  2888. val2str2(domain, nm_domain_vals));
  2889. printf(" Alert Threshold Policy ID: %d\n",
  2890. policy_id);
  2891. printf(" Alert Threshold 1: %d\n",
  2892. list[0]);
  2893. printf(" Alert Threshold 2: %d\n",
  2894. list[1]);
  2895. printf(" Alert Threshold 3: %d\n",
  2896. list[2]);
  2897. return 0;
  2898. }
  2899. static int
  2900. ipmi_nm_thresh(struct ipmi_intf * intf, int argc, char **argv)
  2901. {
  2902. uint8_t option;
  2903. uint8_t action;
  2904. uint8_t domain = 0; /* default domain of platform */
  2905. uint8_t policy_id = -1;
  2906. struct nm_thresh thresh;
  2907. int i = 0;
  2908. argv++;
  2909. argc--;
  2910. /* set or get */
  2911. if ((argv[0] == NULL) || (argc < 3) ||
  2912. ((action = str2val2(argv[0], nm_thresh_cmds)) == 0xFF)) {
  2913. print_strs(nm_thresh_cmds, "Theshold commands", LOG_ERR, 0);
  2914. return -1;
  2915. }
  2916. memset(&thresh, 0, sizeof(thresh));
  2917. while (--argc) {
  2918. argv++;
  2919. if (argv[0] == NULL) break;
  2920. option = str2val2(argv[0], nm_thresh_param);
  2921. switch (option) {
  2922. case 0x01: /* get domain scope */
  2923. if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
  2924. print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
  2925. return -1;
  2926. }
  2927. argc--;
  2928. argv++;
  2929. break;
  2930. case 0x02: /* policy ID */
  2931. if (str2uchar(argv[1], &policy_id) < 0) {
  2932. lprintf(LOG_ERR,"Policy ID must be a positive integer.\n");
  2933. return -1;
  2934. }
  2935. argc--;
  2936. argv++;
  2937. break;
  2938. case 0xFF:
  2939. if (i > 2) {
  2940. lprintf(LOG_ERR,"Set Threshold requires 1, 2, or 3 threshold integer values.\n");
  2941. return -1;
  2942. }
  2943. if (str2ushort(argv[0], &thresh.thresholds[i++]) < 0) {
  2944. lprintf(LOG_ERR,"threshold value %d count must be a positive integer.\n", i);
  2945. return -1;
  2946. }
  2947. default:
  2948. break;
  2949. }
  2950. }
  2951. if (policy_id == 0xFF) {
  2952. print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
  2953. return -1;
  2954. }
  2955. if (action == 0x02) /* get */
  2956. return (ipmi_nm_get_thresh(intf, domain, policy_id));
  2957. thresh.domain = domain;
  2958. thresh.policy_id = policy_id;
  2959. thresh.count = i;
  2960. if (_ipmi_nm_set_thresh(intf, &thresh) < 0)
  2961. return -1;
  2962. return 0;
  2963. }
  2964. static inline int
  2965. click2hour(int click)
  2966. {
  2967. if ((click*6) < 60) return 0;
  2968. return ((click*6)/60);
  2969. }
  2970. static inline int
  2971. click2min(int click)
  2972. {
  2973. if (!click) return 0;
  2974. if ((click*6) < 60) return click*6;
  2975. return (click*6)%60;
  2976. }
  2977. static int
  2978. ipmi_nm_get_suspend(struct ipmi_intf *intf, uint8_t domain, uint8_t policy_id)
  2979. {
  2980. struct nm_period periods[5];
  2981. int i;
  2982. int j;
  2983. int count = 0;
  2984. const char *days[7] = {"M", "Tu", "W", "Th", "F", "Sa", "Su"};
  2985. memset(periods, 0, sizeof(periods));
  2986. if (_ipmi_nm_get_suspend(intf, domain, policy_id, &count, &periods[0]))
  2987. return -1;
  2988. printf(" Suspend Policy domain: %s\n",
  2989. val2str2(domain, nm_domain_vals));
  2990. printf(" Suspend Policy Policy ID: %d\n",
  2991. policy_id);
  2992. if (!count) {
  2993. printf(" No suspend Periods.\n");
  2994. return 0;
  2995. }
  2996. for (i = 0; i < count; i++) {
  2997. printf(" Suspend Period %d: %02d:%02d to %02d:%02d",
  2998. i, click2hour(periods[i].start), click2min(periods[i].start),
  2999. click2hour(periods[i].stop), click2min(periods[i].stop));
  3000. if (periods[i].repeat) printf(", ");
  3001. for (j = 0; j < 7; j++)
  3002. printf("%s", (periods[i].repeat >> j)&1 ? days[j] : "");
  3003. printf("\n");
  3004. }
  3005. return 0;
  3006. }
  3007. static int
  3008. ipmi_nm_suspend(struct ipmi_intf * intf, int argc, char **argv)
  3009. {
  3010. uint8_t option;
  3011. uint8_t action;
  3012. uint8_t domain = 0; /* default domain of platform */
  3013. uint8_t policy_id = -1;
  3014. uint8_t count = 0;
  3015. struct nm_suspend suspend;
  3016. int i;
  3017. argv++;
  3018. argc--;
  3019. /* set or get */
  3020. if ((argv[0] == NULL) || (argc < 3) ||
  3021. ((action = str2val2(argv[0], nm_suspend_cmds)) == 0xFF)) {
  3022. print_strs(nm_suspend_cmds, "Suspend commands", LOG_ERR, 0);
  3023. return -1;
  3024. }
  3025. memset(&suspend, 0, sizeof(suspend));
  3026. while (--argc > 0) {
  3027. argv++;
  3028. if (argv[0] == NULL) break;
  3029. option = str2val2(argv[0], nm_thresh_param);
  3030. switch (option) {
  3031. case 0x01: /* get domain scope */
  3032. if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
  3033. print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
  3034. return -1;
  3035. }
  3036. argc--;
  3037. argv++;
  3038. break;
  3039. case 0x02: /* policy ID */
  3040. if (str2uchar(argv[1], &policy_id) < 0) {
  3041. lprintf(LOG_ERR,"Policy ID must be a positive integer.\n");
  3042. return -1;
  3043. }
  3044. argc--;
  3045. argv++;
  3046. break;
  3047. case 0xFF: /* process periods */
  3048. for (i = 0; count < IPMI_NM_SUSPEND_PERIOD_MAX; i += 3, count++) {
  3049. if (argc < 3) {
  3050. lprintf(LOG_ERR,"Error: suspend period requires a start, stop, and repeat values.\n");
  3051. return -1;
  3052. }
  3053. if (str2uchar(argv[i+0], &suspend.period[count].start) < 0) {
  3054. lprintf(LOG_ERR,"suspend start value %d must be 0-239.\n", count);
  3055. return -1;
  3056. }
  3057. if (str2uchar(argv[i+1], &suspend.period[count].stop) < 0) {
  3058. lprintf(LOG_ERR,"suspend stop value %d must be 0-239.\n", count);
  3059. return -1;
  3060. }
  3061. if (str2uchar(argv[i+2], &suspend.period[count].repeat) < 0) {
  3062. lprintf(LOG_ERR,"suspend repeat value %d unable to convert.\n", count);
  3063. return -1;
  3064. }
  3065. argc -= 3;
  3066. if (argc <= 0)
  3067. break;
  3068. }
  3069. if (argc <= 0)
  3070. break;
  3071. break;
  3072. default:
  3073. break;
  3074. }
  3075. }
  3076. if (action == 0x02) /* get */
  3077. return (ipmi_nm_get_suspend(intf, domain, policy_id));
  3078. suspend.domain = domain;
  3079. suspend.policy_id = policy_id;
  3080. if (_ipmi_nm_set_suspend(intf, &suspend) < 0)
  3081. return -1;
  3082. return 0;
  3083. }
  3084. /* end nm */
  3085. static int
  3086. ipmi_dcmi_set_limit(struct ipmi_intf * intf, int argc, char **argv)
  3087. {
  3088. int rc = 0;
  3089. if ( argc == 10) {
  3090. /* Let`s initialize dcmi power parameters */
  3091. struct ipmi_rq req;
  3092. uint8_t data[256];
  3093. uint16_t sample = 0;
  3094. uint16_t limit = 0;
  3095. uint32_t correction = 0;
  3096. struct ipmi_rs *rsp;
  3097. memset(data, 0, sizeof(data));
  3098. memset(&req, 0, sizeof(req));
  3099. req.msg.netfn = IPMI_NETFN_DCGRP;
  3100. req.msg.lun = 0x00;
  3101. req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */
  3102. req.msg.data = data; /* Contents above */
  3103. req.msg.data_len = 15;
  3104. data[0] = IPMI_DCMI; /* Group Extension Identification */
  3105. data[1] = 0x0; /* reserved */
  3106. data[2] = 0x0; /* reserved */
  3107. data[3] = 0x0; /* reserved */
  3108. /* action */
  3109. switch (str2val2(argv[2], dcmi_pwrmgmt_action_vals)) {
  3110. case 0x00:
  3111. /* no_action */
  3112. data[4] = 0x00;
  3113. break;
  3114. case 0x01:
  3115. /* power_off */
  3116. data[4] = 0x01;
  3117. break;
  3118. case 0x11:
  3119. /* sel_logging*/
  3120. data[4] = 0x11;
  3121. break;
  3122. case 0xFF:
  3123. /* error - not a string we knew what to do with */
  3124. lprintf(LOG_ERR, "Given Action '%s' is invalid.",
  3125. argv[2]);
  3126. return -1;
  3127. }
  3128. /* limit */
  3129. if (str2ushort(argv[4], &limit) != 0) {
  3130. lprintf(LOG_ERR,
  3131. "Given Limit '%s' is invalid.",
  3132. argv[4]);
  3133. return (-1);
  3134. }
  3135. data[5] = limit >> 0;
  3136. data[6] = limit >> 8;
  3137. /* correction */
  3138. if (str2uint(argv[6], &correction) != 0) {
  3139. lprintf(LOG_ERR,
  3140. "Given Correction '%s' is invalid.",
  3141. argv[6]);
  3142. return (-1);
  3143. }
  3144. data[7] = correction >> 0;
  3145. data[8] = correction >> 8;
  3146. data[9] = correction >> 16;
  3147. data[10] = correction >> 24;
  3148. data[11] = 0x00; /* reserved */
  3149. data[12] = 0x00; /* reserved */
  3150. /* sample */
  3151. if (str2ushort(argv[8], &sample) != 0) {
  3152. lprintf(LOG_ERR,
  3153. "Given Sample '%s' is invalid.",
  3154. argv[8]);
  3155. return (-1);
  3156. }
  3157. data[13] = sample >> 0;
  3158. data[14] = sample >> 8;
  3159. rsp = intf->sendrecv(intf, &req);
  3160. if (chk_rsp(rsp)) {
  3161. return -1;
  3162. }
  3163. } else {
  3164. /* loop through each parameter and value until we have neither */
  3165. while ((argv[1] != NULL) && (argv[2] != NULL)) {
  3166. rc = ipmi_dcmi_pwr_slimit(intf, argv[1], argv[2]);
  3167. /* catch any error that the set limit function returned */
  3168. if (rc > 0) {
  3169. print_strs(dcmi_pwrmgmt_set_usage_vals,
  3170. "set_limit <parameter> <value>", LOG_ERR, 0);
  3171. return -1;
  3172. }
  3173. /* the first argument is the command and the second is the
  3174. * value. Move argv two places; what is now 3 will be 1
  3175. */
  3176. argv+=2;
  3177. }
  3178. }
  3179. return rc;
  3180. }
  3181. static int
  3182. ipmi_dcmi_parse_power(struct ipmi_intf * intf, int argc, char **argv)
  3183. {
  3184. int rc = 0;
  3185. uint8_t sample_time = 0;
  3186. /* power management */
  3187. switch (str2val2(argv[0], dcmi_pwrmgmt_vals)) {
  3188. case 0x00:
  3189. /* get reading */
  3190. if (argv[1] != NULL) {
  3191. if (!(sample_time = str2val2(argv[1], dcmi_sampling_vals))) {
  3192. print_strs(dcmi_sampling_vals,
  3193. "Invalid sample time. Valid times are: ",
  3194. LOG_ERR, 1);
  3195. printf("\n");
  3196. return -1;
  3197. }
  3198. }
  3199. rc = ipmi_dcmi_pwr_rd(intf, sample_time);
  3200. break;
  3201. case 0x01:
  3202. /* get limit */
  3203. /* because the get limit function is also used to
  3204. * populate unchanged values for the set limit
  3205. * command it returns an ipmi response structure
  3206. */
  3207. rc = ipmi_dcmi_pwr_prnt_glimit(intf);
  3208. break;
  3209. case 0x02:
  3210. /* set limit */
  3211. if (argc < 4) {
  3212. print_strs(dcmi_pwrmgmt_set_usage_vals,
  3213. "set_limit <parameter> <value>",
  3214. LOG_ERR, 0);
  3215. return -1;
  3216. }
  3217. if (ipmi_dcmi_set_limit(intf, argc, argv) < 0)
  3218. return -1;
  3219. rc = ipmi_dcmi_pwr_prnt_glimit(intf);
  3220. break;
  3221. case 0x03:
  3222. /* activate */
  3223. rc = ipmi_dcmi_pwr_actdeact(intf, 1);
  3224. break;
  3225. case 0x04:
  3226. /* deactivate */
  3227. rc = ipmi_dcmi_pwr_actdeact(intf, 0);
  3228. break;
  3229. default:
  3230. /* no valid options */
  3231. print_strs(dcmi_pwrmgmt_vals,
  3232. "power <command>", LOG_ERR, 0);
  3233. break;
  3234. }
  3235. return rc;
  3236. }
  3237. /* end dcmi power command */
  3238. static int
  3239. ipmi_dcmi_thermalpolicy(struct ipmi_intf * intf, int argc, char **argv)
  3240. {
  3241. int rc = 0;
  3242. uint8_t entityID = 0;
  3243. uint8_t entityInst = 0;
  3244. uint8_t persistanceFlag;
  3245. uint8_t actionHardPowerOff;
  3246. uint8_t actionLogToSEL;
  3247. uint8_t tempLimit = 0;
  3248. uint8_t samplingTimeLSB;
  3249. uint8_t samplingTimeMSB;
  3250. uint16_t samplingTime = 0;
  3251. /* Thermal policy get/set */
  3252. /* dcmitool dcmi thermalpolicy get */
  3253. switch (str2val2(argv[1], dcmi_thermalpolicy_vals)) {
  3254. case 0x00:
  3255. if (argc < 4) {
  3256. lprintf(LOG_NOTICE, "Get <entityID> <instanceID>");
  3257. return -1;
  3258. }
  3259. if (str2uchar(argv[2], &entityID) != 0) {
  3260. lprintf(LOG_ERR,
  3261. "Given Entity ID '%s' is invalid.",
  3262. argv[2]);
  3263. return (-1);
  3264. }
  3265. if (str2uchar(argv[3], &entityInst) != 0) {
  3266. lprintf(LOG_ERR,
  3267. "Given Instance ID '%s' is invalid.",
  3268. argv[3]);
  3269. return (-1);
  3270. }
  3271. rc = ipmi_dcmi_getthermalpolicy(intf, entityID, entityInst);
  3272. break;
  3273. case 0x01:
  3274. if (argc < 4) {
  3275. lprintf(LOG_NOTICE, "Set <entityID> <instanceID>");
  3276. return -1;
  3277. } else if (argc < 9) {
  3278. print_strs(dcmi_thermalpolicy_set_parameters_vals,
  3279. "Set thermalpolicy instance parameters: "
  3280. "<volatile/nonvolatile/disabled> "
  3281. "<poweroff/nopoweroff/disabled> "
  3282. "<sel/nosel/disabled> <templimitByte> <exceptionTime>",
  3283. LOG_ERR, 0);
  3284. return -1;
  3285. }
  3286. if (str2uchar(argv[2], &entityID) != 0) {
  3287. lprintf(LOG_ERR,
  3288. "Given Entity ID '%s' is invalid.",
  3289. argv[2]);
  3290. return (-1);
  3291. }
  3292. if (str2uchar(argv[3], &entityInst) != 0) {
  3293. lprintf(LOG_ERR,
  3294. "Given Instance ID '%s' is invalid.",
  3295. argv[3]);
  3296. return (-1);
  3297. }
  3298. persistanceFlag = (uint8_t) str2val2(argv[4], dcmi_thermalpolicy_set_parameters_vals);
  3299. actionHardPowerOff = (uint8_t) str2val2(argv[5], dcmi_thermalpolicy_set_parameters_vals);
  3300. actionLogToSEL = (uint8_t) str2val2(argv[6], dcmi_thermalpolicy_set_parameters_vals);
  3301. if (str2uchar(argv[7], &tempLimit) != 0) {
  3302. lprintf(LOG_ERR,
  3303. "Given Temp Limit '%s' is invalid.",
  3304. argv[7]);
  3305. return (-1);
  3306. }
  3307. if (str2ushort(argv[8], &samplingTime) != 0) {
  3308. lprintf(LOG_ERR,
  3309. "Given Sampling Time '%s' is invalid.",
  3310. argv[8]);
  3311. return (-1);
  3312. }
  3313. samplingTimeLSB = (samplingTime & 0xFF);
  3314. samplingTimeMSB = ((samplingTime & 0xFF00) >> 8);
  3315. rc = ipmi_dcmi_setthermalpolicy(intf,
  3316. entityID,
  3317. entityInst,
  3318. persistanceFlag,
  3319. actionHardPowerOff,
  3320. actionLogToSEL,
  3321. tempLimit,
  3322. samplingTimeLSB,
  3323. samplingTimeMSB);
  3324. break;
  3325. default:
  3326. print_strs(dcmi_thermalpolicy_vals,
  3327. "thermalpolicy <command>",
  3328. LOG_ERR, 0);
  3329. return -1;
  3330. }
  3331. return rc;
  3332. }
  3333. /* main
  3334. *
  3335. * @intf: dcmi interface handler
  3336. * @argc: argument count
  3337. * @argv: argument vector
  3338. */
  3339. int
  3340. ipmi_dcmi_main(struct ipmi_intf * intf, int argc, char **argv)
  3341. {
  3342. int rc = 0;
  3343. int i;
  3344. struct ipmi_rs *rsp;
  3345. if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) {
  3346. print_strs(dcmi_cmd_vals,
  3347. "Data Center Management Interface commands",
  3348. LOG_ERR, 0);
  3349. return -1;
  3350. }
  3351. /* start the cmd requested */
  3352. switch (str2val2(argv[0], dcmi_cmd_vals)) {
  3353. case 0x00:
  3354. /* discover capabilities*/
  3355. for (i = 1; dcmi_capable_vals[i-1].str != NULL; i++) {
  3356. if (ipmi_dcmi_prnt_getcapabilities(intf, i) < 0) {
  3357. lprintf(LOG_ERR,"Error discovering %s capabilities!\n",
  3358. val2str2(i, dcmi_capable_vals));
  3359. return -1;
  3360. }
  3361. }
  3362. break;
  3363. case 0x01:
  3364. /* power */
  3365. argv++;
  3366. if (argv[0] == NULL) {
  3367. print_strs(dcmi_pwrmgmt_vals, "power <command>",
  3368. LOG_ERR, 0);
  3369. return -1;
  3370. }
  3371. rc = ipmi_dcmi_parse_power(intf, argc, argv);
  3372. break;
  3373. /* end power command */
  3374. case 0x02:
  3375. /* sensor print */
  3376. /* Look for each item in the dcmi_discvry_snsr_vals struct
  3377. * and if it exists, print the sdr record id(s) for it.
  3378. * Use the val from each one as the sensor number.
  3379. */
  3380. for (i = 0; dcmi_discvry_snsr_vals[i].str != NULL; i++) {
  3381. /* get all of the information about this sensor */
  3382. rc = ipmi_dcmi_prnt_discvry_snsr(intf,
  3383. dcmi_discvry_snsr_vals[i].val);
  3384. }
  3385. break;
  3386. /* end sensor print */
  3387. case 0x03:
  3388. /* asset tag */
  3389. if(ipmi_dcmi_prnt_getassettag(intf) < 0) {
  3390. lprintf(LOG_ERR, "Error getting asset tag!");
  3391. return -1;
  3392. }
  3393. break;
  3394. /* end asset tag */
  3395. case 0x04:
  3396. {
  3397. /* set asset tag */
  3398. if (argc == 1 ) {
  3399. print_strs(dcmi_cmd_vals,
  3400. "Data Center Management Interface commands",
  3401. LOG_ERR, 0);
  3402. return -1;
  3403. }
  3404. if (ipmi_dcmi_prnt_setassettag(intf, (uint8_t *)argv[1]) < 0) {
  3405. lprintf(LOG_ERR, "\nError setting asset tag!");
  3406. return -1;
  3407. }
  3408. break;
  3409. }
  3410. /* end set asset tag */
  3411. case 0x05:
  3412. /* get management controller identifier string */
  3413. if (ipmi_dcmi_prnt_getmngctrlids(intf) < 0) {
  3414. lprintf(LOG_ERR,
  3415. "Error getting management controller identifier string!");
  3416. return -1;
  3417. }
  3418. break;
  3419. /* end get management controller identifier string */
  3420. case 0x06:
  3421. {
  3422. /* set management controller identifier string */
  3423. if (argc == 1 ) {
  3424. print_strs(dcmi_cmd_vals,
  3425. "Data Center Management Interface commands",
  3426. LOG_ERR, 0);
  3427. return -1;
  3428. }
  3429. if (ipmi_dcmi_prnt_setmngctrlids(intf, (uint8_t *)argv[1]) < 0) {
  3430. lprintf(LOG_ERR,
  3431. "Error setting management controller identifier string!");
  3432. return -1;
  3433. }
  3434. break;
  3435. }
  3436. /* end set management controller identifier string */
  3437. case 0x07:
  3438. /* get/set thermal policy */
  3439. rc = ipmi_dcmi_thermalpolicy(intf, argc, argv);
  3440. break;
  3441. case 0x08:
  3442. if(ipmi_dcmi_prnt_get_temp_readings(intf) < 0 ) {
  3443. lprintf(LOG_ERR,
  3444. "Error get temperature readings!");
  3445. return -1;
  3446. }
  3447. break;
  3448. case 0x09:
  3449. if(ipmi_dcmi_prnt_getconfparam(intf) < 0 ) {
  3450. lprintf(LOG_ERR,
  3451. "Error Get DCMI Configuration Parameters!");
  3452. return -1;
  3453. };
  3454. break;
  3455. case 0x0A:
  3456. {
  3457. switch (argc) {
  3458. case 2:
  3459. if (strncmp(argv[1], "activate_dhcp", 13) != 0) {
  3460. print_strs( dcmi_conf_param_vals,
  3461. "DCMI Configuration Parameters",
  3462. LOG_ERR, 0);
  3463. return -1;
  3464. }
  3465. break;
  3466. default:
  3467. if (argc != 3 || strncmp(argv[1], "help", 4) == 0) {
  3468. print_strs(dcmi_conf_param_vals,
  3469. "DCMI Configuration Parameters",
  3470. LOG_ERR, 0);
  3471. return -1;
  3472. }
  3473. }
  3474. if (strncmp(argv[1], "activate_dhcp", 13) == 0) {
  3475. rsp = ipmi_dcmi_setconfparam(intf, 1, 1);
  3476. } else {
  3477. uint16_t tmp_val = 0;
  3478. if (str2ushort(argv[2], &tmp_val) != 0) {
  3479. lprintf(LOG_ERR,
  3480. "Given %s '%s' is invalid.",
  3481. argv[1], argv[2]);
  3482. return (-1);
  3483. }
  3484. rsp = ipmi_dcmi_setconfparam(intf,
  3485. str2val2(argv[1], dcmi_conf_param_vals),
  3486. tmp_val);
  3487. }
  3488. if (chk_rsp(rsp)) {
  3489. lprintf(LOG_ERR,
  3490. "Error Set DCMI Configuration Parameters!");
  3491. }
  3492. break;
  3493. }
  3494. case 0x0B:
  3495. {
  3496. if (intf->session == NULL) {
  3497. lprintf(LOG_ERR,
  3498. "\nOOB discovery is available only via RMCP interface.");
  3499. return -1;
  3500. }
  3501. if(ipmi_dcmi_prnt_oobDiscover(intf) < 0) {
  3502. lprintf(LOG_ERR, "\nOOB discovering capabilities failed.");
  3503. return -1;
  3504. }
  3505. break;
  3506. }
  3507. default:
  3508. /* couldn't detect what the user entered */
  3509. print_strs(dcmi_cmd_vals,
  3510. "Data Center Management Interface commands",
  3511. LOG_ERR, 0);
  3512. return -1;
  3513. break;
  3514. }
  3515. printf("\n");
  3516. return rc;
  3517. }
  3518. /* Node Manager main
  3519. *
  3520. * @intf: nm interface handler
  3521. * @argc: argument count
  3522. * @argv: argument vector
  3523. */
  3524. int
  3525. ipmi_nm_main(struct ipmi_intf * intf, int argc, char **argv)
  3526. {
  3527. struct nm_discover disc;
  3528. if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) {
  3529. print_strs(nm_cmd_vals,
  3530. "Node Manager Interface commands",
  3531. LOG_ERR, 0);
  3532. return -1;
  3533. }
  3534. switch (str2val2(argv[0], nm_cmd_vals)) {
  3535. /* discover */
  3536. case 0x00:
  3537. if (_ipmi_nm_discover(intf, &disc))
  3538. return -1;
  3539. printf(" Node Manager Version %s\n", val2str2(disc.nm_version, nm_version_vals));
  3540. printf(" revision %d.%d%d patch version %d\n", disc.major_rev,
  3541. disc.minor_rev>>4, disc.minor_rev&0xf, disc.patch_version);
  3542. break;
  3543. /* capability */
  3544. case 0x01:
  3545. if (ipmi_nm_getcapabilities(intf, argc, argv))
  3546. return -1;
  3547. break;
  3548. /* policy control enable-disable */
  3549. case 0x02:
  3550. if (ipmi_nm_control(intf, argc, argv))
  3551. return -1;
  3552. break;
  3553. /* policy */
  3554. case 0x03:
  3555. if (ipmi_nm_policy(intf, argc, argv))
  3556. return -1;
  3557. break;
  3558. /* Get statistics */
  3559. case 0x04:
  3560. if (ipmi_nm_get_statistics(intf, argc, argv))
  3561. return -1;
  3562. break;
  3563. /* set power draw range */
  3564. case 0x05:
  3565. if (ipmi_nm_set_range(intf, argc, argv))
  3566. return -1;
  3567. break;
  3568. /* set/get suspend periods */
  3569. case 0x06:
  3570. if (ipmi_nm_suspend(intf, argc, argv))
  3571. return -1;
  3572. break;
  3573. /* reset statistics */
  3574. case 0x07:
  3575. if (ipmi_nm_reset_statistics(intf, argc, argv))
  3576. return -1;
  3577. break;
  3578. /* set/get alert destination */
  3579. case 0x08:
  3580. if (ipmi_nm_alert(intf, argc, argv))
  3581. return -1;
  3582. break;
  3583. /* set/get alert thresholds */
  3584. case 0x09:
  3585. if (ipmi_nm_thresh(intf, argc, argv))
  3586. return -1;
  3587. break;
  3588. default:
  3589. print_strs(nm_cmd_vals, "Node Manager Interface commands", LOG_ERR, 0);
  3590. break;
  3591. }
  3592. return 0;
  3593. }
  3594. /* Display DCMI sensor information
  3595. * Uses the ipmi_sdr_get_next_header to read SDR header and compare to the
  3596. * target Record ID. Then either ipmi_sensor_print_full or
  3597. * ipmi_sensor_print_compact is called to print the data
  3598. *
  3599. * @intf: ipmi interface handler
  3600. * @rec_id: target Record ID
  3601. */
  3602. static int
  3603. ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id)
  3604. {
  3605. struct sdr_get_rs *header;
  3606. struct ipmi_sdr_iterator *itr;
  3607. int rc = 0;
  3608. uint8_t *rec = NULL;
  3609. itr = ipmi_sdr_start(intf, 0);
  3610. if (itr == NULL) {
  3611. lprintf(LOG_ERR, "Unable to open SDR for reading");
  3612. return (-1);
  3613. }
  3614. while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
  3615. if (header->id == rec_id) {
  3616. break;
  3617. }
  3618. }
  3619. if (header == NULL) {
  3620. lprintf(LOG_DEBUG, "header == NULL");
  3621. ipmi_sdr_end(intf, itr);
  3622. return (-1);
  3623. }
  3624. /* yes, we found the SDR for this record ID, now get full record */
  3625. rec = ipmi_sdr_get_record(intf, header, itr);
  3626. if (rec == NULL) {
  3627. lprintf(LOG_DEBUG, "rec == NULL");
  3628. ipmi_sdr_end(intf, itr);
  3629. return (-1);
  3630. }
  3631. if ((header->type == SDR_RECORD_TYPE_FULL_SENSOR) ||
  3632. (header->type == SDR_RECORD_TYPE_COMPACT_SENSOR)) {
  3633. rc = ipmi_sdr_print_rawentry(intf, header->type,
  3634. rec, header->length);
  3635. } else {
  3636. rc = (-1);
  3637. }
  3638. free(rec);
  3639. rec = NULL;
  3640. ipmi_sdr_end(intf, itr);
  3641. return rc;
  3642. }