Reactos
1/*
2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/atapi/atapi.h
5 * PURPOSE: ATAPI IDE miniport driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
7 */
8
9#include <srb.h>
10#include <scsi.h>
11
12//
13// IDE register definition
14//
15
16typedef struct _IDE_REGISTERS_1 {
17 USHORT Data;
18 UCHAR BlockCount;
19 UCHAR BlockNumber;
20 UCHAR CylinderLow;
21 UCHAR CylinderHigh;
22 UCHAR DriveSelect;
23 UCHAR Command;
24} IDE_REGISTERS_1, *PIDE_REGISTERS_1;
25
26typedef struct _IDE_REGISTERS_2 {
27 UCHAR AlternateStatus;
28 UCHAR DriveAddress;
29} IDE_REGISTERS_2, *PIDE_REGISTERS_2;
30
31typedef struct _IDE_REGISTERS_3 {
32 ULONG Data;
33 UCHAR Others[4];
34} IDE_REGISTERS_3, *PIDE_REGISTERS_3;
35
36//
37// Device Extension Device Flags
38//
39
40#define DFLAGS_DEVICE_PRESENT 0x0001 // Indicates that some device is present.
41#define DFLAGS_ATAPI_DEVICE 0x0002 // Indicates whether Atapi commands can be used.
42#define DFLAGS_TAPE_DEVICE 0x0004 // Indicates whether this is a tape device.
43#define DFLAGS_INT_DRQ 0x0008 // Indicates whether device interrupts as DRQ is set after
44 // receiving Atapi Packet Command
45#define DFLAGS_REMOVABLE_DRIVE 0x0010 // Indicates that the drive has the 'removable' bit set in
46 // identify data (offset 128)
47#define DFLAGS_MEDIA_STATUS_ENABLED 0x0020 // Media status notification enabled
48#define DFLAGS_ATAPI_CHANGER 0x0040 // Indicates atapi 2.5 changer present.
49#define DFLAGS_SANYO_ATAPI_CHANGER 0x0080 // Indicates multi-platter device, not conforming to the 2.5 spec.
50#define DFLAGS_CHANGER_INITED 0x0100 // Indicates that the init path for changers has already been done.
51//
52// Used to disable 'advanced' features.
53//
54
55#define MAX_ERRORS 4
56
57//
58// ATAPI command definitions
59//
60
61#define ATAPI_MODE_SENSE 0x5A
62#define ATAPI_MODE_SELECT 0x55
63#define ATAPI_FORMAT_UNIT 0x24
64
65//
66// ATAPI Command Descriptor Block
67//
68
69typedef struct _MODE_SENSE_10 {
70 UCHAR OperationCode;
71 UCHAR Reserved1;
72 UCHAR PageCode : 6;
73 UCHAR Pc : 2;
74 UCHAR Reserved2[4];
75 UCHAR ParameterListLengthMsb;
76 UCHAR ParameterListLengthLsb;
77 UCHAR Reserved3[3];
78} MODE_SENSE_10, *PMODE_SENSE_10;
79
80typedef struct _MODE_SELECT_10 {
81 UCHAR OperationCode;
82 UCHAR Reserved1 : 4;
83 UCHAR PFBit : 1;
84 UCHAR Reserved2 : 3;
85 UCHAR Reserved3[5];
86 UCHAR ParameterListLengthMsb;
87 UCHAR ParameterListLengthLsb;
88 UCHAR Reserved4[3];
89} MODE_SELECT_10, *PMODE_SELECT_10;
90
91typedef struct _MODE_PARAMETER_HEADER_10 {
92 UCHAR ModeDataLengthMsb;
93 UCHAR ModeDataLengthLsb;
94 UCHAR MediumType;
95 UCHAR Reserved[5];
96}MODE_PARAMETER_HEADER_10, *PMODE_PARAMETER_HEADER_10;
97
98//
99// IDE command definitions
100//
101
102#define IDE_COMMAND_ATAPI_RESET 0x08
103#define IDE_COMMAND_RECALIBRATE 0x10
104#define IDE_COMMAND_READ 0x20
105#define IDE_COMMAND_WRITE 0x30
106#define IDE_COMMAND_VERIFY 0x40
107#define IDE_COMMAND_SEEK 0x70
108#define IDE_COMMAND_SET_DRIVE_PARAMETERS 0x91
109#define IDE_COMMAND_ATAPI_PACKET 0xA0
110#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1
111#define IDE_COMMAND_READ_MULTIPLE 0xC4
112#define IDE_COMMAND_WRITE_MULTIPLE 0xC5
113#define IDE_COMMAND_SET_MULTIPLE 0xC6
114#define IDE_COMMAND_READ_DMA 0xC8
115#define IDE_COMMAND_WRITE_DMA 0xCA
116#define IDE_COMMAND_GET_MEDIA_STATUS 0xDA
117#define IDE_COMMAND_ENABLE_MEDIA_STATUS 0xEF
118#define IDE_COMMAND_IDENTIFY 0xEC
119#define IDE_COMMAND_MEDIA_EJECT 0xED
120
121//
122// IDE status definitions
123//
124
125#define IDE_STATUS_ERROR 0x01
126#define IDE_STATUS_INDEX 0x02
127#define IDE_STATUS_CORRECTED_ERROR 0x04
128#define IDE_STATUS_DRQ 0x08
129#define IDE_STATUS_DSC 0x10
130#define IDE_STATUS_DRDY 0x40
131#define IDE_STATUS_IDLE 0x50
132#define IDE_STATUS_BUSY 0x80
133
134//
135// IDE drive select/head definitions
136//
137
138#define IDE_DRIVE_SELECT_1 0xA0
139#define IDE_DRIVE_SELECT_2 0x10
140
141//
142// IDE drive control definitions
143//
144
145#define IDE_DC_DISABLE_INTERRUPTS 0x02
146#define IDE_DC_RESET_CONTROLLER 0x04
147#define IDE_DC_REENABLE_CONTROLLER 0x00
148
149//
150// IDE error definitions
151//
152
153#define IDE_ERROR_BAD_BLOCK 0x80
154#define IDE_ERROR_DATA_ERROR 0x40
155#define IDE_ERROR_MEDIA_CHANGE 0x20
156#define IDE_ERROR_ID_NOT_FOUND 0x10
157#define IDE_ERROR_MEDIA_CHANGE_REQ 0x08
158#define IDE_ERROR_COMMAND_ABORTED 0x04
159#define IDE_ERROR_END_OF_MEDIA 0x02
160#define IDE_ERROR_ILLEGAL_LENGTH 0x01
161
162//
163// ATAPI register definition
164//
165
166typedef struct _ATAPI_REGISTERS_1 {
167 USHORT Data;
168 UCHAR InterruptReason;
169 UCHAR Unused1;
170 UCHAR ByteCountLow;
171 UCHAR ByteCountHigh;
172 UCHAR DriveSelect;
173 UCHAR Command;
174} ATAPI_REGISTERS_1, *PATAPI_REGISTERS_1;
175
176typedef struct _ATAPI_REGISTERS_2 {
177 UCHAR AlternateStatus;
178 UCHAR DriveAddress;
179} ATAPI_REGISTERS_2, *PATAPI_REGISTERS_2;
180
181//
182// ATAPI interrupt reasons
183//
184
185#define ATAPI_IR_COD 0x01
186#define ATAPI_IR_IO 0x02
187
188//
189// IDENTIFY data
190//
191
192typedef struct _IDENTIFY_DATA {
193 USHORT GeneralConfiguration; // 00 00
194 USHORT NumberOfCylinders; // 02 1
195 USHORT Reserved1; // 04 2
196 USHORT NumberOfHeads; // 06 3
197 USHORT UnformattedBytesPerTrack; // 08 4
198 USHORT UnformattedBytesPerSector; // 0A 5
199 USHORT SectorsPerTrack; // 0C 6
200 USHORT VendorUnique1[3]; // 0E 7-9
201 USHORT SerialNumber[10]; // 14 10-19
202 USHORT BufferType; // 28 20
203 USHORT BufferSectorSize; // 2A 21
204 USHORT NumberOfEccBytes; // 2C 22
205 USHORT FirmwareRevision[4]; // 2E 23-26
206 USHORT ModelNumber[20]; // 36 27-46
207 UCHAR MaximumBlockTransfer; // 5E 47
208 UCHAR VendorUnique2; // 5F
209 USHORT DoubleWordIo; // 60 48
210 USHORT Capabilities; // 62 49
211 USHORT Reserved2; // 64 50
212 UCHAR VendorUnique3; // 66 51
213 UCHAR PioCycleTimingMode; // 67
214 UCHAR VendorUnique4; // 68 52
215 UCHAR DmaCycleTimingMode; // 69
216 USHORT TranslationFieldsValid:1; // 6A 53
217 USHORT Reserved3:15;
218 USHORT NumberOfCurrentCylinders; // 6C 54
219 USHORT NumberOfCurrentHeads; // 6E 55
220 USHORT CurrentSectorsPerTrack; // 70 56
221 ULONG CurrentSectorCapacity; // 72 57-58
222 USHORT CurrentMultiSectorSetting; // 59
223 ULONG UserAddressableSectors; // 60-61
224 USHORT SingleWordDMASupport : 8; // 62
225 USHORT SingleWordDMAActive : 8;
226 USHORT MultiWordDMASupport : 8; // 63
227 USHORT MultiWordDMAActive : 8;
228 USHORT AdvancedPIOModes : 8; // 64
229 USHORT Reserved4 : 8;
230 USHORT MinimumMWXferCycleTime; // 65
231 USHORT RecommendedMWXferCycleTime; // 66
232 USHORT MinimumPIOCycleTime; // 67
233 USHORT MinimumPIOCycleTimeIORDY; // 68
234 USHORT Reserved5[2]; // 69-70
235 USHORT ReleaseTimeOverlapped; // 71
236 USHORT ReleaseTimeServiceCommand; // 72
237 USHORT MajorRevision; // 73
238 USHORT MinorRevision; // 74
239 USHORT Reserved6[50]; // 75-126
240 USHORT SpecialFunctionsEnabled; // 127
241 USHORT Reserved7[128]; // 128-255
242} IDENTIFY_DATA, *PIDENTIFY_DATA;
243
244//
245// Identify data without the Reserved4.
246//
247
248typedef struct _IDENTIFY_DATA2 {
249 USHORT GeneralConfiguration; // 00
250 USHORT NumberOfCylinders; // 02
251 USHORT Reserved1; // 04
252 USHORT NumberOfHeads; // 06
253 USHORT UnformattedBytesPerTrack; // 08
254 USHORT UnformattedBytesPerSector; // 0A
255 USHORT SectorsPerTrack; // 0C
256 USHORT VendorUnique1[3]; // 0E
257 USHORT SerialNumber[10]; // 14
258 USHORT BufferType; // 28
259 USHORT BufferSectorSize; // 2A
260 USHORT NumberOfEccBytes; // 2C
261 USHORT FirmwareRevision[4]; // 2E
262 USHORT ModelNumber[20]; // 36
263 UCHAR MaximumBlockTransfer; // 5E
264 UCHAR VendorUnique2; // 5F
265 USHORT DoubleWordIo; // 60
266 USHORT Capabilities; // 62
267 USHORT Reserved2; // 64
268 UCHAR VendorUnique3; // 66
269 UCHAR PioCycleTimingMode; // 67
270 UCHAR VendorUnique4; // 68
271 UCHAR DmaCycleTimingMode; // 69
272 USHORT TranslationFieldsValid:1; // 6A
273 USHORT Reserved3:15;
274 USHORT NumberOfCurrentCylinders; // 6C
275 USHORT NumberOfCurrentHeads; // 6E
276 USHORT CurrentSectorsPerTrack; // 70
277 ULONG CurrentSectorCapacity; // 72
278} IDENTIFY_DATA2, *PIDENTIFY_DATA2;
279
280#define IDENTIFY_DATA_SIZE sizeof(IDENTIFY_DATA)
281
282//
283// IDENTIFY capability bit definitions.
284//
285
286#define IDENTIFY_CAPABILITIES_DMA_SUPPORTED 0x0100
287#define IDENTIFY_CAPABILITIES_LBA_SUPPORTED 0x0200
288
289//
290// IDENTIFY DMA timing cycle modes.
291//
292
293#define IDENTIFY_DMA_CYCLES_MODE_0 0x00
294#define IDENTIFY_DMA_CYCLES_MODE_1 0x01
295#define IDENTIFY_DMA_CYCLES_MODE_2 0x02
296
297
298typedef struct _BROKEN_CONTROLLER_INFORMATION {
299 PCHAR VendorId;
300 ULONG VendorIdLength;
301 PCHAR DeviceId;
302 ULONG DeviceIdLength;
303}BROKEN_CONTROLLER_INFORMATION, *PBROKEN_CONTROLLER_INFORMATION;
304
305BROKEN_CONTROLLER_INFORMATION const BrokenAdapters[] = {
306 { "1095", 4, "0640", 4},
307 { "1039", 4, "0601", 4}
308};
309
310#define BROKEN_ADAPTERS (sizeof(BrokenAdapters) / sizeof(BROKEN_CONTROLLER_INFORMATION))
311
312typedef struct _NATIVE_MODE_CONTROLLER_INFORMATION {
313 PCHAR VendorId;
314 ULONG VendorIdLength;
315 PCHAR DeviceId;
316 ULONG DeviceIdLength;
317}NATIVE_MODE_CONTROLLER_INFORMATION, *PNATIVE_MODE_CONTROLLER_INFORMATION;
318
319NATIVE_MODE_CONTROLLER_INFORMATION const NativeModeAdapters[] = {
320 { "10ad", 4, "0105", 4}
321};
322#define NUM_NATIVE_MODE_ADAPTERS (sizeof(NativeModeAdapters) / sizeof(NATIVE_MODE_CONTROLLER_INFORMATION))
323
324//
325// Beautification macros
326//
327
328#define GetStatus(BaseIoAddress, Status) \
329 Status = ScsiPortReadPortUchar(&BaseIoAddress->AlternateStatus);
330
331#define GetBaseStatus(BaseIoAddress, Status) \
332 Status = ScsiPortReadPortUchar(&BaseIoAddress->Command);
333
334#define WriteCommand(BaseIoAddress, Command) \
335 ScsiPortWritePortUchar(&BaseIoAddress->Command, Command);
336
337
338
339#define ReadBuffer(BaseIoAddress, Buffer, Count) \
340 ScsiPortReadPortBufferUshort(&BaseIoAddress->Data, \
341 Buffer, \
342 Count);
343
344#define WriteBuffer(BaseIoAddress, Buffer, Count) \
345 ScsiPortWritePortBufferUshort(&BaseIoAddress->Data, \
346 Buffer, \
347 Count);
348
349#define ReadBuffer2(BaseIoAddress, Buffer, Count) \
350 ScsiPortReadPortBufferUlong(&BaseIoAddress->Data, \
351 Buffer, \
352 Count);
353
354#define WriteBuffer2(BaseIoAddress, Buffer, Count) \
355 ScsiPortWritePortBufferUlong(&BaseIoAddress->Data, \
356 Buffer, \
357 Count);
358
359#define WaitOnBusy(BaseIoAddress, Status) \
360{ \
361 ULONG i; \
362 for (i=0; i<20000; i++) { \
363 GetStatus(BaseIoAddress, Status); \
364 if (Status & IDE_STATUS_BUSY) { \
365 ScsiPortStallExecution(150); \
366 continue; \
367 } else { \
368 break; \
369 } \
370 } \
371}
372
373#define WaitOnBaseBusy(BaseIoAddress, Status) \
374{ \
375 ULONG i; \
376 for (i=0; i<20000; i++) { \
377 GetBaseStatus(BaseIoAddress, Status); \
378 if (Status & IDE_STATUS_BUSY) { \
379 ScsiPortStallExecution(150); \
380 continue; \
381 } else { \
382 break; \
383 } \
384 } \
385}
386
387#define WaitForDrq(BaseIoAddress, Status) \
388{ \
389 ULONG i; \
390 for (i=0; i<1000; i++) { \
391 GetStatus(BaseIoAddress, Status); \
392 if (Status & IDE_STATUS_BUSY) { \
393 ScsiPortStallExecution(100); \
394 } else if (Status & IDE_STATUS_DRQ) { \
395 break; \
396 } else { \
397 ScsiPortStallExecution(200); \
398 } \
399 } \
400}
401
402
403#define WaitShortForDrq(BaseIoAddress, Status) \
404{ \
405 ULONG i; \
406 for (i=0; i<2; i++) { \
407 GetStatus(BaseIoAddress, Status); \
408 if (Status & IDE_STATUS_BUSY) { \
409 ScsiPortStallExecution(100); \
410 } else if (Status & IDE_STATUS_DRQ) { \
411 break; \
412 } else { \
413 ScsiPortStallExecution(100); \
414 } \
415 } \
416}
417
418#define AtapiSoftReset(BaseIoAddress,DeviceNumber) \
419{\
420 UCHAR statusByte; \
421 ULONG i = 1000*1000;\
422 ScsiPortWritePortUchar(&BaseIoAddress->DriveSelect,(UCHAR)(((DeviceNumber & 0x1) << 4) | 0xA0)); \
423 ScsiPortStallExecution(500);\
424 ScsiPortWritePortUchar(&BaseIoAddress->Command, IDE_COMMAND_ATAPI_RESET); \
425 while ((ScsiPortReadPortUchar(&BaseIoAddress->Command) & IDE_STATUS_BUSY) && i--)\
426 ScsiPortStallExecution(30);\
427 ScsiPortWritePortUchar(&BaseIoAddress->DriveSelect,(UCHAR)((DeviceNumber << 4) | 0xA0)); \
428 WaitOnBusy( ((PIDE_REGISTERS_2)((PUCHAR)BaseIoAddress + 0x206)), statusByte); \
429 ScsiPortStallExecution(500);\
430}
431
432#define IdeHardReset(BaseIoAddress,result) \
433{\
434 UCHAR statusByte;\
435 ULONG i;\
436 ScsiPortWritePortUchar(&BaseIoAddress->AlternateStatus,IDE_DC_RESET_CONTROLLER );\
437 ScsiPortStallExecution(50 * 1000);\
438 ScsiPortWritePortUchar(&BaseIoAddress->AlternateStatus,IDE_DC_REENABLE_CONTROLLER);\
439 for (i = 0; i < 1000 * 1000; i++) {\
440 statusByte = ScsiPortReadPortUchar(&BaseIoAddress->AlternateStatus);\
441 if (statusByte != IDE_STATUS_IDLE && statusByte != 0x0) {\
442 ScsiPortStallExecution(5);\
443 } else {\
444 break;\
445 }\
446 }\
447 if (i == 1000*1000) {\
448 result = FALSE;\
449 }\
450 result = TRUE;\
451}
452
453#define IS_RDP(OperationCode)\
454 ((OperationCode == SCSIOP_ERASE)||\
455 (OperationCode == SCSIOP_LOAD_UNLOAD)||\
456 (OperationCode == SCSIOP_LOCATE)||\
457 (OperationCode == SCSIOP_REWIND) ||\
458 (OperationCode == SCSIOP_SPACE)||\
459 (OperationCode == SCSIOP_SEEK)||\
460 (OperationCode == SCSIOP_WRITE_FILEMARKS))
461