XCOPY and ODX in ddpt utility

  1. XCOPY and ODX in ddpt utility
    1. Introduction
    2. Terminology
    3. ODX in ddpt
    4. ddptctl
    5. xcopy in ddpt
    6. Examples
    7. References

Introduction

This page describes two offloaded copy mechanisms that may be used to copy data with the ddpt utility. The "offload" refers to the machine requesting the copy not needing to read all the data into its memory then write it out again to the destination. The copy operation is offloaded to some intermediate device such as a storage array. The terminology used here is based on that used by the T10 committee (see www.t10.org) plus some terms the market has defined such as ODX which stands for Offloaded Data Xfer (i.e. transfer).

The T10 committee are the current maintainers of SCSI related standards and drafts. An overview of their standards' structure can be found in this diagram. The first SCSI standard (ANSI X3.131-1986) had a COPY command as did SCSI-2 (ANSI X3.131-1994) After SCSI-2 the committee split their work into multiple documents. The relevant series of documents here are SAM (architecture model), SPC (primary commands) and SBC (block commands: specialized for disks and SSDs). The first  SPC standard (ANSI INCITS 301-1997) also contained the COPY command. Then in SPC-2 (ANSI INCITS 351-2001)  EXTENDED COPY displaced COPY which was made obsolete. EXTENDED COPY is often abbreviated to XCOPY or xcopy and sometimes refers to the whole offloaded copy mechanism, including some associated commands, rather than just the EXTENDED COPY command itself. Possibly the most common type of copy is disk to disk; however sequential devices such as tapes might be involved. There may also be inline and embedded data. This flexibility is why the EXTENDED COPY command and its helpers are found in the SPC series of standards and drafts and not in the SBC series.

EXTENDED COPY stayed in place for SPC-3 ( ANSI INCITS 408-2005) with only small enhancements. Parts of EXTENDED COPY became popular commercially and today many storage array vendors support it. Since 2005, SPC-4 drafts have been moving along glacially and it may be standardized in 2014. In SPC-4 revision 34 (February 2012) a new, expanded a somewhat incompatible version of xcopy was introduced. A small part of the changes was to increase the List IDentifier field (LID) length from 1 byte to 4 bytes. It is the LID size change that T10 uses to distinguish the two variants. So XCOPY(LID1) is compatible with the XCOPY introduced in SPC-2 and still popular today. The new variant is know as XCOPY(LID4) [i.e. its List identifier field length is 4 bytes (32 bits) long].

ODX can be viewed as a subset of XCOPY(LID4) which is primarily aimed at disk to disk copies. Another vendor term for ODX is "xcopy version 2, lite" which is more descriptive but not a TLA (three letter acronym). Since ODX supports disk to disk copies and has two special commands, those commands have been placed in SBC-3. SBC-3 is also close to standardization.

The ddpt utility is a more generic version of the Linux specific sg_dd and sg_xcopy utilities found in the sg3_utils package.

This page outlines the features of xcopy and ODX offloaded copies found in the ddpt utility version 0.95 . The ddpt utility is found in the package of the same name.

Terminology

In T10 terminology an application client in a host issues SCSI commands through a SCSI initiator across a transport to a SCSI target which contains one or more logical units. Associated with each logical unit is a software component called a device server which decodes and implements most SCSI commands sent by the application client. A device server needs to be aware of its sibling logical units and the target it is contained within in order to respond to SCSI commands like REPORT LUNS and to properly build the device identification VPD page. Storage arrays and Operating System target sub-systems often appear as SCSI targets with user configurable logical units. If those targets support any generation of XCOPY then each contained logical unit's standard INQUIRY response must set the 3PC bit. XCOPY capable logical units have a companion software component to the device server called a copy manager. One possible copy manager implementation receives XCOPY commands and performs the copy by issuing SCSI READ and WRITE commands to the source and destination logical units. The following figure is borrowed  from SPC-4's section titled copy manager model (section 5.16.2 in spc4r36r.pdf):


copy manager examples diagram
 Examples of copy manager configurations

Note that only the "Standalone Copy Manager" example is a true third party copy, however the term third party copy (and abbreviations like 3PC and TPC) has become synonymous with all forms of xcopy.

<Description here of xcopy(LID1) terms that are relevant to ddpt's xcopy(LID1) implementation.>

ODX is a subset of XCOPY(LID4) that does a ROD based, disk to disk copy. ROD stands for Representation Of Data and in its most general form is a scatter gather list held by the device (Logical Unit or LU) whose data the scatter gather list refers to. T10 uses the term populate to refer to the creation of such a ROD. After such a ROD is populated it can be used as copy source or copy destination. Access upon reference is the type associated such RODs.

ODX uses another type of ROD called point in time copy ROD. When a point in time copy ROD is populated by a gather list, the data it refers to is read into the ROD. No data (normally) changes in a logical unit's storage without being permitted by its device server. This tight coupling between a logical unit's device server and copy manager makes it possible for part or all of the read associated with populating a point in time copy ROD to be deferred. A point in time ROD can only be used subsequently as a copy source.

For an application client to use a ROD to do (or complete) a copy operation, it needs a way of identifying a ROD. In ODX, after a POPULATE TOKEN command creates a ROD, the copy manager that owns that ROD generates a unique, 512 byte handle called a ROD Token. The application client should follow up a POPULATE TOKEN command with a RECEIVE ROD TOKEN INFORMATION command which reports about the ROD creation process (e.g. its transfer count which is the number of blocks read) and if the process was successful the report also includes the ROD Token itself.

The header part of a 512 byte ROD Token contains some fields that can be decoded. These include its ROD type and the creator's logical unit designator which is also found in the device identification VPD page. The other major (originating) SCSI command in ODX is WRITE USING TOKEN. As its name suggests it takes a ROD Token in its parameter list. It also takes a scatter list and must be sent to the logical unit that is the destination of the copy operation. That logical unit might be the same as the source (i.e. where the POPULATE TOKEN was sent) or a different logical unit in the same target. At the option of the ODX implementation, the ROD Token in a POPULATE TOKEN can be sent to a logical unit in another target. In the latter case SPC-4 says the copy mangers in the source and destination can exchange data by whatever methods they want (i.e. not necessarily using SCSI READs and WRITEs).

Another interesting technique is to use the network to send a ROD Token from one machine (host) to another. Then the receiving machine can use that ROD Token to do a WRITE USING TOKEN. This is essentially a network copy in which a large amount of data might be sent with minimal impact on the network as it only needs to pass a 512 byte ROD Token. To simplify the following diagram, the source LU (src) and the destination LU (dst) are virtual disks on a common storage array.

ODX network copy diagram
Network copy with ODX, a three step process

A point in time copy ROD can be viewed as an array of bytes held by the copy manager associated with the logical unit that processed the POPULATE TOKEN command. The associated ROD Token belongs to the same copy manager which decides when both a ROD and its ROD Token become invalid. For this purpose ODX specifies an inactivity timeout but is rather lax in defining exactly how it works. Viewing a ROD as an array of bytes helps when considering an ODX copy between logical units with different block sizes (e.g. source block size is 512 bytes while the destination block size is 4096 bytes).

ODX in ddpt

ddpt supports 4 ODX variants. They are listed below with simple examples:
  1. full copy: ddpt if=/dev/sg3 bs=512 of=/dev/sg4 --odx
  2. zero output blocks: ddpt if=/dev/null bs=512 of=/dev/sg5 rtype=zero
  3. read to tokens: ddpt if=/dev/sg6 bs=512 skip=@a_gather.lst rtf=a_rt.bin
  4. write from tokens: ddpt rtf=a_rt.bin of=/dev/sg7 bs=512 seek=@a_scatter.lst
A full copy will copy any amount of data between two disks (logical units) or could be used to move data from one part to another part of the same disk. It does this by calling the largest permitted POPULATE TOKEN command (PT)  which creates a ROD on the source logical unit and yields a ROD Token. This is followed by one or more WRITE USING TOKEN commands (WUT) using the ROD Token and is sent to the destination logical unit. More than one WUT command may be required because the destination may be more constrained than the source. These ODX constraints are found in the Third Party Copy VPD page (in the  Block Device ROD Token Limits descriptor) and limit the total number of blocks and the number of scatter-gather list elements in each PT and WUT command. The copy continues working its way through the requested number of blocks with a PT command followed by one or more WUT commands until the copy is complete or an error occurs. The full copy example above shows a disk (logical unit) being copied to another. For large disks this could take a long time with many SCSI commands being issued by ddpt, the "win" here is the lack of data moving into and out of the host machine. At the other extreme the odx full copy variant could be used to move one block (e.g. with count=1); Microsoft documentation states that it uses a traditional copy (i.e. moving all the data to and fro) for a copy involving a small number of blocks.

The zero output blocks will copy zero blocks to the destination disk. It is a special case of the full copy in which no POPULATE TOKEN commands are sent. Instead a special ROD Token whose ROD type is indicated by either rtype=zero or rtype=0xffff0001 is given to each WRITE USING TOKEN command until the operation is complete.

The read to tokens variant sends multiple POPULATE TOKEN commands to the source (input) logical unit. It reads data into the RODs based on the SKIP and COUNT options, or the gather list given to the skip=GL option.The resulting ROD Tokens are appended to the ROD Token file as they are generated. If conv=rtf_len or iflag=rtf_len is given then the byte length that the ROD represents is placed after each ROD Token as an 8 byte, big endian integer.

The write from tokens variant is designed to take as input a ROD Token file that has been generated by the read to tokens variant. Multiple WRITE USING TOKEN commands to write the data to the destination (output) logical unit. It writes data from the RODs based on the SEEK and COUNT options, or the scatter list given to the seek=SL option.  The writing continues until either the number of blocks given on the command line (i.e. COUNT or the sum of blocks in the scatter list) is reached, or the ROD Tokens in the RTF file are exhausted.

All four variants can take the immed flag (or both iflag=immed and oflag=immed in the case of the full copy variant). This will change the internal processing used by ddpt but should not alter the overall result. The PT and WUT commands have an IMMED field which is set when this flag is given. For very big ROD sizes (and current implementations do not have particularly large maximum ROD sizes (e.g. 256 MB)) without the IMMED field set, the PT and WUT commands could take a long time. Long enough to potentially trigger command timeouts which are best avoided. The solution is to use the immed flag or use the to=TO option which is less desirable. PT and WUT complete quickly when the IMMED field is set but that is typically before the data transfer to or from the ROD is complete. ddpt uses RECEIVE ROD TOKEN INFORMATION commands to poll the logical unit when the immed flag is given. This will continue (with the period of the poll chosen by the RRTI command) until the data transfer is complete, or an error has occurred.

Notice the difference between a full copy variant and the combination of a read to tokens variant followed by a write from tokens variant. Both copy data but the order that the ROD Tokens are created and used is different. The full copy does this command sequence: PT, WUT, [WUT, ...], PT, WUT ... while the read to tokens variant does all the required PT commands and then the write to tokens variant does all the required WUT commands. This latter ordering facilitates a network copy using the read to tokens variant on the read/input/source machine, something like scp to send the RTF file to the destination machine. Then using that RTF file do a write to tokens variant on the write/output/destination machine.


Below is a table of ddpt options that are specific to ODX:

ODX specific ddpt options
ODX ddpt option
ddpt default
Brief description
ito=ITO from TPC VPD page Inactivity timeout specifies the lifetime of a ROD Token (units: seconds)
list_id=LID 257 or 258
The list identifier is used to associate a POPULATE TOKEN with the following RRTI command used to fetch the ROD Token. Another list identifier associates a WRITE USING TOKEN with its following RRTI command
oir=OIR 0
Offset In Rod: used by WRITE USING TOKEN command to start reading at a block offset (units: OBS) in the ROD
rtf=RTF
RTF is a filename to read or write ROD Token(s) to or from.
rtype=RTYPE 0
ROD type field in POPULATE TOKEN command. Default of 0 lets copy manager decide.Apart from numerical values these abbreviations are accepted: pit-any, pit-def, pit-pers, and zero .
seek=SL
0
apart from the normal dd usage where the argument is a (starting) LBA for the destination (output), in ODX the argument can be a scatter list. This has the form A1,N1[,A2,N2...] and can be given inline, in a file or via stdin. The file syntax is seek=@<filename> and the stdin syntax is either seek=- or seek=@- .
skip=GL
0
apart from the normal dd usage where the argument is a (starting) LBA for the source (input), in ODX the argument can be a gather list. See the seek= description for the list format.
to=TO 600
timeout associated with all XCOPY commands (units: seconds)
--odx
indicates an ODX full or partial copy is requested. Other options only used by ODX (e.g. rtype=pit-any) may make using this option superfluous; but it doesn't hurt.

Below is a table of ddpt options shared with ODX. These options have the same or perhaps a slightly different meaning when used in a non-ODX copy by ddpt:

ddpt options shared with ODX
ddpt option
ddpt default
Brief description of meaning with ODX
bpt=BPT[,BPC] from TPC VPD page If BPT is less than the PT command maximum block size then BPT replace it. BPT=0 is ignored or taken as the default. If BPC is less than the WUT command maximum block size then BPC replaces it. This option should only be used in ODX for testing purposes.
delay=MS[,W_MS] 0,0
MS is a delay in milliseconds prior to each PT command, apart from the first one. W_MS is a delay in milliseconds prior to each WUT command. May be helpful if there are resource problems.
intio=0|1 0
Interrupt IO. If set to 1 then the Unix system calls used by the pass-through to issue SCSI commands can be interrupted by usual signals. This is not always a good idea hence the default is 0. This causes common signals to be masked out during IO operations. A check for pending interrupts is done in a window prior to each PT and WUT command. Note that a progress report is generated if the SIGUSR1 (or equivalent) is sent to the ddpt process; the copy continues after the progress report.
retries=RETR
not implemented yet. ODX copies will exit on its first error and provide an error report.
verbose=VERB
the amount of debug output increases as VERB increases. With 1 or 2 mainly debug from the setup and completion is output. With 3, 4, or 5 output is generated for repetitive operations, so large copies may generate a lot of output. All verbose output goes to stderr which may be redirected to a file.
--verbose
when used once is equivalent to verbose=1 . Probably more useful in the short form. For example -vvv is equivalent to verbose=3 .


Below is a table of flags that are specific to ODX. They can either be arguments to iflag=, oflag= or both as indicated in the second column.


ODX specific ddpt flags
ODX ddpt
FLAG
iflag or oflag comments
append
oflag
append new ROD Tokens to an existing RTF file. Default action is to truncate an existing RTF file before new ROD tokens are written.
force
both
override certain discrepancies that would otherwise cause ddpt to exit before attempting a copy.
immed
both
sets the IMMED bit on all PT and/or WUT commands. For the single PT and WUT variants, ddpt exits soon after and the user should use ddptctl to check for completion. For the full copy and zero output blocks variants, polls within ddpt with the RRTI command. Useful if copy manager supports large RODs.
no_del_tkn
oflag
do not set DEL_TKN on the last WUT on each ROD Token during a full copy. Probably has little impact because copy manager deletes each ROD Token after all its data has been copied.
odx
both
requests on of the four ODX variants
rtf_len
both
the full copy and read to tokens variants append the number of bytes represented value after each ROD Token in the RTF file. the write from tokens variants expects to read this value after each ROD Token in the RTF file. That field should be reported inside the ROD Token but not all vendors comply.


The conversion conv=rtf_len is permitted and has the same meaning as iflag=rtf_len or oflag=rtf_len. For ODX implementations that don't set the the number of bytes represented field properly inside the ROD Token; specifying conv=rtf_len can be a nuisance. Setting the environment variable ODX_RTF_LEN will cause ddpt to act as if either the rtf_len flag or conversion has been defined.

ddptctl

ddptctl is a helper/companion utility for ddpt. ddptctl has more conventional Unix command line options and takes a single device name or no device name (e.g. when decoding an RTF Token file). ddptctl has options to do the following:
The ddptctl command line options are very similar to those in ddpt, allowing for the different format of their command lines. For example in ddpt a list identifier can be given with by list_id=255 and in ddptctl it is --list_id=255 .

xcopy in ddpt

The section covers the older XCOPY(LID1) functionality for disk to disk copies in ddpt. This was ported from the sg_xcopy utility found in the sg3_utils package.

Individual SCSI and ATA disks do not typically support xcopy; disk arrays and iSCSI servers do. There is a 3PC field in a standard SCSI INQUIRY response that when set indicates a "logical unit" (an abstraction of a disk) supports at least some xcopy functionality.  Prior to the copy, the source (i.e. IFILE) and destination (i.e. OFILE) are checked (via the pt interface) to find their xcopy capabilities. Usually the EXTENDED COPY(LID1) command is usually sent to destination device. ddpt sends the EXTENDED COPY(LID1) command to the destination device if the '--xcopy' or 'oflag=xcopy' options are given; and it sends that command to the source device if the 'iflag=xcopy' option is given. ddpt cannot currently send the EXTENDED COPY(LID1) command to a copy manager that is other than the source and destination devices; that is the standalone case shown in the "examples of copy manager configurations" diagram above.

The xcopy functionality in ddpt is ported from the sg_xcopy utility in the sg3_utils package. See the man page for sg_xcopy and also the man page for the related sg_copy_results utility for more information.

Below is a table of ddpt options that are specific to xcopy:

xcopy specific ddpt options
xcopy ddpt option
ddpt default
Brief description
id_usage=LIU 0 or 2 LIST ID USAGE field. Can be 0 to 3 or the string hold (for 0), discard (for 2) or disable (for 3).
list_id=LID 0 or 1
The list identifier is used to associate a EXTENDED COPY(LID1) with the following RECEIVE COPY STATUS command. This is a single byte so the maximum value is 255.
prio=PRIO 1
value for PRIORITY field in the EXTENDED COPY(LID1) command.
to=TO 600
timeout associated with all XCOPY commands (units: seconds)
--xcopy
indicates an XCOPY(LID1) disk to disk copy is requested. In the absence of iflag=xcopy

Below is a table of ddpt options shared with xcopy. These options have the same or perhaps a slightly different meaning when used in a non-ODX copy by ddpt:

ddpt options shared with xcopy
ddpt option
ddpt default
Brief description of meaning with xcopy
delay=MS[,W_MS] 0,0
not implemented yet for xcopy but may be in the future.
retries=RETR
not implemented yet. xcopy will exit on its first error and provide an error report.
verbose=VERB
the amount of debug output increases as VERB increases. With 1 or 2 mainly debug from the setup and completion is output. With 3, 4, or 5 output is generated for repetitive operations, so large copies may generate a lot of output. All verbose output goes to stderr which may be redirected to a file.
--verbose
when used once is equivalent to verbose=1 . Probably more useful in the short form. For example -vvv is equivalent to verbose=3


Below is a table of flags that are specific to xcopy. They can either be arguments to iflag=, oflag= or both as indicated in the second column.


xcopy specific ddpt flags
xcopy ddpt
FLAG
iflag or oflag comments
cat
both
sets the CAT bit in XCOPY(LID1) parameter list segment descriptor header. Associated with residual data handling.
dc
both
sets the DC (destination counter) bit in XCOPY(LID1)  parameter  list  segment  descriptor header.
pad
both
sets the PAD bit in the CSCD descriptor of the associated IFILE or OFILE.  Is  associated  with residual data handling and works together with the cat flag.
xcopy
both
indicates both that a XCOPY(LID1) is requested and whether it should be sent to IFILE (i.e. source) or OFILE (i.e. the destination). If xcopy is selected and the location to send the command is not unambiguously shown, then it is ent to the OFILE.


Note that between ddpt versions 0.93 and 0.94 the default LU to send the XCOPY(LID1) command to changed from IFILE to OFILE. In the absence of any command line guidance (e.g. iflag=xcopy causes the XCOPY(LID1) command to be sent to IFILE), then a check is made for these environment variables: XCOPY_TO_SRC and XCOPY_TO_DST, if either is present then it will guide where the XCOPY(LID1) command is sent.

Examples

Most of these examples use Linux device names. See the device naming page for appropriate device names in other supported operating systems.

With some arrays, using a pass-through or an offloaded copy may trick an Operating System's buffer cache. In Linux these commands where found to be useful to turn off the buffer cache:

# sync; echo 3 > /proc/sys/vm/drop_caches

To check if something like the above is needed, use a command like md5sum or sha1sum to determine whether both the source and destination sides of a copy are the same after the copy has taken place. Obviously copying into a storage area that contains a mounted file system is dangerous.

To start with, do a disk to disk copy with ODX. The full copy variant is appropriate for this task. The first example uses device nodes which are pass-throughs. The second uses normal block devices which accept pass-through commands. These "disks" are relatively small (10 GB each) and are in the same target within a storage array that supports ODX:

# ddpt --odx if=/dev/sg3 of=/dev/sg4 bs=512
20971520+0 records in
20971520+0 records out
time to transfer data: 38.994866 secs at 275.35 MB/sec

# ddpt --odx if=/dev/sdb of=/dev/sdc bs=512
20971520+0 records in
20971520+0 records out
time to transfer data: 38.592403 secs at 278.23 MB/sec

The examples after this will use pass-through devices. To zero out all blocks on a device, the zero output blocks variant is most efficient:

# ddpt rtype=zero if=/dev/null of=/dev/sg4 bs=512
20971520+0 records out
time to transfer data: 25.348843 secs at 423.59 MB/sec

The rtype=zero refers to a special ROD Type whose format is defined by T10 and thus does not need the usual populate step performed by the POPULATE TOKEN command. Note since the rtype= option implies ODX then the --odx option is not needed.

Next we look at the block device ROD Token limits descriptors for our source and destination devices. These LUs belong to the same target and have the same limits. The interesting case is when the destination is more constrained that the source. This is more likely to happen when ODX copies between targets are supported, especially if those targets come from different vendors. A smaller size maximum token transfer size can be simulated, for example: bpt=0,200000 which will leave the source's maximum per ROD size at 524288 blocks and reduce the destination's to 200000 .

# ddptctl -i /dev/sg3
  /dev/sg3 [pt]: num_blocks=20971520 [0x1400000], block_size=512, 10.73 GB
3PC (third party copy) bit set in standard INQUIRY response
  Print Third Party Copy VPD page:
 Block Device ROD Token Limits:
  Maximum Range Descriptors: 8
  Maximum Inactivity Timeout: 60 seconds
  Default Inactivity Timeout: 30 seconds
  Maximum Token Transfer Size: 524288
  Optimal Transfer Count: 524288

# ddptctl -i /dev/sg4
  /dev/sg4 [pt]: num_blocks=20971520 [0x1400000], block_size=512, 10.73 GB
3PC (third party copy) bit set in standard INQUIRY response
  Print Third Party Copy VPD page:
 Block Device ROD Token Limits:
  Maximum Range Descriptors: 8
  Maximum Inactivity Timeout: 60 seconds
  Default Inactivity Timeout: 30 seconds
  Maximum Token Transfer Size: 524288
  Optimal Transfer Count: 524288

Since ROD Tokens are freestanding (e.g. they are not tied to a particular I_T nexus) they can be used by any machine that can "see" the source LU. In the example below two machines called mach_a and mach_b have access to the same storage array. One of the array's targets has two LUs: /dev/sg3 and /dev/sg4 . The example shows a network copy in which mach_a reads from /dev/sg3 and receives several ROD Tokens. A file containing those ROD tokens is then sent to mach_b via the network. Thereafter mach_b can use those ROD Tokens to write the data held in the ROD to /dev/sg4 . In this case the read on /dev/sg3 starts at LBA 0x1234 and goes for 1m (2**20) blocks; the data written to /dev/sg4 starts at LBA 0 (because seek= is not given so it defaults to 0) for 1m blocks.

mach_a # ddpt if=/dev/sg3 bs=512 skip=0x1234,1m rtf=my.tk
1048576+0 records in
time to transfer data: 0.002217 secs at 242160.99 MB/sec

mach_a # scp -p my.tk user@mach_b:/tmp

mach_b # ddpt rtf=/tmp/my.tk bs=512 of=/dev/sg4 count=1m
1048576+0 records out
time to transfer data: 0.747828 secs at 717.91 MB/sec

To implement the write side (second half) of this copy the logic is much simpler if the "number of bytes represented" by each ROD is known. T10 does not mandate that implementations supply this field within the ROD Token. To bypass this difficulty there is the rtf_len flag (and conversion option) that instructs that value (as an 8 byte big endian integer) to be appended to each ROD Token written to the ROD Token file. Depending on the implementation the rtf_len flag will need to be specified all or none of the time. To ease the pain of the case when it must be specified all the time (like the implementation used these examples) the presence ODX_RTF_LEN environment variable will default the rtf_len flag on. In above example, the extra "number of bytes represented" integer was needed. Before the above commands were executed this was done:

mach_a # export  ODX_RTF_LEN=1
mach_b # export  ODX_RTF_LEN=1

Looking at the length of the my.tk file is instructive:

# ls -l my.tk
-rw-r--r-- 1 users users 1040 Mar 30 11:07 my.tk

So it contains 2 ROD Tokens (512 bytes each), each of which is followed by an 8 byte "number of bytes represented" field for a total of 1040 bytes. If the ODX_RTF_LEN environment variable had not been given (or any other rtf_len indication) then the length of that file would have been 1024 bytes.

There are also some examples in the ddpt man page and the doc/ddpt_examples.txt file in the distribution tarball.

References

XCOPY(LID4) and the ODX subset were introduced in SPC-4 and SBC-3 drafts found at www.t10.org . Both are approaching standardization. Expect enhancements to ODX in SPC-5 and SBC-4 (the latter already has drafts at T10). XCOPY which is now known as XCOPY(LID1) has been in place since the SPC-2 standard. Standards can be purchased from ANSI (as pdf files); a cheaper approach is to get the last draft prior to the standard from T10 (or the first one in the next series (e.g. draft sbc4r00.pdf will be very close to the SBC-3 standard)).

MSDN has several high and medium level documents about ODX. For low level information search for "MSDN POPULATE_TOKEN_HEADER" and follow its sibling links. Some storage array vendors support ODX and more plan to in the future (so they say), so searching for ODX and a vendor name should find their higher level (i.e. marketing) documentation. Storage arrays that already support XCOPY(LID1) typically require a firmware upgrade to support ODX.

Return to ddpt page.

Last updated: 27th December 2014