📄 scsi2.c
字号:
Returns: If fail, Win32 error.
If pass, total number of bytes transferred.
Completion status returned in pSqReq->sr_status.
--*/
DWORD
ScsiRWSG(
PSCSI_DEVICE pDevice,
PSG_REQ pSgReq,
UCHAR Lun,
BOOL bRead
)
{
UINT uiExpectedBytesXferred = 0; // Expected total size of transfer (bytes).
UINT uiActualBytesXferred = 0; // Actual total size of transfer (bytes).
DWORD dwFlags = 0; // Flags indicating need for double buffering.
DWORD dwErr; // Error code.
DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC>ScsiRWSG\n")));
//
// Don't trust pSqReq.
//
dwErr = InspectSgReq(pSgReq, pDevice->DiskInfo.di_bytes_per_sect);
if (dwErr != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERR, (TEXT("USBMSC>ScsiRWSG: Invalid SG_REQ (%d)\r\n"), dwErr));
return dwErr;
}
dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL);
if (ERROR_SUCCESS != dwErr) {
DEBUGMSG(ZONE_ERR, (TEXT("USBMSC>ScsiRWSG: AcquireRemoveLock failed. Error: %d\n"), dwErr));
return dwErr;
}
EnterCriticalSection(&pDevice->Lock);
//
// Determine whether the Scatter/Gather buffers are sector aligned.
// If the buffers are not sector aligned, then double buffering is
// required.
// If the buffers are sector aligned, then dwFlags == 0.
// Otherwise, dwFlags != 0.
//
dwErr = CheckSegments(pDevice, pSgReq, (PDWORD) &uiExpectedBytesXferred, &dwFlags);
if (ERROR_SUCCESS == dwErr) {
HANDLE hProc = GetCallerProcess(); // Calling process.
LONGLONG llSectorsRemaining = pSgReq->sr_num_sec; // Total number of sectors to transfer.
UINT uiStartingSector = pSgReq->sr_start; // Starting sector.
UINT uiSectorsToXfer = 0; // Number of sectors to transfer in current sub-transfer.
UINT uiBytesXferred = 0; // Number of bytes to transfer in current sub-transfer.
UINT sg; // Index of current Scatter/Gather buffer.
if (dwFlags == 0) {
//
// Scatter/Gather buffers ARE sector aligned.
// Double buffering is NOT required.
// TRANSFER EACH SCATTER/GATHER BUFFER SEPARATELY.
//
for (sg = 0; (sg < pSgReq->sr_num_sg) && (llSectorsRemaining > 0) && (pSgReq->sr_sglist[sg].sb_buf != NULL) && (pSgReq->sr_sglist[sg].sb_len != 0); sg++) {
//
// Map the caller's buffer into our context, if necessary.
//
PVOID pBuffer = MapCallerPtr((LPVOID)pSgReq->sr_sglist[sg].sb_buf, pSgReq->sr_sglist[sg].sb_len);
if (pSgReq->sr_sglist[sg].sb_buf != NULL && pBuffer == NULL) {
DEBUGMSG(ZONE_ERR,(TEXT("USBMSC>ScsiRWSG: Security violation\r\n")));
return ERROR_ACCESS_DENIED;
}
ASSERT(pBuffer != NULL);
ASSERT((pSgReq->sr_sglist[sg].sb_len % pDevice->DiskInfo.di_bytes_per_sect) == 0);
//
// Calculate the number of contiguous sectors to transfer
// (from the current Scatter/Gather buffer).
// This is not redundant, as pSgReq->sr_num_sec gives the total
// number of sectors transferred through the Scatter/Gather
// request, and this calculation determines the number of
// contiguous sectors in the current Scatter/Gather buffer.
//
uiSectorsToXfer = min((pSgReq->sr_sglist[sg].sb_len / pDevice->DiskInfo.di_bytes_per_sect), (DWORD) llSectorsRemaining);
uiBytesXferred = pSgReq->sr_sglist[sg].sb_len;
ASSERT(uiSectorsToXfer != 0);
ASSERT(uiSectorsToXfer <= llSectorsRemaining);
DEBUGMSG(ZONE_READ, (TEXT("Scsi%sSG[%d] uiStartingSector: %d, uiSectorsToXfer: %d\n"), bRead ? TEXT("Read") : TEXT("Write"), sg, uiStartingSector, uiSectorsToXfer));
//
// Transfer the contiguous sectors in the current
// Scatter/Gather buffer.
// (Recall) Double buffer is not required, as all buffers are
// sector aligned.
//
dwErr = ScsiReadWrite(pDevice, uiStartingSector, uiSectorsToXfer, pBuffer, &uiBytesXferred, Lun, bRead);
if (ERROR_SUCCESS == dwErr) {
llSectorsRemaining -= uiSectorsToXfer;
ASSERT(llSectorsRemaining >= 0);
uiStartingSector += uiSectorsToXfer;
pBuffer = (PVOID) ((PUCHAR) pBuffer + uiBytesXferred);
uiActualBytesXferred += uiBytesXferred;
}
else {
LeaveCriticalSection(&pDevice->Lock);
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
DEBUGMSG(ZONE_ERR,(TEXT("USBMSC>ScsiRWSG: ScsiReadWrite failed. Error: %d\n"), dwErr));
return dwErr;
}
}
}
else {
//
// Scatter/Gather buffers are NOT sector aligned.
// Double buffering IS required.
//
UINT uiDbBuffOffset = 0; // Current position in double buffer.
UINT uiBytesInSgBuff = 0; // Number of bytes in current Scatter/Gather buffer.
PUCHAR pucSgBuffOffset = NULL; // Pointer to current position in double buffer.
memset(&pDevice->SgBuff[0], 0, SG_BUFF_SIZE);
DEBUGMSG(ZONE_TRACE, (TEXT("USBMSC>ScsiRWSG: SgReq (%s) buffers not sector aligned, double buffer\n"), bRead ? (TEXT("Read")) : (TEXT("Write"))));
//
// If reading, read from storage device to double buffer, and fill
// each Scatter/Gather buffer in order, re-filling the double
// buffer as necessary.
// If writing, fill double buffer from each Scatter/Gather buffer
// in order, flushing the double buffer to storage device as
// necessary.
//
for (sg = 0; sg < pSgReq->sr_num_sg; sg += 1) {
pucSgBuffOffset = MapCallerPtr((LPVOID)pSgReq->sr_sglist[sg].sb_buf, pSgReq->sr_sglist[sg].sb_len);
ASSERT(pucSgBuffOffset);
uiBytesInSgBuff = (bRead ? 0 : (UINT) pSgReq->sr_sglist[sg].sb_len);
while (bRead ? (uiBytesInSgBuff < pSgReq->sr_sglist[sg].sb_len) : (uiBytesInSgBuff > 0)) {
if (bRead) {
if (uiDbBuffOffset == uiBytesXferred) {
uiSectorsToXfer = ((llSectorsRemaining > (SG_BUFF_SIZE / pDevice->DiskInfo.di_bytes_per_sect)) ? (SG_BUFF_SIZE / pDevice->DiskInfo.di_bytes_per_sect) : (UINT) llSectorsRemaining);
uiBytesXferred = uiSectorsToXfer * pDevice->DiskInfo.di_bytes_per_sect;
goto __DbXfer;
__DbRead:
;
}
}
//
// If reading, copy a byte from the double buffer to the
// current Scatter/Gather buffer.
// If writing, copy a byte from the current Scatter/Gather
// buffer to the double buffer.
//
bRead ? (*pucSgBuffOffset = pDevice->SgBuff[uiDbBuffOffset]) : (pDevice->SgBuff[uiDbBuffOffset] = *pucSgBuffOffset);
bRead ? (uiBytesInSgBuff += 1) : (uiBytesInSgBuff -= 1);
uiDbBuffOffset += 1;
pucSgBuffOffset++;
uiActualBytesXferred += 1;
if ( ! bRead ) {
uiSectorsToXfer = ((llSectorsRemaining > (SG_BUFF_SIZE / pDevice->DiskInfo.di_bytes_per_sect)) ? (SG_BUFF_SIZE / pDevice->DiskInfo.di_bytes_per_sect) : (UINT) llSectorsRemaining);
uiBytesXferred = uiSectorsToXfer * pDevice->DiskInfo.di_bytes_per_sect;
if (uiDbBuffOffset == uiBytesXferred) {
goto __DbXfer;
__DbWrite:
;
}
}
goto __DbEnd;
__DbXfer:
//
// Fill/flush the double buffer from/to the storage device.
//
DEBUGMSG(ZONE_TRACE, (TEXT("USBMSC>ScsiRWSG: StartSec: %d, SecsToXfer: %d, BytesXfer'd: %d\n"), uiStartingSector, uiSectorsToXfer, uiBytesXferred));
dwErr = ScsiReadWrite(pDevice, uiStartingSector, uiSectorsToXfer, &pDevice->SgBuff[0], &uiBytesXferred, Lun, bRead);
if (dwErr != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERR, (TEXT("USBMSC>ScsiRWSG: ScsiReadWrite failed. Error: %d\n"), dwErr));
LeaveCriticalSection(&pDevice->Lock);
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
return dwErr;
}
uiDbBuffOffset = 0;
llSectorsRemaining -= uiSectorsToXfer;
uiStartingSector += uiSectorsToXfer;
if ((uiBytesXferred != (uiSectorsToXfer * pDevice->DiskInfo.di_bytes_per_sect))) {
LeaveCriticalSection(&pDevice->Lock);
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
return ERROR_DISK_OPERATION_FAILED;
}
if (bRead) goto __DbRead;
goto __DbWrite;
__DbEnd:
;
}
}
if ((llSectorsRemaining != 0) || (uiStartingSector != (pSgReq->sr_start + pSgReq->sr_num_sec))) {
LeaveCriticalSection(&pDevice->Lock);
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
return ERROR_DISK_OPERATION_FAILED;
}
if (( ! bRead ) && uiBytesInSgBuff != 0) {
LeaveCriticalSection(&pDevice->Lock);
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
return ERROR_DISK_OPERATION_FAILED;
}
}
} else {
DEBUGMSG(ZONE_ERR,(TEXT("USBMSC>ScsiRWSG: CheckSegments failed. Error: %d.\n"),dwErr));
}
if (uiExpectedBytesXferred != uiActualBytesXferred) {
LeaveCriticalSection(&pDevice->Lock);
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
return ERROR_DISK_OPERATION_FAILED;
}
pSgReq->sr_status = dwErr;
LeaveCriticalSection(&pDevice->Lock);
ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC<ScsiRWSG: ->sr_status: %d\n"), dwErr));
return uiActualBytesXferred;
}
/* ++
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: invalid 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;
tCommand.dwLun=Lun;
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 {
dwErr = UsbsDataTransfer( pDevice->hUsbTransport,
&tCommand,
&tData );
if ( ERROR_SUCCESS == dwErr ) {
*pdwTransferSize = tData.TransferLength;
} else {
// since we do retries we also have to (re)poke the device
dwErr = ScsiUnitAttention(pDevice, pDevice->Lun);
if (ERROR_SUCCESS != dwErr)
break;
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 + -