Я нахожусь в середине преобразования некоторого старого кода, чтобы общаться с пользовательским устройством SCSI. Исходный код был написан для WinXP и ASPI, а новый код должен работать на Win7 и SPTI. Моя проблема заключается в том, что более новый код не работает при вызове операции SCSI «Выбор режима» с кодом состояния 2, что является ошибкой SCSI «Проверить условие», но этого не происходит с более старым кодом под WinXP.
Обычно, когда вы получаете код «Проверить состояние», вы можете отправить на устройство команду «Request Sense», чтобы узнать, что произошло. К сожалению, это устройство (на мой взгляд) глючит и всегда возвращает «все в порядке», когда вы выполняете Request Sense. Так что я работаю в темноте здесь.
Поэтому я надеюсь на некоторые предложения о том, что я мог делать неправильно с кодом SPTI, и был бы признателен за любую обратную связь.
Вот несколько вещей, которые, как я думал, могут повлиять на это:
- Последовательность, которую ожидает устройство: «Резервный блок», «Обнуление блока», «Выбор режима», затем некоторые другие операции, затем «Выпуск блока». Похоже, что «Reserve Unit», «Rezero Unit» и «Release Unit» работают нормально, но другие операции завершаются сбоем из-за сбоя «Mode Select».
- Для каждой операции код SPTI открывает и закрывает дескриптор хост-адаптера SCSI. Должен ли я открыть дескриптор в «Резервном блоке» и оставить его открытым для всей последовательности?
- ioctl, отправленный в DeviceIoControl(), — это 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);
}