📄 scsi2.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
scsi2.c
Abstract:
Scsi2 Interface for USB Disk Class
bInterfaceSubClass = 0x02 : SFF8020i (ATAPI) CD-ROM
bInterfaceSubClass = 0x04 : USB Floppy Interface (UFI)
bInterfaceSubClass = 0x06 : SCSI Passthrough
This code basically builds a SCSI2 Command Descriptor Block (CDB) for
transport via the USB Mass Storage Class.
--*/
#include <ntcompat.h>
#include <pkfuncs.h>
#include "usbmsc.h"
#include "scsi2.h"
//*****************************************************************************
// S C S I - 2 I N T E R F A C E
//*****************************************************************************
DWORD
ScsiPassthrough(
PSCSI_DEVICE pDevice,
PTRANSPORT_COMMAND pCommand,
PTRANSPORT_DATA pData
)
{
DWORD dwErr;
DEBUGMSG(ZONE_SCSI,(TEXT("USBDISK6>ScsiPassthrough\n")));
do {
if ( !pDevice || !pCommand || !pData ) {
dwErr = ERROR_INVALID_PARAMETER;
break;
}
dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL);
if ( ERROR_SUCCESS != dwErr) {
break;
}
__try {
dwErr = UsbsDataTransfer( pDevice->hUsbTransport,
pCommand,
pData );
} __except ( EXCEPTION_EXECUTE_HANDLER ) {
//
// This could happen if the caller has embedded pointers in the
// struct. In these cases the caller should use IOCTL_DISK_Xxx
// which knows about the contents of the command buffers, and
// correctly maps them in. Otherwise, a filter driver would be
// responsible for knowing about the command buffers and do the
// correct mapping.
//
dwErr = GetExceptionCode();
DEBUGMSG(ZONE_ERR,(TEXT("USBDISK6::ScsiPassthrough:EXCEPTION:0x%x\n")
, dwErr));
}
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
} while (0);
DEBUGMSG(ZONE_SCSI,(TEXT("USBDISK6<ScsiPassthrough:%d\n"), dwErr));
SetLastError(dwErr);
return dwErr;
}
DWORD
ScsiUnitAttention(
PSCSI_DEVICE pDevice,
UCHAR Lun
)
{
DWORD dwRepeat, dwErr, dwStartErr, dwSenseErr;
DEBUGMSG(ZONE_TRACE,(TEXT("USBDISK6>ScsiUnitAttention\n")));
dwRepeat = pDevice->Timeouts.UnitAttnRepeat;
do
{
#if 0
if (pDevice->DiskSubClass == USBMSC_SUBCLASS_UFI) {
__asm int 3;
// UFI floppies seem to require start unit first
dwStartErr = ScsiStartStopUnit(pDevice, TRUE, FALSE, Lun);
if (ERROR_ACCESS_DENIED == dwStartErr || ERROR_INVALID_HANDLE == dwStartErr)
return dwStartErr;
}
#endif 0
dwErr = ScsiTestUnitReady(pDevice, Lun);
if (ERROR_ACCESS_DENIED == dwErr || ERROR_INVALID_HANDLE == dwErr)
return dwErr;
else if (ERROR_SUCCESS != dwErr)
{
DEBUGMSG(ZONE_ERR,(TEXT("ScsiUnitAttention:%d\n"), dwErr));
// some devices require a (re)start
dwStartErr = ScsiStartStopUnit(pDevice, TRUE, FALSE, Lun);
if (ERROR_ACCESS_DENIED == dwStartErr || ERROR_INVALID_HANDLE == dwStartErr)
return dwStartErr;
else if (ERROR_SUCCESS != dwStartErr)
{
// try to clear any persistant error
dwSenseErr = ScsiGetSenseData(pDevice, Lun);
if (ERROR_ACCESS_DENIED == dwSenseErr || ERROR_INVALID_HANDLE == dwSenseErr)
return dwSenseErr;
}
Sleep(10);
}
} while (ERROR_SUCCESS != dwErr && --dwRepeat != 0 );
DEBUGMSG(ZONE_TRACE,(TEXT("USBDISK6<ScsiUnitAttention:%d\n"), dwErr));
return dwErr;
}
DWORD
ScsiTestUnitReady(
PSCSI_DEVICE pDevice,
UCHAR Lun
)
{
TRANSPORT_COMMAND tCommand;
UCHAR bCDB[MAX_CDB];
DWORD dwErr;
DEBUGMSG(ZONE_TRACE,(TEXT("USBDISK6>ScsiTestUnitReady\n")));
dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL);
if ( ERROR_SUCCESS != dwErr) {
return dwErr;
}
tCommand.Flags = DATA_OUT;
tCommand.Timeout = pDevice->Timeouts.ScsiCommandTimeout;
tCommand.Length = USBMSC_SUBCLASS_SCSI == pDevice->DiskSubClass ?
SCSI_CDB_6 : UFI_CDB;
tCommand.CommandBlock = bCDB;
memset(bCDB, 0, sizeof(bCDB));
bCDB[0] = SCSI_TEST_UNIT_READY;
ASSERT(Lun <= 0x7);
bCDB[1] = ((Lun & 0x7) << 5);
dwErr = UsbsDataTransfer( pDevice->hUsbTransport,
&tCommand,
NULL );
if ( dwErr != ERROR_SUCCESS ) {
dwErr = ScsiGetSenseData( pDevice, Lun );
DEBUGMSG(ZONE_ERR,(TEXT("ScsiTestUnitReady ERROR:%d\n"), dwErr));
SetLastError(dwErr);
}
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
DEBUGMSG(ZONE_TRACE,(TEXT("USBDISK6<ScsiTestUnitReady:%d\n"), dwErr));
return dwErr;
}
DWORD
ScsiRequestSense(
PSCSI_DEVICE pDevice,
PTRANSPORT_DATA pTData,
UCHAR Lun
)
{
TRANSPORT_COMMAND tCommand;
UCHAR bCDB[MAX_CDB];
DWORD dwErr;
DEBUGMSG(ZONE_TRACE,(TEXT("USBDISK6>ScsiRequestSense\n")));
dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL) ;
if ( ERROR_SUCCESS != dwErr) {
return dwErr;
}
tCommand.Flags = DATA_IN;
tCommand.Timeout = pDevice->Timeouts.ScsiCommandTimeout;
tCommand.Length = USBMSC_SUBCLASS_SCSI == pDevice->DiskSubClass ?
SCSI_CDB_6 : UFI_CDB;
tCommand.CommandBlock = bCDB;
memset(bCDB,0,sizeof(bCDB));
bCDB[0] = SCSI_REQUEST_SENSE;
ASSERT(Lun <= 0x7);
bCDB[1] = ((Lun & 0x7) << 5);
bCDB[4] = (UCHAR)pTData->RequestLength;
dwErr = UsbsDataTransfer( pDevice->hUsbTransport,
&tCommand,
pTData );
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
DEBUGMSG(ZONE_TRACE,(TEXT("USBDISK6<ScsiRequestSense:%d\n"), dwErr));
return dwErr;
}
//
// Translates SCSI device error to Win32 error.
//
DWORD
ScsiGetSenseData(
PSCSI_DEVICE pDevice,
UCHAR Lun
)
{
TRANSPORT_DATA tData;
UCHAR senseData[18];
DWORD dwErr;
UCHAR SenseKey, ASC, ASCQ;
DEBUGMSG(ZONE_TRACE,(TEXT("USBDISK6>ScsiGetSenseData\n")));
dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL) ;
if ( ERROR_SUCCESS != dwErr) {
return dwErr;
}
tData.TransferLength = 0;
tData.RequestLength = sizeof(senseData);
tData.DataBlock = senseData;
memset(senseData,0,sizeof(senseData));
dwErr = ScsiRequestSense(pDevice, &tData, Lun);
// did we receive a valid SenseKey
if ( ERROR_SUCCESS == dwErr &&
(0x70 & senseData[0]) || (0x71 & senseData[0]) &&
tData.TransferLength > 13 ) {
// ASSERT( senseData[0] & 0x80 ); // Valid bit
SenseKey = senseData[2] & 0x0f;
ASC = senseData[12];
ASCQ = senseData[13];
DEBUGMSG(ZONE_WARN,(TEXT("ScsiGetSenseData - SenseKey:0x%x ASC:0x%x ASCQ:0x%x\n")
, SenseKey, ASC, ASCQ));
EnterCriticalSection(&pDevice->Lock);
switch (SenseKey) {
case SENSE_NONE :
case SENSE_RECOVERED_ERROR :
dwErr = ERROR_SUCCESS;
break;
case SENSE_NOT_READY :
switch( ASC ) {
case ASC_LUN:
DEBUGMSG(ZONE_WARN,(TEXT("SENSE_NOT_READY : ASC_LUN: %d\n"),
Lun));
if (0x02 == ASCQ) { // Initialization Required
TEST_TRAP();
ScsiStartStopUnit(pDevice, START, FALSE, pDevice->Lun);
}
dwErr = ERROR_NOT_READY;
break;
case ASC_MEDIUM_NOT_PRESENT :
DEBUGMSG(ZONE_WARN,(TEXT("SENSE_NOT_READY : ASC_MEDIUM_NOT_PRESENT\n")));
ASSERT(!ASCQ);
pDevice->Flags.MediumPresent = FALSE;
pDevice->Flags.MediumChanged = TRUE;
pDevice->MediumType = SCSI_MEDIUM_UNKNOWN;
memset(&pDevice->DiskInfo, 0, sizeof(DISK_INFO) );
dwErr = DISK_REMOVED_ERROR;
break;
default:
DEBUGMSG(ZONE_WARN,(TEXT("SENSE_NOT_READY : Unhandled ASC:0x%x ASCQ:0x%x\n"),
ASC, ASCQ));
dwErr = ERROR_NOT_READY;
break;
}
break;
case SENSE_MEDIUM_ERROR :
DEBUGMSG(ZONE_WARN,(TEXT("SENSE_MEDIUM_ERROR\n")));
dwErr = ERROR_UNRECOGNIZED_MEDIA;
//TEST_TRAP();
break;
case SENSE_HARDWARE_ERROR :
DEBUGMSG(ZONE_WARN,(TEXT("SENSE_HARDWARE_ERROR\n")));
dwErr = ERROR_DISK_OPERATION_FAILED;
TEST_TRAP();
break;
case SENSE_ILLEGAL_REQUEST :
DEBUGMSG(ZONE_WARN,(TEXT("SENSE_ILLEGAL_REQUEST\n")));
dwErr = ERROR_INVALID_PARAMETER;
// TEST_TRAP();
break;
case SENSE_UNIT_ATTENTION :
switch( ASC ) {
case ASC_MEDIA_CHANGED :
DEBUGMSG(ZONE_WARN,(TEXT("SENSE_UNIT_ATTENTION : ASC_MEDIA_CHANGED\n")));
ASSERT(!ASCQ);
pDevice->Flags.MediumPresent = !pDevice->Flags.MediumPresent;
pDevice->Flags.MediumChanged = TRUE;
pDevice->MediumType = SCSI_MEDIUM_UNKNOWN;
memset(&pDevice->DiskInfo, 0, sizeof(DISK_INFO) );
break;
case ASC_RESET :
DEBUGMSG(ZONE_WARN,(TEXT("SENSE_UNIT_ATTENTION : ASC_RESET\n")));
break;
case ASC_COMMANDS_CLEARED :
default:
DEBUGMSG(ZONE_WARN,(TEXT("SENSE_UNIT_ATTENTION : Unhandled ASC:0x%x\n"),
ASC));
ASSERT(0);
break;
}
dwErr = DISK_REMOVED_ERROR;
break;
case SENSE_DATA_PROTECT :
dwErr = ERROR_WRITE_PROTECT;
break;
default:
dwErr = ERROR_FLOPPY_UNKNOWN_ERROR;
break;
}
LeaveCriticalSection(&pDevice->Lock);
} else {
DEBUGMSG(ZONE_ERR,(TEXT("ScsiGetSenseData error:%d\n"), dwErr));
}
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
DEBUGMSG(ZONE_TRACE,(TEXT("USBDISK6<ScsiGetSenseData:%d\n"), dwErr));
return dwErr;
}
// returns Win32 error
DWORD
ScsiInquiry(
PSCSI_DEVICE pDevice,
UCHAR Lun
)
{
TRANSPORT_COMMAND tCommand;
UCHAR bCDB[MAX_CDB];
TRANSPORT_DATA tData = {0};
UCHAR bDataBlock[36]; // Standard Inquiry Data
#ifdef DEBUG
DWORD dwStatus;
ANSI_STRING asString;
UNICODE_STRING usString = {0, 0, 0};
WCHAR wcBuff[128]; // excessively large for the unexcected
#endif
DWORD dwErr = ERROR_SUCCESS;;
DEBUGMSG(ZONE_SCSI,(TEXT("USBDISK6>ScsiInquiry:Lun:%d\n"), Lun));
dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL) ;
if ( ERROR_SUCCESS != dwErr) {
return dwErr;
}
tCommand.Flags = DATA_IN;
tCommand.Timeout = pDevice->Timeouts.ScsiCommandTimeout;
tCommand.Length = USBMSC_SUBCLASS_SCSI == pDevice->DiskSubClass ?
SCSI_CDB_6 : UFI_CDB;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -