From b65b56b9553d543a2d99f5d1409ad509204328ff Mon Sep 17 00:00:00 2001 From: Ryan Goodfellow Date: Fri, 13 Dec 2024 05:49:33 +0200 Subject: [PATCH 1/2] basic osfp support, combine the powers of reads/parse --- decode/src/datapath.rs | 13 +++++++++++-- decode/src/ident.rs | 15 +++++++++++---- decode/src/lib.rs | 10 ++++++++++ decode/src/monitors.rs | 10 ++++++++-- decode/src/power.rs | 10 ++++++++-- 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/decode/src/datapath.rs b/decode/src/datapath.rs index 82f2e6c..7ac16b5 100644 --- a/decode/src/datapath.rs +++ b/decode/src/datapath.rs @@ -81,6 +81,7 @@ pub enum ConnectorType { Rj45, Mpo2x12, Mpo1x16, + NoSeperableConnector, Other(u8), Reserved(u8), VendorSpecific(u8), @@ -96,6 +97,7 @@ impl From for ConnectorType { 0x0c => Mpo1x12, 0x0d => Mpo2x16, 0x22 => Rj45, + 0x23 => NoSeperableConnector, 0x27 => Mpo2x12, 0x28 => Mpo1x16, 0x0e..=0x1f | 0x29..=0x7f => Reserved(value), @@ -116,6 +118,7 @@ impl fmt::Display for ConnectorType { ConnectorType::Rj45 => write!(f, "RJ-45"), ConnectorType::Mpo2x12 => write!(f, "MPO-2x12"), ConnectorType::Mpo1x16 => write!(f, "MPO-1x16"), + ConnectorType::NoSeperableConnector => write!(f, "No seperable connector"), ConnectorType::Other(x) => write!(f, "Other ({x:02x})"), ConnectorType::Reserved(x) => write!(f, "Reserved ({x:02x})"), ConnectorType::VendorSpecific(x) => write!(f, "Vendor-specific ({x:02x})"), @@ -183,7 +186,10 @@ impl ParseFromModule for Datapath { MemoryRead::new(sff8636::Page::Upper(sff8636::UpperPage::new(0)?), 192, 1)?; Ok(vec![tx_enable, los, cdr, compliance, extended_compliance]) } - Identifier::QsfpPlusCmis | Identifier::QsfpDD => { + Identifier::QsfpPlusCmis + | Identifier::QsfpDD + | Identifier::Osfp8 + | Identifier::OsfpXd => { // As with most module data, CMIS is _far_ more complicated than // SFF-8636. Lanes can be assigned to different datapaths, // though only one at a time, and modules can have a large @@ -401,7 +407,10 @@ impl ParseFromModule for Datapath { lanes, }) } - Identifier::QsfpPlusCmis | Identifier::QsfpDD => { + Identifier::QsfpPlusCmis + | Identifier::QsfpDD + | Identifier::Osfp8 + | Identifier::OsfpXd => { // First, read the connector type and which lanes are // _unsupported_. let connector_type = reads.next().expect("No connector type read"); diff --git a/decode/src/ident.rs b/decode/src/ident.rs index d18a52c..4f79af1 100644 --- a/decode/src/ident.rs +++ b/decode/src/ident.rs @@ -48,12 +48,13 @@ crate::bitfield_enum! { 0x16, Cdfp3, "CDFP (Style 3)", 0x17, MicroQsfp, "MicroQSFP", 0x18, QsfpDD, "QSFP-DD Double Density 8X Pluggable Transceiver", - 0x19, Qsfp8, "QSFP 8X Pluggable Transceiver", + 0x19, Osfp8, "OSFP 8X Pluggable Transceiver", 0x1a, SfpDD, "SFP-DD 2X Double Density Pluggable Transceiver", 0x1b, Dsfp, "DSFP Dual Small Form Factor Pluggable Transceiver", 0x1c, X4MultiLink, "x4 MiniLink/OcuLink", 0x1d, X8MiniLink, "x8 MiniLink", 0x1e, QsfpPlusCmis, "QSFP+ or later with Common Management Interface Specification", + 0x21, OsfpXd, "OSFP-XD with with Common Management interface Specification" }, other_variants = { Reserved : 0x21..=0x7f, @@ -67,7 +68,7 @@ impl Identifier { use Identifier::*; match self { QsfpPlusSff8636 | Qsfp28 => Ok(ManagementInterface::Sff8636), - QsfpPlusCmis | QsfpDD => Ok(ManagementInterface::Cmis), + QsfpPlusCmis | QsfpDD | Osfp8 | OsfpXd => Ok(ManagementInterface::Cmis), _ => Err(Error::UnsupportedIdentifier(*self)), } } @@ -189,7 +190,10 @@ impl ParseFromModule for VendorInfo { const END: u8 = 220; Ok(vec![MemoryRead::new(page, START, END - START)?]) } - Identifier::QsfpPlusCmis | Identifier::QsfpDD => { + Identifier::QsfpPlusCmis + | Identifier::QsfpDD + | Identifier::Osfp8 + | Identifier::OsfpXd => { // See CMIS rev 5.0 Table 8-24. // // In contrast to SFF-8636, these bytes are all contiguous. @@ -256,7 +260,10 @@ impl ParseFromModule for VendorInfo { vendor, }) } - Identifier::QsfpPlusCmis | Identifier::QsfpDD => { + Identifier::QsfpPlusCmis + | Identifier::QsfpDD + | Identifier::Osfp8 + | Identifier::OsfpXd => { // The byte offsets in the `reads` data, offset by first byte. const NAME: Range = 0..16; // 16 bytes const OUI: Range = 16..19; // 3 bytes diff --git a/decode/src/lib.rs b/decode/src/lib.rs index aca4e7a..94ee394 100644 --- a/decode/src/lib.rs +++ b/decode/src/lib.rs @@ -57,4 +57,14 @@ pub trait ParseFromModule: Sized { /// Parse the result of the above reads into `Self`. fn parse<'a>(id: Identifier, reads: impl Iterator) -> Result; + + /// Use `reads` and `parse` together to collect data from a buffer. + fn from_buf(id: Identifier, data: &[u8]) -> Result { + let chunks = Self::reads(id)?.into_iter().map(|r| { + let begin = r.offset() as usize; + let end = (r.offset() + r.len()) as usize; + &data[begin..end] + }); + Ok(Self::parse(id, chunks.into_iter())?) + } } diff --git a/decode/src/monitors.rs b/decode/src/monitors.rs index e808edb..bef4c3b 100644 --- a/decode/src/monitors.rs +++ b/decode/src/monitors.rs @@ -316,7 +316,10 @@ impl ParseFromModule for Monitors { reads.extend(per_lane); Ok(reads) } - Identifier::QsfpPlusCmis | Identifier::QsfpDD => { + Identifier::QsfpPlusCmis + | Identifier::QsfpDD + | Identifier::Osfp8 + | Identifier::OsfpXd => { // TODO-completeness: There are two additional complexities // here. First, this data is technically only available when the // MemoryModel of the module indicates it is paged. Nearly all @@ -487,7 +490,10 @@ impl ParseFromModule for Monitors { aux_monitors: None, }) } - Identifier::QsfpPlusCmis | Identifier::QsfpDD => { + Identifier::QsfpPlusCmis + | Identifier::QsfpDD + | Identifier::Osfp8 + | Identifier::OsfpXd => { // First read of 2 bytes indicates support for module level // monitors. let support = reads.next().ok_or(Error::ParseFailed)?; diff --git a/decode/src/power.rs b/decode/src/power.rs index 24e2b62..233de65 100644 --- a/decode/src/power.rs +++ b/decode/src/power.rs @@ -39,7 +39,10 @@ impl ParseFromModule for PowerControl { let power = MemoryRead::new(page, 93, 1).unwrap(); Ok(vec![power]) } - Identifier::QsfpPlusCmis | Identifier::QsfpDD => { + Identifier::QsfpPlusCmis + | Identifier::QsfpDD + | Identifier::Osfp8 + | Identifier::OsfpXd => { // See CMIS 5.0 table 8-10. // // Byte 26, bit 6 contains the software override bit, and bit 4 @@ -73,7 +76,10 @@ impl ParseFromModule for PowerControl { } }) } - Identifier::QsfpPlusCmis | Identifier::QsfpDD => { + Identifier::QsfpPlusCmis + | Identifier::QsfpDD + | Identifier::Osfp8 + | Identifier::OsfpXd => { // Bit 6 -> override (but see above), bit 4 -> force low-power. reads .next() From fd90967883a91c8af37608c54abb626c49eb2137 Mon Sep 17 00:00:00 2001 From: Ryan Goodfellow Date: Fri, 13 Dec 2024 09:48:46 -0800 Subject: [PATCH 2/2] review feedback --- decode/src/datapath.rs | 6 +++--- decode/src/ident.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/decode/src/datapath.rs b/decode/src/datapath.rs index 7ac16b5..7d9a781 100644 --- a/decode/src/datapath.rs +++ b/decode/src/datapath.rs @@ -81,7 +81,7 @@ pub enum ConnectorType { Rj45, Mpo2x12, Mpo1x16, - NoSeperableConnector, + NoSeparableConnector, Other(u8), Reserved(u8), VendorSpecific(u8), @@ -97,7 +97,7 @@ impl From for ConnectorType { 0x0c => Mpo1x12, 0x0d => Mpo2x16, 0x22 => Rj45, - 0x23 => NoSeperableConnector, + 0x23 => NoSeparableConnector, 0x27 => Mpo2x12, 0x28 => Mpo1x16, 0x0e..=0x1f | 0x29..=0x7f => Reserved(value), @@ -118,7 +118,7 @@ impl fmt::Display for ConnectorType { ConnectorType::Rj45 => write!(f, "RJ-45"), ConnectorType::Mpo2x12 => write!(f, "MPO-2x12"), ConnectorType::Mpo1x16 => write!(f, "MPO-1x16"), - ConnectorType::NoSeperableConnector => write!(f, "No seperable connector"), + ConnectorType::NoSeparableConnector => write!(f, "No separable connector"), ConnectorType::Other(x) => write!(f, "Other ({x:02x})"), ConnectorType::Reserved(x) => write!(f, "Reserved ({x:02x})"), ConnectorType::VendorSpecific(x) => write!(f, "Vendor-specific ({x:02x})"), diff --git a/decode/src/ident.rs b/decode/src/ident.rs index 4f79af1..b2e9338 100644 --- a/decode/src/ident.rs +++ b/decode/src/ident.rs @@ -54,7 +54,7 @@ crate::bitfield_enum! { 0x1c, X4MultiLink, "x4 MiniLink/OcuLink", 0x1d, X8MiniLink, "x8 MiniLink", 0x1e, QsfpPlusCmis, "QSFP+ or later with Common Management Interface Specification", - 0x21, OsfpXd, "OSFP-XD with with Common Management interface Specification" + 0x21, OsfpXd, "OSFP-XD with Common Management Interface Specification" }, other_variants = { Reserved : 0x21..=0x7f,