📄 scsi2.c
字号:
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)));
}
// we are limited by our static sg buffer
if (dwErr == ERROR_SUCCESS && *pFlags &&
*pTransferLength > SG_BUFF_SIZE)
{
dwErr = ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_WARN,(TEXT("CheckSegments ERROR:6: overrun our SG buffer (%u > %u)\n"),
*pTransferLength, SG_BUFF_SIZE));
TEST_TRAP();
*pFlags |= 0x2;
}
LeaveCriticalSection(&pDevice->Lock);
}
DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC<CheckSegments:%d\n"), dwErr));
return dwErr;
}
/* ++
Returns number of bytes transferred.
Returns Status in the PSG_REQ status field.
BUGBUG: this code does not pass "s tux -o -d rwtest -x1021-3099"
for the following case:
*** Test Name: Buffer Sizes: 1025, 1025, 1025, 1025
*** Test ID: 1033
*** Library Path: rwtest
The fix: use our SG buffer in a loop for the overrun case, signaled by dwFlags.
-- */
DWORD
ScsiRWSG(
PSCSI_DEVICE pDevice,
PSG_REQ pSgReq,
UCHAR Lun,
BOOL bRead
)
{
DWORD dwTtlTransferLength;
DWORD dwTtlBytesTransferred = 0;
DWORD dwFlags = 0;
DWORD dwErr;
DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC>ScsiRWSG\n")));
dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL);
if ( ERROR_SUCCESS != dwErr) {
return dwErr;
}
EnterCriticalSection(&pDevice->Lock);
dwErr = CheckSegments(pDevice, pSgReq, &dwTtlTransferLength, &dwFlags);
if (ERROR_SUCCESS == dwErr)
{
LONGLONG iTotalSector = pSgReq->sr_num_sec;
DWORD dwStartSector = pSgReq->sr_start;
HANDLE hProc = GetCallerProcess();
DWORD dwContigSectors = 0;
DWORD dwBytesTransferred = 0;
DWORD sg;
// sector aligned buffers require no double buffering
//
if (!dwFlags) {
for (sg = 0;
sg < pSgReq->sr_num_sg && iTotalSector > 0 &&
pSgReq->sr_sglist[sg].sb_buf && pSgReq->sr_sglist[sg].sb_len;
sg++)
{
// map the current user buffer into our context if necessary
PVOID pBuffer = (hProc == pDevice->hProc) ? pSgReq->sr_sglist[sg].sb_buf :
MapPtrToProcess((LPVOID)pSgReq->sr_sglist[sg].sb_buf, hProc);
ASSERT((pSgReq->sr_sglist[sg].sb_len % pDevice->DiskInfo.di_bytes_per_sect) == 0);
// get the number of contigious sectors we can transfer
dwContigSectors = min((pSgReq->sr_sglist[sg].sb_len / pDevice->DiskInfo.di_bytes_per_sect),
(DWORD)iTotalSector);
dwBytesTransferred = pSgReq->sr_sglist[sg].sb_len;
ASSERT(dwContigSectors);
ASSERT(dwContigSectors <= iTotalSector);
ASSERT(pBuffer);
DEBUGMSG(ZONE_READ,(TEXT("Scsi%sSG[%d] dwStartSector:%d, dwContigSectors:%d\n"),
bRead ? TEXT("Read") : TEXT("Write"), sg, dwStartSector, dwContigSectors));
//
// transfer contigious sector segments
//
dwErr = ScsiReadWrite( pDevice,
dwStartSector,
dwContigSectors,
pBuffer,
&dwBytesTransferred,
Lun,
bRead );
if ( ERROR_SUCCESS == dwErr )
{
iTotalSector -= dwContigSectors;
dwStartSector += dwContigSectors;
ASSERT(iTotalSector >= 0);
pBuffer = (PVOID)((PUCHAR)pBuffer + dwBytesTransferred);
dwTtlBytesTransferred += dwBytesTransferred;
} else {
DEBUGMSG(ZONE_ERR,(TEXT("ScsiRWSG ERROR:%d\n"), dwErr));
break;
}
}
} else {
//
// Double Buffering
//
DWORD offset;
dwContigSectors = pSgReq->sr_num_sec;
dwBytesTransferred = dwContigSectors * pDevice->DiskInfo.di_bytes_per_sect;
ASSERT(dwBytesTransferred <= SG_BUFF_SIZE);
// BUGBUG: we need to use our SG buffer in a loop here for test case 1033
// when overrun our SG buffer as set by the flags above.
memset(&pDevice->SgBuff[0], 0, dwBytesTransferred);
//
// pre-copy all the write data into our local sg buffer
//
if (!bRead)
{
for (sg = 0, offset = 0; sg < pSgReq->sr_num_sg; sg++)
{
// map the current buffer into our context if necessary
PVOID pBuffer = (hProc == pDevice->hProc) ? pSgReq->sr_sglist[sg].sb_buf :
MapPtrToProcess((LPVOID)pSgReq->sr_sglist[sg].sb_buf, hProc);
memcpy(&pDevice->SgBuff[offset], pBuffer, pSgReq->sr_sglist[sg].sb_len);
offset += pSgReq->sr_sglist[sg].sb_len;
}
}
DEBUGMSG(ZONE_READ,(TEXT("Scsi%sSG: dwStartSector:%d, dwContigSectors:%d, bBuffered:%d\n"),
bRead ? TEXT("Read") : TEXT("Write"), dwStartSector, dwContigSectors, dwFlags));
//
// transfer contigious sector segments
//
dwErr = ScsiReadWrite( pDevice,
dwStartSector,
dwContigSectors,
&pDevice->SgBuff[0],
&dwBytesTransferred,
Lun,
bRead );
if ( ERROR_SUCCESS == dwErr )
{
dwTtlBytesTransferred += dwBytesTransferred;
//
// post-copy all the read data from our local sg buffer
//
if (bRead)
{
for (sg = 0, offset = 0; sg < pSgReq->sr_num_sg; sg++)
{
// map the current buffer into our context if necessary
PVOID pBuffer = (hProc == pDevice->hProc) ? pSgReq->sr_sglist[sg].sb_buf :
MapPtrToProcess((LPVOID)pSgReq->sr_sglist[sg].sb_buf, hProc);
memcpy(pBuffer, &pDevice->SgBuff[offset], pSgReq->sr_sglist[sg].sb_len);
offset += pSgReq->sr_sglist[sg].sb_len;
}
}
} else {
DEBUGMSG(ZONE_ERR,(TEXT("ScsiRWSG ERROR:%d\n"), dwErr));
}
}
} else {
DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:%d\n"),dwErr));
}
//
// set Win32 status
//
pSgReq->sr_status = dwErr;
LeaveCriticalSection(&pDevice->Lock);
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC<ScsiRWSG:%d\n"), dwErr));
return dwTtlBytesTransferred;
}
/* ++
ScsiReadWrite:
Transfers full sectors.
-- */
DWORD
ScsiReadWrite(
IN PSCSI_DEVICE pDevice,
IN DWORD dwStartSector,
IN DWORD dwNumSectors,
IN OUT PVOID pvBuffer, // pointer to transfer buffer
IN OUT PDWORD pdwTransferSize, // IN: sizeof input buffer, OUT: number of bytes transferred
IN UCHAR Lun,
IN BOOL bRead
)
{
TRANSPORT_COMMAND tCommand;
UCHAR bCDB[MAX_CDB];
TRANSPORT_DATA tData;
DWORD dwErr;
DWORD dwSectorBytes;
UCHAR retries = 0;
DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC>ScsiReadWrite\n")));
if (!pDevice || !pDevice->DiskInfo.di_bytes_per_sect ||
!pvBuffer || !pdwTransferSize) {
return ERROR_INVALID_PARAMETER;
}
// buffer size limitations.
if (0 == *pdwTransferSize || !dwNumSectors) {
DEBUGMSG(ZONE_ERR,(TEXT("ScsiReadWrite: inlalid transfer size:%u, %u\n"),
*pdwTransferSize, dwNumSectors));
TEST_TRAP();
return ERROR_INVALID_PARAMETER;
}
dwSectorBytes = dwNumSectors * pDevice->DiskInfo.di_bytes_per_sect;
// Transfer buffers must be large enough to fit the requested # sectors
if (*pdwTransferSize < dwSectorBytes)
{
DEBUGMSG(ZONE_ERR,(TEXT("ScsiReadWrite: buffer too small (%u < %u)\n"), *pdwTransferSize, dwSectorBytes));
return ERROR_INSUFFICIENT_BUFFER;
}
dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL);
if ( ERROR_SUCCESS != dwErr) {
return dwErr;
}
EnterCriticalSection(&pDevice->Lock);
tCommand.Flags = bRead ? DATA_IN : DATA_OUT;
tCommand.Timeout = dwNumSectors * (bRead ? pDevice->Timeouts.ReadSector : pDevice->Timeouts.WriteSector);
tCommand.Length = USBMSC_SUBCLASS_SCSI == pDevice->DiskSubClass ? SCSI_CDB_10 : UFI_CDB;
tCommand.CommandBlock = bCDB;
memset(bCDB, 0, sizeof(bCDB) );
bCDB[0] = bRead ? SCSI_READ10 : SCSI_WRITE10;
ASSERT(Lun <= 0x7);
bCDB[1] = ((Lun & 0x7) << 5);
// Logical Block Address
SetDWORD( &bCDB[2], dwStartSector);
// TransferLength (in sectors)
SetWORD( &bCDB[7], (WORD)dwNumSectors);
tData.TransferLength = 0;
tData.RequestLength = dwSectorBytes;
tData.DataBlock = pvBuffer;
DEBUGMSG(ZONE_READ,(TEXT("Scsi%s - LBA:%d TL:%d TimeOut:%d\n"),
bRead ? TEXT("Read") : TEXT("Write"), dwStartSector, dwNumSectors, tCommand.Timeout));
do {
// since we do retries we also have to (re)poke the device
dwErr = ScsiUnitAttention(pDevice, pDevice->Lun);
if (ERROR_SUCCESS != dwErr)
break;
dwErr = UsbsDataTransfer( pDevice->hUsbTransport,
&tCommand,
&tData );
if ( ERROR_SUCCESS == dwErr ) {
*pdwTransferSize = tData.TransferLength;
} else {
dwErr = ScsiGetSenseData(pDevice, Lun);
if (ERROR_SUCCESS == dwErr)
dwErr = ERROR_GEN_FAILURE;
DEBUGMSG(ZONE_ERR,(TEXT("ScsiReadWrite ERROR:%d\n"), dwErr));
*pdwTransferSize = 0;
}
} while ((ERROR_SUCCESS != dwErr) && (++retries < 3));
LeaveCriticalSection(&pDevice->Lock);
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC<ScsiReadWrite:%d\n"), dwErr));
return dwErr;
}
// EOF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -