I'm in the middle of converting some older code to talk with a custom SCSI device. The original code was written for WinXP and ASPI, and the newer code needs to work on Win7 and SPTI. My problem is that the newer code fails on a call to do a SCSI "Mode Select" operation with an status code of 2, which is a SCSI "Check Condition" error - but this doesn't happen with the older code under WinXP.
Normally, when you get a "Check Condition" code, you can issue a "Request Sense" command to the device to find out what happened. Unfortunately, this device is (in my opinion) buggy, and always returns "everything is okay" when you do a Request Sense. So I'm working in the dark here.
So I'm hoping for some suggestions on what I could be doing wrong with the SPTI code, and would be grateful for any feedback.
Here are a few things I've thought of that may be affecting this:
- The sequence the device expects is "Reserve Unit", "Rezero Unit", "Mode Select", then some other operations, then "Release Unit". It appears "Reserve Unit", "Rezero Unit", and "Release Unit are all working fine, but the other operations fail because "Mode Select" failed.
- For each operation, the SPTI code opens and closes a handle to the SCSI host adapter. Should I open a handle in "Reserve Unit" and leave it open for the entire sequence?
- The ioctl sent to DeviceIoControl() is IOCTL_SCSI_PASS_THROUGH. Should I be using IOCTL_SCSI_PASS_THROUGH_DIRECT for the "Mode Select" operation? It's a simple operation, so I figured the simpler API would be adequate for this, but maybe I'm wrong about that.
The code in question is:
void MSSModeSelect(const ModeSelectRequestPacket& inRequest, StatusResponsePacket& outResponse)
{
IPC_LOG("MSSModeSelect(): PathID=%d, TargetID=%d, LUN=%d", inRequest.m_Device.m_PathId,
inRequest.m_Device.m_TargetId, inRequest.m_Device.m_Lun);
int adapterIndex = inRequest.m_Device.m_PathId;
HANDLE adapterHandle = prvOpenScsiAdapter(inRequest.m_Device.m_PathId);
if (adapterHandle == INVALID_HANDLE_VALUE)
{
outResponse.m_Status = eScsiAdapterErr;
return;
}
SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;
memset(&sptwb, 0, sizeof(sptwb));
#define MODESELECT_BUF_SIZE 32
sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH);
sptwb.spt.PathId = inRequest.m_Device.m_PathId;
sptwb.spt.TargetId = inRequest.m_Device.m_TargetId;
sptwb.spt.Lun = inRequest.m_Device.m_Lun;
sptwb.spt.CdbLength = CDB6GENERIC_LENGTH;
sptwb.spt.SenseInfoLength = 0;
sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN;
sptwb.spt.DataTransferLength = MODESELECT_BUF_SIZE;
sptwb.spt.TimeOutValue = 2;
sptwb.spt.DataBufferOffset =
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
sptwb.spt.Cdb[0] = SCSIOP_MODE_SELECT;
sptwb.spt.Cdb[4] = MODESELECT_BUF_SIZE;
DWORD length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) +
sptwb.spt.DataTransferLength;
memset(sptwb.ucDataBuf, 0, sizeof(sptwb.ucDataBuf));
sptwb.ucDataBuf[2] = 0x10;
sptwb.ucDataBuf[4] = 0x01;
sptwb.ucDataBuf[5] = 0x04;
ULONG bytesReturned = 0;
BOOL okay = DeviceIoControl(adapterHandle,
IOCTL_SCSI_PASS_THROUGH,
&sptwb,
sizeof(SCSI_PASS_THROUGH),
&sptwb,
length,
&bytesReturned,
FALSE);
DWORD gle = GetLastError();
IPC_LOG(" DeviceIoControl() %s", okay ? "worked" : "failed");
if (okay)
{
outResponse.m_Status = (sptwb.spt.ScsiStatus == 0) ? eOk : ePrinterStatusErr;
}
else
{
outResponse.m_Status = eScsiPermissionsErr;
}
CloseHandle(adapterHandle);
}