📄 diskmain.cpp
字号:
}
dwSize = (wcslen(szDiskName) + 1) * sizeof(TCHAR);
if (pIOReq->dwOutBufSize < dwSize) {
return ERROR_INSUFFICIENT_BUFFER;
}
wcscpy((PTCHAR) pIOReq->pOutBuf, szDiskName);
*(pIOReq->pBytesReturned) = dwSize;
return ERROR_SUCCESS;
}
// ----------------------------------------------------------------------------
// Function: ReadWriteDisk
// This function reads from/writes to an ATA device.
//
// Parameters:
// pIOReq -
// fRead -
//
// Notes:
// ----------------------------------------------------------------------------
DWORD CDisk::ReadWriteDisk(PIOREQ pIOReq, BOOL fRead)
{
DWORD dwError = ERROR_SUCCESS;
PBYTE pBuffer;
PSG_REQ pSgReq = (PSG_REQ)pIOReq->pInBuf;
DWORD dwStartSector, dwNumSectors, dwSectorsToTransfer, dwSectorsPerBlock, dwSgLeft, dwSgLen;
DWORD dwMaxPerBlock = m_bSectorsPerBlock > 1 ? m_bSectorsPerBlock >> 1 : m_bSectorsPerBlock;
PSG_BUF pSgBuf;
BYTE bCmd = fRead ? m_bReadCommand : m_bWriteCommand;
DEBUGMSG( ZONE_IOCTL, (TEXT("ATAPI:ReadWriteDisk Entered\r\n")));
if ((pSgReq == NULL) ||
(pIOReq->dwInBufSize < sizeof(SG_REQ))) {
return ERROR_INVALID_PARAMETER;
}
if ((pSgReq->sr_num_sec == 0) ||
(pSgReq->sr_num_sg == 0)) {
return ERROR_INVALID_PARAMETER;
}
GetBaseStatus(); // Clear Interrupt if it is already set
#ifdef SECTOR_CHECK_ENABLE
if ( ( pSgReq->sr_start + pSgReq->sr_num_sec) >= m_DiskInfo.di_total_sectors ) {
dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
return dwError;
}
#endif
dwSgLeft = pSgReq->sr_num_sg; // The number of SG segments
dwNumSectors = pSgReq->sr_num_sec;
dwStartSector = pSgReq->sr_start; // Get the Start Sector
pSgBuf = &(pSgReq->sr_sglist[0]);
pBuffer = (PBYTE)MapPtrToProcess((LPVOID)pSgBuf->sb_buf, GetCallerProcess());
m_wNextByte = 0xFFFF;
DEBUGMSG( ZONE_IO, (TEXT("ATAPI:ReadWriteDisk StartSector=%ld NumSectors=%ld NumSg=%ld\r\n"), dwStartSector, dwNumSectors, dwSgLeft));
while(dwNumSectors) {
if (dwNumSectors > dwMaxPerBlock)
dwSectorsToTransfer = dwMaxPerBlock;
else
dwSectorsToTransfer = dwNumSectors;
dwNumSectors -= dwSectorsToTransfer;
if (!SendIOCommand(dwStartSector,dwSectorsToTransfer, bCmd)) {
dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
break;
}
dwStartSector += dwSectorsToTransfer;
// The read command expects an interrupt before data transfer.
// The write command, on the other side, expects an interrupt after
dwSectorsPerBlock = dwMaxPerBlock;
while(dwSectorsToTransfer && (dwSgLeft > 0)) {
if (dwSectorsPerBlock > dwSectorsToTransfer)
dwSectorsPerBlock = dwSectorsToTransfer;
dwSectorsToTransfer -= dwSectorsPerBlock;
if (fRead && m_fInterruptSupported) {
if (!WaitForInterrupt(m_dwDiskIoTimeOut) || (CheckIntrState() == ATA_INTR_ERROR)) {
DEBUGMSG( ZONE_IO, (TEXT("ATAPI:ReadWrite- WaitforInterrupt failed (DevId %x) \r\n"),m_dwDeviceId));
dwError = ERROR_READ_FAULT;
break;
}
}
if (!WaitForDRQ()) {
DEBUGMSG( ZONE_IO, (TEXT("ATAPI:ReadWrite- WaitforDRQ failed (DevId %x) \r\n"),m_dwDeviceId));
dwError = ERROR_READ_FAULT;
break;
}
DWORD dwBytesPerBlock = dwSectorsPerBlock * m_DiskInfo.di_bytes_per_sect;
dwSgLen = pSgBuf->sb_len;
while ((dwBytesPerBlock>0) && (dwSgLeft >0))
{
DWORD dwIndex = (dwSgLen < dwBytesPerBlock) ? dwSgLen : dwBytesPerBlock;
dwSgLen -= dwIndex;
dwBytesPerBlock -= dwIndex;
fRead ? ReadBuffer(pBuffer,dwIndex) : WriteBuffer(pBuffer,dwIndex);
pBuffer += dwIndex; //
// Go to the next scatter/gather if no more space left
if ((dwSgLen == 0) && ( --dwSgLeft > 0)) {
pSgBuf++;
pBuffer = (PBYTE)MapPtrToProcess((LPVOID)pSgBuf->sb_buf, GetCallerProcess());
dwSgLen = pSgBuf->sb_len;
}
}
if (fRead) {
while (dwBytesPerBlock > 0) {
(void) ReadWord();
dwBytesPerBlock-=2 ;
}
}
}
if (ERROR_SUCCESS != dwError)
break;
// In case of write command an interrupt is generated upon each block.
// We can either wait for the interrupt or simply ignore it.
// However this is danger because an interrupt is pending and blocks all
// other interrupts on the same or lower level.
if ( !fRead && m_fInterruptSupported) {
if (!WaitForInterrupt(m_dwDiskIoTimeOut) || (CheckIntrState() == ATA_INTR_ERROR)) {
DEBUGMSG( ZONE_IO, (TEXT("ATAPI:ReadWrite- WaitforInterrupt failed (DevId %x) \r\n"),m_dwDeviceId));
dwError = ERROR_READ_FAULT;
break;
}
}
}
if (ERROR_SUCCESS != dwError) {
ResetController();
if (!(m_Id.Capabilities & 0x0200) && m_fLBAMode) {
m_fLBAMode = FALSE;
dwError = ReadWriteDisk(pIOReq, fRead);
} else {
}
}
pSgReq->sr_status = dwError;
return dwError;
}
// ----------------------------------------------------------------------------
// Function: ReadWriteDiskDMA
// This function reads from/writes to an ATA device
//
// Parameters:
// pIOReq -
// fRead -
// ----------------------------------------------------------------------------
DWORD
CDisk::ReadWriteDiskDMA(
PIOREQ pIOReq,
BOOL fRead
)
{
DWORD dwError = ERROR_SUCCESS;
PSG_REQ pSgReq = (PSG_REQ)pIOReq->pInBuf;
DWORD dwSectorsToTransfer;
SG_BUF CurBuffer[MAX_SG_BUF];
BYTE bCmd;
SG_BUF SgBufTemp;
if ((pSgReq == NULL) || (pIOReq->dwInBufSize < sizeof(SG_REQ))) {
return ERROR_INVALID_PARAMETER;
}
if ((pSgReq->sr_num_sec == 0) || (pSgReq->sr_num_sg == 0)) {
return ERROR_INVALID_PARAMETER;
}
if ((pSgReq->sr_start + pSgReq->sr_num_sec) > m_DiskInfo.di_total_sectors) {
return ERROR_SECTOR_NOT_FOUND;
}
DEBUGMSG(ZONE_IO, (_T(
"Atapi!ReadWriteDiskDMA> sr_start(%ld), sr_num_sec(%ld), sr_num_sg(%ld)\r\n"
), pSgReq->sr_start, pSgReq->sr_num_sec, pSgReq->sr_num_sg));
GetBaseStatus(); // clear pending interrupt
DWORD dwStartBufferNum = 0, dwEndBufferNum = 0, dwEndBufferOffset = 0;
DWORD dwNumSectors = pSgReq->sr_num_sec;
DWORD dwStartSector = pSgReq->sr_start;
DWORD dwSectorsToTransferMax = (ATAPI_BUFFER_SIZE / BYTES_PER_SECTOR) > MAX_SECT_PER_COMMAND ? MAX_SECT_PER_COMMAND : (ATAPI_BUFFER_SIZE / BYTES_PER_SECTOR);
// process scatter/gather buffers in groups of MAX_SEC_PER_COMMAND sectors
// each DMA request handles a new SG_BUF array which is a subset of the
// original request, and may start/stop in the middle of the original buffer
while (dwNumSectors) {
// determine number of sectors to transfer
dwSectorsToTransfer = (dwNumSectors > dwSectorsToTransferMax) ? dwSectorsToTransferMax : dwNumSectors;
// determine size (in bytes) of transfer
DWORD dwBufferLeft = dwSectorsToTransfer * BYTES_PER_SECTOR;
DWORD dwNumSg = 0;
// while the transfer is not complete
while (dwBufferLeft) {
// determine the size of the current scatter/gather buffer
DWORD dwCurBufferLen = pSgReq->sr_sglist[dwEndBufferNum].sb_len - dwEndBufferOffset;
if (dwBufferLeft < dwCurBufferLen) {
CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_buf = pSgReq->sr_sglist[dwEndBufferNum].sb_buf + dwEndBufferOffset;
CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_len = dwBufferLeft;
dwEndBufferOffset += dwBufferLeft;
dwBufferLeft = 0;
}
else {
CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_buf = pSgReq->sr_sglist[dwEndBufferNum].sb_buf + dwEndBufferOffset;
CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_len = dwCurBufferLen;
dwEndBufferOffset = 0;
dwEndBufferNum++;
dwBufferLeft -= dwCurBufferLen;
}
dwNumSg++;
}
bCmd = fRead ? ATA_CMD_READ_DMA : ATA_CMD_WRITE_DMA;
WaitForInterrupt(0);
SgBufTemp.sb_len = dwSectorsToTransfer * BYTES_PER_SECTOR;
SgBufTemp.sb_buf = CurBuffer[0].sb_buf;
// setup the DMA transfer
if (!SetupDMA( &SgBufTemp, 1, fRead)) {
dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
goto ExitFailure;
}
// write the read/write command
if (!SendIOCommand(dwStartSector, dwSectorsToTransfer, bCmd)) {
dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
AbortDMA();
goto ExitFailure;
}
// start the DMA transfer
if (BeginDMA(fRead)) {
if (m_fInterruptSupported) {
if (!WaitForInterrupt(m_dwDiskIoTimeOut) || (CheckIntrState() == ATA_INTR_ERROR)) {
DEBUGMSG(ZONE_IO || ZONE_WARNING, (_T(
"Atapi!CDisk::ReadWriteDiskDMA> Failed to wait for interrupt; device(%d)\r\n"
), m_dwDeviceId));
dwError = ERROR_READ_FAULT;
AbortDMA();
goto ExitFailure;
}
}
// stop the DMA transfer
if (EndDMA()) {
WaitOnBusy(FALSE);
CompleteDMA(CurBuffer, dwNumSg, fRead);
}
/*
else{
dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
AbortDMA();
goto ExitFailure;
}
*/
}
// update transfer
dwStartSector += dwSectorsToTransfer;
dwStartBufferNum = dwEndBufferNum;
dwNumSectors -= dwSectorsToTransfer;
}
ExitFailure:
if (ERROR_SUCCESS != dwError) {
ResetController();
}
pSgReq->sr_status = dwError;
return dwError;
}
// ----------------------------------------------------------------------------
// Function: GetStorageId
// Implement IOCTL_DISK_GET_STORAGEID
//
// Parameters:
// pIOReq -
// ----------------------------------------------------------------------------
DWORD
CDisk::GetStorageId(
PIOREQ pIOReq
)
{
DWORD dwBytesLeft;
PBYTE pDstOffset;
PSTORAGE_IDENTIFICATION pStorageId = (PSTORAGE_IDENTIFICATION)pIOReq->pOutBuf;
// validate arguments
if (!pStorageId || (pIOReq->dwOutBufSize < sizeof(STORAGE_IDENTIFICATION)) || !pIOReq->pBytesReturned) {
return ERROR_INVALID_PARAMETER;
}
// prepare return structure
pStorageId->dwSize = sizeof(STORAGE_IDENTIFICATION);
pStorageId->dwFlags = 0; // {MANUFACTUREID,SERIALNUM}_INVALID
// prepare return structure indicies, for write
dwBytesLeft = pIOReq->dwOutBufSize - sizeof(STORAGE_IDENTIFICATION);
pDstOffset = (PBYTE)(pStorageId + 1);
pStorageId->dwManufactureIDOffset = pDstOffset - (PBYTE)pStorageId;
SetLastError(ERROR_SUCCESS);
// fetch manufacturer ID
if (!ATAParseIdString((PBYTE)m_Id.ModelNumber, sizeof(m_Id.ModelNumber), &(pStorageId->dwManufactureIDOffset), &pDstOffset, &dwBytesLeft)) {
pStorageId->dwFlags |= MANUFACTUREID_INVALID;
}
pStorageId->dwSerialNumOffset = pDstOffset - (PBYTE)pStorageId;
// fetch serial number
if (!ATAParseIdString((PBYTE)m_Id.SerialNumber, sizeof(m_Id.SerialNumber), &(pStorageId->dwSerialNumOffset), &pDstOffset, &dwBytesLeft)) {
pStorageId->dwFlags |= SERIALNUM_INVALID;
}
pStorageId->dwSize = pDstOffset - (PBYTE)pStorageId;
// store bytes written
*(pIOReq->pBytesReturned)= min(pStorageId->dwSize, pIOReq->dwOutBufSize);
return GetLastError();
}
// ----------------------------------------------------------------------------
// Function: SetWriteCacheMode
// Issue SET FEATURES enable write cache command
//
// Parameters:
// fEnable -
// ----------------------------------------------------------------------------
BOOL
CDisk::SetWriteCacheMode(
BOOL fEnable
)
{
BYTE bError, bStatus;
// select device
SelectDevice();
// wait for device to acknowledge selection
WaitForDisc(WAIT_TYPE_NOT_BUSY, 100);
WaitForDisc(WAIT_TYPE_READY, 1000);
WaitOnBusy(TRUE);
// write command
SelectDevice();
WriteFeature(fEnable ? ATA_ENABLE_WRITECACHE : ATA_DISABLE_WRITECACHE);
WriteCommand(ATAPI_CMD_SET_FEATURES);
// wait for device to respond to command
SelectDevice();
WaitOnBusy(TRUE);
SelectDevice();
WaitForDisc(WAIT_TYPE_NOT_BUSY, 200);
// check response
bStatus = GetBaseStatus();
bError = GetError();
if ((bStatus & ATA_STATUS_ERROR) && (bError & ATA_ERROR_ABORTED)) {
DEBUGMSG(ZONE_ERROR, (_T(
"Atapi!CDisk::SetWriteCacheMode> Failed to enable write cache; status(%02X), error(%02X)\r\n"
), bStatus, bEr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -