Revert "[CMAKE] Make unattended bootcd configurable via cmake"
[reactos.git] / boot / freeldr / freeldr / arch / drivers / hwide.c
1 /*
2 * PROJECT: FreeLoader
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: ATA/ATAPI programmed I/O driver.
5 * COPYRIGHT: Copyright 2019-2020 Dmitry Borisov (di.sean@protonmail.com)
6 */
7
8 /* INCLUDES *******************************************************************/
9
10 #include <freeldr.h>
11 #include <hwide.h>
12
13 /* DDK */
14 #include <ata.h>
15 #include <scsi.h>
16
17 #include <debug.h>
18 DBG_DEFAULT_CHANNEL(DISK);
19
20 /* GLOBALS ********************************************************************/
21
22 #define TAG_ATA_DEVICE 'DatA'
23 #define ATAPI_PACKET_SIZE(IdentifyData) (IdentifyData.AtapiCmdSize ? 16 : 12)
24 #define ATA_STATUS_TIMEOUT 31e5
25
26 #define AtaWritePort(Channel, Port, Data) \
27 WRITE_PORT_UCHAR(UlongToPtr(BaseArray[(Channel)] + (Port)), (Data))
28
29 #define AtaReadPort(Channel, Port) \
30 READ_PORT_UCHAR(UlongToPtr(BaseArray[(Channel)] + (Port)))
31
32 #define AtaWriteBuffer(Channel, Buffer, Count) \
33 WRITE_PORT_BUFFER_USHORT(UlongToPtr(BaseArray[(Channel)] + IDX_IO1_o_Data), \
34 (PUSHORT)(Buffer), (Count)/sizeof(USHORT))
35
36 #define AtaReadBuffer(Channel, Buffer, Count) \
37 READ_PORT_BUFFER_USHORT(UlongToPtr(BaseArray[(Channel)] + IDX_IO1_i_Data), \
38 (PUSHORT)(Buffer), (Count)/sizeof(USHORT))
39
40 /* IDE/ATA Channels base - Primary, Secondary, Tertiary, Quaternary */
41 static const ULONG BaseArray[] =
42 {
43 #if defined(SARCH_XBOX)
44 0x1F0
45 #elif defined(SARCH_PC98)
46 0x640, 0x640
47 #else
48 0x1F0, 0x170, 0x1E8, 0x168
49 #endif
50 };
51
52 #define MAX_CHANNELS RTL_NUMBER_OF(BaseArray)
53 #define MAX_DEVICES 2 /* Master/Slave */
54
55 static PDEVICE_UNIT Units[MAX_CHANNELS * MAX_DEVICES];
56
57 /* PRIVATE PROTOTYPES *********************************************************/
58
59 static
60 BOOLEAN
61 WaitForFlags(
62 IN UCHAR Channel,
63 IN UCHAR Flags,
64 IN UCHAR ExpectedValue,
65 IN ULONG Timeout
66 );
67
68 static
69 BOOLEAN
70 WaitForFlagsOr(
71 IN UCHAR Channel,
72 IN UCHAR FirstValue,
73 IN UCHAR SecondValue,
74 IN ULONG Timeout
75 );
76
77 static
78 BOOLEAN
79 WaitForBusy(
80 IN UCHAR Channel,
81 IN ULONG Timeout
82 );
83
84 static
85 VOID
86 SelectDevice(
87 IN UCHAR Channel,
88 IN UCHAR DeviceNumber
89 );
90
91 static
92 BOOLEAN
93 IdentifyDevice(
94 IN UCHAR Channel,
95 IN UCHAR DeviceNumber,
96 OUT PDEVICE_UNIT *DeviceUnit
97 );
98
99 static
100 BOOLEAN
101 AtapiRequestSense(
102 IN PDEVICE_UNIT DeviceUnit,
103 OUT PSENSE_DATA SenseData
104 );
105
106 static
107 VOID
108 AtapiPrintSenseData(
109 IN PDEVICE_UNIT DeviceUnit
110 );
111
112 static
113 BOOLEAN
114 AtapiReadyCheck(
115 IN OUT PDEVICE_UNIT DeviceUnit
116 );
117
118 static
119 BOOLEAN
120 AtapiReadLogicalSectorLBA(
121 IN PDEVICE_UNIT DeviceUnit,
122 IN ULONGLONG SectorNumber,
123 OUT PVOID Buffer
124 );
125
126 static
127 BOOLEAN
128 AtaReadLogicalSectorsLBA(
129 IN PDEVICE_UNIT DeviceUnit,
130 IN ULONGLONG SectorNumber,
131 IN ULONG SectorCount,
132 OUT PVOID Buffer
133 );
134
135 /* FUNCTIONS ******************************************************************/
136
137 /* Don't call this before running the system timer calibration and MM initialization */
138 BOOLEAN
139 AtaInit(OUT PUCHAR DetectedCount)
140 {
141 UCHAR Channel, DeviceNumber;
142 PDEVICE_UNIT DeviceUnit = NULL;
143
144 TRACE("AtaInit()\n");
145
146 *DetectedCount = 0;
147
148 RtlZeroMemory(&Units, sizeof(Units));
149
150 /* Detect and enumerate ATA/ATAPI devices */
151 for (Channel = 0; Channel < MAX_CHANNELS; ++Channel)
152 {
153 for (DeviceNumber = 0; DeviceNumber < MAX_DEVICES; ++DeviceNumber)
154 {
155 if (IdentifyDevice(Channel, DeviceNumber, &DeviceUnit))
156 {
157 Units[(*DetectedCount)++] = DeviceUnit;
158 }
159 }
160 }
161
162 return (*DetectedCount > 0);
163 }
164
165 VOID
166 AtaFree(VOID)
167 {
168 UCHAR i;
169
170 for (i = 0; i < RTL_NUMBER_OF(Units); ++i)
171 {
172 if (Units[i])
173 FrLdrTempFree(Units[i], TAG_ATA_DEVICE);
174 }
175 }
176
177 PDEVICE_UNIT
178 AtaGetDevice(IN UCHAR UnitNumber)
179 {
180 if (UnitNumber < RTL_NUMBER_OF(Units))
181 return Units[UnitNumber];
182 else
183 return NULL;
184 }
185
186 BOOLEAN
187 AtaAtapiReadLogicalSectorsLBA(
188 IN OUT PDEVICE_UNIT DeviceUnit,
189 IN ULONGLONG SectorNumber,
190 IN ULONG SectorCount,
191 OUT PVOID Buffer)
192 {
193 UCHAR RetryCount;
194 BOOLEAN Success;
195
196 if (DeviceUnit == NULL || SectorCount == 0)
197 return FALSE;
198
199 if (DeviceUnit->Flags & ATA_DEVICE_ATAPI)
200 {
201 if ((DeviceUnit->Flags & ATA_DEVICE_NO_MEDIA) || (DeviceUnit->Flags & ATA_DEVICE_NOT_READY))
202 {
203 /* Retry 4 times */
204 for (RetryCount = 0; RetryCount < 4; ++RetryCount)
205 {
206 /* Make the device ready */
207 if (AtapiReadyCheck(DeviceUnit))
208 break;
209 }
210 if (RetryCount >= 4)
211 {
212 ERR("AtaAtapiReadLogicalSectorsLBA(): Device not ready.\n");
213 return FALSE;
214 }
215 }
216 if (SectorNumber + SectorCount > DeviceUnit->TotalSectors + 1)
217 {
218 ERR("AtaAtapiReadLogicalSectorsLBA(): Attempt to read more than there is to read.\n");
219 return FALSE;
220 }
221
222 while (SectorCount > 0)
223 {
224 /* Read a single sector */
225 Success = AtapiReadLogicalSectorLBA(DeviceUnit, SectorNumber, Buffer);
226 if (!Success)
227 return FALSE;
228
229 --SectorCount;
230 ++SectorNumber;
231 Buffer = (PVOID)((ULONG_PTR)Buffer + DeviceUnit->SectorSize);
232 }
233 }
234 else
235 {
236 /* Retry 3 times */
237 for (RetryCount = 0; RetryCount < 3; ++RetryCount)
238 {
239 /* Read a multiple sectors */
240 Success = AtaReadLogicalSectorsLBA(DeviceUnit, SectorNumber, SectorCount, Buffer);
241 if (Success)
242 return TRUE;
243 }
244 return FALSE;
245 }
246
247 return TRUE;
248 }
249
250 static
251 BOOLEAN
252 AtaReadLogicalSectorsLBA(
253 IN PDEVICE_UNIT DeviceUnit,
254 IN ULONGLONG SectorNumber,
255 IN ULONG SectorCount,
256 OUT PVOID Buffer)
257 {
258 UCHAR Command;
259 ULONG ChsTemp;
260 USHORT Cylinder;
261 UCHAR Head;
262 UCHAR Sector;
263 ULONG BlockCount;
264 ULONG RemainingBlockCount;
265 ULONGLONG Lba;
266 BOOLEAN UseLBA48;
267
268 UseLBA48 = (DeviceUnit->Flags & ATA_DEVICE_LBA48) &&
269 (((SectorNumber + SectorCount) >= UINT64_C(0x0FFFFF80)) || SectorCount > 256);
270
271 while (SectorCount > 0)
272 {
273 /* Prevent sector count overflow, divide it into maximum possible chunks and loop each one */
274 if (UseLBA48)
275 BlockCount = min(SectorCount, USHRT_MAX);
276 else
277 BlockCount = min(SectorCount, UCHAR_MAX);
278
279 /* Convert LBA into a format CHS if needed */
280 if (DeviceUnit->Flags & ATA_DEVICE_CHS)
281 {
282 ChsTemp = DeviceUnit->IdentifyData.SectorsPerTrack * DeviceUnit->IdentifyData.NumberOfHeads;
283 if (ChsTemp)
284 {
285 Cylinder = SectorNumber / ChsTemp;
286 Head = (SectorNumber % ChsTemp) / DeviceUnit->IdentifyData.SectorsPerTrack;
287 Sector = (SectorNumber % DeviceUnit->IdentifyData.SectorsPerTrack) + 1;
288 }
289 else
290 {
291 Cylinder = 0;
292 Head = 0;
293 Sector = 1;
294 }
295 Lba = (Sector & 0xFF) | ((Cylinder & 0xFFFFF) << 8) | ((Head & 0x0F) << 24);
296 }
297 else
298 {
299 Lba = SectorNumber;
300 }
301
302 /* Select the drive */
303 SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber);
304 if (!WaitForBusy(DeviceUnit->Channel, ATA_STATUS_TIMEOUT))
305 {
306 ERR("AtaReadLogicalSectorsLBA() failed. Device is busy.\n");
307 return FALSE;
308 }
309
310 /* Disable interrupts */
311 AtaWritePort(DeviceUnit->Channel, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS);
312 StallExecutionProcessor(1);
313
314 if (UseLBA48)
315 {
316 /* FIFO */
317 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Feature, 0);
318 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Feature, ATA_PIO);
319 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockCount, (BlockCount >> 8) & 0xFF);
320 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockCount, BlockCount & 0xFF);
321 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockNumber, (Lba >> 24) & 0xFF);
322 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockNumber, Lba & 0xFF);
323 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderLow, (Lba >> 32) & 0xFF);
324 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderLow, (Lba >> 8) & 0xFF);
325 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderHigh, (Lba >> 40) & 0xFF);
326 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderHigh, (Lba >> 16) & 0xFF);
327 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_DriveSelect,
328 IDE_USE_LBA | (DeviceUnit->DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1));
329 Command = IDE_COMMAND_READ_EXT;
330 }
331 else
332 {
333 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Feature, ATA_PIO);
334 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockCount, BlockCount & 0xFF);
335 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockNumber, Lba & 0xFF);
336 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderLow, (Lba >> 8) & 0xFF);
337 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderHigh, (Lba >> 16) & 0xFF);
338 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_DriveSelect,
339 ((Lba >> 24) & 0x0F) |
340 (DeviceUnit->Flags & ATA_DEVICE_CHS ? 0x00 : IDE_USE_LBA) |
341 (DeviceUnit->DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1));
342 Command = IDE_COMMAND_READ;
343 }
344
345 /* Send read command */
346 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Command, Command);
347 StallExecutionProcessor(5);
348
349 for (RemainingBlockCount = BlockCount; RemainingBlockCount > 0; --RemainingBlockCount)
350 {
351 /* Wait for ready to transfer data block */
352 if (!WaitForFlags(DeviceUnit->Channel, IDE_STATUS_DRQ,
353 IDE_STATUS_DRQ, ATA_STATUS_TIMEOUT))
354 {
355 ERR("AtaReadLogicalSectorsLBA() failed. Status: 0x%02x, Error: 0x%02x\n",
356 AtaReadPort(DeviceUnit->Channel, IDX_IO1_i_Status),
357 AtaReadPort(DeviceUnit->Channel, IDX_IO1_i_Error));
358 return FALSE;
359 }
360
361 /* Transfer the data block */
362 AtaReadBuffer(DeviceUnit->Channel, Buffer, DeviceUnit->SectorSize);
363
364 Buffer = (PVOID)((ULONG_PTR)Buffer + DeviceUnit->SectorSize);
365 }
366
367 SectorNumber += BlockCount;
368 SectorCount -= BlockCount;
369 }
370
371 return TRUE;
372 }
373
374 static
375 BOOLEAN
376 AtaSendAtapiPacket(
377 IN UCHAR Channel,
378 IN PUCHAR AtapiPacket,
379 IN UCHAR PacketSize,
380 IN USHORT ByteCount)
381 {
382 /*
383 * REQUEST SENSE is used by driver to clear the ATAPI 'Bus reset' indication.
384 * TEST UNIT READY doesn't require space for returned data.
385 */
386 UCHAR ExpectedFlagsMask = (AtapiPacket[0] == SCSIOP_REQUEST_SENSE) ?
387 IDE_STATUS_DRDY : (IDE_STATUS_DRQ | IDE_STATUS_DRDY);
388 UCHAR ExpectedFlags = ((AtapiPacket[0] == SCSIOP_TEST_UNIT_READY) ||
389 (AtapiPacket[0] == SCSIOP_REQUEST_SENSE)) ?
390 IDE_STATUS_DRDY : (IDE_STATUS_DRQ | IDE_STATUS_DRDY);
391
392 /* PIO mode */
393 AtaWritePort(Channel, IDX_ATAPI_IO1_o_Feature, ATA_PIO);
394
395 /* Maximum byte count that is to be transferred */
396 AtaWritePort(Channel, IDX_ATAPI_IO1_o_ByteCountLow, ByteCount & 0xFF);
397 AtaWritePort(Channel, IDX_ATAPI_IO1_o_ByteCountHigh, (ByteCount >> 8) & 0xFF);
398
399 /* Prepare to transfer a device command via a command packet */
400 AtaWritePort(Channel, IDX_ATAPI_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
401 StallExecutionProcessor(50);
402 if (!WaitForFlagsOr(Channel, IDE_STATUS_DRQ, IDE_STATUS_DRDY, ATA_STATUS_TIMEOUT))
403 {
404 ERR("AtaSendAtapiPacket(0x%x) failed. A device error occurred Status: 0x%02x, Error: 0x%02x\n",
405 AtapiPacket[0], AtaReadPort(Channel, IDX_ATAPI_IO1_i_Status), AtaReadPort(Channel, IDX_ATAPI_IO1_i_Error));
406 return FALSE;
407 }
408
409 /* Command packet transfer */
410 AtaWriteBuffer(Channel, AtapiPacket, PacketSize);
411 if (!WaitForFlags(Channel, ExpectedFlagsMask, ExpectedFlags, ATA_STATUS_TIMEOUT))
412 {
413 TRACE("AtaSendAtapiPacket(0x%x) failed. An execution error occurred Status: 0x%02x, Error: 0x%02x\n",
414 AtapiPacket[0], AtaReadPort(Channel, IDX_ATAPI_IO1_i_Status), AtaReadPort(Channel, IDX_ATAPI_IO1_i_Error));
415 return FALSE;
416 }
417
418 return TRUE;
419 }
420
421 static
422 BOOLEAN
423 AtapiReadLogicalSectorLBA(
424 IN PDEVICE_UNIT DeviceUnit,
425 IN ULONGLONG SectorNumber,
426 OUT PVOID Buffer)
427 {
428 UCHAR AtapiPacket[16];
429 USHORT DataSize;
430 BOOLEAN Success;
431
432 /* Select the drive */
433 SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber);
434 if (!WaitForBusy(DeviceUnit->Channel, ATA_STATUS_TIMEOUT))
435 {
436 ERR("AtapiReadLogicalSectorLBA() failed. Device is busy!\n");
437 return FALSE;
438 }
439
440 /* Disable interrupts */
441 AtaWritePort(DeviceUnit->Channel, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS);
442 StallExecutionProcessor(1);
443
444 /* Send the SCSI READ command */
445 RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
446 AtapiPacket[0] = SCSIOP_READ;
447 AtapiPacket[2] = (SectorNumber >> 24) & 0xFF;
448 AtapiPacket[3] = (SectorNumber >> 16) & 0xFF;
449 AtapiPacket[4] = (SectorNumber >> 8) & 0xFF;
450 AtapiPacket[5] = SectorNumber & 0xFF;
451 AtapiPacket[8] = 1;
452 Success = AtaSendAtapiPacket(DeviceUnit->Channel,
453 AtapiPacket,
454 ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
455 DeviceUnit->SectorSize);
456 if (!Success)
457 {
458 ERR("AtapiReadLogicalSectorLBA() failed. A read error occurred.\n");
459 AtapiPrintSenseData(DeviceUnit);
460 return FALSE;
461 }
462
463 DataSize = (AtaReadPort(DeviceUnit->Channel, IDX_ATAPI_IO1_i_ByteCountHigh) << 8) |
464 AtaReadPort(DeviceUnit->Channel, IDX_ATAPI_IO1_i_ByteCountLow);
465
466 /* Transfer the data block */
467 AtaReadBuffer(DeviceUnit->Channel, Buffer, DataSize);
468
469 return TRUE;
470 }
471
472 static
473 VOID
474 AtapiCapacityDetect(
475 IN PDEVICE_UNIT DeviceUnit,
476 OUT PULONGLONG TotalSectors,
477 OUT PULONG SectorSize)
478 {
479 UCHAR AtapiPacket[16];
480 UCHAR AtapiCapacity[8];
481
482 /* Send the SCSI READ CAPACITY(10) command */
483 RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
484 AtapiPacket[0] = SCSIOP_READ_CAPACITY;
485 if (AtaSendAtapiPacket(DeviceUnit->Channel, AtapiPacket, ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData), 8))
486 {
487 AtaReadBuffer(DeviceUnit->Channel, &AtapiCapacity, 8);
488
489 *TotalSectors = (AtapiCapacity[0] << 24) | (AtapiCapacity[1] << 16) |
490 (AtapiCapacity[2] << 8) | AtapiCapacity[3];
491
492 *SectorSize = (AtapiCapacity[4] << 24) | (AtapiCapacity[5] << 16) |
493 (AtapiCapacity[6] << 8) | AtapiCapacity[7];
494
495 /* If device reports a non-zero block length, reset to defaults (we use READ command instead of READ CD) */
496 if (*SectorSize != 0)
497 *SectorSize = 2048;
498 }
499 else
500 {
501 *TotalSectors = 0;
502 *SectorSize = 0;
503
504 AtapiPrintSenseData(DeviceUnit);
505 }
506 }
507
508 static
509 BOOLEAN
510 AtapiRequestSense(
511 IN PDEVICE_UNIT DeviceUnit,
512 OUT PSENSE_DATA SenseData)
513 {
514 UCHAR AtapiPacket[16];
515 BOOLEAN Success;
516
517 RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
518 RtlZeroMemory(SenseData, sizeof(SENSE_DATA));
519 AtapiPacket[0] = SCSIOP_REQUEST_SENSE;
520 AtapiPacket[4] = SENSE_BUFFER_SIZE;
521 Success = AtaSendAtapiPacket(DeviceUnit->Channel,
522 AtapiPacket,
523 ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
524 SENSE_BUFFER_SIZE);
525 if (Success)
526 {
527 AtaReadBuffer(DeviceUnit->Channel, SenseData, SENSE_BUFFER_SIZE);
528 return TRUE;
529 }
530 else
531 {
532 ERR("Cannot read the sense data.\n");
533 return FALSE;
534 }
535 }
536
537 static
538 VOID
539 AtapiPrintSenseData(IN PDEVICE_UNIT DeviceUnit)
540 {
541 SENSE_DATA SenseData;
542
543 if (AtapiRequestSense(DeviceUnit, &SenseData))
544 {
545 ERR("SK 0x%x, ASC 0x%x, ASCQ 0x%x\n",
546 SenseData.SenseKey,
547 SenseData.AdditionalSenseCode,
548 SenseData.AdditionalSenseCodeQualifier);
549 }
550 }
551
552 static
553 BOOLEAN
554 AtapiReadyCheck(IN OUT PDEVICE_UNIT DeviceUnit)
555 {
556 UCHAR AtapiPacket[16];
557 UCHAR DummyData[MAXIMUM_CDROM_SIZE];
558 SENSE_DATA SenseData;
559 BOOLEAN Success;
560
561 /* Select the drive */
562 SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber);
563 if (!WaitForBusy(DeviceUnit->Channel, ATA_STATUS_TIMEOUT))
564 return FALSE;
565
566 /* Send the SCSI TEST UNIT READY command */
567 RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
568 AtapiPacket[0] = SCSIOP_TEST_UNIT_READY;
569 AtaSendAtapiPacket(DeviceUnit->Channel,
570 AtapiPacket,
571 ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
572 0);
573
574 if (!AtapiRequestSense(DeviceUnit, &SenseData))
575 return FALSE;
576
577 AtaReadBuffer(DeviceUnit->Channel, &SenseData, SENSE_BUFFER_SIZE);
578 TRACE("SK 0x%x, ASC 0x%x, ASCQ 0x%x\n",
579 SenseData.SenseKey,
580 SenseData.AdditionalSenseCode,
581 SenseData.AdditionalSenseCodeQualifier);
582
583 if (SenseData.SenseKey == SCSI_SENSE_NOT_READY)
584 {
585 if (SenseData.AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)
586 {
587 switch (SenseData.AdditionalSenseCodeQualifier)
588 {
589 case SCSI_SENSEQ_BECOMING_READY:
590 /* Wait until the CD is spun up */
591 StallExecutionProcessor(4e6);
592 return FALSE;
593
594 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
595 /* The drive needs to be spun up, send the SCSI READ TOC command */
596 RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
597 AtapiPacket[0] = SCSIOP_READ_TOC;
598 AtapiPacket[7] = (MAXIMUM_CDROM_SIZE << 8) & 0xFF;
599 AtapiPacket[8] = MAXIMUM_CDROM_SIZE & 0xFF;
600 AtapiPacket[9] = READ_TOC_FORMAT_SESSION << 6;
601 Success = AtaSendAtapiPacket(DeviceUnit->Channel,
602 AtapiPacket,
603 ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
604 MAXIMUM_CDROM_SIZE);
605 if (!Success)
606 {
607 AtapiPrintSenseData(DeviceUnit);
608 return FALSE;
609 }
610
611 AtaReadBuffer(DeviceUnit->Channel, &DummyData, MAXIMUM_CDROM_SIZE);
612 /* fall through */
613
614 default:
615 DeviceUnit->Flags &= ~ATA_DEVICE_NOT_READY;
616 return FALSE;
617
618 }
619 }
620 else if (SenseData.AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)
621 {
622 DeviceUnit->Flags |= ATA_DEVICE_NO_MEDIA;
623 return FALSE;
624 }
625 }
626 else
627 {
628 DeviceUnit->Flags &= ~ATA_DEVICE_NOT_READY;
629 }
630
631 if (DeviceUnit->Flags & ATA_DEVICE_NO_MEDIA)
632 {
633 /* Detect a medium's capacity */
634 AtapiCapacityDetect(DeviceUnit, &DeviceUnit->TotalSectors, &DeviceUnit->SectorSize);
635
636 /* If nothing was returned, reset to defaults */
637 if (DeviceUnit->SectorSize == 0)
638 DeviceUnit->SectorSize = 2048;
639 if (DeviceUnit->TotalSectors == 0)
640 DeviceUnit->TotalSectors = 0xFFFFFFFF;
641
642 DeviceUnit->Flags &= ~ATA_DEVICE_NO_MEDIA;
643 }
644
645 return TRUE;
646 }
647
648 static
649 BOOLEAN
650 WaitForFlags(
651 IN UCHAR Channel,
652 IN UCHAR Flags,
653 IN UCHAR ExpectedValue,
654 IN ULONG Timeout)
655 {
656 UCHAR Status;
657
658 ASSERT(Timeout != 0);
659
660 WaitForBusy(Channel, ATA_STATUS_TIMEOUT);
661
662 while (Timeout--)
663 {
664 StallExecutionProcessor(10);
665
666 Status = AtaReadPort(Channel, IDX_IO1_i_Status);
667 if (Status & IDE_STATUS_ERROR)
668 return FALSE;
669 else if ((Status & Flags) == ExpectedValue)
670 return TRUE;
671 }
672 return FALSE;
673 }
674
675 static
676 BOOLEAN
677 WaitForFlagsOr(
678 IN UCHAR Channel,
679 IN UCHAR FirstValue,
680 IN UCHAR SecondValue,
681 IN ULONG Timeout)
682 {
683 UCHAR Status;
684
685 ASSERT(Timeout != 0);
686
687 WaitForBusy(Channel, ATA_STATUS_TIMEOUT);
688
689 while (Timeout--)
690 {
691 StallExecutionProcessor(10);
692
693 Status = AtaReadPort(Channel, IDX_IO1_i_Status);
694 if (Status & IDE_STATUS_ERROR)
695 return FALSE;
696 else if ((Status & FirstValue) || (Status & SecondValue))
697 return TRUE;
698 }
699 return FALSE;
700 }
701
702 static
703 BOOLEAN
704 WaitForBusy(
705 IN UCHAR Channel,
706 IN ULONG Timeout)
707 {
708 ASSERT(Timeout != 0);
709
710 while (Timeout--)
711 {
712 StallExecutionProcessor(10);
713
714 if ((AtaReadPort(Channel, IDX_IO1_i_Status) & IDE_STATUS_BUSY) == 0)
715 return TRUE;
716 }
717 return FALSE;
718 }
719
720 static
721 VOID
722 AtaHardReset(IN UCHAR Channel)
723 {
724 TRACE("AtaHardReset(Controller %d)\n", Channel);
725
726 AtaWritePort(Channel, IDX_IO2_o_Control, IDE_DC_RESET_CONTROLLER);
727 StallExecutionProcessor(100000);
728 AtaWritePort(Channel, IDX_IO2_o_Control, IDE_DC_REENABLE_CONTROLLER);
729 StallExecutionProcessor(5);
730 WaitForBusy(Channel, ATA_STATUS_TIMEOUT);
731 }
732
733 static
734 VOID
735 SelectDevice(IN UCHAR Channel, IN UCHAR DeviceNumber)
736 {
737 #if defined(SARCH_PC98)
738 /* Select IDE Channel */
739 WRITE_PORT_UCHAR((PUCHAR)IDE_IO_o_BankSelect, Channel);
740 StallExecutionProcessor(5);
741 #endif
742
743 AtaWritePort(Channel, IDX_IO1_o_DriveSelect,
744 DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1);
745 StallExecutionProcessor(5);
746 }
747
748 static
749 BOOLEAN
750 IdentifyDevice(
751 IN UCHAR Channel,
752 IN UCHAR DeviceNumber,
753 OUT PDEVICE_UNIT *DeviceUnit)
754 {
755 UCHAR SignatureLow, SignatureHigh, SignatureCount, SignatureNumber;
756 UCHAR Command;
757 IDENTIFY_DATA Id;
758 SENSE_DATA SenseData;
759 ULONG i;
760 ULONG SectorSize;
761 ULONGLONG TotalSectors;
762 USHORT Flags = 0;
763
764 TRACE("IdentifyDevice() Channel = %x, Device = %x, BaseIoAddress = 0x%x\n",
765 Channel, DeviceNumber, BaseArray[Channel]);
766
767 /* Look at controller */
768 SelectDevice(Channel, DeviceNumber);
769 StallExecutionProcessor(5);
770 AtaWritePort(Channel, IDX_IO1_o_BlockNumber, 0x55);
771 AtaWritePort(Channel, IDX_IO1_o_BlockNumber, 0x55);
772 StallExecutionProcessor(5);
773 if (AtaReadPort(Channel, IDX_IO1_i_BlockNumber) != 0x55)
774 goto Failure;
775
776 /* Reset the controller */
777 AtaHardReset(Channel);
778
779 /* Select the drive */
780 SelectDevice(Channel, DeviceNumber);
781 if (!WaitForBusy(Channel, ATA_STATUS_TIMEOUT))
782 goto Failure;
783
784 /* Signature check */
785 SignatureLow = AtaReadPort(Channel, IDX_IO1_i_CylinderLow);
786 SignatureHigh = AtaReadPort(Channel, IDX_IO1_i_CylinderHigh);
787 SignatureCount = AtaReadPort(Channel, IDX_IO1_i_BlockCount);
788 SignatureNumber = AtaReadPort(Channel, IDX_IO1_i_BlockNumber);
789 TRACE("IdentifyDevice(): SL = 0x%x, SH = 0x%x, SC = 0x%x, SN = 0x%x\n",
790 SignatureLow, SignatureHigh, SignatureCount, SignatureNumber);
791 if (SignatureLow == 0x00 && SignatureHigh == 0x00 &&
792 SignatureCount == 0x01 && SignatureNumber == 0x01)
793 {
794 TRACE("IdentifyDevice(): Found PATA device at %d:%d\n", Channel, DeviceNumber);
795 Command = IDE_COMMAND_IDENTIFY;
796 }
797 else if (SignatureLow == ATAPI_MAGIC_LSB &&
798 SignatureHigh == ATAPI_MAGIC_MSB)
799 {
800 TRACE("IdentifyDevice(): Found ATAPI device at %d:%d\n", Channel, DeviceNumber);
801 Flags |= ATA_DEVICE_ATAPI | ATA_DEVICE_LBA | ATA_DEVICE_NOT_READY;
802 Command = IDE_COMMAND_ATAPI_IDENTIFY;
803 }
804 else
805 {
806 goto Failure;
807 }
808
809 /* Disable interrupts */
810 AtaWritePort(Channel, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS);
811 StallExecutionProcessor(5);
812
813 /* Send the identify command */
814 AtaWritePort(Channel, IDX_IO1_o_Command, Command);
815 StallExecutionProcessor(50);
816 if (!WaitForFlags(Channel, IDE_STATUS_DRQ, IDE_STATUS_DRQ, ATA_STATUS_TIMEOUT))
817 {
818 ERR("IdentifyDevice(): Identify command failed.\n");
819 goto Failure;
820 }
821
822 /* Receive parameter information from the device */
823 AtaReadBuffer(Channel, &Id, IDENTIFY_DATA_SIZE);
824
825 /* Swap byte order of the ASCII data */
826 for (i = 0; i < RTL_NUMBER_OF(Id.SerialNumber); ++i)
827 Id.SerialNumber[i] = RtlUshortByteSwap(Id.SerialNumber[i]);
828
829 for (i = 0; i < RTL_NUMBER_OF(Id.FirmwareRevision); ++i)
830 Id.FirmwareRevision[i] = RtlUshortByteSwap(Id.FirmwareRevision[i]);
831
832 for (i = 0; i < RTL_NUMBER_OF(Id.ModelNumber); ++i)
833 Id.ModelNumber[i] = RtlUshortByteSwap(Id.ModelNumber[i]);
834
835 TRACE("S/N %.*s\n", sizeof(Id.SerialNumber), Id.SerialNumber);
836 TRACE("FR %.*s\n", sizeof(Id.FirmwareRevision), Id.FirmwareRevision);
837 TRACE("MN %.*s\n", sizeof(Id.ModelNumber), Id.ModelNumber);
838
839 /* Allocate a new device unit structure */
840 *DeviceUnit = FrLdrTempAlloc(sizeof(DEVICE_UNIT), TAG_ATA_DEVICE);
841 if (*DeviceUnit == NULL)
842 {
843 ERR("Failed to allocate device unit!\n");
844 return FALSE;
845 }
846
847 RtlZeroMemory(*DeviceUnit, sizeof(DEVICE_UNIT));
848 (*DeviceUnit)->Channel = Channel;
849 (*DeviceUnit)->DeviceNumber = DeviceNumber;
850 (*DeviceUnit)->IdentifyData = Id;
851
852 if (Flags & ATA_DEVICE_ATAPI)
853 {
854 /* Clear the ATAPI 'Bus reset' indication */
855 for (i = 0; i < 10; ++i)
856 {
857 AtapiRequestSense(*DeviceUnit, &SenseData);
858 StallExecutionProcessor(10);
859 }
860
861 /* Detect a medium's capacity */
862 AtapiCapacityDetect(*DeviceUnit, &TotalSectors, &SectorSize);
863 if (SectorSize == 0 || TotalSectors == 0)
864 {
865 /* It's ok and can be used to show alert like "Please insert the CD" */
866 TRACE("No media found.\n");
867 Flags |= ATA_DEVICE_NO_MEDIA;
868 }
869 }
870 else
871 {
872 if (Id.SupportLba || (Id.MajorRevision && Id.UserAddressableSectors))
873 {
874 if (Id.FeaturesSupport.Address48)
875 {
876 TRACE("Using LBA48 addressing mode.\n");
877 Flags |= ATA_DEVICE_LBA48 | ATA_DEVICE_LBA;
878 TotalSectors = Id.UserAddressableSectors48;
879 }
880 else
881 {
882 TRACE("Using LBA28 addressing mode.\n");
883 Flags |= ATA_DEVICE_LBA;
884 TotalSectors = Id.UserAddressableSectors;
885 }
886
887 /* LBA ATA drives always have a sector size of 512 */
888 SectorSize = 512;
889 }
890 else
891 {
892 TRACE("Using CHS addressing mode.\n");
893 Flags |= ATA_DEVICE_CHS;
894
895 if (Id.UnformattedBytesPerSector == 0)
896 {
897 SectorSize = 512;
898 }
899 else
900 {
901 for (i = 1 << 15; i > 0; i >>= 1)
902 {
903 if ((Id.UnformattedBytesPerSector & i) != 0)
904 {
905 SectorSize = i;
906 break;
907 }
908 }
909 }
910 TotalSectors = Id.NumberOfCylinders * Id.NumberOfHeads * Id.SectorsPerTrack;
911 }
912 }
913 TRACE("Sector size %d ; Total sectors %I64d\n", SectorSize, TotalSectors);
914
915 (*DeviceUnit)->Flags = Flags;
916 (*DeviceUnit)->SectorSize = SectorSize;
917 (*DeviceUnit)->TotalSectors = TotalSectors;
918 if (Flags & ATA_DEVICE_ATAPI)
919 {
920 (*DeviceUnit)->Cylinders = 0xFFFFFFFF;
921 (*DeviceUnit)->Heads = 0xFFFFFFFF;
922 (*DeviceUnit)->Sectors = 0xFFFFFFFF;
923 }
924 else
925 {
926 (*DeviceUnit)->Cylinders = Id.NumberOfCylinders;
927 (*DeviceUnit)->Heads = Id.NumberOfHeads;
928 (*DeviceUnit)->Sectors = Id.SectorsPerTrack;
929 }
930
931 #if DBG
932 DbgDumpBuffer(DPRINT_DISK, &Id, IDENTIFY_DATA_SIZE);
933 #endif
934
935 TRACE("IdentifyDevice() done.\n");
936 return TRUE;
937
938 Failure:
939 TRACE("IdentifyDevice() done. No device present at %d:%d\n", Channel, DeviceNumber);
940 return FALSE;
941 }