title: Sending ATA commands directly to device in Windows?
body: <p>I’m trying to send ATA commands to a physical disk in Windows, and get the response from the device.</p>
  
  <blockquote>
    <p><strong>Note:</strong> In this case I want to send the <a href="http://www.scribd.com/doc/39053327/35/Identify-Device-command" rel="noreferrer"><code>IDENTIFY DEVICE</code></a> (0xEC)
    command. The device will respond with
    a 512-byte block of data. (In
    particular I’m interested in bit 0 of
    word 119 - the device’s <a href="http://docs.google.com/viewer?a=v&amp;q=cache:gqAtqTinZLkJ:www.t13.org/documents/UploadedDocuments/docs2008/e07154r6-Data_Set_Management_Proposal_for_ATA-ACS2.pdf+%22DATA+SET+MANAGEMENT%22+command&amp;hl=en&amp;gl=ca&amp;pid=bl&amp;srcid=ADGEESg6GqyQvp4pIym_K4_DRGsfOIOXL1Y-H1NdBbjEFsAooJmTVTOLRQKvl0ckB_Gn8XsE26bH2Zh662B8fS1nBcsb-hg87QkD95TWK7RwaMm__eiN6mf698P7EhOosX9MzODHIBDV&amp;sig=AHIEtbQZohGCA8qIF1_D9nsgnZ81AGvOyg" rel="noreferrer">support for
    the <code>TRIM</code> command</a>).</p>
  </blockquote>
  
  <p>I know that I need to use <a href="http://msdn.microsoft.com/en-us/library/aa363858(v=vs.85).aspx" rel="noreferrer"><code>CreateFile</code></a> to open the device:</p>
  
  <pre><code>handle = CreateFile(
      "\\.\PhysicalDrive0", GENERIC_READ, FILE_SHARE_READ, 
      nil,            // no security attributes
      OPEN_EXISTING,
      0,              // flags and attributes
      nil             // no template file
  );
  </code></pre>
  
  <p>But after this I’m stymied about what to do. </p>
  
  <p>I thought about sending <code>0xEC</code> using <code>[DeviceIoControl][4]</code>:</p>
  
  <pre><code>// const ATACommand_IdentifyDevice = 0xEC;
  uint bytesReturned = 0;
  
  DeviceIoControl(handle, 
      0xEC,               // IO Control Code
      nil,                // input buffer not needed
      0,                  // input buffer is zero bytes
      @buffer,            // output buffer to store the returned 512-bytes
      512,                // output buffer is 512 bytes long
      out bytesReturned, 
      nil                 // not an overlapped operation
  );
  </code></pre>
  
  <p>But this is completely wrong. An IoControlCode sent to <a href="http://msdn.microsoft.com/en-us/library/aa363216(v=vs.85).aspx" rel="noreferrer">DeviceIoControl</a> must be a valid IO_CTL, which are <a href="http://www.osronline.com/ddkx/kmarch/irps_1l0n.htm" rel="noreferrer">built using the macro</a>:</p>
  
  <pre><code>#define CTL_CODE(DeviceType, Function, Method, Access) (
     ((DeviceType) &lt;&lt; 16) | ((Access) &lt;&lt; 14) | ((Function) &lt;&lt; 2) | (Method)
  )
  </code></pre>
  
  <p>Looking at the SDK, there are a number of valid <a href="http://msdn.microsoft.com/en-us/library/aa363979(v=vs.85).aspx" rel="noreferrer">Disk Management Control Codes</a>, e.g.:</p>
  
  <ul>
  <li>IOCTL_DISK_CREATE_DISK</li>
  <li>IOCTL_DISK_GET_DRIVE_GEOMETRY</li>
  <li>IOCTL_DISK_GET_DRIVE_GEOMETRY_EX</li>
  <li>IOCTL_DISK_GET_PARTITION_INFO</li>
  <li>IOCTL_STORAGE_QUERY_PROPERTY</li>
  </ul>
  
  <p>But none of them are <code>IDENTIFY DEVICE</code> command, or return anything it returns.</p>
  
  <p>So I believe I have to use some “raw” method of sending commands.</p>
  
  <hr>
  
  <p>Searching around, I came across and undocumented IOCTL</p>
  
  <pre><code>#define  DFP_RECEIVE_DRIVE_DATA   0x0007c088   
  </code></pre>
  
  <p>Which when you break down the IOCTL pieces, means:</p>
  
  <pre><code>Custom: (0)
  Device Type: (7) FILE_DEVICE_DISK
  Required Access: (3) METHOD_NEITHER
  Custom: (0)
  Function Code: (34)
  Transfer Type: (0)
  </code></pre>
  
  <p>But there is no documentation anywhere on what the <code>inputBuffer</code> must contain, its size, and what its <code>outputBuffer</code> will contain, or its required. Nor can I figure out what <code>functionCode</code> 34 (0x22) is.</p>
  
  <hr>
  
  <p>My question: How do I send raw ATA commands (e.g. 0xEC) to an ATA device, and read its response?</p>
  
  <h2>See also</h2>
  
  <ul>
  <li><a href="http://msdn.microsoft.com/en-us/library/ff559309(v=VS.85).aspx" rel="noreferrer">IOCTL_ATA_PASS_THROUGH Control Code</a></li>
  <li><a href="http://msdn.microsoft.com/en-us/library/ff559315(v=VS.85).aspx" rel="noreferrer">IOCTL_ATA_PASS_THROUGH_DIRECT Control Code</a></li>
  <li><a href="http://msdn.microsoft.com/en-us/library/ff551323(v=VS.85).aspx" rel="noreferrer">ATA_PASS_THROUGH_EX Structure</a></li>
  </ul>
  
  <hr>
  
  <h2>Answer pieces</h2>
  
  <p>Open the drive with ReadWrite access:</p>
  
  <pre><code>handle = CreateFile(
      "\\.\PhysicalDrive0", 
      GENERIC_READ or GENERIC_WRITE, // IOCTL_ATA_PASS_THROUGH requires read-write
      FILE_SHARE_READ, 
      nil,            // no security attributes
      OPEN_EXISTING,
      0,              // flags and attributes
      nil             // no template file
  );
  </code></pre>
  
  <p>Setup an <code>ATA_PASS_THROUGH_EX</code> structure as our input buffer to use with <code>IOCTL_ATA_PASS_THROUGH</code> IO control code:</p>
  
  <pre><code>ATA_PASS_THROUGH_EX inputBuffer;
  inputBuffer.Length = sizeof(ATA_PASS_THROUGH_EX);
  inputBuffer.AtaFlags = ATA_FLAGS_DATA_IN;
  inputBuffer.DataTransferLength = 0;
  inputBuffer.DataBufferOffset = 0;
  // todo: put the ATA command (e.g. 0xEC) somewhere
  
  uint inputBufferSize = sizeof(ATA_PASS_THROUGH_EX);
  </code></pre>
  
  <p>Setup an output buffer to hold our expected 512-byte response from the drive:</p>
  
  <pre><code>Byte[] outputBuffer = new Byte[512];
  uint outputBufferSize = 512;
  </code></pre>
  
  <p>Call <code>DeviceIoControl</code>:</p>
  
  <pre><code>int ioControlCode = IOCTL_ATA_PASS_THROUGH; // or maybe IOCTL_ATA_PASS_THROUGH_DIRECT
  uint bytesReturned = 0;
  
  DeviceIoControl(handle, ioControlCode,
      inputBuffer, inputBufferSize,
      outputBuffer, outputBufferSize,
      out bytesReturned,
      nil      // not an overlapped operation    
  );
  </code></pre>
  
  <p>Close the file handle:</p>
  
  <pre><code>handle.Close();
  </code></pre>