📄 diskmain.cpp
字号:
ZONE_DMA,
(
TEXT("ATAPI:ReadWriteDiskDMA StartSector=%ld NumSectors=%ld NumSg=%ld\r\n"),
pSgReq->sr_start,
pSgReq->sr_num_sec,
pSgReq->sr_num_sg
)
);
GetBaseStatus(); // Clear Interrupt if it is already set
DWORD dwStartBufferNum = 0, dwEndBufferNum = 0, dwEndBufferOffset = 0;
DWORD dwNumSectors = pSgReq->sr_num_sec;
DWORD dwStartSector = pSgReq->sr_start;
// Process the SG buffers in blocks of MAX_SECT_PER_COMMAND. Each DMA request will have a new SG_BUF array
// which will be a subset of the original request, and may start/stop in the middle of the original buffer.
while (dwNumSectors)
{
//dwSectorsToTransfer = (dwNumSectors > MAX_SECT_PER_COMMAND) ? MAX_SECT_PER_COMMAND : dwNumSectors;
dwSectorsToTransfer = (dwNumSectors > MAX_DMA_SECT_PER_COMMAND) ?
MAX_DMA_SECT_PER_COMMAND : dwNumSectors;
DWORD dwBufferLeft = dwSectorsToTransfer * BYTES_PER_SECTOR;
DWORD dwNumSg = 0;
while (dwBufferLeft)
{
DWORD dwCurBufferLen = pSgReq->sr_sglist[dwEndBufferNum].sb_len - dwEndBufferOffset;
if (dwBufferLeft < dwCurBufferLen)
{
// The buffer left for this block is less than the current SG buffer length
CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_buf = pSgReq->sr_sglist[dwEndBufferNum].sb_buf + dwEndBufferOffset;
CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_len = dwBufferLeft;
dwEndBufferOffset += dwBufferLeft;
dwBufferLeft = 0;
}
else
{
// The buffer left for this block is greater than or equal to the current SG buffer length. Move on to the next SG buffer.
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;
for(;;)
{
if( !SetupDMA(CurBuffer, dwNumSg, fRead))
{
dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
break;
}
if( !SendIOCommand(dwStartSector, dwSectorsToTransfer, bCmd))
{
dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
AbortDMA();
//
// Segate drives get stuck in the busy after a incomplete
// transfer. Reset the drive and try in PIO mode.
//
// Seagate drives also do not respond to the device reset
// command when busy. Need to reset both devices.
//
HardResetAndForcePIOMode();
bRetryUsingPIO = TRUE;
break;
}
bRet = WaitOnDMARQ(DISK_IO_TIME_OUT * 1000);
if(!bRet)
{
DEBUGMSG
(
ZONE_ERROR,
(
L"WaitOnDMARQ Failed\r\n"
)
);
dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
AbortDMA();
break;
}
//
// Begin DMA always returns true
//
BeginDMA(fRead);
ulWaitReturn = WaitForDmaInterrupt(DISK_IO_TIME_OUT);
//
// Dma Completed Successfully
//
if(ulWaitReturn == DMAWAIT_NOERROR )
{
EndDMA();
WaitOnBusy(FALSE);
//Fix for CETK Storage_API #4010 failed in UDMA mode.
CompleteDMA( CurBuffer, dwNumSg, fRead);
break;
}
//
// Hit EP931x hardware DMA bug.
//
else if(ulWaitReturn == DMAWAIT_ERROR_WRITE_1 )
{
DEBUGMSG
(
ZONE_ERROR,
(
TEXT("ATAPI:ReadWriteDMA Failed Retrying\r\n")
)
);
AbortDMA();
m_fWriteBug1Failure = TRUE;
bRetryUsingPIO = TRUE;
dwError = ERROR_WRITE_FAULT;
break;
}
else if (ulWaitReturn == DMAWAIT_ERROR_WRITE_2)
{
DEBUGMSG
(
ZONE_ERROR,
(
TEXT("ATAPI:ReadWriteDMA Failed, Switching to PIO\r\n")
)
);
AbortDMA();
m_fWriteBug2Failure = TRUE;
bRetryUsingPIO = TRUE;
dwError = ERROR_WRITE_FAULT;
break;
}
else if (ulWaitReturn == DMAWAIT_ERROR_READ_1)
{
DEBUGMSG
(
ZONE_ERROR,
(
TEXT("ATAPI:ReadWriteDMA Failed, Switching to PIO\r\n")
)
);
AbortDMA();
m_fReadBug1Failure = TRUE;
bRetryUsingPIO = TRUE;
dwError = ERROR_READ_FAULT ;
break;
}
//
// Other Error.
//
else
{
DEBUGMSG
(
ZONE_ERROR,
(
TEXT("ATAPI:ReadWriteDma Failed Not Retrying \r\n")
)
);
bRetryUsingPIO = TRUE;
AbortDMA();
dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
break;
}
} //end for
if(dwError != ERROR_SUCCESS)
{
break;
}
dwStartSector += dwSectorsToTransfer;
dwStartBufferNum = dwEndBufferNum;
dwNumSectors -= dwSectorsToTransfer;
} //end while
if (ERROR_SUCCESS != dwError)
{
//
// Reset the controller and try in PIO mode.
//
//
// Reset the device and issue commands to set up the dma mode
// again.
//
// AtapiSoftReset();
// WaitForInterrupt(50);
// SetBestTransferMode();
if(bRetryUsingPIO)
{
dwError = ReadWriteDisk(pIOReq, fRead);
DEBUGMSG( ZONE_WARNING, (TEXT("CDisk::ReadWriteDiskDMA using PIO for the transfer.\r\n")));
}
}
pSgReq->sr_status = dwError;
DEBUGMSG( ZONE_DMA, (TEXT("-CDisk::ReadWriteDiskDMA\r\n")));
return dwError;
}
/*------------------------------------------------------------------------------------------*/
DWORD CDisk::GetStorageId(PIOREQ pIOReq)
{
DWORD dwError = ERROR_SUCCESS;
DWORD dwBytesLeft;
PBYTE pDstOffset;
PSTORAGE_IDENTIFICATION pStorageId = (PSTORAGE_IDENTIFICATION)pIOReq->pOutBuf;
if (!pStorageId || (pIOReq->dwOutBufSize < sizeof(STORAGE_IDENTIFICATION)) || !pIOReq->pBytesReturned)
return ERROR_INVALID_PARAMETER;
pStorageId->dwSize = sizeof(STORAGE_IDENTIFICATION);
pStorageId->dwFlags = 0; // can be or of {MANUFACTUREID,SERIALNUM}_INVALID
dwBytesLeft = pIOReq->dwOutBufSize - sizeof(STORAGE_IDENTIFICATION);
pDstOffset = (PBYTE)(pStorageId + 1);
pStorageId->dwManufactureIDOffset = pDstOffset - (PBYTE)pStorageId;
SetLastError(ERROR_SUCCESS); // TODO: Once ATAParseIdString is changed we can modify this
if (!ATAParseIdString((PBYTE)m_Id.ModelNumber, sizeof(m_Id.ModelNumber), &(pStorageId->dwManufactureIDOffset), &pDstOffset, &dwBytesLeft))
pStorageId->dwFlags |= MANUFACTUREID_INVALID;
pStorageId->dwSerialNumOffset = pDstOffset - (PBYTE)pStorageId;
if (!ATAParseIdString((PBYTE)m_Id.SerialNumber, sizeof(m_Id.SerialNumber), &(pStorageId->dwSerialNumOffset), &pDstOffset, &dwBytesLeft))
pStorageId->dwFlags |= SERIALNUM_INVALID;
pStorageId->dwSize = pDstOffset - (PBYTE)pStorageId; // required size
*(pIOReq->pBytesReturned)= min(pStorageId->dwSize, pIOReq->dwOutBufSize); // bytes written
// ATAParseIdString sets the error value
dwError = GetLastError();
return dwError;
}
//****************************************************************************
// GetDriveIdentifyData
//****************************************************************************
// Allows test programs to get the drive information data.
//
//
DWORD CDisk::GetDriveIdentifyData(IDENTIFY_DATA *pId)
{
memcpy((void *)pId, (void *) &m_Id, sizeof(IDENTIFY_DATA));
return ERROR_SUCCESS;
}
#define NUM_SECTORS 1
unsigned short usReadBuffer[NUM_SECTORS*(BYTES_PER_SECTOR>>1)];
unsigned short usWriteBuffer[NUM_SECTORS*(BYTES_PER_SECTOR>>1)];
//****************************************************************************
// TestDisk
//****************************************************************************
// Routine to test the disk read and write routines.
//
//
DWORD CDisk::TestDisk(void)
{
IOREQ sIOReqWrite,sIOReqRead;
SG_REQ sSgReqWrite,sSgReqRead;
int i;
DWORD dwError;
sIOReqWrite.pInBuf = (PUCHAR)&sSgReqWrite;
sIOReqRead.pInBuf = (PUCHAR)&sSgReqRead;
//
// Required to make the ReadWriteDiskDma Call.
//
sIOReqWrite.dwInBufSize = sizeof(SG_REQ);
sIOReqRead.dwInBufSize = sizeof(SG_REQ);
for(i = 0; i<(NUM_SECTORS * (BYTES_PER_SECTOR>>1)) ; i++)
{
usWriteBuffer[i] = (i<<16) | i ;
}
//
// Write the boot sector with a pattern.
//
sSgReqWrite.sr_start = 1;
sSgReqWrite.sr_num_sec = NUM_SECTORS;
sSgReqWrite.sr_num_sg = 1;
sSgReqWrite.sr_sglist[0].sb_len = BYTES_PER_SECTOR * NUM_SECTORS;
sSgReqWrite.sr_sglist[0].sb_buf = (PUCHAR)&usWriteBuffer;
dwError = ReadWriteDiskDMA(&sIOReqWrite, FALSE);
if(dwError != ERROR_SUCCESS)
{
DEBUGMSG
(
ZONE_DMA,
(
TEXT("ATAPI:TestDisk Write Failed.\r\n")
)
);
return dwError;
}
//
// Read back the pattern.
//
sSgReqRead.sr_start = 1;
sSgReqRead.sr_num_sec = NUM_SECTORS;
sSgReqRead.sr_num_sg = 1;
sSgReqRead.sr_sglist[0].sb_len = BYTES_PER_SECTOR * NUM_SECTORS;
sSgReqRead.sr_sglist[0].sb_buf = (PUCHAR)&usReadBuffer;
dwError = ReadWriteDiskDMA(&sIOReqRead, TRUE);
if(dwError != ERROR_SUCCESS)
{
DEBUGMSG
(
ZONE_DMA,
(
TEXT("ATAPI:TestDisk Read Failed.\r\n")
)
);
return dwError;
}
//
// Print out the debug information.
//
for(i = 0 ; i < (NUM_SECTORS * (BYTES_PER_SECTOR>>1)); i+=8)
{
NKDbgPrintfW
(
L"0x%04x 0x%04x 0x%04x 0x%04x "
L"0x%04x 0x%04x 0x%04x 0x%04x\r\n"
,
usReadBuffer[i + 0], usReadBuffer[i + 1],
usReadBuffer[i + 2], usReadBuffer[i + 3],
usReadBuffer[i + 4], usReadBuffer[i + 5],
usReadBuffer[i + 6], usReadBuffer[i + 7]
);
}
return dwError;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -