📄 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"
//*****************************************************************************
// P R I V A T E
//*****************************************************************************
static
DWORD
InspectSgReq(
PSG_REQ pSgReq,
UINT uiBytesPerSector
);
//*****************************************************************************
// 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 {
pCommand->dwLun=pDevice->Lun;
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;
DEBUGMSG(ZONE_TRACE,(TEXT("Usbdisk6!ScsiUnitAttention++\r\n")));
dwRepeat = pDevice->Timeouts.UnitAttnRepeat;
do {
dwErr = ScsiTestUnitReady(pDevice, Lun);
if (ERROR_SUCCESS != dwErr && SCSI_DEVICE_CDROM == pDevice->DeviceType) {
if (ERROR_SUCCESS != ScsiStartStopUnit(pDevice, TRUE, FALSE, pDevice->Lun)) {
ScsiGetSenseData(pDevice, pDevice->Lun);
}
}
--dwRepeat;
if (ERROR_SUCCESS != dwErr && dwRepeat != 0) Sleep(10);
} while (ERROR_SUCCESS != dwErr && dwRepeat != 0);
DEBUGMSG(ZONE_TRACE,(TEXT("Usbdisk6!ScsiUnitAttention-- Error(%d)\r\n"), dwErr));
return dwErr;
}
typedef struct _USBMSC_DEVICE {
ULONG Sig;
CRITICAL_SECTION Lock;
} USBMSC_DEVICE;
DWORD
ScsiTestUnitReady(
PSCSI_DEVICE pDevice,
UCHAR Lun
)
{
USBMSC_DEVICE *pUsbDevice = (USBMSC_DEVICE *)pDevice->hUsbTransport;
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;
tCommand.dwLun=Lun;
memset(bCDB, 0, sizeof(bCDB));
bCDB[0] = SCSI_TEST_UNIT_READY;
ASSERT(Lun <= 0x7);
bCDB[1] = ((Lun & 0x7) << 5);
EnterCriticalSection(&pUsbDevice->Lock);
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);
}
LeaveCriticalSection(&pUsbDevice->Lock);
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;
tCommand.dwLun=Lun;
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -