Drive locked / Reset a cdrom drive

I am trying to find a way to regain control over a cdrom drive when a burning program was burning to the drive, then is terminated before completion. When the burning program is terminated, the drive is left in a state where it is locked and will not open. I have tried to unlock the drive using the code below:

DWORD dwBytesReturned;
PREVENT_MEDIA_REMOVAL PMRBuffer;

PMRBuffer.PreventMediaRemoval = fPreventRemoval;

BOOL result = DeviceIoControl( hVolume,
    IOCTL_STORAGE_MEDIA_REMOVAL,
   &PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),
   NULL, 0,
   &dwBytesReturned,
   NULL);

This code works if the drive has been locked normally, but does not work in my case. Does anyone know of a windows call that will effectively reset the drive? The solution should allow me to get the drive back into a known state.
exvagabondAsked:
Who is Participating?
 
EE_AutoDeleterConnect With a Mentor Commented:
exvagabond,
Because you have presented a solution to your own problem which may be helpful to future searches, this question is now PAQed and your points have been refunded.

EE_AutoDeleter
0
 
exvagabondAuthor Commented:
Here is another data point:
The drive in question is a PATA drive connected to the computer using an USB adaptor. I rebooted the attached computer and tried to open the drive with no success. After the reboot I opened the drive with a paperclip to find the disc still spinning in the drive. At any time I can try to open the drive using Explorer, and I get the following error:
D:\ is not accessible. Incorrect function.
0
 
exvagabondAuthor Commented:
For anyone interested, the problem ended up being with the state of the drive cache. The drive cache was waiting for more data. Synchronizing the drive cache solved half of the problem. This involved sending SCSI command 0x35 to the drive. The easy way to do this is to download sdparm.exe [http://sg.torque.net/sg/sdparm.html#mozTocId891504]. The difficult way is to write some windows driver code that looks like the following:

<code>
typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS
{
SCSI_PASS_THROUGH spt;
ULONG Filler; // realign buffers to double word boundary
UCHAR ucSenseBuf[32];
UCHAR ucDataBuf[1024];
} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;

memset(&sptwb, 0,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));

sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH);
sptwb.spt.PathId = 0;
sptwb.spt.TargetId = 0;
sptwb.spt.Lun = 0;
sptwb.spt.CdbLength = CDB6GENERIC_LENGTH;
sptwb.spt.SenseInfoLength = 24;
sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN;
sptwb.spt.DataTransferLength = 192;
sptwb.spt.TimeOutValue = 120;
sptwb.spt.DataBufferOffset =
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) ;
sptwb.spt.SenseInfoOffset =
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf );
sptwb.spt.Cdb[0] = 0xXX;
sptwb.spt.Cdb[1] = 0xXX;
sptwb.spt.Cdb[2] = 0xXX;
sptwb.spt.Cdb[3] = 0xXX;
dwLength = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) +
sptwb.spt.DataTransferLength;

dwStatus = DeviceIoControl(g_hUsbDriver,
IOCTL_SCSI_PASS_THROUGH,
&sptwb,
sizeof(SCSI_PASS_THROUGH),
&sptwb,
dwLength,
&dwReturn,
FALSE);
</code>

At this point the drive will respond. However, it is locked. There are two ways to fix this. The first way is to use sdparm.exe again. The second way is to unlock the drive using Windows driver code that looks like the following:

<code>
   #include <windows.h>
   #include <winioctl.h>
   #include <tchar.h>
   #include <stdio.h>
   #include <strsafe.h>

   HANDLE OpenVolume(TCHAR cDriveLetter)
   {
       HANDLE hVolume;
       UINT uDriveType;
       TCHAR szVolumeName[8];
       TCHAR szRootName[5];
       DWORD dwAccessFlags;

       wsprintf(szRootName, szRootFormat, cDriveLetter);

       uDriveType = GetDriveType(szRootName);
       switch(uDriveType) {
       case DRIVE_REMOVABLE:
           dwAccessFlags = GENERIC_READ | GENERIC_WRITE;
           break;
       case DRIVE_CDROM:
           dwAccessFlags = GENERIC_READ;
           break;
       default:
           _tprintf(TEXT("Cannot eject.  Drive type is incorrect.\n"));
           return INVALID_HANDLE_VALUE;
       }

       wsprintf(szVolumeName, szVolumeFormat, cDriveLetter);

       hVolume = CreateFile(   szVolumeName,
                               dwAccessFlags,
                               FILE_SHARE_READ | FILE_SHARE_WRITE,
                               NULL,
                               OPEN_EXISTING,
                               0,
                               NULL );
       if (hVolume == INVALID_HANDLE_VALUE)
           ReportError(TEXT("CreateFile"));

       return hVolume;
   }

   BOOL CloseVolume(HANDLE hVolume)
   {
       return CloseHandle(hVolume);
   }

   #define LOCK_TIMEOUT        10000       // 10 Seconds
   #define LOCK_RETRIES        20

   BOOL LockVolume(HANDLE hVolume)
   {
       DWORD dwBytesReturned;
       DWORD dwSleepAmount;
       int nTryCount;

       dwSleepAmount = LOCK_TIMEOUT / LOCK_RETRIES;

       // Do this in a loop until a timeout period has expired
       for (nTryCount = 0; nTryCount < LOCK_RETRIES; nTryCount++) {
           if (DeviceIoControl(hVolume,
                               FSCTL_LOCK_VOLUME,
                               NULL, 0,
                               NULL, 0,
                               &dwBytesReturned,
                               NULL))
               {
                        printf("locked volume\n");
               return TRUE;
               }

           Sleep(dwSleepAmount);
       }

         printf("did not lock volume\n");
       return FALSE;
   }

   BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPreventRemoval)
   {
       DWORD dwBytesReturned;
       PREVENT_MEDIA_REMOVAL PMRBuffer;

       PMRBuffer.PreventMediaRemoval = fPreventRemoval;

       BOOL result = DeviceIoControl( hVolume,
                               IOCTL_STORAGE_MEDIA_REMOVAL,
                               &PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),
                               NULL, 0,
                               &dwBytesReturned,
                               NULL);
         printf("%s prevent removal\n",result ? "did" : "did not");

         return result;
   }

   void main(int argc, char * argv[])
   {

      HANDLE cdrom = OpenVolume(argv[1][0]);

      if(cdrom == INVALID_HANDLE_VALUE)
      {
            printf("invalid handle\n");
            return;
      }      
      if(LockVolume(cdrom) == false)
      {
            printf("could not lock volume\n");
            return;
      }
      if(PreventRemovalOfVolume(cdrom, true) == false)
      {
            printf("could not prevent removal\n");
            return;
      }

      CloseVolume(cdrom);
      printf("complete\n");
       return ;
   }
</code>


In both accounts, sdparm is nicer. However, with the unlocking of the drive, I am not sure if there are any window side software locks being used in addition to the hardware lock on the drive. So, for unlocking it may be safer to do the windows call. You will need to download the Windows driver development kit in order to compile it, though.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.