/drivers/storage/ide/uniata/id_ata.cpp
C++ | 9575 lines | 6997 code | 1343 blank | 1235 comment | 1413 complexity | a9c6a1e31e8b6930e2482b6edb54b0e8 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-3.0, CC-BY-SA-3.0, AGPL-3.0, GPL-3.0, CPL-1.0
Large files files are truncated, but you can click here to view the full file
- /*++
- Copyright (c) 2002-2011 Alexandr A. Telyatnikov (Alter)
- Module Name:
- id_ata.cpp
- Abstract:
- This is the miniport driver for ATA/ATAPI IDE controllers
- with Busmaster DMA and Serial ATA support
- Author:
- Alexander A. Telyatnikov (Alter)
- Environment:
- kernel mode only
- Notes:
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Revision History:
- The skeleton was taken from standard ATAPI.SYS from NT4 DDK by
- Mike Glass (MGlass)
- Chuck Park (ChuckP)
- Some parts of code were taken from FreeBSD 4.3-6.1 ATA driver by
- S?ren Schmidt, Copyright (c) 1998-2007
- All parts of code are greatly changed/updated by
- Alter, Copyright (c) 2002-2007:
- 1. Internal command queueing/reordering
- 2. Drive identification
- 3. Support for 2 _independent_ channels in a single PCI device
- 4. Smart host<->drive transfer rate slowdown (for bad cable)
- 5. W2k support (binary compatibility)
- 6. HDD hot swap under NT4
- 7. XP support (binary compatibility)
- 8. Serial ATA (SATA/SATA2) support
- 9. NT 3.51 support (binary compatibility)
- etc. (See todo.txt)
- --*/
- #include "stdafx.h"
- #ifndef UNIATA_CORE
- static const CHAR ver_string[] = "\n\nATAPI IDE MiniPort Driver (UniATA) v 0." UNIATA_VER_STR "\n";
- static const CHAR uniata_comm_name[] = UNIATA_COMM_PORT_VENDOR_STR " \n";
- UNICODE_STRING SavedRegPath;
- WCHAR SavedRegPathBuffer[256];
- #endif //UNIATA_CORE
- UCHAR AtaCommands48[256];
- UCHAR AtaCommandFlags[256];
- ULONG SkipRaids = 1;
- ULONG ForceSimplex = 0;
- LONGLONG g_Perf = 0;
- ULONG g_PerfDt = 0;
- #ifdef _DEBUG
- ULONG g_LogToDisplay = 0;
- #endif //_DEBUG
- ULONG g_WaitBusyInISR = 1;
- ULONG g_opt_WaitBusyCount = 200; // 20000
- ULONG g_opt_WaitBusyDelay = 10; // 150
- ULONG g_opt_WaitDrqDelay = 10; // 100
- BOOLEAN g_opt_AtapiSendDisableIntr = 1; // 0
- BOOLEAN g_opt_AtapiDmaRawRead = 1; // 0
- ULONG g_opt_VirtualMachine = 0; // Auto
- BOOLEAN InDriverEntry = TRUE;
- BOOLEAN g_opt_Verbose = 0;
- BOOLEAN WinVer_WDM_Model = FALSE;
- //UCHAR EnableDma = FALSE;
- //UCHAR EnableReorder = FALSE;
- UCHAR g_foo = 0;
- BOOLEAN
- NTAPI
- AtapiResetController__(
- IN PVOID HwDeviceExtension,
- IN ULONG PathId,
- IN UCHAR CompleteType
- );
- VOID
- NTAPI
- AtapiHwInitialize__(
- IN PHW_DEVICE_EXTENSION deviceExtension,
- IN ULONG lChannel
- );
- #define RESET_COMPLETE_CURRENT 0x00
- #define RESET_COMPLETE_ALL 0x01
- #define RESET_COMPLETE_NONE 0x02
- #ifndef UNIATA_CORE
- VOID
- NTAPI
- AtapiCallBack_X(
- IN PVOID HwDeviceExtension
- );
- #ifdef UNIATA_USE_XXableInterrupts
- #define RETTYPE_XXableInterrupts BOOLEAN
- #define RETVAL_XXableInterrupts TRUE
- #else
- #define RETTYPE_XXableInterrupts VOID
- #define RETVAL_XXableInterrupts
- #endif
- RETTYPE_XXableInterrupts
- NTAPI
- AtapiInterruptDpc(
- IN PVOID HwDeviceExtension
- );
- RETTYPE_XXableInterrupts
- NTAPI
- AtapiEnableInterrupts__(
- IN PVOID HwDeviceExtension
- );
- VOID
- NTAPI
- AtapiQueueTimerDpc(
- IN PVOID HwDeviceExtension,
- IN ULONG lChannel,
- IN PHW_TIMER HwScsiTimer,
- IN ULONG MiniportTimerValue
- );
- SCSI_ADAPTER_CONTROL_STATUS
- NTAPI
- AtapiAdapterControl(
- IN PVOID HwDeviceExtension,
- IN SCSI_ADAPTER_CONTROL_TYPE ControlType,
- IN PVOID Parameters
- );
- #endif //UNIATA_CORE
- #ifndef UNIATA_CORE
- BOOLEAN
- NTAPI
- AtapiRegGetStringParameterValue(
- IN PWSTR RegistryPath,
- IN PWSTR Name,
- IN PWCHAR Str,
- IN ULONG MaxLen
- )
- {
- #define ITEMS_TO_QUERY 2 // always 1 greater than what is searched
- NTSTATUS status;
- RTL_QUERY_REGISTRY_TABLE parameters[ITEMS_TO_QUERY];
- UNICODE_STRING ustr;
- ustr.Buffer = Str;
- ustr.Length =
- ustr.MaximumLength = (USHORT)MaxLen;
- RtlZeroMemory(parameters, (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
- parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
- parameters[0].Name = Name;
- parameters[0].EntryContext = &ustr;
- parameters[0].DefaultType = REG_SZ;
- parameters[0].DefaultData = Str;
- parameters[0].DefaultLength = MaxLen;
- status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/,
- RegistryPath, parameters, NULL, NULL);
- if(!NT_SUCCESS(status))
- return FALSE;
- return TRUE;
- #undef ITEMS_TO_QUERY
- } // end AtapiRegGetStringParameterValue()
- #endif //UNIATA_CORE
- VOID
- DDKFASTAPI
- UniataNanoSleep(
- ULONG nano
- )
- {
- LONGLONG t;
- LARGE_INTEGER t0;
- #ifdef NAVO_TEST
- return;
- #endif //NAVO_TEST
- if(!nano || !g_Perf || !g_PerfDt)
- return;
- t = (g_Perf * nano) / g_PerfDt / 1000;
- if(!t) {
- t = 1;
- }
- do {
- KeQuerySystemTime(&t0);
- t--;
- } while(t);
- } // end UniataNanoSleep()
- #define AtapiWritePortN_template(_type, _Type, sz) \
- VOID \
- DDKFASTAPI \
- AtapiWritePort##sz( \
- IN PHW_CHANNEL chan, \
- IN ULONGIO_PTR _port, \
- IN _type data \
- ) \
- { \
- PIORES res; \
- if(_port >= IDX_MAX_REG) { \
- res = (PIORES)(_port); \
- } else \
- if(chan) { \
- res = &chan->RegTranslation[_port]; \
- } else { \
- KdPrint(("invalid io write request @ ch %x, res* %x\n", chan, _port)); \
- return; \
- } \
- if(res->Proc) { \
- } else \
- if(!res->MemIo) { \
- ScsiPortWritePort##_Type((_type*)(res->Addr), data); \
- } else { \
- /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
- ScsiPortWriteRegister##_Type((_type*)(res->Addr), data); \
- } \
- return; \
- }
- AtapiWritePortN_template(ULONG, Ulong, 4);
- AtapiWritePortN_template(USHORT, Ushort, 2);
- AtapiWritePortN_template(UCHAR, Uchar, 1);
- #define AtapiWritePortExN_template(_type, _Type, sz) \
- VOID \
- DDKFASTAPI \
- AtapiWritePortEx##sz( \
- IN PHW_CHANNEL chan, \
- IN ULONGIO_PTR _port, \
- IN ULONG offs, \
- IN _type data \
- ) \
- { \
- PIORES res; \
- if(_port >= IDX_MAX_REG) { \
- res = (PIORES)(_port); \
- } else \
- if(chan) { \
- res = &chan->RegTranslation[_port]; \
- } else { \
- KdPrint(("invalid io write request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
- return; \
- } \
- if(res->Proc) { \
- } else \
- if(!res->MemIo) { \
- ScsiPortWritePort##_Type((_type*)(res->Addr+offs), data); \
- } else { \
- /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
- ScsiPortWriteRegister##_Type((_type*)(res->Addr+offs), data); \
- } \
- return; \
- }
- AtapiWritePortExN_template(ULONG, Ulong, 4);
- //AtapiWritePortExN_template(USHORT, Ushort, 2);
- AtapiWritePortExN_template(UCHAR, Uchar, 1);
- #define AtapiReadPortN_template(_type, _Type, sz) \
- _type \
- DDKFASTAPI \
- AtapiReadPort##sz( \
- IN PHW_CHANNEL chan, \
- IN ULONGIO_PTR _port \
- ) \
- { \
- PIORES res; \
- if(_port >= IDX_MAX_REG) { \
- res = (PIORES)(_port); \
- } else \
- if(chan) { \
- res = &chan->RegTranslation[_port]; \
- } else { \
- KdPrint(("invalid io read request @ ch %x, res* %x\n", chan, _port)); \
- return (_type)(-1); \
- } \
- if(res->Proc) { \
- return 0; \
- } else \
- if(!res->MemIo) { \
- /*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
- return ScsiPortReadPort##_Type((_type*)(res->Addr)); \
- } else { \
- /*KdPrint(("r_mem @ (%x) %x\n", _port, res->Addr));*/ \
- return ScsiPortReadRegister##_Type((_type*)(res->Addr)); \
- } \
- }
- AtapiReadPortN_template(ULONG, Ulong, 4);
- AtapiReadPortN_template(USHORT, Ushort, 2);
- AtapiReadPortN_template(UCHAR, Uchar, 1);
- #define AtapiReadPortExN_template(_type, _Type, sz) \
- _type \
- DDKFASTAPI \
- AtapiReadPortEx##sz( \
- IN PHW_CHANNEL chan, \
- IN ULONGIO_PTR _port, \
- IN ULONG offs \
- ) \
- { \
- PIORES res; \
- if(_port >= IDX_MAX_REG) { \
- res = (PIORES)(_port); \
- } else \
- if(chan) { \
- res = &chan->RegTranslation[_port]; \
- } else { \
- KdPrint(("invalid io read request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
- return (_type)(-1); \
- } \
- if(res->Proc) { \
- return 0; \
- } else \
- if(!res->MemIo) { \
- return ScsiPortReadPort##_Type((_type*)(res->Addr+offs)); \
- } else { \
- /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
- return ScsiPortReadRegister##_Type((_type*)(res->Addr+offs)); \
- } \
- }
- AtapiReadPortExN_template(ULONG, Ulong, 4);
- //AtapiReadPortExN_template(USHORT, Ushort, 2);
- AtapiReadPortExN_template(UCHAR, Uchar, 1);
- #define AtapiReadPortBufferN_template(_type, _Type, sz) \
- VOID \
- DDKFASTAPI \
- AtapiReadBuffer##sz( \
- IN PHW_CHANNEL chan, \
- IN ULONGIO_PTR _port, \
- IN PVOID Buffer, \
- IN ULONG Count, \
- IN ULONG Timing \
- ) \
- { \
- PIORES res; \
- \
- if(Timing) { \
- while(Count) { \
- (*((_type*)Buffer)) = AtapiReadPort##sz(chan, _port); \
- Count--; \
- Buffer = ((_type*)Buffer)+1; \
- UniataNanoSleep(Timing); \
- } \
- return; \
- } \
- \
- if(_port >= IDX_MAX_REG) { \
- res = (PIORES)(_port); \
- } else \
- if(chan) { \
- res = &chan->RegTranslation[_port]; \
- } else { \
- KdPrint(("invalid io read request @ ch %x, res* %x\n", chan, _port)); \
- return; \
- } \
- if(!res->MemIo) { \
- /*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
- ScsiPortReadPortBuffer##_Type((_type*)(res->Addr), (_type*)Buffer, Count); \
- return; \
- } \
- while(Count) { \
- (*((_type*)Buffer)) = ScsiPortReadRegister##_Type((_type*)(res->Addr)); \
- Count--; \
- Buffer = ((_type*)Buffer)+1; \
- } \
- return; \
- }
- #define AtapiWritePortBufferN_template(_type, _Type, sz) \
- VOID \
- DDKFASTAPI \
- AtapiWriteBuffer##sz( \
- IN PHW_CHANNEL chan, \
- IN ULONGIO_PTR _port, \
- IN PVOID Buffer, \
- IN ULONG Count, \
- IN ULONG Timing \
- ) \
- { \
- PIORES res; \
- \
- if(Timing) { \
- while(Count) { \
- AtapiWritePort##sz(chan, _port, *((_type*)Buffer)); \
- Buffer = ((_type*)Buffer)+1; \
- Count--; \
- UniataNanoSleep(Timing); \
- } \
- return; \
- } \
- \
- if(_port >= IDX_MAX_REG) { \
- res = (PIORES)(_port); \
- } else \
- if(chan) { \
- res = &chan->RegTranslation[_port]; \
- } else { \
- KdPrint(("invalid io write request @ ch %x, res* %x\n", chan, _port)); \
- return; \
- } \
- if(!res->MemIo) { \
- /*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
- ScsiPortWritePortBuffer##_Type((_type*)(res->Addr), (_type*)Buffer, Count); \
- return; \
- } \
- while(Count) { \
- ScsiPortWriteRegister##_Type((_type*)(res->Addr), *((_type*)Buffer)); \
- Count--; \
- Buffer = ((_type*)Buffer)+1; \
- } \
- return; \
- }
- AtapiWritePortBufferN_template(ULONG, Ulong, 4);
- AtapiWritePortBufferN_template(USHORT, Ushort, 2);
- AtapiReadPortBufferN_template(ULONG, Ulong, 4);
- AtapiReadPortBufferN_template(USHORT, Ushort, 2);
- UCHAR
- DDKFASTAPI
- AtapiSuckPort2(
- IN PHW_CHANNEL chan
- )
- {
- UCHAR statusByte;
- ULONG i;
- WaitOnBusyLong(chan);
- for (i = 0; i < 0x10000; i++) {
- GetStatus(chan, statusByte);
- if (statusByte & IDE_STATUS_DRQ) {
- // Suck out any remaining bytes and throw away.
- AtapiReadPort2(chan, IDX_IO1_i_Data);
- } else {
- break;
- }
- }
- if(i) {
- KdPrint2((PRINT_PREFIX "AtapiSuckPort2: overrun detected (%#x words)\n", i ));
- }
- return statusByte;
- } // AtapiSuckPort2()
- UCHAR
- DDKFASTAPI
- WaitOnBusy(
- IN PHW_CHANNEL chan
- )
- {
- ULONG i;
- UCHAR Status;
- for (i=0; i<200; i++) {
- GetStatus(chan, Status);
- if (Status & IDE_STATUS_BUSY) {
- AtapiStallExecution(10);
- continue;
- } else {
- break;
- }
- }
- return Status;
- } // end WaitOnBusy()
- UCHAR
- DDKFASTAPI
- WaitOnBusyLong(
- IN PHW_CHANNEL chan
- )
- {
- ULONG i;
- UCHAR Status;
- Status = WaitOnBusy(chan);
- if(!(Status & IDE_STATUS_BUSY))
- return Status;
- for (i=0; i<2000; i++) {
- GetStatus(chan, Status);
- if (Status & IDE_STATUS_BUSY) {
- AtapiStallExecution(250);
- continue;
- } else {
- break;
- }
- }
- return Status;
- } // end WaitOnBusyLong()
- UCHAR
- DDKFASTAPI
- WaitOnBaseBusy(
- IN PHW_CHANNEL chan
- )
- {
- ULONG i;
- UCHAR Status = 0xff;
- for (i=0; i<g_opt_WaitBusyCount; i++) {
- GetBaseStatus(chan, Status);
- if (Status & IDE_STATUS_BUSY) {
- AtapiStallExecution(g_opt_WaitBusyDelay);
- continue;
- } else {
- break;
- }
- }
- return Status;
- } // end WaitOnBaseBusy()
- UCHAR
- DDKFASTAPI
- WaitOnBaseBusyLong(
- IN PHW_CHANNEL chan
- )
- {
- ULONG i;
- UCHAR Status;
- Status = WaitOnBaseBusy(chan);
- if(!(Status & IDE_STATUS_BUSY))
- return Status;
- for (i=0; i<2000; i++) {
- GetBaseStatus(chan, Status);
- if (Status & IDE_STATUS_BUSY) {
- AtapiStallExecution(250);
- continue;
- } else {
- break;
- }
- }
- return Status;
- } // end WaitOnBaseBusyLong()
- UCHAR
- DDKFASTAPI
- UniataIsIdle(
- IN struct _HW_DEVICE_EXTENSION* deviceExtension,
- IN UCHAR Status
- )
- {
- UCHAR Status2;
- if(Status == 0xff) {
- return 0xff;
- }
- if(Status & IDE_STATUS_BUSY) {
- return Status;
- }
- // if(deviceExtension->HwFlags & UNIATA_SATA) {
- if(UniataIsSATARangeAvailable(deviceExtension, 0)) {
- if(Status & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
- return Status;
- }
- } else {
- Status2 = Status & ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX);
- if ((Status & IDE_STATUS_BUSY) ||
- (Status2 != IDE_STATUS_IDLE && Status2 != IDE_STATUS_DRDY)) {
- return Status;
- }
- }
- return IDE_STATUS_IDLE;
- } // end UniataIsIdle()
- UCHAR
- DDKFASTAPI
- WaitForIdleLong(
- IN PHW_CHANNEL chan
- )
- {
- ULONG i;
- UCHAR Status;
- UCHAR Status2;
- for (i=0; i<20000; i++) {
- GetStatus(chan, Status);
- Status2 = UniataIsIdle(chan->DeviceExtension, Status);
- if(Status2 == 0xff) {
- // no drive ?
- break;
- } else
- if(Status2 & IDE_STATUS_BUSY) {
- AtapiStallExecution(10);
- continue;
- } else {
- break;
- }
- }
- return Status;
- } // end WaitForIdleLong()
- UCHAR
- DDKFASTAPI
- WaitForDrq(
- IN PHW_CHANNEL chan
- )
- {
- ULONG i;
- UCHAR Status;
- for (i=0; i<1000; i++) {
- GetStatus(chan, Status);
- if (Status & IDE_STATUS_BUSY) {
- AtapiStallExecution(g_opt_WaitDrqDelay);
- } else if (Status & IDE_STATUS_DRQ) {
- break;
- } else {
- AtapiStallExecution(g_opt_WaitDrqDelay*2);
- }
- }
- return Status;
- } // end WaitForDrq()
- UCHAR
- DDKFASTAPI
- WaitShortForDrq(
- IN PHW_CHANNEL chan
- )
- {
- ULONG i;
- UCHAR Status;
- for (i=0; i<2; i++) {
- GetStatus(chan, Status);
- if (Status & IDE_STATUS_BUSY) {
- AtapiStallExecution(g_opt_WaitDrqDelay);
- } else if (Status & IDE_STATUS_DRQ) {
- break;
- } else {
- AtapiStallExecution(g_opt_WaitDrqDelay);
- }
- }
- return Status;
- } // end WaitShortForDrq()
- VOID
- DDKFASTAPI
- AtapiSoftReset(
- IN PHW_CHANNEL chan,
- ULONG DeviceNumber
- )
- {
- //ULONG c = chan->lChannel;
- ULONG i = 30 * 1000;
- UCHAR dma_status = 0;
- KdPrint2((PRINT_PREFIX "AtapiSoftReset:\n"));
- UCHAR statusByte2;
- if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
- UniataAhciSoftReset(chan->DeviceExtension, chan->lChannel, DeviceNumber);
- return;
- }
- GetBaseStatus(chan, statusByte2);
- KdPrint2((PRINT_PREFIX " statusByte2 %x:\n", statusByte2));
- SelectDrive(chan, DeviceNumber);
- AtapiStallExecution(500);
- AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET);
- // ReactOS modification: Already stop looping when we know that the drive has finished resetting.
- // Not all controllers clear the IDE_STATUS_BUSY flag (e.g. not the VMware one), so ensure that
- // the maximum waiting time (30 * i = 0.9 seconds) does not exceed the one of the original
- // implementation. (which is around 1 second)
- while ((AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
- i--)
- {
- AtapiStallExecution(30);
- }
- SelectDrive(chan, DeviceNumber);
- WaitOnBusy(chan);
- GetBaseStatus(chan, statusByte2);
- AtapiStallExecution(500);
- GetBaseStatus(chan, statusByte2);
- if(chan && chan->DeviceExtension) {
- dma_status = GetDmaStatus(chan->DeviceExtension, chan->lChannel);
- KdPrint2((PRINT_PREFIX " DMA status %#x\n", dma_status));
- } else {
- KdPrint2((PRINT_PREFIX " can't get DMA status\n"));
- }
- if(dma_status & BM_STATUS_INTR) {
- // bullshit, we have DMA interrupt, but had never initiate DMA operation
- KdPrint2((PRINT_PREFIX " clear unexpected DMA intr on ATAPI reset\n"));
- AtapiDmaDone(chan->DeviceExtension, DeviceNumber, chan->lChannel, NULL);
- GetBaseStatus(chan, statusByte2);
- }
- if(chan->DeviceExtension->HwFlags & UNIATA_SATA) {
- UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT, DeviceNumber);
- /* if(!(chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
- UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT, 1);
- }*/
- }
- return;
- } // end AtapiSoftReset()
- /*
- Send command to device.
- Translate to 48-Lba form if required
- */
- UCHAR
- NTAPI
- AtaCommand48(
- IN PHW_DEVICE_EXTENSION deviceExtension,
- IN ULONG DeviceNumber,
- IN ULONG lChannel,
- IN UCHAR command,
- IN ULONGLONG lba,
- IN USHORT count,
- IN USHORT feature,
- IN ULONG flags
- )
- {
- PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
- UCHAR statusByte;
- ULONG i;
- PUCHAR plba;
- KdPrint2((PRINT_PREFIX "AtaCommand48: cntrlr %#x:%#x dev %#x, cmd %#x, lba %#I64x count %#x feature %#x\n",
- deviceExtension->DevIndex, deviceExtension->Channel, DeviceNumber, command, lba, count, feature ));
- if(deviceExtension->HwFlags & UNIATA_AHCI) {
- PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd);
- KdPrint3((" (ahci)\n"));
- RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis));
- if(!UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
- &(AHCI_CMD->cfis[0]),
- command,
- lba,
- count,
- feature,
- ATA_IMMEDIATE
- )) {
- return 0xff;
- }
- if(UniataAhciSendCommand(deviceExtension, lChannel, DeviceNumber, 0, 3000) == 0xff) {
- KdPrint2((" timeout\n"));
- return 0xff;
- }
- return IDE_STATUS_IDLE;
- }
- SelectDrive(chan, DeviceNumber);
- statusByte = WaitOnBusy(chan);
- /* ready to issue command ? */
- if (statusByte & IDE_STATUS_BUSY) {
- KdPrint2((PRINT_PREFIX " Returning BUSY status\n"));
- return statusByte;
- }
- // !!! We should not check ERROR condition here
- // ERROR bit may be asserted durring previous operation
- // and not cleared after SELECT
- //>>>>>> NV: 2006/08/03
- if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) &&
- CheckIfBadBlock(chan->lun[DeviceNumber], lba, count)) {
- KdPrint3((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count));
- return IDE_STATUS_ERROR;
- //return SRB_STATUS_ERROR;
- }
- //<<<<<< NV: 2006/08/03
- /* only use 48bit addressing if needed because of the overhead */
- if (UniAta_need_lba48(command, lba, count,
- chan->lun[DeviceNumber]->IdentifyData.FeaturesSupport.Address48)) {
- KdPrint2((PRINT_PREFIX " dev %#x USE_LBA_48\n", DeviceNumber ));
- /* translate command into 48bit version */
- if(AtaCommandFlags[command] & ATA_CMD_FLAG_48supp) {
- command = AtaCommands48[command];
- } else {
- KdPrint2((PRINT_PREFIX " unhandled LBA48 command\n"));
- return (UCHAR)-1;
- }
- chan->ChannelCtrlFlags |= CTRFLAGS_LBA48;
- plba = (PUCHAR)&lba;
- AtapiWritePort1(chan, IDX_IO1_o_Feature, (UCHAR)(feature>>8));
- AtapiWritePort1(chan, IDX_IO1_o_Feature, (UCHAR)feature);
- AtapiWritePort1(chan, IDX_IO1_o_BlockCount, (UCHAR)(count>>8));
- AtapiWritePort1(chan, IDX_IO1_o_BlockCount, (UCHAR)count);
- AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, (UCHAR)(plba[3]));
- AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, (UCHAR)(plba[0]));
- AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, (UCHAR)(plba[4]));
- AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, (UCHAR)(plba[1]));
- AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)(plba[5]));
- AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)(plba[2]));
- //KdPrint2((PRINT_PREFIX "AtaCommand48: dev %#x USE_LBA48 (2)\n", DeviceNumber ));
- AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1) );
- } else {
- plba = (PUCHAR)&lba; //ktp
- chan->ChannelCtrlFlags &= ~CTRFLAGS_LBA48;
-
- //if(feature ||
- // (chan->lun[DeviceNumber]->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_TAPE_DEVICE | DFLAGS_LBA_ENABLED))) {
- AtapiWritePort1(chan, IDX_IO1_o_Feature, (UCHAR)feature);
- //}
- AtapiWritePort1(chan, IDX_IO1_o_BlockCount, (UCHAR)count);
- AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, (UCHAR)plba[0]);
- AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, (UCHAR)plba[1]);
- AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)plba[2]);
- if(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_LBA_ENABLED) {
- //KdPrint2((PRINT_PREFIX "AtaCommand28: dev %#x USE_LBA\n", DeviceNumber ));
- AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, (UCHAR)(plba[3] & 0xf) | IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1) );
- } else {
- //KdPrint2((PRINT_PREFIX "AtaCommand28: dev %#x USE_CHS\n", DeviceNumber ));
- AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, (UCHAR)(plba[3] & 0xf) | (DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1) );
- }
- }
- // write command code to device
- AtapiWritePort1(chan, IDX_IO1_o_Command, command);
- switch (flags) {
- case ATA_WAIT_INTR:
- // caller requested wait for interrupt
- for(i=0;i<4;i++) {
- WaitOnBusy(chan);
- statusByte = WaitForDrq(chan);
- if (statusByte & IDE_STATUS_DRQ)
- break;
- AtapiStallExecution(500);
- KdPrint2((PRINT_PREFIX " retry waiting DRQ, status %#x\n", statusByte));
- }
- return statusByte;
- case ATA_WAIT_IDLE:
- // caller requested wait for entering Wait state
- for (i=0; i<30 * 1000; i++) {
- GetStatus(chan, statusByte);
- statusByte = UniataIsIdle(deviceExtension, statusByte);
- if(statusByte == 0xff) {
- // no drive ?
- break;
- } else
- if(statusByte & IDE_STATUS_ERROR) {
- break;
- } else
- if(statusByte & IDE_STATUS_BUSY) {
- AtapiStallExecution(100);
- continue;
- } else
- if(statusByte == IDE_STATUS_IDLE) {
- break;
- } else {
- //if(deviceExtension->HwFlags & UNIATA_SATA) {
- if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
- break;
- }
- AtapiStallExecution(100);
- }
- }
- //statusByte |= IDE_STATUS_BUSY;
- break;
- case ATA_WAIT_READY:
- statusByte = WaitOnBusyLong(chan);
- break;
- case ATA_WAIT_BASE_READY:
- statusByte = WaitOnBaseBusyLong(chan);
- break;
- case ATA_IMMEDIATE:
- GetStatus(chan, statusByte);
- if (statusByte & IDE_STATUS_ERROR) {
- KdPrint2((PRINT_PREFIX " Warning: Immed Status %#x :(\n", statusByte));
- if(statusByte == (IDE_STATUS_IDLE | IDE_STATUS_ERROR)) {
- break;
- }
- KdPrint2((PRINT_PREFIX " try to continue\n"));
- statusByte &= ~IDE_STATUS_ERROR;
- }
- chan->ExpectingInterrupt = TRUE;
- // !!!!!
- InterlockedExchange(&(chan->CheckIntr),
- CHECK_INTR_IDLE);
- statusByte = 0;
- break;
- }
- KdPrint2((PRINT_PREFIX " Status %#x\n", statusByte));
- return statusByte;
- } // end AtaCommand48()
- /*
- Send command to device.
- This is simply wrapper for AtaCommand48()
- */
- UCHAR
- NTAPI
- AtaCommand(
- IN PHW_DEVICE_EXTENSION deviceExtension,
- IN ULONG DeviceNumber,
- IN ULONG lChannel,
- IN UCHAR command,
- IN USHORT cylinder,
- IN UCHAR head,
- IN UCHAR sector,
- IN UCHAR count,
- IN UCHAR feature,
- IN ULONG flags
- )
- {
- if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
- return AtaCommand48(deviceExtension, DeviceNumber, lChannel,
- command,
- (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
- count, feature, flags);
- } else {
- PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
- PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd);
- KdPrint3(("AtaCommand(ahci)\n"));
- RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis));
- if(!UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
- &(AHCI_CMD->cfis[0]),
- command,
- (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
- count,
- feature,
- ATA_IMMEDIATE
- )) {
- return 0xff;
- }
- if(UniataAhciSendCommand(deviceExtension, lChannel, DeviceNumber, 0, 3000) == 0xff) {
- KdPrint2((" timeout\n"));
- return 0xff;
- }
- return IDE_STATUS_IDLE;
- }
- } // end AtaCommand()
- LONG
- NTAPI
- AtaPio2Mode(LONG pio)
- {
- switch (pio) {
- default: return ATA_PIO;
- case 0: return ATA_PIO0;
- case 1: return ATA_PIO1;
- case 2: return ATA_PIO2;
- case 3: return ATA_PIO3;
- case 4: return ATA_PIO4;
- case 5: return ATA_PIO5;
- }
- } // end AtaPio2Mode()
- LONG
- NTAPI
- AtaPioMode(PIDENTIFY_DATA2 ident)
- {
- if (ident->PioTimingsValid) {
- if (ident->AdvancedPIOModes & AdvancedPIOModes_5)
- return 5;
- if (ident->AdvancedPIOModes & AdvancedPIOModes_4)
- return 4;
- if (ident->AdvancedPIOModes & AdvancedPIOModes_3)
- return 3;
- }
- if (ident->PioCycleTimingMode == 2)
- return 2;
- if (ident->PioCycleTimingMode == 1)
- return 1;
- if (ident->PioCycleTimingMode == 0)
- return 0;
- return -1;
- } // end AtaPioMode()
- LONG
- NTAPI
- AtaWmode(PIDENTIFY_DATA2 ident)
- {
- if (ident->MultiWordDMASupport & 0x04)
- return 2;
- if (ident->MultiWordDMASupport & 0x02)
- return 1;
- if (ident->MultiWordDMASupport & 0x01)
- return 0;
- return -1;
- } // end AtaWmode()
- LONG
- NTAPI
- AtaUmode(PIDENTIFY_DATA2 ident)
- {
- if (!ident->UdmaModesValid)
- return -1;
- if (ident->UltraDMASupport & 0x40)
- return 6;
- if (ident->UltraDMASupport & 0x20)
- return 5;
- if (ident->UltraDMASupport & 0x10)
- return 4;
- if (ident->UltraDMASupport & 0x08)
- return 3;
- if (ident->UltraDMASupport & 0x04)
- return 2;
- if (ident->UltraDMASupport & 0x02)
- return 1;
- if (ident->UltraDMASupport & 0x01)
- return 0;
- return -1;
- } // end AtaUmode()
- #ifndef UNIATA_CORE
- VOID
- NTAPI
- AtapiTimerDpc(
- IN PVOID HwDeviceExtension
- )
- {
- PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
- PHW_TIMER HwScsiTimer;
- LARGE_INTEGER time;
- ULONG MiniportTimerValue;
- BOOLEAN recall = FALSE;
- ULONG lChannel;
- PHW_CHANNEL chan;
- KdPrint2((PRINT_PREFIX "AtapiTimerDpc:\n"));
- lChannel = deviceExtension->ActiveDpcChan = deviceExtension->FirstDpcChan;
- if(lChannel == CHAN_NOT_SPECIFIED) {
- KdPrint2((PRINT_PREFIX "AtapiTimerDpc: no items\n"));
- return;
- }
- chan = &deviceExtension->chan[lChannel];
- while(TRUE) {
- HwScsiTimer = chan->HwScsiTimer;
- chan->HwScsiTimer = NULL;
- deviceExtension->FirstDpcChan = chan->NextDpcChan;
- if(deviceExtension->FirstDpcChan != CHAN_NOT_SPECIFIED) {
- recall = TRUE;
- }
- HwScsiTimer(HwDeviceExtension);
- chan->NextDpcChan = CHAN_NOT_SPECIFIED;
- lChannel = deviceExtension->ActiveDpcChan = deviceExtension->FirstDpcChan;
- if(lChannel == CHAN_NOT_SPECIFIED) {
- KdPrint2((PRINT_PREFIX "AtapiTimerDpc: no more items\n"));
- deviceExtension->FirstDpcChan =
- deviceExtension->ActiveDpcChan = CHAN_NOT_SPECIFIED;
- return;
- }
- KeQuerySystemTime(&time);
- KdPrint2((PRINT_PREFIX "AtapiTimerDpc: KeQuerySystemTime=%#x%#x\n", time.HighPart, time.LowPart));
- chan = &deviceExtension->chan[lChannel];
- if(time.QuadPart >= chan->DpcTime - 10) {
- // call now
- KdPrint2((PRINT_PREFIX "AtapiTimerDpc: get next DPC, DpcTime1=%#x%#x\n",
- (ULONG)(chan->DpcTime >> 32), (ULONG)(chan->DpcTime)));
- continue;
- }
- break;
- }
- if(recall) {
- deviceExtension->ActiveDpcChan = CHAN_NOT_SPECIFIED;
- MiniportTimerValue = (ULONG)(time.QuadPart - chan->DpcTime)/10;
- if(!MiniportTimerValue)
- MiniportTimerValue = 1;
- KdPrint2((PRINT_PREFIX "AtapiTimerDpc: recall AtapiTimerDpc\n"));
- ScsiPortNotification(RequestTimerCall, HwDeviceExtension,
- AtapiTimerDpc,
- MiniportTimerValue
- );
- }
- return;
- } // end AtapiTimerDpc()
- /*
- Wrapper for ScsiPort, that implements smart Dpc
- queueing. We need it to allow parallel functioning
- of IDE channles with shared interrupt. Standard Dpc mechanism
- cancels previous Dpc request (if any), but we need Dpc queue.
- */
- VOID
- NTAPI
- AtapiQueueTimerDpc(
- IN PVOID HwDeviceExtension,
- IN ULONG lChannel,
- IN PHW_TIMER HwScsiTimer,
- IN ULONG MiniportTimerValue
- )
- {
- PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
- LARGE_INTEGER time;
- LARGE_INTEGER time2;
- ULONG i;
- PHW_CHANNEL prev_chan;
- PHW_CHANNEL chan;
- // BOOLEAN UseRequestTimerCall = TRUE;
- KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: dt=%d for lChn %#x\n", MiniportTimerValue, lChannel));
- KeQuerySystemTime(&time);
- time2 = time;
- KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: KeQuerySystemTime=%#x%#x\n", time.HighPart, time.LowPart));
- time.QuadPart += MiniportTimerValue*10;
- KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: KeQuerySystemTime2=%#x%#x\n", time.HighPart, time.LowPart));
- KdPrint2((PRINT_PREFIX " ActiveDpcChan=%d, FirstDpcChan=%d\n", deviceExtension->ActiveDpcChan, deviceExtension->FirstDpcChan));
- i = deviceExtension->FirstDpcChan;
- chan = prev_chan = NULL;
- while(i != CHAN_NOT_SPECIFIED) {
- prev_chan = chan;
- chan = &deviceExtension->chan[i];
- if(chan->DpcTime > time.QuadPart) {
- break;
- }
- i = chan->NextDpcChan;
- }
- chan = &deviceExtension->chan[lChannel];
- if(!prev_chan) {
- deviceExtension->FirstDpcChan = lChannel;
- } else {
- prev_chan->NextDpcChan = lChannel;
- }
- chan->NextDpcChan = i;
- chan->HwScsiTimer = HwScsiTimer;
- chan->DpcTime = time.QuadPart;
- KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: KeQuerySystemTime3=%#x%#x\n", time2.HighPart, time2.LowPart));
- if(time.QuadPart <= time2.QuadPart) {
- MiniportTimerValue = 1;
- } else {
- MiniportTimerValue = (ULONG)((time.QuadPart - time2.QuadPart) / 10);
- }
- KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: dt=%d for lChn %#x\n", MiniportTimerValue, lChannel));
- ScsiPortNotification(RequestTimerCall, HwDeviceExtension,
- AtapiTimerDpc,
- MiniportTimerValue);
- } // end AtapiQueueTimerDpc()
- #endif //UNIATA_CORE
- VOID
- NTAPI
- UniataDumpATARegs(
- IN PHW_CHANNEL chan
- )
- {
- ULONG j;
- UCHAR statusByteAlt;
- GetStatus(chan, statusByteAlt);
- KdPrint2((PRINT_PREFIX " AltStatus (%#x)\n", statusByteAlt));
- for(j=1; j<IDX_IO1_SZ; j++) {
- statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
- KdPrint2((PRINT_PREFIX
- " Reg_%#x (%#x) = %#x\n",
- j,
- chan->RegTranslation[IDX_IO1+j].Addr,
- statusByteAlt));
- }
- for(j=0; j<IDX_BM_IO_SZ-1; j++) {
- statusByteAlt = AtapiReadPort1(chan, IDX_BM_IO+j);
- KdPrint2((PRINT_PREFIX
- " BM_%#x (%#x) = %#x\n",
- j,
- chan->RegTranslation[IDX_BM_IO+j].Addr,
- statusByteAlt));
- }
- return;
- } // end UniataDumpATARegs()
- /*++
- Routine Description:
- Issue IDENTIFY command to a device.
- Arguments:
- HwDeviceExtension - HBA miniport driver's adapter data storage
- DeviceNumber - Indicates which device.
- Command - Either the standard (EC) or the ATAPI packet (A1) IDENTIFY.
- Return Value:
- TRUE if all goes well.
- --*/
- BOOLEAN
- NTAPI
- IssueIdentify(
- IN PVOID HwDeviceExtension,
- IN ULONG DeviceNumber,
- IN ULONG lChannel,
- IN UCHAR Command,
- IN BOOLEAN NoSetup
- )
- {
- PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
- PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
- ULONG waitCount = 50000;
- ULONG j;
- UCHAR statusByte;
- UCHAR statusByte2;
- UCHAR signatureLow,
- signatureHigh;
- BOOLEAN atapiDev = FALSE;
- PHW_LU_EXTENSION LunExt = chan->lun[DeviceNumber];
- if(chan->ChannelCtrlFlags & CTRFLAGS_AHCI_PM) {
- if(chan->PmLunMap & (1 << DeviceNumber)) {
- // OK
- } else {
- KdPrint2((PRINT_PREFIX "IssueIdentify: PM empty port\n"));
- return FALSE;
- }
- } else
- if(DeviceNumber && (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: NO SLAVE\n"));
- return FALSE;
- }
- if(LunExt->DeviceFlags & DFLAGS_HIDDEN) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: HIDDEN\n"));
- return FALSE;
- }
- if(deviceExtension->HwFlags & UNIATA_AHCI) {
- statusByte = WaitOnBusyLong(chan);
- } else {
- SelectDrive(chan, DeviceNumber);
- AtapiStallExecution(10);
- statusByte = WaitOnBusyLong(chan);
- // Check that the status register makes sense.
- GetBaseStatus(chan, statusByte2);
- UniataDumpATARegs(chan);
- }
- if (Command == IDE_COMMAND_IDENTIFY) {
- // Mask status byte ERROR bits.
- statusByte = UniataIsIdle(deviceExtension, statusByte & ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX));
- KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for IDE. Status (%#x)\n", statusByte));
- // Check if register value is reasonable.
- if(statusByte != IDE_STATUS_IDLE) {
- // No reset here !!!
- KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte != IDE_STATUS_IDLE\n"));
- //if(!(deviceExtension->HwFlags & UNIATA_SATA)) {
- if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
- SelectDrive(chan, DeviceNumber);
- WaitOnBusyLong(chan);
- signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
- signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
- if (signatureLow == ATAPI_MAGIC_LSB &&
- signatureHigh == ATAPI_MAGIC_MSB) {
- // Device is Atapi.
- KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (dev %d)\n", DeviceNumber));
- return FALSE;
- }
- // We really should wait up to 31 seconds
- // The ATA spec. allows device 0 to come back from BUSY in 31 seconds!
- // (30 seconds for device 1)
- do {
- // Wait for Busy to drop.
- AtapiStallExecution(100);
- GetStatus(chan, statusByte);
- } while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
- GetBaseStatus(chan, statusByte2);
- SelectDrive(chan, DeviceNumber);
- } else {
- GetBaseStatus(chan, statusByte2);
- }
- // Another check for signature, to deal with one model Atapi that doesn't assert signature after
- // a soft reset.
- signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
- signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
- if (signatureLow == ATAPI_MAGIC_LSB &&
- signatureHigh == ATAPI_MAGIC_MSB) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (2) (dev %d)\n", DeviceNumber));
- // Device is Atapi.
- return FALSE;
- }
- statusByte = UniataIsIdle(deviceExtension, statusByte) & ~IDE_STATUS_INDEX;
- if (statusByte != IDE_STATUS_IDLE) {
- // Give up on this.
- KdPrint2((PRINT_PREFIX "IssueIdentify: no dev (dev %d)\n", DeviceNumber));
- return FALSE;
- }
- }
- } else {
- KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for ATAPI. Status (%#x)\n", statusByte));
- //if(!(deviceExtension->HwFlags & UNIATA_SATA)) {
- if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
- statusByte = WaitForIdleLong(chan);
- KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for ATAPI (2). Status (%#x)\n", statusByte));
- }
- atapiDev = TRUE;
- }
- // if(deviceExtension->HwFlags & UNIATA_SATA) {
- if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
- j = 4; // skip old-style checks
- } else {
- j = 0;
- }
- for (; j < 4*2; j++) {
- // Send IDENTIFY command.
- statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, Command, 0, 0, 0, (j >= 4) ? 0x200 : 0, 0, ATA_WAIT_INTR);
- // Clear interrupt
- if (statusByte & IDE_STATUS_DRQ) {
- // Read status to acknowledge any interrupts generated.
- KdPrint2((PRINT_PREFIX "IssueIdentify: IDE_STATUS_DRQ (%#x)\n", statusByte));
- GetBaseStatus(chan, statusByte);
- // One last check for Atapi.
- if (Command == IDE_COMMAND_IDENTIFY) {
- signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
- signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
- if (signatureLow == ATAPI_MAGIC_LSB &&
- signatureHigh == ATAPI_MAGIC_MSB) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (3) (dev %d)\n", DeviceNumber));
- // Device is Atapi.
- return FALSE;
- }
- }
- break;
- } else {
- KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (%#x)\n", statusByte));
- if (Command == IDE_COMMAND_IDENTIFY) {
- // Check the signature. If DRQ didn't come up it's likely Atapi.
- signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
- signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
- if (signatureLow == ATAPI_MAGIC_LSB &&
- signatureHigh == ATAPI_MAGIC_MSB) {
- // Device is Atapi.
- KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (4) (dev %d)\n", DeviceNumber));
- return FALSE;
- }
- } else {
- if(!(statusByte & IDE_STATUS_ERROR) && (statusByte & IDE_STATUS_BUSY)) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: DRQ not asserted immediately, BUSY -> WaitForDrq\n"));
- break;
- }
- }
- // Device didn't respond correctly. It will be given one more chances.
- KdPrint2((PRINT_PREFIX "IssueIdentify: DRQ never asserted (%#x). Error reg (%#x)\n",
- statusByte, AtapiReadPort1(chan, IDX_IO1_i_Error)));
- GetBaseStatus(chan, statusByte);
- AtapiSoftReset(chan,DeviceNumber);
- AtapiDisableInterrupts(deviceExtension, lChannel);
- AtapiEnableInterrupts(deviceExtension, lChannel);
- GetBaseStatus(chan, statusByte);
- //GetStatus(chan, statusByte);
- KdPrint2((PRINT_PREFIX "IssueIdentify: Status after soft reset (%#x)\n", statusByte));
- }
- }
- // Check for error on really stupid master devices that assert random
- // patterns of bits in the status register at the slave address.
- if ((Command == IDE_COMMAND_IDENTIFY) && (statusByte & IDE_STATUS_ERROR)) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: Exit on error (%#x)\n", statusByte));
- return FALSE;
- }
- KdPrint2((PRINT_PREFIX "IssueIdentify: Status before read words %#x\n", statusByte));
- // Suck out 256 words. After waiting for one model that asserts busy
- // after receiving the Packet Identify command.
- statusByte = WaitForDrq(chan);
- statusByte = WaitOnBusyLong(chan);
- KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
- if (!(statusByte & IDE_STATUS_DRQ)) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#x)\n", statusByte));
- GetBaseStatus(chan, statusByte);
- return FALSE;
- }
- GetBaseStatus(chan, statusByte);
- KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
- if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
- KdPrint2((PRINT_PREFIX " use 16bit IO\n"));
- #if 0
- USHORT w;
- ULONG i;
- // ATI/SII chipsets with memory-mapped IO hangs when
- // I call ReadBuffer(), probably due to PCI burst/prefetch enabled
- // Unfortunately, I don't know yet how to workaround it except the way you see below.
- KdPrint2((PRINT_PREFIX
- " IO_%#x (%#x), %s:\n",
- IDX_IO1_i_Data,
- chan->RegTranslation[IDX_IO1_i_Data].Addr,
- chan->RegTranslation[IDX_IO1_i_Data].MemIo ? "Mem" : "IO"));
- for(i=0; i<256; i++) {
- /*
- KdPrint2((PRINT_PREFIX
- " IO_%#x (%#x):\n",
- IDX_IO1_i_Data,
- chan->RegTranslation[IDX_IO1_i_Data].Addr));
- */
- w = AtapiReadPort2(chan, IDX_IO1_i_Data);
- KdPrint2((PRINT_PREFIX
- " %x\n", w));
- AtapiStallExecution(1);
- ((PUSHORT)&deviceExtension->FullIdentifyData)[i] = w;
- }
- #else
- ReadBuffer(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256, PIO0_TIMING);
- #endif
- // Work around for some IDE and one model Atapi that will present more than
- // 256 bytes for the Identify data.
- KdPrint2((PRINT_PREFIX "IssueIdentify: suck data port\n", statusByte));
- statusByte = AtapiSuckPort2(chan);
- } else {
- KdPrint2((PRINT_PREFIX " use 32bit IO\n"));
- ReadBuffer2(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256/2, PIO0_TIMING);
- }
- KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
- statusByte = WaitForDrq(chan);
- KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
- GetBaseStatus(chan, statusByte);
- KdPrint2((PRINT_PREFIX "IssueIdentify: Status after read words %#x\n", statusByte));
- if(NoSetup) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: no setup, exiting\n"));
- return TRUE;
- }
- KdPrint2((PRINT_PREFIX "Model: %20.20s\n", deviceExtension->FullIdentifyData.ModelNumber));
- KdPrint2((PRINT_PREFIX "FW: %4.4s\n", deviceExtension->FullIdentifyData.FirmwareRevision));
- KdPrint2((PRINT_PREFIX "S/N: %20.20s\n", deviceExtension->FullIdentifyData.SerialNumber));
- KdPrint2((PRINT_PREFIX "Pio: %x\n", deviceExtension->FullIdentifyData.PioCycleTimingMode));
- if(deviceExtension->FullIdentifyData.PioTimingsValid) {
- KdPrint2((PRINT_PREFIX "APio: %x\n", deviceExtension->FullIdentifyData.AdvancedPIOModes));
- }
- KdPrint2((PRINT_PREFIX "SWDMA: %x\n", deviceExtension->FullIdentifyData.SingleWordDMAActive));
- KdPrint2((PRINT_PREFIX "MWDMA: %x\n", deviceExtension->FullIdentifyData.MultiWordDMAActive));
- if(deviceExtension->FullIdentifyData.UdmaModesValid) {
- KdPrint2((PRINT_PREFIX "UDMA: %x\n", deviceExtension->FullIdentifyData.UltraDMAActive));
- }
- KdPrint2((PRINT_PREFIX "SATA: %x\n", deviceExtension->FullIdentifyData.SataEnable));
- // Check out a few capabilities / limitations of the device.
- if (deviceExtension->FullIdentifyData.RemovableStatus & 1) {
- // Determine if this drive supports the MSN functions.
- KdPrint2((PRINT_PREFIX "IssueIdentify: Marking drive %d as removable. SFE = %d\n",
- DeviceNumber,
- deviceExtension->FullIdentifyData.RemovableStatus));
- LunExt->DeviceFlags |= DFLAGS_REMOVABLE_DRIVE;
- }
- if (deviceExtension->FullIdentifyData.MaximumBlockTransfer) {
- // Determine max. block transfer for this device.
- LunExt->MaximumBlockXfer =
- (UCHAR)(deviceExtension->FullIdentifyData.MaximumBlockTransfer & 0xFF);
- }
- LunExt->NumOfSectors = 0;
- if (Command == IDE_COMMAND_IDENTIFY) {
- ULONGLONG NumOfSectors=0;
- ULONGLONG NativeNumOfSectors=0;
- ULONGLONG cylinders=0;
- ULONGLONG tmp_cylinders=0;
- // Read very-old-style drive geometry
- KdPrint2((PRINT_PREFIX "CHS %#x:%#x:%#x\n",
- deviceExtension->FullIdentifyData.NumberOfCylinders,
- deviceExtension->FullIdentifyData.NumberOfHeads,
- deviceExtension->FullIdentifyData.SectorsPerTrack
- ));
- NumOfSectors = deviceExtension->FullIdentifyData.NumberOfCylinders *
- deviceExtension->FullIdentifyData.NumberOfHeads *
- deviceExtension->FullIdentifyData.SectorsPerTrack;
- KdPrint2((PRINT_PREFIX "NumOfSectors %#I64x\n", NumOfSectors));
- // Check for HDDs > 8Gb
- if ((deviceExtension->FullIdentifyData.NumberOfCylinders == 0x3fff) &&
- /* (deviceExtension->FullIdentifyData.TranslationFieldsValid) &&*/
- (NumOfSectors < deviceExtension->FullIdentifyData.UserAddressableSectors)) {
- KdPrint2((PRINT_PREFIX "NumberOfCylinders == 0x3fff\n"));
- cylinders =
- (deviceExtension->FullIdentifyData.UserAddressableSectors /
- (deviceExtension->FullIdentifyData.NumberOfHeads *
- deviceExtension->FullIdentifyData.SectorsPerTrack));
- KdPrint2((PRINT_PREFIX "cylinders %#I64x\n", cylinders));
- NumOfSectors = cylinders *
- deviceExtension->FullIdentifyData.NumberOfHeads *
- deviceExtension->FullIdentifyData.SectorsPerTrack;
- KdPrint2((PRINT_PREFIX "NumOfSectors %#I64x\n", NumOfSectors));
- } else {
- }
- // Check for LBA mode
- KdPrint2((PRINT_PREFIX "Suppo…
Large files files are truncated, but you can click here to view the full file