ReactOS 0.4.16-dev-2633-g8dc9e50
pata_hw.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS ATA Bus Driver
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: PATA hardware support
5 * COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include "pciidex.h"
11
12/* FUNCTIONS ******************************************************************/
13
14static
17 _In_ PCHANNEL_DATA_PATA ChanData,
19{
20 UCHAR IdeStatus;
21
22 /* Select the device */
24
25 /* Do a quick check first */
26 IdeStatus = ChanData->ReadStatus(ChanData);
27 INFO("CH %lu: Device %lu status %02x\n", ChanData->Channel, DeviceNumber, IdeStatus);
28 if (IdeStatus == 0xFF || IdeStatus == 0x7F)
29 return FALSE;
30
31 /* Look at controller */
32 ATA_WRITE(ChanData->Regs.ByteCountLow, 0x55, ChanData, MRES_TF);
33 ATA_WRITE(ChanData->Regs.ByteCountLow, 0xAA, ChanData, MRES_TF);
34 ATA_WRITE(ChanData->Regs.ByteCountLow, 0x55, ChanData, MRES_TF);
35 if (ATA_READ(ChanData->Regs.ByteCountLow, ChanData, MRES_TF) != 0x55)
36 return FALSE;
37 ATA_WRITE(ChanData->Regs.ByteCountHigh, 0xAA, ChanData, MRES_TF);
38 ATA_WRITE(ChanData->Regs.ByteCountHigh, 0x55, ChanData, MRES_TF);
39 ATA_WRITE(ChanData->Regs.ByteCountHigh, 0xAA, ChanData, MRES_TF);
40 if (ATA_READ(ChanData->Regs.ByteCountHigh, ChanData, MRES_TF) != 0xAA)
41 return FALSE;
42
43 return TRUE;
44}
45
46static
47VOID
49 _In_ PCHANNEL_DATA_PATA ChanData)
50{
51 ATA_WRITE(ChanData->Regs.Control, IDE_DC_RESET_CONTROLLER | IDE_DC_ALWAYS,
52 ChanData, MRES_CTRL);
54 ATA_WRITE(ChanData->Regs.Control, IDE_DC_DISABLE_INTERRUPTS | IDE_DC_ALWAYS,
55 ChanData, MRES_CTRL);
57}
58
59static
60VOID
62 _In_ PCHANNEL_DATA_PATA ChanData)
63{
64 ULONG i;
65 USHORT LocalBuffer;
66
67 /* Try to clear the DRQ indication */
68 for (i = 0; i < ATA_MAX_TRANSFER_LENGTH / sizeof(USHORT); ++i)
69 {
70 UCHAR IdeStatus = ChanData->ReadStatus(ChanData);
71
72 if (!(IdeStatus & IDE_STATUS_DRQ))
73 break;
74
75 ATA_READ_BLOCK_16((PUSHORT)ChanData->Regs.Data,
76 &LocalBuffer,
77 1,
78 ChanData,
79 MRES_TF);
80 }
81
82 if (i > 0)
83 INFO("CH %lu: Total drained %lu bytes\n", ChanData->Channel, i * sizeof(USHORT));
84}
85
88 _In_ PVOID ChannelContext)
89{
90 PCHANNEL_DATA_PATA ChanData = ChannelContext;
91
92#if defined(_M_IX86)
93 if (ChanData->ChanInfo & CHANNEL_FLAG_CBUS)
94 return 4;
95#endif
96
97 return (ChanData->ChanInfo & CHANNEL_FLAG_NO_SLAVE) ? 1 : 2;
98}
99
100VOID
102 _In_ PVOID ChannelContext)
103{
104 PCHANNEL_DATA_PATA ChanData = ChannelContext;
105 ULONG i, DeviceNumber, DeviceCount, DeviceBitmap = 0;
106
107 ChanData->IsPollingActive = FALSE;
108
109#if defined(_M_IX86)
110 if (ChanData->ChanInfo & CHANNEL_FLAG_CBUS)
111 ChanData->LastAtaBankId = 0xFF;
112#endif
113
114 /*
115 * Reset the start/stop bus master bit, also needed on some chips to recover,
116 * see for example Intel 82371AB/EB/MB Specification Update 297738-017 #10.
117 */
118 if (ChanData->Regs.Dma != NULL)
119 PciIdeDmaStop(ChanData);
120
121 PataDrainDeviceBuffer(ChanData);
122
125 {
126 if (PataIsDevicePresent(ChanData, DeviceNumber))
127 DeviceBitmap |= 1 << DeviceNumber;
128 }
129 /* Restore the device selection */
131
132 WARN("CH %lu: Resetting IDE channel, devices map 0x%lx\n", ChanData->Channel, DeviceBitmap);
133
134#if defined(_M_IX86)
135 if (ChanData->ChanInfo & CHANNEL_FLAG_CBUS)
136 {
137 /* Reset the secondary IDE channel if present */
138 if (DeviceBitmap & ((1 << 2) | (1 << 3)))
139 {
141 PataIssueSoftwareReset(ChanData);
142 }
143
145 ChanData->LastAtaBankId = 0xFF;
146 }
147#endif
148 PataIssueSoftwareReset(ChanData);
149
151 {
152 UCHAR IdeStatus;
153
154 /* The reset will cause the master device to be selected */
155 if ((DeviceNumber % 2) != 0)
156 {
157 /* Always check BSY for the master device regardless of its presence */
158 if (!(DeviceBitmap & (1 << DeviceNumber)))
159 continue;
160
161 for (i = ATA_TIME_RESET_SELECT; i > 0; i--)
162 {
163 /* Select the device again */
164 ATA_SELECT_DEVICE(ChanData,
166 IDE_DRIVE_SELECT | ((DeviceNumber & 1) << 4));
167
168 /* Check whether the selection was successful */
169 ATA_WRITE(ChanData->Regs.ByteCountLow, 0xAA, ChanData, MRES_TF);
170 ATA_WRITE(ChanData->Regs.ByteCountLow, 0x55, ChanData, MRES_TF);
171 ATA_WRITE(ChanData->Regs.ByteCountLow, 0xAA, ChanData, MRES_TF);
172 if (ATA_READ(ChanData->Regs.ByteCountLow, ChanData, MRES_TF) == 0xAA)
173 break;
174
175 AtaSleep();
176 }
177 if (i == 0)
178 {
179 ERR("CH %lu: Device %lu selection timeout %02x\n",
180 ChanData->Channel, DeviceNumber, ChanData->ReadStatus(ChanData));
181 continue;
182 }
183 }
184
185 /* Now wait for busy to clear */
186 for (i = 0; i < ATA_TIME_BUSY_RESET; ++i)
187 {
188 IdeStatus = ChanData->ReadStatus(ChanData);
189 if (IdeStatus == 0xFF)
190 break;
191
192 if (!(IdeStatus & IDE_STATUS_BUSY))
193 break;
194
195 AtaSleep();
196 }
197
198 if (IdeStatus & IDE_STATUS_BUSY)
199 {
200 ERR("CH %lu: Failed to reset device %lu, status %02x\n",
201 ChanData->Channel, DeviceNumber, IdeStatus);
202 }
203 else
204 {
205 INFO("CH %lu: Device %lu online with status %02x\n",
206 ChanData->Channel, DeviceNumber, IdeStatus);
207 }
208 }
209
211}
212
215 _In_ PVOID ChannelContext,
217{
218 PCHANNEL_DATA_PATA ChanData = ChannelContext;
219 UCHAR IdeStatus;
220
221 if (!PataIsDevicePresent(ChanData, DeviceNumber))
223
224 /* Wait for busy to clear */
225 IdeStatus = ATA_WAIT(ChanData, ATA_TIME_BUSY_SELECT, IDE_STATUS_BUSY, 0);
226 if (IdeStatus & (IDE_STATUS_BUSY | IDE_STATUS_DRQ))
227 {
228 /*
229 * This status indicates that the previous command hasn't been completed
230 * and the device is left in an unexpected state.
231 * A device reset is required to recover.
232 */
233 WARN("CH %lu: Device %lu is busy %02x\n", ChanData->Channel, DeviceNumber, IdeStatus);
234 return CONN_STATUS_FAILURE;
235 }
236
237 /*
238 * Also we do not check the device signature,
239 * because early ATAPI drives (NEC CDR-260, and some other devices)
240 * report an ATA signature.
241 */
243}
244
245ULONG
247 _In_ PVOID ChannelContext)
248{
249 PCHANNEL_DATA_PATA ChanData = ChannelContext;
250
251 /*
252 * By default, we do not issue the software reset to detect the device signature,
253 * since attached devices may reset their current transfer mode.
254 * We need to know what transfer mode is actually set by BIOS in order to
255 * select any transfer mode correctly by our generic PATA chipset driver
256 * (PciIdeAcpiSetTransferMode() or PciIdeBiosSetTransferMode()).
257 */
258 return PataChannelGetMaximumDeviceCount(ChanData);
259}
unsigned char BOOLEAN
Definition: actypes.h:127
@ CONN_STATUS_FAILURE
Definition: ata_shared.h:83
@ CONN_STATUS_DEV_UNKNOWN
Definition: ata_shared.h:85
@ CONN_STATUS_NO_DEVICE
Definition: ata_shared.h:84
#define ATA_MAX_TRANSFER_LENGTH
Definition: ata_shared.h:26
enum _ATA_CONNECTION_STATUS ATA_CONNECTION_STATUS
#define IDE_STATUS_BUSY
Definition: atapi.h:132
#define IDE_DC_RESET_CONTROLLER
Definition: atapi.h:146
#define IDE_STATUS_DRQ
Definition: atapi.h:128
#define IDE_DC_DISABLE_INTERRUPTS
Definition: atapi.h:145
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
_In_ PCHAR _In_ ULONG DeviceNumber
Definition: classpnp.h:1230
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define INFO
Definition: debug.h:89
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define ATA_TIME_BUSY_RESET
10 s
Definition: hwidep.h:72
#define ATA_WRITE(Port, Value)
Definition: hwidep.h:80
#define ATA_READ_BLOCK_16(Port, Buffer, Count)
Definition: hwidep.h:92
#define IDE_DC_ALWAYS
Definition: hwidep.h:54
#define ATA_TIME_RESET_SELECT
2 s
Definition: hwidep.h:73
#define ATA_TIME_BUSY_SELECT
20 ms
Definition: hwidep.h:69
#define ATA_READ(Port)
Definition: hwidep.h:89
#define IDE_DRIVE_SELECT
Definition: hwidep.h:56
#define KeStallExecutionProcessor(MicroSeconds)
Definition: precomp.h:27
ULONG DeviceCount
Definition: mpu401.c:26
#define _In_
Definition: no_sal2.h:158
#define PC98_ATA_BANK
Definition: pata.h:28
FORCEINLINE VOID ATA_SELECT_DEVICE(_In_ PCHANNEL_DATA_PATA ChanData, _In_ UCHAR DeviceNumber, _In_ UCHAR DeviceSelect)
Definition: pata.h:271
FORCEINLINE UCHAR ATA_WAIT(_In_ PCHANNEL_DATA_PATA ChanData, _In_range_(>, 0) ULONG Timeout, _In_ UCHAR Mask, _In_ UCHAR Value)
Definition: pata.h:301
static BOOLEAN PataIsDevicePresent(_In_ PCHANNEL_DATA_PATA ChanData, _In_ ULONG DeviceNumber)
Definition: pata_hw.c:16
static VOID PataDrainDeviceBuffer(_In_ PCHANNEL_DATA_PATA ChanData)
Definition: pata_hw.c:61
static VOID PataIssueSoftwareReset(_In_ PCHANNEL_DATA_PATA ChanData)
Definition: pata_hw.c:48
ULONG PataChannelGetMaximumDeviceCount(_In_ PVOID ChannelContext)
Definition: pata_hw.c:87
VOID PciIdeDmaStop(_In_ PCHANNEL_DATA_PATA ChanData)
Definition: pata_io.c:247
#define WRITE_PORT_UCHAR(p, d)
Definition: pc98vid.h:21
VOID AtaSleep(VOID)
Definition: pciidex.c:100
#define CHANNEL_FLAG_NO_SLAVE
Definition: pciidex.h:270
CHANNEL_IDENTIFY_DEVICE PataIdentifyDevice
Definition: pciidex.h:690
CHANNEL_ENUMERATE_CHANNEL PataEnumerateChannel
Definition: pciidex.h:689
#define CHANNEL_FLAG_CBUS
Definition: pciidex.h:283
CHANNEL_RESET_CHANNEL PataResetChannel
Definition: pciidex.h:688
unsigned short USHORT
Definition: pedump.c:61
DECLSPEC_NOINLINE_FROM_PAGED VOID AtaChanEnableInterruptsSync(_In_ PVOID ChannelContext, _In_ BOOLEAN Enable)
Definition: fdo.c:62
PCHANNEL_READ_STATUS ReadStatus
Definition: pciidex.h:299
BOOLEAN IsPollingActive
Definition: pciidex.h:311
IDE_REGISTERS Regs
Definition: pciidex.h:302
IDE_REG ByteCountLow
Definition: hwidep.h:122
unsigned char UCHAR
Definition: typedefs.h:53
uint16_t * PUSHORT
Definition: typedefs.h:56
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59