我在把一些旧的代码与自定义SCSI设备谈话的中间。原始代码是为WinXP和ASPI编写的,而较新的代码需要在Win7和SPTI上运行。我的问题是,新的代码无法在通话过程中做一个SCSI“模式选择”操作为2的状态码,这是一个SCSI“检查条件”的错误 - 但这并不与在WinXP下的旧的代码发生。SPTI“模式选择”意外失败在Win 7 64位
通常情况下,当您收到“检查条件”代码时,您可以向设备发出“请求感知”命令以了解发生的情况。不幸的是,这个设备(在我看来)是越野车,并且当你做请求感时总是返回“一切正常”。所以我在这里黑暗中工作。
因此,我希望提供一些关于我可能在SPTI代码上做错了什么的建议,并且会很感激任何反馈。
这里有一些事情我已经想到了可能会影响此:
- 器件期待的顺序是“保留单位”,“重新调零单位”,“模式选择”,那么其他一些操作,然后是“释放单元”。看起来“Reserve Unit”,“Rezero Unit”和“Release Unit are working fine,but other operations failed because because”Mode Select“failed。
- 对于每个操作,SPTI代码打开和关闭句柄SCSI主机适配器我应该在“预留单元”中打开一个句柄并将其保留为打开整个序列吗?
- 发送到DeviceIoControl()的ioctl是IOCTL_SCSI_PASS_THROUGH。是否应该将IOCTL_SCSI_PASS_THROUGH_DIRECT用于“模式选择”操作?简单的操作,所以我想简单的API就足够了这一点,但也许我错了
有问题的代码是:
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);
}
我推出这个回去。有人添加了“设备驱动程序”标签,但所涉及的代码不是设备驱动程序,而是Windows服务中的设备驱动程序,而设备本身没有Windows驱动程序,这就是为什么该服务确实指导ioctl操作。所以回滚会移除该标签。 –