1#![forbid(unsafe_code)]
9
10use disk_backend::pr;
11use nvme_spec::nvm;
12use thiserror::Error;
13
14pub fn to_nvme_reservation_type(reservation_type: pr::ReservationType) -> nvm::ReservationType {
16 match reservation_type {
17 pr::ReservationType::WriteExclusive => nvm::ReservationType::WRITE_EXCLUSIVE,
18 pr::ReservationType::ExclusiveAccess => nvm::ReservationType::EXCLUSIVE_ACCESS,
19 pr::ReservationType::WriteExclusiveRegistrantsOnly => {
20 nvm::ReservationType::WRITE_EXCLUSIVE_REGISTRANTS_ONLY
21 }
22 pr::ReservationType::ExclusiveAccessRegistrantsOnly => {
23 nvm::ReservationType::EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
24 }
25 pr::ReservationType::WriteExclusiveAllRegistrants => {
26 nvm::ReservationType::WRITE_EXCLUSIVE_ALL_REGISTRANTS
27 }
28 pr::ReservationType::ExclusiveAccessAllRegistrants => {
29 nvm::ReservationType::EXCLUSIVE_ACCESS_ALL_REGISTRANTS
30 }
31 }
32}
33
34#[derive(Debug, Error)]
36#[error("invalid nvme reservation type: {0:#x?}")]
37pub struct InvalidReservationType(nvm::ReservationType);
38
39pub fn from_nvme_reservation_type(
41 nvme_type: nvm::ReservationType,
42) -> Result<pr::ReservationType, InvalidReservationType> {
43 let reservation_type = match nvme_type {
44 nvm::ReservationType::WRITE_EXCLUSIVE => pr::ReservationType::WriteExclusive,
45 nvm::ReservationType::EXCLUSIVE_ACCESS => pr::ReservationType::ExclusiveAccess,
46 nvm::ReservationType::WRITE_EXCLUSIVE_REGISTRANTS_ONLY => {
47 pr::ReservationType::WriteExclusiveRegistrantsOnly
48 }
49 nvm::ReservationType::EXCLUSIVE_ACCESS_REGISTRANTS_ONLY => {
50 pr::ReservationType::ExclusiveAccessRegistrantsOnly
51 }
52 nvm::ReservationType::WRITE_EXCLUSIVE_ALL_REGISTRANTS => {
53 pr::ReservationType::WriteExclusiveAllRegistrants
54 }
55 nvm::ReservationType::EXCLUSIVE_ACCESS_ALL_REGISTRANTS => {
56 pr::ReservationType::ExclusiveAccessAllRegistrants
57 }
58 _ => return Err(InvalidReservationType(nvme_type)),
59 };
60 Ok(reservation_type)
61}
62
63pub fn from_nvme_reservation_capabilities(
65 rescap: nvm::ReservationCapabilities,
66) -> pr::ReservationCapabilities {
67 pr::ReservationCapabilities {
68 write_exclusive: rescap.write_exclusive(),
69 exclusive_access: rescap.exclusive_access(),
70 write_exclusive_registrants_only: rescap.write_exclusive_registrants_only(),
71 exclusive_access_registrants_only: rescap.exclusive_access_registrants_only(),
72 write_exclusive_all_registrants: rescap.write_exclusive_all_registrants(),
73 exclusive_access_all_registrants: rescap.exclusive_access_all_registrants(),
74 persist_through_power_loss: rescap.persist_through_power_loss(),
75 }
76}
77
78pub fn from_nvme_reservation_report(
80 report_header: &nvm::ReservationReport,
81 controllers: &[nvm::RegisteredControllerExtended],
82) -> Result<pr::ReservationReport, InvalidReservationType> {
83 let reservation_type = if report_header.rtype.0 != 0 {
84 Some(from_nvme_reservation_type(report_header.rtype)?)
85 } else {
86 None
87 };
88
89 let get_host_id = |c: &nvm::RegisteredControllerExtended| {
90 if c.hostid.starts_with(&[6, 0, 0, 0]) {
97 tracelimit::warn_ratelimited!(
98 ?c.cntlid,
99 ?c.rkey,
100 ?c.hostid,
101 "NVMe controller sent SAS SCSI Transport ID as Host ID"
102 );
103
104 let mut host_id = c.hostid.to_vec();
105 host_id.copy_within(4..16, 0);
106 host_id[12..16].fill(0);
107 host_id
108 } else {
109 c.hostid.to_vec()
110 }
111 };
112 let controllers = controllers
113 .iter()
114 .map(|controller| pr::RegisteredController {
115 key: controller.rkey,
116 holds_reservation: controller.rcsts.holds_reservation(),
117 controller_id: controller.cntlid,
118 host_id: get_host_id(controller),
119 })
120 .collect();
121
122 let report = pr::ReservationReport {
123 generation: report_header.generation,
124 reservation_type,
125 controllers,
126 persist_through_power_loss: report_header.ptpls != 0,
127 };
128
129 Ok(report)
130}