@@ -61,6 +61,20 @@ use crate::{
6161
6262const MELLANOX_UEFI_HTTP_IPV4 : & str = "UEFI HTTP IPv4 Mellanox Network Adapter" ;
6363const NVIDIA_UEFI_HTTP_IPV4 : & str = "UEFI HTTP IPv4 Nvidia Network Adapter" ;
64+
65+ /// MGX C2 systems use SSIF instead of x86 KCS for in-band BMC communication,
66+ /// so the KCSInterface endpoint doesn't exist. These models require the
67+ /// IPMIHostInterface fallback on Systems/{id}.
68+ const MGX_C2_MODELS : [ & str ; 4 ] = [
69+ "ARS-121L-DNR" ,
70+ "ARS-221GL-NR" ,
71+ "SYS-221H-TNR" ,
72+ "SYS-221H-TN24R" ,
73+ ] ;
74+
75+ /// Minimum BMC firmware version that exposes `IPMIHostInterface` on
76+ /// `Systems/{id}` for MGX C2 systems.
77+ const MIN_BMC_FW_IPMI_HOST_IFACE : & str = "01.05.01" ;
6478const HARD_DISK : & str = "UEFI Hard Disk" ;
6579const NETWORK : & str = "UEFI Network" ;
6680
@@ -336,19 +350,7 @@ impl Redfish for Bmc {
336350 fn lockdown_status < ' a > ( & ' a self ) -> crate :: RedfishFuture < ' a , Result < Status , RedfishError > > {
337351 Box :: pin ( async move {
338352 let is_hi_on = self . is_host_interface_enabled ( ) . await ?;
339- let kcs_privilege = match self . get_kcs_privilege ( ) . await {
340- Ok ( priviledge) => Ok ( Some ( priviledge) ) ,
341- Err ( e) => {
342- // The Grace-Grace Supermicros in our GB200 lab do not seem to support
343- // querying KCS access from the host to its BMC. Use this workaround to
344- // temporarily enable ingesting these servers.
345- if e. not_found ( ) {
346- Ok ( None )
347- } else {
348- Err ( e)
349- }
350- }
351- } ?;
353+ let kcs_privilege = self . get_kcs_privilege ( ) . await ?;
352354
353355 let is_syslockdown = self . get_syslockdown ( ) . await ?;
354356 let message = format ! ( "SysLockdownEnabled={is_syslockdown}, kcs_privilege={kcs_privilege:#?}, host_interface_enabled={is_hi_on}" ) ;
@@ -357,14 +359,10 @@ impl Redfish for Bmc {
357359 let is_grace_grace = self . is_grace_grace_smc ( ) . await ?;
358360
359361 let is_locked = is_syslockdown
360- && kcs_privilege
361- . clone ( )
362- . unwrap_or ( supermicro:: Privilege :: Callback )
363- == supermicro:: Privilege :: Callback
362+ && kcs_privilege == supermicro:: Privilege :: Callback
364363 && ( is_grace_grace || !is_hi_on) ;
365364 let is_unlocked = !is_syslockdown
366- && kcs_privilege. unwrap_or ( supermicro:: Privilege :: Administrator )
367- == supermicro:: Privilege :: Administrator
365+ && kcs_privilege == supermicro:: Privilege :: Administrator
368366 && is_hi_on;
369367 Ok ( Status {
370368 message,
@@ -1362,11 +1360,24 @@ impl Bmc {
13621360 }
13631361
13641362 async fn get_kcs_privilege ( & self ) -> Result < supermicro:: Privilege , RedfishError > {
1363+ if self . is_mgx_c2 ( ) . await ? {
1364+ let enabled = self . get_ipmi_host_interface_enabled ( ) . await ?;
1365+ return if enabled {
1366+ Ok ( supermicro:: Privilege :: Administrator )
1367+ } else {
1368+ Ok ( supermicro:: Privilege :: Callback )
1369+ } ;
1370+ }
1371+
13651372 let url = format ! (
13661373 "Managers/{}/Oem/Supermicro/KCSInterface" ,
13671374 self . s. manager_id( )
13681375 ) ;
1369- let ( _, body) : ( _ , HashMap < String , serde_json:: Value > ) = self . s . client . get ( & url) . await ?;
1376+ let ( _, body) = self
1377+ . s
1378+ . client
1379+ . get :: < HashMap < String , serde_json:: Value > > ( & url)
1380+ . await ?;
13701381 let key = "Privilege" ;
13711382 let p_str = body
13721383 . get ( key)
@@ -1391,29 +1402,77 @@ impl Bmc {
13911402 & self ,
13921403 privilege : supermicro:: Privilege ,
13931404 ) -> Result < ( ) , RedfishError > {
1405+ if self . is_mgx_c2 ( ) . await ? {
1406+ let enabled = privilege == supermicro:: Privilege :: Administrator ;
1407+ return self . set_ipmi_host_interface ( enabled) . await ;
1408+ }
1409+
13941410 let url = format ! (
13951411 "Managers/{}/Oem/Supermicro/KCSInterface" ,
13961412 self . s. manager_id( )
13971413 ) ;
13981414 let body = HashMap :: from ( [ ( "Privilege" , privilege. to_string ( ) ) ] ) ;
1399- self . s
1400- . client
1401- . patch ( & url, body)
1402- . await
1403- . or_else ( |err| {
1404- // The Grace-Grace Supermicros in our GB200 lab do not seem to support
1405- // disabling KCS access from the host to its BMC. Use this workaround to
1406- // temporarily enable ingesting these servers.
1407- if err. not_found ( ) {
1408- tracing:: warn!(
1409- "Supermicro was uanble to find {url}: {err}; not returning error to caller"
1410- ) ;
1411- Ok ( ( StatusCode :: OK , None ) )
1412- } else {
1413- Err ( err)
1414- }
1415- } )
1416- . map ( |_status_code| ( ) )
1415+ self . s . client . patch ( & url, body) . await ?;
1416+ Ok ( ( ) )
1417+ }
1418+
1419+ /// Returns `true` when the BMC firmware version is at least
1420+ /// [`MIN_BMC_FW_IPMI_HOST_IFACE`] (`01.05.01`), which is the first
1421+ /// version to expose `IPMIHostInterface` on `Systems/{id}`.
1422+ async fn bmc_supports_ipmi_host_iface ( & self ) -> Result < bool , RedfishError > {
1423+ let manager = self . s . get_manager ( ) . await ?;
1424+ let fw = manager. firmware_version . unwrap_or_default ( ) ;
1425+ Ok ( version_compare:: compare ( & fw, MIN_BMC_FW_IPMI_HOST_IFACE )
1426+ . is_ok_and ( |c| c != version_compare:: Cmp :: Lt ) )
1427+ }
1428+
1429+ /// Disable/enable SSIF in-band access via `IPMIHostInterface` on `Systems/{id}`.
1430+ /// Used for MGX C2 systems that lack the KCSInterface endpoint.
1431+ /// No-op when the BMC firmware is older than 01.05.01.
1432+ async fn set_ipmi_host_interface ( & self , enabled : bool ) -> Result < ( ) , RedfishError > {
1433+ if !self . bmc_supports_ipmi_host_iface ( ) . await ? {
1434+ let smc_bmc_ip = self . s . client . host ( ) ;
1435+ tracing:: warn!(
1436+ smc_bmc_ip,
1437+ "MGX C2 BMC firmware is older than {MIN_BMC_FW_IPMI_HOST_IFACE}; \
1438+ skipping IPMIHostInterface write"
1439+ ) ;
1440+ return Ok ( ( ) ) ;
1441+ }
1442+
1443+ use crate :: model:: system:: IpmiHostInterface ;
1444+ let url = format ! ( "Systems/{}" , self . s. system_id( ) ) ;
1445+ let body = HashMap :: from ( [ (
1446+ "IPMIHostInterface" ,
1447+ IpmiHostInterface {
1448+ service_enabled : enabled,
1449+ } ,
1450+ ) ] ) ;
1451+ self . s . client . patch ( & url, body) . await . map ( |_status_code| ( ) )
1452+ }
1453+
1454+ /// Get whether SSIF in-band access is enabled via `IPMIHostInterface` on `Systems/{id}`.
1455+ /// Used for MGX C2 systems that lack the KCSInterface endpoint.
1456+ /// Returns `false` when the BMC firmware is older than 01.05.01.
1457+ async fn get_ipmi_host_interface_enabled ( & self ) -> Result < bool , RedfishError > {
1458+ if !self . bmc_supports_ipmi_host_iface ( ) . await ? {
1459+ let smc_bmc_ip = self . s . client . host ( ) ;
1460+ tracing:: warn!(
1461+ smc_bmc_ip,
1462+ "MGX C2 BMC firmware is older than {MIN_BMC_FW_IPMI_HOST_IFACE}; \
1463+ IPMIHostInterface unavailable, reporting disabled"
1464+ ) ;
1465+ return Ok ( false ) ;
1466+ }
1467+
1468+ let system = self . s . get_system ( ) . await ?;
1469+ let iface = system
1470+ . ipmi_host_interface
1471+ . ok_or_else ( || RedfishError :: MissingKey {
1472+ key : "IPMIHostInterface" . to_string ( ) ,
1473+ url : format ! ( "Systems/{}" , self . s. system_id( ) ) ,
1474+ } ) ?;
1475+ Ok ( iface. service_enabled )
14171476 }
14181477
14191478 async fn is_host_interface_enabled ( & self ) -> Result < bool , RedfishError > {
@@ -1633,7 +1692,13 @@ impl Bmc {
16331692 Ok ( by_name)
16341693 }
16351694
1636- // Check if this is a Grace-Grace SMC (ARS-121L-DNR) that needs host_interface enabled
1695+ /// MGX C2 systems use SSIF instead of x86 KCS, so the KCSInterface
1696+ /// endpoint doesn't exist. Detect them by matching the system model.
1697+ async fn is_mgx_c2 ( & self ) -> Result < bool , RedfishError > {
1698+ let model = self . s . get_system ( ) . await ?. model . unwrap_or_default ( ) ;
1699+ Ok ( MGX_C2_MODELS . iter ( ) . any ( |m| model. contains ( m) ) )
1700+ }
1701+
16371702 async fn is_grace_grace_smc ( & self ) -> Result < bool , RedfishError > {
16381703 Ok ( self
16391704 . s
0 commit comments