scsi2.c
来自「嵌入式操作系统WINCE5.0下的USB驱动程序」· C语言 代码 · 共 1,496 行 · 第 1/4 页
C
1,496 行
#define MAX_LIST_LENGTH 512 // Note: USB Mass Storage Spec says this is max 72 bytes
UCHAR bDataBlock[MAX_LIST_LENGTH] = {0}; // Standard Header + mode pages
USHORT usPageLength = 8; // Standard Header size
DWORD dwErr = ERROR_SUCCESS;
DEBUGMSG(ZONE_SCSI,(TEXT("USBDISK6>ScsiModeSense\n")));
dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL) ;
if ( ERROR_SUCCESS != dwErr) {
return dwErr;
}
ASSERT( SCSI_DEVICE_DIRECT_ACCESS == pDevice->DeviceType ||
SCSI_DEVICE_CDROM == pDevice->DeviceType );
memset( bCDB, 0, sizeof(bCDB));
tCommand.Flags = DATA_IN;
tCommand.Timeout = pDevice->Timeouts.ScsiCommandTimeout;
tCommand.Length = USBMSC_SUBCLASS_SCSI == pDevice->DiskSubClass ?
SCSI_CDB_10 : UFI_CDB;
tCommand.CommandBlock = bCDB;
tCommand.dwLun=Lun;
bCDB[0] = SCSI_MODE_SENSE10;
ASSERT(Lun <= 0x7);
bCDB[1] = ((Lun & 0x7) << 5);
// bCDB[1] |= 0x8; // DBD Note: USB Mass Storage Spec says this is 0
// PC = current
// Page Code = ALL
bCDB[2] = 0x3f; // this was original set to 0 but 0 is not defined in the USB Mass Storage Spec
// some devices return ILLEGAL REQUEST. So use some defines value as default
switch (pDevice->DeviceType)
{
case SCSI_DEVICE_DIRECT_ACCESS:
if (pDevice->DiskSubClass == USBMSC_SUBCLASS_UFI) {
bCDB[2] = MODE_PAGE_FLEXIBLE_DISK;
usPageLength += 32;
} else {
usPageLength = sizeof(bDataBlock);
}
break;
case SCSI_DEVICE_CDROM:
bCDB[2] = MODE_PAGE_CDROM;
usPageLength += 8;
break;
default:
DEBUGMSG(ZONE_ERR,(TEXT("ScsiModeSense10: Unknown DeviceType:0x%x\n"),
pDevice->DeviceType));
TEST_TRAP();
usPageLength = sizeof(bDataBlock);
break;
}
bCDB[7] = (sizeof(bDataBlock) & 0xFF00) >> 8; // MSB
bCDB[8] = sizeof(bDataBlock) & 0x00FF; // LSB
memset( bDataBlock, 0, sizeof(bDataBlock));
ASSERT( usPageLength <= sizeof(bDataBlock));
tData.TransferLength = 0;
// Note: some devices fail with only 8 byte header request length,
// but all should recover with extra buffer space.
tData.RequestLength = usPageLength;
tData.DataBlock = bDataBlock;
dwErr = UsbsDataTransfer( pDevice->hUsbTransport,
&tCommand,
&tData );
if ( dwErr != ERROR_SUCCESS || tData.TransferLength < 8 ) { // want at least the header
dwErr = ScsiGetSenseData( pDevice, Lun );
SetLastError(dwErr);
DEBUGMSG(ZONE_ERR,(TEXT("ScsiModeSense ERROR:%d\n"), dwErr));
} else {
EnterCriticalSection(&pDevice->Lock);
// look at the Header
DEBUGMSG(ZONE_SCSI,(TEXT("Medium Type:0x%x\n"), bDataBlock[2]));
pDevice->MediumType = bDataBlock[2];
// bit7 is WP bit
DEBUGMSG(ZONE_SCSI,(TEXT("Device Specific:0x%x\n"), bDataBlock[3] ));
pDevice->Flags.WriteProtect = bDataBlock[3] & 0x80;
LeaveCriticalSection(&pDevice->Lock);
//
// TBD: look at the the requested page ...
//
}
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
DEBUGMSG(ZONE_SCSI,(TEXT("USBDISK6<ScsiModeSense:%d\n"), dwErr));
return dwErr;
}
DWORD
ScsiModeSense6(
PSCSI_DEVICE pDevice,
UCHAR Lun
)
{
TRANSPORT_DATA tData;
TRANSPORT_COMMAND tCommand;
UCHAR bCDB[SCSI_CDB_6];
UCHAR bDataBlock[MAX_LIST_LENGTH] = {0}; // standard header + mode pages
USHORT usPageLength = 8; // standard header size
DWORD dwErr = ERROR_SUCCESS;
dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL);
if (ERROR_SUCCESS != dwErr) {
return dwErr;
}
ASSERT(SCSI_DEVICE_DIRECT_ACCESS == pDevice->DeviceType || SCSI_DEVICE_CDROM == pDevice->DeviceType);
memset(bCDB, 0, sizeof(bCDB));
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;
DEBUGCHK(Lun <= 0x7);
bCDB[0] = SCSI_MODE_SENSE6;
bCDB[1] = ((Lun & 0x7) << 5);
bCDB[2] = 0x3f;
switch (pDevice->DeviceType) {
case SCSI_DEVICE_DIRECT_ACCESS:
if (pDevice->DiskSubClass == USBMSC_SUBCLASS_UFI) {
bCDB[2] = MODE_PAGE_FLEXIBLE_DISK;
usPageLength += 32;
}
else {
usPageLength = sizeof(bDataBlock);
}
break;
case SCSI_DEVICE_CDROM:
bCDB[2] = MODE_PAGE_CDROM;
usPageLength += 8;
break;
default:
usPageLength = sizeof(bDataBlock);
break;
}
usPageLength = 8;
DEBUGCHK(usPageLength <= sizeof(bDataBlock));
memset(bDataBlock, 0, sizeof(bDataBlock));
// a device may fail this command if the header request length is only 8 bytes;
// if this is the case, then the device should recover with extra buffer space
tData.TransferLength = 0;
tData.RequestLength = usPageLength;
tData.DataBlock = bDataBlock;
dwErr = UsbsDataTransfer(pDevice->hUsbTransport, &tCommand, &tData);
if (dwErr != ERROR_SUCCESS || tData.TransferLength < 8 ) { // we want at least the header
dwErr = ScsiGetSenseData(pDevice, Lun);
SetLastError(dwErr);
DEBUGMSG(ZONE_ERR,(TEXT("ScsiModeSense6: device failed command\r\n"), dwErr));
}
else {
EnterCriticalSection(&pDevice->Lock);
DEBUGMSG(ZONE_SCSI,(TEXT("Scsi2ModeSense6: medium type=0x%x\n"), bDataBlock[2]));
pDevice->MediumType = bDataBlock[2];
pDevice->Flags.WriteProtect = bDataBlock[3] & 0x80; // inspect WP bit
LeaveCriticalSection(&pDevice->Lock);
}
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
return dwErr;
}
DWORD
ScsiStartStopUnit(
PSCSI_DEVICE pDevice,
BOOL Start, // TRUE = START, else STOP
BOOL LoEj,
UCHAR Lun
)
{
TRANSPORT_COMMAND tCommand;
UCHAR bCDB[MAX_CDB];
DWORD dwErr;
DEBUGMSG(ZONE_SCSI,(TEXT("USBDISK6>ScsiStartStopUnit\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_START_STOP;
ASSERT(Lun <= 0x7);
bCDB[1] = ((Lun & 0x7) << 5);
bCDB[4] = (LoEj & 0x1) << 1;
bCDB[4] |= Start & 0x1;
dwErr = UsbsDataTransfer(pDevice->hUsbTransport,
&tCommand,
NULL );
if ( dwErr != ERROR_SUCCESS ) {
dwErr = ScsiGetSenseData( pDevice, Lun );
DEBUGMSG(ZONE_ERR,(TEXT("ScsiStartStopUnit ERROR:%d\n"), dwErr));
SetLastError(dwErr);
}
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
DEBUGMSG(ZONE_SCSI,(TEXT("USBDISK6<ScsiStartStopUnit:%d\n"), dwErr));
return dwErr;
}
//
// Checks the users SG to see if we can use it.
// Since we basically do a prescan then return flag saying
// if we need to use double buffering.
//
DWORD
CheckSegments(
IN PSCSI_DEVICE pDevice,
IN PSG_REQ pSgReq,
IN OUT PDWORD pTransferLength,
IN OUT PDWORD pFlags
)
{
DWORD dwErr = ERROR_SUCCESS;
DWORD sg;
DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC>CheckSegments\n")));
if ( !pDevice || 0 == pDevice->DiskInfo.di_bytes_per_sect ||
0 == pDevice->DiskInfo.di_total_sectors )
{
dwErr = ERROR_FLOPPY_UNKNOWN_ERROR;
DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:1: di_bytes_per_sect:%d di_total_sectors:%d\n"),
pDevice?pDevice->DiskInfo.di_bytes_per_sect:-1, pDevice?pDevice->DiskInfo.di_total_sectors:-1));
TEST_TRAP();
} else if ( !pSgReq || !pTransferLength || !pFlags) {
dwErr=ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:2: %d\n"), dwErr ));
} else if (pSgReq->sr_num_sg > MAX_SG_BUF ||
pSgReq->sr_start + pSgReq->sr_num_sec > pDevice->DiskInfo.di_total_sectors)
{
dwErr=ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:3: sg:%d sr_start:%d, sr_num_sec:%d, di_total_sectors:%d di_bytes_per_sect:%d\n"),
pSgReq->sr_num_sg, pSgReq->sr_start, pSgReq->sr_num_sec, pDevice->DiskInfo.di_total_sectors, pDevice->DiskInfo.di_bytes_per_sect));
} else {
//
// ensure all the buffers in the SG list are OK
//
ASSERT(pFlags);
ASSERT(pTransferLength);
EnterCriticalSection(&pDevice->Lock);
for (sg = 0, *pTransferLength = 0, *pFlags = 0; sg < pSgReq->sr_num_sg; sg++)
{
if ( !pSgReq->sr_sglist[sg].sb_buf )
{
dwErr = ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:4:%d\n"), dwErr));
break;
}
// do we need double buffering?
if ((pSgReq->sr_sglist[sg].sb_len % pDevice->DiskInfo.di_bytes_per_sect) != 0)
{
*pFlags |= 0x1;
DEBUGMSG(ZONE_READ,(TEXT("CheckSegments: Double Buffered\n")));
}
// sum all the buffer lengths to make sure they match
// the requested number of sectors
*pTransferLength += pSgReq->sr_sglist[sg].sb_len;
}
if (dwErr == ERROR_SUCCESS &&
*pTransferLength > (pSgReq->sr_num_sec * pDevice->DiskInfo.di_bytes_per_sect))
{
dwErr = ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:5: invalid user SG buffers (%u > %u)\n"),
*pTransferLength, (pSgReq->sr_num_sg * pDevice->DiskInfo.di_bytes_per_sect)));
}
LeaveCriticalSection(&pDevice->Lock);
}
DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC<CheckSegments:%d\n"), dwErr));
return dwErr;
}
/*++
Validate a Scatter/Gather request object.
Returns: If fail, Win32 error.
If pass, ERROR_SUCCESS.
--*/
static DWORD
InspectSgReq(
PSG_REQ pSgReq,
UINT uiBytesPerSector
)
{
UINT uiSgIndex; // Index into Scatter/Gather buffer array.
UINT uiBytesToTransfer; // Running count of the number of bytes requested to transfer.
DEBUGMSG(ZONE_TRACE, (TEXT("USBMSC>InspectSgReq\n")));
if (pSgReq == NULL) {
DEBUGMSG(ZONE_ERR, (TEXT("USBMSC>InspectSgReq: Error: pSqReq: NULL\n")));
return ERROR_BAD_ARGUMENTS;
}
if (pSgReq->sr_num_sec == 0) {
DEBUGMSG(ZONE_ERR, (TEXT("USBMSC>InspectSgReq: Error: ->sr_num_sec: 0\n")));
return ERROR_BAD_ARGUMENTS;
}
if (pSgReq->sr_num_sg == 0) {
DEBUGMSG(ZONE_ERR, (TEXT("USBMSC>InspectSgReq: Error: ->sr_num_sg: 0\n")));
return ERROR_BAD_ARGUMENTS;
}
DEBUGMSG(ZONE_TRACE, (TEXT("USBMSC>InspectSgReq: ->sr_num_sec: %d, ->sr_num_sg: %d, bytes/sec: %d\n"), pSgReq->sr_num_sec, pSgReq->sr_num_sg, uiBytesPerSector));
for (uiSgIndex = 0, uiBytesToTransfer = 0; uiSgIndex < pSgReq->sr_num_sg; uiSgIndex += 1) {
if (pSgReq->sr_sglist[uiSgIndex].sb_buf == NULL) {
DEBUGMSG(ZONE_ERR, (TEXT("USBMSC>InspectSgReq: Error: ->sr_sglist[%d].sb_buf: NULL\n"), uiSgIndex));
return ERROR_BAD_ARGUMENTS;
}
if (pSgReq->sr_sglist[uiSgIndex].sb_len == 0) {
DEBUGMSG(ZONE_ERR, (TEXT("USBMSC>InspectSgReq: Error: ->sr_sglist[%d].sb_len: 0\n"), uiSgIndex));
return ERROR_BAD_ARGUMENTS;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?