1

カスタム SCSI デバイスと通信するために古いコードを変換している最中です。元のコードは WinXP と ASPI 用に書かれており、新しいコードは Win7 と SPTI で動作する必要があります。私の問題は、新しいコードが SCSI の「モード選択」操作を実行するための呼び出しで、ステータス コード 2 で失敗することです。これは SCSI の「条件の確認」エラーです。しかし、これは WinXP の古いコードでは発生しません。

通常、「Check Condition」コードを取得すると、デバイスに「Request Sense」コマンドを発行して、何が起こったかを調べることができます。残念ながら、このデバイスは (私の意見では) バグが多く、Request Sense を実行すると常に「すべて問題ありません」と返されます。だから私はここで暗闇の中で働いています。

そのため、SPTI コードで何が間違っている可能性があるかについての提案を期待しており、フィードバックをいただければ幸いです。

これに影響を与えている可能性があると私が考えたいくつかのことを次に示します。

  • デバイスが期待するシーケンスは、"Reserve Unit"、"Rezero Unit"、"Mode Select"、その他の操作、"Release Unit" です。「リザーブユニット」「リゼロユニット」「リリースユニット」は正常に動作しているように見えますが、「モードセレクト」に失敗したため、その他の操作は失敗しています。
  • 操作ごとに、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);
}
4

1 に答える 1

0

ソリューションには 2 つの部分があることがわかりました。

まず、sptwb.spt.DataIn は、SCSI_IOCTL_DATA_IN ではなく SCSI_IOCTL_DATA_OUT である必要がありました。これは、もちろん、「モード選択」がデバイスに情報を求めるのではなく、何をすべきかを指示しているためです。これにより、DeviceIoControl() の結果が TRUE から FALSE に変更され、GetLastError() は無効なパラメーターを示す値 87 を返しました。

第二に、私が推測したように、IOCTL_SCSI_PASS_THROUGH ではなく IOCTL_SCSI_PASS_THROUGH_DIRECT を使用して ioctl トランザクションを実行する必要があります。

これら 2 つの変更ですべてが正しく設定されると、「モード選択」コマンドは成功しました。

于 2012-11-30T17:57:00.667 に答える