-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #39 from navidys/class_sas_phy
added /sys/class/sas_phy
- Loading branch information
Showing
4 changed files
with
363 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
use procsys::sysfs::class_sas_phy; | ||
|
||
fn main() { | ||
let sasphys = class_sas_phy::collect().expect("sas phys information"); | ||
|
||
match serde_json::to_string_pretty(&sasphys) { | ||
Ok(output) => println!("{}", output), | ||
Err(err) => { | ||
log::error!("{}", err); | ||
std::process::exit(1); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,331 @@ | ||
use regex::Regex; | ||
use serde::Serialize; | ||
use std::{ | ||
collections::HashMap, | ||
fs, | ||
path::{Path, PathBuf}, | ||
}; | ||
|
||
use crate::{ | ||
error::{CollectResult, MetricError}, | ||
utils, | ||
}; | ||
|
||
#[derive(Debug, Serialize, Clone, Default)] | ||
pub struct SASPhy { | ||
/// /sys/class/sas_phy/<Name>/sas_address | ||
pub sas_address: String, | ||
|
||
/// /sys/class/sas_phy/<Name>/device/port | ||
pub sas_port: String, | ||
|
||
/// /sys/class/sas_phy/<Name>/device_type | ||
pub device_type: String, | ||
|
||
/// /sys/class/sas_phy/<Name>/initiator_port_protocols | ||
pub initiator_port_protocols: Vec<String>, | ||
|
||
/// /sys/class/sas_phy/<Name>/invalid_dword_count | ||
pub invalid_dword_count: i64, | ||
|
||
/// /sys/class/sas_phy/<Name>/loss_of_dword_sync_count | ||
pub loss_of_dword_sync_count: i64, | ||
|
||
/// /sys/class/sas_phy/<Name>/maximum_linkrate | ||
pub maximum_linkrate: f64, | ||
|
||
/// /sys/class/sas_phy/<Name>/maximum_linkrate_hw | ||
pub maximum_linkrate_hw: f64, | ||
|
||
/// /sys/class/sas_phy/<Name>/minimum_linkrate | ||
pub minimum_linkrate: f64, | ||
|
||
/// /sys/class/sas_phy/<Name>/minimum_linkrate_hw | ||
pub minimum_linkrate_hw: f64, | ||
|
||
/// /sys/class/sas_phy/<Name>/negotiated_linkrate | ||
pub negotiated_linkrate: f64, | ||
|
||
/// /sys/class/sas_phy/<Name>/phy_identifier | ||
pub phy_identifier: String, | ||
|
||
/// /sys/class/sas_phy/<Name>/phy_reset_problem_count | ||
pub phy_reset_problem_count: i64, | ||
|
||
/// /sys/class/sas_phy/<Name>/running_disparity_error_count | ||
pub running_disparity_error_count: i64, | ||
|
||
/// /sys/class/sas_phy/<Name>/target_port_protocols | ||
pub target_port_protocols: Vec<String>, | ||
} | ||
|
||
impl SASPhy { | ||
fn new() -> Self { | ||
Default::default() | ||
} | ||
} | ||
|
||
/// collects sas phys information | ||
/// # Example | ||
/// ``` | ||
/// use procsys::sysfs::class_sas_phy; | ||
/// | ||
/// let sas_phys = class_sas_phy::collect().expect("sas phys information"); | ||
/// let json_output = serde_json::to_string_pretty(&sas_phys).unwrap(); | ||
/// println!("{}", json_output); | ||
/// | ||
/// ``` | ||
pub fn collect() -> CollectResult<HashMap<String, SASPhy>> { | ||
collect_from("/sys/class/sas_phy/") | ||
} | ||
|
||
fn collect_from(dirname: &str) -> CollectResult<HashMap<String, SASPhy>> { | ||
let mut sas_phys: HashMap<String, SASPhy> = HashMap::new(); | ||
let sas_phy_path = PathBuf::from(dirname); | ||
|
||
for sas_phy_item in utils::list_dir_content(&sas_phy_path, "", "sas_phy") { | ||
let mut sas_phy = SASPhy::new(); | ||
let mut sas_phy_item_path = sas_phy_path.clone(); | ||
sas_phy_item_path.push(&sas_phy_item); | ||
|
||
for phy_info in utils::list_dir_content(&sas_phy_item_path, "", &sas_phy_item) { | ||
match phy_info.as_str() { | ||
"sas_address" => { | ||
sas_phy.sas_address = | ||
utils::collect_info_string("sas_address", &sas_phy_item_path)? | ||
.unwrap_or_default(); | ||
} | ||
"device" => { | ||
let re_port = match Regex::new(r"^port-[0-9:]+$") { | ||
Ok(r) => r, | ||
Err(err) => return Err(MetricError::RegexError(err)), | ||
}; | ||
let mut sas_phy_ports_path = sas_phy_item_path.clone(); | ||
sas_phy_ports_path.push("device"); | ||
sas_phy_ports_path.push("port"); | ||
sas_phy.sas_port = match fs::read_link(&sas_phy_ports_path) { | ||
Ok(p) => { | ||
let port = p | ||
.file_name() | ||
.unwrap_or_default() | ||
.to_str() | ||
.unwrap_or_default(); | ||
|
||
if re_port.is_match(port) { | ||
port.to_string() | ||
} else { | ||
"".to_string() | ||
} | ||
} | ||
Err(err) => return Err(MetricError::IOError(sas_phy_ports_path, err)), | ||
}; | ||
} | ||
"device_type" => { | ||
sas_phy.device_type = | ||
utils::collect_info_string("device_type", &sas_phy_item_path)? | ||
.unwrap_or_default(); | ||
} | ||
"initiator_port_protocols" => { | ||
let port_protocols = | ||
utils::collect_info_string("initiator_port_protocols", &sas_phy_item_path)? | ||
.unwrap_or_default(); | ||
let initiator_port_protocols: Vec<String> = port_protocols | ||
.trim() | ||
.replace(", ", ",") | ||
.split(',') | ||
.filter(|s| !s.is_empty()) | ||
.map(str::to_string) | ||
.collect(); | ||
|
||
sas_phy.initiator_port_protocols = initiator_port_protocols | ||
} | ||
"invalid_dword_count" => { | ||
sas_phy.invalid_dword_count = | ||
utils::collect_info_i64("invalid_dword_count", &sas_phy_item_path)? | ||
.unwrap_or_default(); | ||
} | ||
"loss_of_dword_sync_count" => { | ||
sas_phy.loss_of_dword_sync_count = | ||
utils::collect_info_i64("loss_of_dword_sync_count", &sas_phy_item_path)? | ||
.unwrap_or_default(); | ||
} | ||
"maximum_linkrate" => { | ||
let linkrate = get_linkrate("maximum_linkrate", &sas_phy_item_path)?; | ||
sas_phy.maximum_linkrate = linkrate; | ||
} | ||
"maximum_linkrate_hw" => { | ||
let linkrate = get_linkrate("maximum_linkrate_hw", &sas_phy_item_path)?; | ||
sas_phy.maximum_linkrate_hw = linkrate; | ||
} | ||
"minimum_linkrate" => { | ||
let linkrate = get_linkrate("minimum_linkrate", &sas_phy_item_path)?; | ||
sas_phy.minimum_linkrate = linkrate; | ||
} | ||
"minimum_linkrate_hw" => { | ||
let linkrate = get_linkrate("minimum_linkrate_hw", &sas_phy_item_path)?; | ||
sas_phy.minimum_linkrate_hw = linkrate; | ||
} | ||
"negotiated_linkrate" => { | ||
let linkrate = get_linkrate("negotiated_linkrate", &sas_phy_item_path)?; | ||
sas_phy.negotiated_linkrate = linkrate; | ||
} | ||
"phy_identifier" => { | ||
sas_phy.phy_identifier = | ||
utils::collect_info_string("phy_identifier", &sas_phy_item_path)? | ||
.unwrap_or_default(); | ||
} | ||
"phy_reset_problem_count" => { | ||
sas_phy.phy_reset_problem_count = | ||
utils::collect_info_i64("phy_reset_problem_count", &sas_phy_item_path)? | ||
.unwrap_or_default(); | ||
} | ||
"running_disparity_error_count" => { | ||
sas_phy.running_disparity_error_count = utils::collect_info_i64( | ||
"running_disparity_error_count", | ||
&sas_phy_item_path, | ||
)? | ||
.unwrap_or_default(); | ||
} | ||
"target_port_protocols" => { | ||
let port_protocols = | ||
utils::collect_info_string("target_port_protocols", &sas_phy_item_path)? | ||
.unwrap_or_default(); | ||
let target_port_protocols: Vec<String> = port_protocols | ||
.trim() | ||
.replace(", ", ",") | ||
.split(',') | ||
.filter(|s| !s.is_empty()) | ||
.map(str::to_string) | ||
.collect(); | ||
|
||
sas_phy.target_port_protocols = target_port_protocols | ||
} | ||
_ => {} | ||
} | ||
} | ||
|
||
sas_phys.insert(sas_phy_item, sas_phy); | ||
} | ||
|
||
Ok(sas_phys) | ||
} | ||
|
||
fn get_linkrate(link: &str, phy_path: &Path) -> CollectResult<f64> { | ||
let linkrate = utils::collect_info_string(link, phy_path)?.unwrap_or_default(); | ||
|
||
let linkrate_items: Vec<String> = linkrate | ||
.trim() | ||
.split(' ') | ||
.filter(|s| !s.is_empty()) | ||
.map(str::to_string) | ||
.collect(); | ||
|
||
if linkrate_items.is_empty() { | ||
return Ok(0.0); | ||
} | ||
|
||
let linkrate = match linkrate_items[0].parse::<f64>() { | ||
Ok(f) => f, | ||
Err(err) => { | ||
return Err(MetricError::ParseFloatError( | ||
linkrate_items[0].to_owned(), | ||
err, | ||
)) | ||
} | ||
}; | ||
|
||
Ok(linkrate) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn sas_phy_information() { | ||
let sas_phys = | ||
collect_from("test_data/fixtures/sys/class/sas_phy/").expect("sas phys information"); | ||
|
||
for (phy_name, phy_info) in sas_phys { | ||
match phy_name.as_str() { | ||
"phy-11:0:2" => { | ||
assert_eq!(phy_info.sas_address, "0x5000ccab0200947e"); | ||
assert_eq!(phy_info.sas_port, "port-11:0:0"); | ||
assert_eq!(phy_info.device_type, "edge expander"); | ||
assert_eq!(phy_info.initiator_port_protocols, ["smp"]); | ||
assert_eq!(phy_info.invalid_dword_count, 18); | ||
assert_eq!(phy_info.loss_of_dword_sync_count, 1); | ||
assert_eq!(phy_info.maximum_linkrate, 12.0); | ||
assert_eq!(phy_info.maximum_linkrate_hw, 12.0); | ||
assert_eq!(phy_info.minimum_linkrate, 1.5); | ||
assert_eq!(phy_info.minimum_linkrate_hw, 1.5); | ||
assert_eq!(phy_info.negotiated_linkrate, 6.0); | ||
assert_eq!(phy_info.phy_identifier, "2"); | ||
assert_eq!(phy_info.phy_reset_problem_count, 0); | ||
assert_eq!(phy_info.running_disparity_error_count, 18); | ||
assert_eq!(phy_info.target_port_protocols, ["smp"]); | ||
} | ||
"phy-11:0:4" => {} | ||
"phy-11:0:6" => {} | ||
"phy-11:7" => {} | ||
"phy-11:8" => { | ||
assert_eq!(phy_info.sas_address, "0x500062b2047b51c4"); | ||
assert_eq!(phy_info.sas_port, "port-11:0"); | ||
assert_eq!(phy_info.device_type, "end device"); | ||
assert_eq!(phy_info.initiator_port_protocols.len(), 3); | ||
assert_eq!(phy_info.invalid_dword_count, 0); | ||
assert_eq!(phy_info.loss_of_dword_sync_count, 0); | ||
assert_eq!(phy_info.maximum_linkrate, 12.0); | ||
assert_eq!(phy_info.maximum_linkrate_hw, 12.0); | ||
assert_eq!(phy_info.minimum_linkrate, 3.0); | ||
assert_eq!(phy_info.minimum_linkrate_hw, 1.5); | ||
assert_eq!(phy_info.negotiated_linkrate, 12.0); | ||
assert_eq!(phy_info.phy_identifier, "8"); | ||
assert_eq!(phy_info.phy_reset_problem_count, 0); | ||
assert_eq!(phy_info.running_disparity_error_count, 0); | ||
assert_eq!(phy_info.target_port_protocols, ["none"]); | ||
} | ||
"phy-11:9" => {} | ||
"phy-11:10" => {} | ||
"phy-11:11" => { | ||
assert_eq!(phy_info.sas_address, "0x500062b2047b51c4"); | ||
assert_eq!(phy_info.sas_port, "port-11:0"); | ||
assert_eq!(phy_info.device_type, "end device"); | ||
assert_eq!(phy_info.initiator_port_protocols.len(), 3); | ||
assert_eq!(phy_info.invalid_dword_count, 0); | ||
assert_eq!(phy_info.loss_of_dword_sync_count, 0); | ||
assert_eq!(phy_info.maximum_linkrate, 12.0); | ||
assert_eq!(phy_info.maximum_linkrate_hw, 12.0); | ||
assert_eq!(phy_info.minimum_linkrate, 3.0); | ||
assert_eq!(phy_info.minimum_linkrate_hw, 1.5); | ||
assert_eq!(phy_info.negotiated_linkrate, 12.0); | ||
assert_eq!(phy_info.phy_identifier, "11"); | ||
assert_eq!(phy_info.phy_reset_problem_count, 0); | ||
assert_eq!(phy_info.running_disparity_error_count, 0); | ||
assert_eq!(phy_info.target_port_protocols, ["none"]); | ||
} | ||
"phy-11:12" => {} | ||
"phy-11:13" => { | ||
assert_eq!(phy_info.sas_address, "0x500062b2047b51c4"); | ||
assert_eq!(phy_info.sas_port, "port-11:1"); | ||
assert_eq!(phy_info.device_type, "end device"); | ||
assert_eq!(phy_info.initiator_port_protocols.len(), 3); | ||
assert_eq!(phy_info.invalid_dword_count, 0); | ||
assert_eq!(phy_info.loss_of_dword_sync_count, 0); | ||
assert_eq!(phy_info.maximum_linkrate, 12.0); | ||
assert_eq!(phy_info.maximum_linkrate_hw, 12.0); | ||
assert_eq!(phy_info.minimum_linkrate, 3.0); | ||
assert_eq!(phy_info.minimum_linkrate_hw, 1.5); | ||
assert_eq!(phy_info.negotiated_linkrate, 6.0); | ||
assert_eq!(phy_info.phy_identifier, "13"); | ||
assert_eq!(phy_info.phy_reset_problem_count, 0); | ||
assert_eq!(phy_info.running_disparity_error_count, 0); | ||
assert_eq!(phy_info.target_port_protocols, ["none"]); | ||
} | ||
"phy-11:14" => {} | ||
"phy-11:15" => {} | ||
_ => panic!("invalid sas phy name: {}", phy_name), | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters