2012-11-30 51 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来完成。

一旦所有设置都正确,那么“模式选择”命令成功。