我在把一些舊的代碼與自定義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操作。所以回滾會移除該標籤。 –