|
2 | 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. |
4 | 4 |
|
5 | | -use super::bits::{self, StatusCodeType, SubmissionQueueEntry}; |
| 5 | +use super::bits::{ |
| 6 | + self, DatasetManagementRangeDefinition, StatusCodeType, |
| 7 | + SubmissionQueueEntry, |
| 8 | +}; |
6 | 9 | use super::queue::{QueueCreateErr, QueueId}; |
7 | 10 | use crate::block; |
8 | 11 | use crate::common::*; |
@@ -678,6 +681,8 @@ pub enum NvmCmd { |
678 | 681 | Write(WriteCmd), |
679 | 682 | /// Read data and metadata |
680 | 683 | Read(ReadCmd), |
| 684 | + /// Dataset Management Command |
| 685 | + DatasetManagement(DatasetManagementCmd), |
681 | 686 | /// An unknown NVM command |
682 | 687 | Unknown(GuestData<SubmissionQueueEntry>), |
683 | 688 | } |
@@ -709,6 +714,17 @@ impl NvmCmd { |
709 | 714 | prp1: raw.prp1, |
710 | 715 | prp2: raw.prp2, |
711 | 716 | }), |
| 717 | + bits::NVM_OPC_DATASET_MANAGEMENT => { |
| 718 | + NvmCmd::DatasetManagement(DatasetManagementCmd { |
| 719 | + prp1: raw.prp1, |
| 720 | + prp2: raw.prp2, |
| 721 | + // Convert from 0's based value |
| 722 | + nr: (raw.cdw10 & 0xFF) as u16 + 1, |
| 723 | + ad: raw.cdw11 & (1 << 2) != 0, |
| 724 | + idw: raw.cdw11 & (1 << 1) != 0, |
| 725 | + idr: raw.cdw11 & (1 << 0) != 0, |
| 726 | + }) |
| 727 | + } |
712 | 728 | _ => NvmCmd::Unknown(raw), |
713 | 729 | }; |
714 | 730 | Ok(cmd) |
@@ -779,6 +795,95 @@ impl ReadCmd { |
779 | 795 | } |
780 | 796 | } |
781 | 797 |
|
| 798 | +/// Dataset Management Command Parameters |
| 799 | +#[derive(Debug)] |
| 800 | +#[allow(dead_code)] |
| 801 | +pub struct DatasetManagementCmd { |
| 802 | + /// PRP Entry 1 (PRP1) |
| 803 | + /// |
| 804 | + /// Indicates a data buffer that contains the LBA range information. |
| 805 | + prp1: u64, |
| 806 | + |
| 807 | + /// PRP Entry 2 (PRP2) |
| 808 | + /// |
| 809 | + /// This field contains the second PRP entry that specifies the location where data should be |
| 810 | + /// transferred from (if there is a physical discontinuity). |
| 811 | + prp2: u64, |
| 812 | + |
| 813 | + /// Number of Ranges (NR) |
| 814 | + /// |
| 815 | + /// Indicates the number of 16 byte range sets that are specified in the command. This is a |
| 816 | + /// 0’s based value. |
| 817 | + pub nr: u16, |
| 818 | + |
| 819 | + /// Attribute – Deallocate (AD) |
| 820 | + /// |
| 821 | + /// If set to ‘1’ then the NVM subsystem may deallocate all provided ranges. If a read occurs |
| 822 | + /// to a deallocated range, the NVM Express subsystem shall return all zeros, all ones, or |
| 823 | + /// the last data written to the associated LBA. |
| 824 | + /// |
| 825 | + /// Note: The operation of the Deallocate function is similar to the ATA DATA SET MANAGEMENT |
| 826 | + /// with Trim feature described in ACS-2 and SCSI UNMAP command described in SBC-3. |
| 827 | + ad: bool, |
| 828 | + |
| 829 | + /// Attribute – Integral Dataset for Write (IDW) |
| 830 | + /// |
| 831 | + /// If set to ‘1’ then the dataset should be optimized for write access as an integral unit. |
| 832 | + /// The host expects to perform operations on all ranges provided as an integral unit for |
| 833 | + /// writes, indicating that if a portion of the dataset is written it is expected that all of |
| 834 | + /// the ranges in the dataset are going to be written. |
| 835 | + idw: bool, |
| 836 | + |
| 837 | + /// Attribute – Integral Dataset for Read (IDR) |
| 838 | + /// |
| 839 | + /// If set to ‘1’ then the dataset should be optimized for read access as an integral unit. |
| 840 | + /// The host expects to perform operations on all ranges provided as an integral unit for |
| 841 | + /// reads, indicating that if a portion of the dataset is read it is expected that all of the |
| 842 | + /// ranges in the dataset are going to be read. |
| 843 | + idr: bool, |
| 844 | +} |
| 845 | + |
| 846 | +impl DatasetManagementCmd { |
| 847 | + /// Returns an Iterator that yields [`GuestRegion`]'s which contain the array of LBA ranges. |
| 848 | + pub fn data<'a>(&self, mem: &'a MemCtx) -> PrpIter<'a> { |
| 849 | + PrpIter::new( |
| 850 | + u64::from(self.nr) |
| 851 | + * size_of::<DatasetManagementRangeDefinition>() as u64, |
| 852 | + self.prp1, |
| 853 | + self.prp2, |
| 854 | + mem, |
| 855 | + ) |
| 856 | + } |
| 857 | + |
| 858 | + /// Returns an Iterator that yields the LBA ranges specified in this command. Note that if |
| 859 | + /// some of the ranges couldn't be read from guest memory, this will yield fewer than |
| 860 | + /// `Self.nr` ranges. |
| 861 | + pub fn ranges<'a>( |
| 862 | + &self, |
| 863 | + mem: &'a MemCtx, |
| 864 | + ) -> impl Iterator<Item = DatasetManagementRangeDefinition> + 'a { |
| 865 | + self.data(mem).flat_map(|region| { |
| 866 | + let mut ranges = Vec::new(); |
| 867 | + if let Some(mapping) = mem.readable_region(®ion) { |
| 868 | + ranges.resize_with( |
| 869 | + mapping.len() |
| 870 | + / size_of::<DatasetManagementRangeDefinition>(), |
| 871 | + Default::default, |
| 872 | + ); |
| 873 | + if mapping.read_many(&mut ranges).is_err() { |
| 874 | + ranges.clear(); |
| 875 | + } |
| 876 | + }; |
| 877 | + |
| 878 | + ranges.into_iter() |
| 879 | + }) |
| 880 | + } |
| 881 | + |
| 882 | + pub fn is_deallocate(&self) -> bool { |
| 883 | + self.ad |
| 884 | + } |
| 885 | +} |
| 886 | + |
782 | 887 | /// Indicates the possible states of a [`PrpIter`]. |
783 | 888 | #[derive(Clone, Copy, Eq, PartialEq, Debug)] |
784 | 889 | enum PrpNext { |
|
0 commit comments