2012-11-30 126 views
1

我在把一些舊的代碼與自定義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); 
} 
+0

我推出這個回去。有人添加了「設備驅動程序」標籤,但所涉及的代碼不是設備驅動程序,而是Windows服務中的設備驅動程序,而設備本身沒有Windows驅動程序,這就是爲什麼該服務確實指導ioctl操作。所以回滾會移除該標籤。 –

回答

0

該解決方案被證明有兩個部分。

首先,sptwb.spt.DataIn需要是SCSI_IOCTL_DATA_OUT而不是SCSI_IOCTL_DATA_IN - 因爲當然,「Mode Select」告訴設備要做什麼,而不是要求它提供信息。這將DeviceIoControl()的結果從TRUE更改爲FALSE,然後GetLastError()返回值87,表示一個無效參數。

其次,正如我所推測的那樣,ioctl事務需要使用IOCTL_SCSI_PASS_THROUGH_DIRECT而不是IOCTL_SCSI_PASS_THROUGH來完成。

一旦所有設置都正確,那麼「模式選擇」命令成功。