Skip to content

Commit 6dceb9e

Browse files
committed
nvme: Expose MDTS value with basic logic
While the interaction between the block backends and frontends like NVMe could be improved to include negotiation of parameters such as MDTS, it would be nice to define a reasonable value in the mean time.
1 parent 6408b9e commit 6dceb9e

File tree

5 files changed

+51
-2
lines changed

5 files changed

+51
-2
lines changed

bin/propolis-server/src/lib/initializer.rs

+3
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,11 @@ impl<'a> MachineInitializer<'a> {
540540
chipset.pci_attach(bdf, vioblk);
541541
}
542542
DeviceInterface::Nvme => {
543+
// Limit data transfers to 1MiB (2^8 * 4k) in size
544+
let mdts = Some(8);
543545
let nvme = nvme::PciNvme::create(
544546
name.to_string(),
547+
mdts,
545548
self.log.new(
546549
slog::o!("component" => format!("nvme-{}", name)),
547550
),

bin/propolis-standalone/src/main.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -990,7 +990,9 @@ fn setup_instance(
990990
.to_string();
991991
let log =
992992
log.new(slog::o!("dev" => format!("nvme-{}", name)));
993-
let nvme = hw::nvme::PciNvme::create(dev_serial, log);
993+
// Limit data transfers to 1MiB (2^8 * 4k) in size
994+
let mdts = Some(8);
995+
let nvme = hw::nvme::PciNvme::create(dev_serial, mdts, log);
994996

995997
guard.inventory.register_instance(&nvme, &bdf.to_string());
996998
guard.inventory.register_block(&backend, name);

lib/propolis/src/hw/nvme/bits.rs

+6
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,12 @@ bitstruct! {
252252
reserved4: u8 = 56..64;
253253
}
254254
}
255+
impl Capabilities {
256+
/// Size in bytes represented by the MPSMIN value
257+
pub fn mpsmin_sz(&self) -> usize {
258+
1 << (12 + self.mpsmin())
259+
}
260+
}
255261

256262
bitstruct! {
257263
/// Representation of the Controller Configuration (CC) register.

lib/propolis/src/hw/nvme/mod.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,20 @@ impl NvmeCtrl {
411411
b << (self.ns_ident.lbaf[(self.ns_ident.flbas & 0xF) as usize]).lbads
412412
}
413413

414+
/// Check a given request transfer size against any MDTS configured on the
415+
/// controller.
416+
///
417+
/// Returns `true` if the size is acceptable for the MDTS.
418+
fn valid_for_mdts(&self, sz: u64) -> bool {
419+
match self.ctrl_ident.mdts {
420+
0 => true,
421+
mdts => {
422+
let limit = (self.ctrl.cap.mpsmin_sz() as u64) << mdts;
423+
sz <= limit
424+
}
425+
}
426+
}
427+
414428
fn update_block_info(&mut self, info: block::DeviceInfo) {
415429
let nsze = info.total_size;
416430
self.ns_ident = bits::IdentifyNamespace {
@@ -496,7 +510,11 @@ pub struct PciNvme {
496510

497511
impl PciNvme {
498512
/// Create a new pci-nvme device with the given values
499-
pub fn create(serial_number: String, log: slog::Logger) -> Arc<Self> {
513+
pub fn create(
514+
serial_number: String,
515+
mdts: Option<u8>,
516+
log: slog::Logger,
517+
) -> Arc<Self> {
500518
let builder = pci::Builder::new(pci::Ident {
501519
vendor_id: VENDOR_OXIDE,
502520
device_id: PROPOLIS_NVME_DEV_ID,
@@ -526,6 +544,7 @@ impl PciNvme {
526544
ssvid: VENDOR_OXIDE,
527545
sn,
528546
ieee: OXIDE_OUI,
547+
mdts: mdts.unwrap_or(0),
529548
// We use standard Completion/Submission Queue Entry structures with no extra
530549
// data, so required (minimum) == maximum
531550
sqes: NvmQueueEntrySize(0).with_maximum(sqes).with_required(sqes),

lib/propolis/src/hw/nvme/requests.rs

+19
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
accessors::MemAccessor,
77
block::{self, Operation, Request, Result as BlockResult},
88
hw::nvme::{bits, cmds::Completion},
9+
vmm::mem::MemCtx,
910
};
1011

1112
use super::{cmds::NvmCmd, queue::Permit, PciNvme};
@@ -80,10 +81,23 @@ impl PciNvme {
8081
let cid = sub.cid();
8182
let cmd = NvmCmd::parse(sub);
8283

84+
fn fail_mdts(permit: Permit, mem: &MemCtx) {
85+
permit.complete(
86+
Completion::generic_err(bits::STS_INVAL_FIELD).dnr(),
87+
Some(&mem),
88+
);
89+
}
90+
8391
match cmd {
8492
Ok(NvmCmd::Write(cmd)) => {
8593
let off = state.nlb_to_size(cmd.slba as usize) as u64;
8694
let size = state.nlb_to_size(cmd.nlb as usize) as u64;
95+
96+
if !state.valid_for_mdts(size) {
97+
fail_mdts(permit, &mem);
98+
continue;
99+
}
100+
87101
probes::nvme_write_enqueue!(|| (
88102
qid, idx, cid, off, size
89103
));
@@ -100,6 +114,11 @@ impl PciNvme {
100114
let off = state.nlb_to_size(cmd.slba as usize) as u64;
101115
let size = state.nlb_to_size(cmd.nlb as usize) as u64;
102116

117+
if !state.valid_for_mdts(size) {
118+
fail_mdts(permit, &mem);
119+
continue;
120+
}
121+
103122
probes::nvme_read_enqueue!(|| (
104123
qid, idx, cid, off, size
105124
));

0 commit comments

Comments
 (0)