ReactOS 0.4.15-dev-7931-gfd331f1
hwide.c
Go to the documentation of this file.
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>
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 */
41static 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
56
57/* PRIVATE PROTOTYPES *********************************************************/
58
59static
62 IN UCHAR Channel,
64 IN UCHAR ExpectedValue,
66);
67
68static
71 IN UCHAR Channel,
72 IN UCHAR FirstValue,
73 IN UCHAR SecondValue,
75);
76
77static
80 IN UCHAR Channel,
82);
83
84static
85VOID
87 IN UCHAR Channel,
89);
90
91static
94 IN UCHAR Channel,
96 OUT PDEVICE_UNIT *DeviceUnit
97);
98
99static
102 IN PDEVICE_UNIT DeviceUnit,
103 OUT PSENSE_DATA SenseData
104);
105
106static
107VOID
109 IN PDEVICE_UNIT DeviceUnit
110);
111
112static
115 IN OUT PDEVICE_UNIT DeviceUnit
116);
117
118static
121 IN PDEVICE_UNIT DeviceUnit,
122 IN ULONGLONG SectorNumber,
124);
125
126static
129 IN PDEVICE_UNIT DeviceUnit,
130 IN ULONGLONG SectorNumber,
133);
134
135/* FUNCTIONS ******************************************************************/
136
137/* Don't call this before running the system timer calibration and MM initialization */
139AtaInit(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 {
154 {
155 if (IdentifyDevice(Channel, DeviceNumber, &DeviceUnit))
156 {
157 Units[(*DetectedCount)++] = DeviceUnit;
158 }
159 }
160 }
161
162 return (*DetectedCount > 0);
163}
164
165VOID
167{
168 UCHAR i;
169
170 for (i = 0; i < RTL_NUMBER_OF(Units); ++i)
171 {
172 if (Units[i])
174 }
175}
176
179{
180 if (UnitNumber < RTL_NUMBER_OF(Units))
181 return Units[UnitNumber];
182 else
183 return NULL;
184}
185
188 IN OUT PDEVICE_UNIT DeviceUnit,
189 IN ULONGLONG SectorNumber,
192{
193 UCHAR RetryCount;
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
250static
253 IN PDEVICE_UNIT DeviceUnit,
254 IN ULONGLONG SectorNumber,
257{
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 */
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));
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));
343 }
344
345 /* Send read command */
346 AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Command, Command);
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,
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
374static
377 IN UCHAR Channel,
378 IN PUCHAR AtapiPacket,
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) ?
388 UCHAR ExpectedFlags = ((AtapiPacket[0] == SCSIOP_TEST_UNIT_READY) ||
389 (AtapiPacket[0] == SCSIOP_REQUEST_SENSE)) ?
391
392 /* PIO mode */
394
395 /* Maximum byte count that is to be transferred */
398
399 /* Prepare to transfer a device command via a command packet */
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
421static
424 IN PDEVICE_UNIT DeviceUnit,
425 IN ULONGLONG SectorNumber,
427{
428 UCHAR AtapiPacket[16];
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 */
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
472static
473VOID
475 IN PDEVICE_UNIT DeviceUnit,
476 OUT PULONGLONG TotalSectors,
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
508static
511 IN PDEVICE_UNIT DeviceUnit,
512 OUT PSENSE_DATA SenseData)
513{
514 UCHAR AtapiPacket[16];
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),
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
537static
538VOID
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,
549 }
550}
551
552static
555{
556 UCHAR AtapiPacket[16];
558 SENSE_DATA SenseData;
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,
582
583 if (SenseData.SenseKey == SCSI_SENSE_NOT_READY)
584 {
586 {
587 switch (SenseData.AdditionalSenseCodeQualifier)
588 {
590 /* Wait until the CD is spun up */
592 return FALSE;
593
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),
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 }
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
648static
651 IN UCHAR Channel,
652 IN UCHAR Flags,
653 IN UCHAR ExpectedValue,
655{
657
658 ASSERT(Timeout != 0);
659
661
662 while (Timeout--)
663 {
665
668 return FALSE;
669 else if ((Status & Flags) == ExpectedValue)
670 return TRUE;
671 }
672 return FALSE;
673}
674
675static
678 IN UCHAR Channel,
679 IN UCHAR FirstValue,
680 IN UCHAR SecondValue,
682{
684
685 ASSERT(Timeout != 0);
686
688
689 while (Timeout--)
690 {
692
695 return FALSE;
696 else if ((Status & FirstValue) || (Status & SecondValue))
697 return TRUE;
698 }
699 return FALSE;
700}
701
702static
705 IN UCHAR Channel,
707{
708 ASSERT(Timeout != 0);
709
710 while (Timeout--)
711 {
713
714 if ((AtaReadPort(Channel, IDX_IO1_i_Status) & IDE_STATUS_BUSY) == 0)
715 return TRUE;
716 }
717 return FALSE;
718}
719
720static
721VOID
723{
724 TRACE("AtaHardReset(Controller %d)\n", Channel);
725
731}
732
733static
734VOID
736{
737#if defined(SARCH_PC98)
738 /* Select IDE Channel */
739 WRITE_PORT_UCHAR((PUCHAR)IDE_IO_o_BankSelect, Channel);
741#endif
742
746}
747
748static
751 IN UCHAR Channel,
753 OUT PDEVICE_UNIT *DeviceUnit)
754{
755 UCHAR SignatureLow, SignatureHigh, SignatureCount, SignatureNumber;
758 SENSE_DATA SenseData;
759 ULONG i;
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);
770 AtaWritePort(Channel, IDX_IO1_o_BlockNumber, 0x55);
771 AtaWritePort(Channel, IDX_IO1_o_BlockNumber, 0x55);
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);
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);
803 }
804 else
805 {
806 goto Failure;
807 }
808
809 /* Disable interrupts */
812
813 /* Send the identify command */
817 {
818 ERR("IdentifyDevice(): Identify command failed.\n");
819 goto Failure;
820 }
821
822 /* Receive parameter information from the device */
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
853 {
854 /* Clear the ATAPI 'Bus reset' indication */
855 for (i = 0; i < 10; ++i)
856 {
857 AtapiRequestSense(*DeviceUnit, &SenseData);
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");
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");
878 TotalSectors = Id.UserAddressableSectors48;
879 }
880 else
881 {
882 TRACE("Using LBA28 addressing mode.\n");
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");
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;
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
933#endif
934
935 TRACE("IdentifyDevice() done.\n");
936 return TRUE;
937
938Failure:
939 TRACE("IdentifyDevice() done. No device present at %d:%d\n", Channel, DeviceNumber);
940 return FALSE;
941}
DWORD Id
unsigned char BOOLEAN
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
#define IDE_COMMAND_READ_EXT
Definition: ata.h:261
#define IDE_COMMAND_ATAPI_IDENTIFY
Definition: atapi.h:110
#define IDE_COMMAND_IDENTIFY
Definition: atapi.h:118
#define IDE_COMMAND_ATAPI_PACKET
Definition: atapi.h:109
#define IDE_COMMAND_READ
Definition: atapi.h:104
#define DbgDumpBuffer(mask, buf, len)
Definition: debug.h:119
#define DPRINT_DISK
Definition: debug.h:29
#define ERR(fmt,...)
Definition: debug.h:110
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:103
FORCEINLINE PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: mm.h:188
FORCEINLINE VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: mm.h:197
#define SCSI_ADSENSE_LUN_NOT_READY
Definition: cdrw_hw.h:1218
#define SCSIOP_REQUEST_SENSE
Definition: cdrw_hw.h:870
#define SCSIOP_TEST_UNIT_READY
Definition: cdrw_hw.h:866
#define SCSIOP_READ_TOC
Definition: cdrw_hw.h:927
#define SCSIOP_READ_CAPACITY
Definition: cdrw_hw.h:904
#define SCSI_SENSEQ_BECOMING_READY
Definition: cdrw_hw.h:1313
#define SENSE_BUFFER_SIZE
Definition: cdrw_hw.h:1183
#define SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
Definition: cdrw_hw.h:1221
#define SCSI_SENSEQ_INIT_COMMAND_REQUIRED
Definition: cdrw_hw.h:1314
#define SCSIOP_READ
Definition: cdrw_hw.h:905
#define SCSI_SENSE_NOT_READY
Definition: cdrw_hw.h:1189
Definition: bufpool.h:45
_In_ PCHAR _In_ ULONG DeviceNumber
Definition: classpnp.h:1230
ULONG DummyData
Definition: cmdata.c:18
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
@ Success
Definition: eventcreate.c:712
#define UINT64_C(val)
Definition: freeldr.h:27
Status
Definition: gdiplustypes.h:25
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
PDEVICE_UNIT AtaGetDevice(IN UCHAR UnitNumber)
Definition: hwide.c:178
#define ATA_STATUS_TIMEOUT
Definition: hwide.c:24
static BOOLEAN WaitForFlags(IN UCHAR Channel, IN UCHAR Flags, IN UCHAR ExpectedValue, IN ULONG Timeout)
Definition: hwide.c:650
#define AtaWritePort(Channel, Port, Data)
Definition: hwide.c:26
#define AtaReadBuffer(Channel, Buffer, Count)
Definition: hwide.c:36
static BOOLEAN IdentifyDevice(IN UCHAR Channel, IN UCHAR DeviceNumber, OUT PDEVICE_UNIT *DeviceUnit)
Definition: hwide.c:750
#define MAX_DEVICES
Definition: hwide.c:53
static BOOLEAN AtapiReadyCheck(IN OUT PDEVICE_UNIT DeviceUnit)
Definition: hwide.c:554
static VOID AtapiCapacityDetect(IN PDEVICE_UNIT DeviceUnit, OUT PULONGLONG TotalSectors, OUT PULONG SectorSize)
Definition: hwide.c:474
static BOOLEAN WaitForBusy(IN UCHAR Channel, IN ULONG Timeout)
Definition: hwide.c:704
static VOID AtaHardReset(IN UCHAR Channel)
Definition: hwide.c:722
static BOOLEAN AtapiReadLogicalSectorLBA(IN PDEVICE_UNIT DeviceUnit, IN ULONGLONG SectorNumber, OUT PVOID Buffer)
Definition: hwide.c:423
static const ULONG BaseArray[]
Definition: hwide.c:41
static VOID SelectDevice(IN UCHAR Channel, IN UCHAR DeviceNumber)
Definition: hwide.c:735
static BOOLEAN AtapiRequestSense(IN PDEVICE_UNIT DeviceUnit, OUT PSENSE_DATA SenseData)
Definition: hwide.c:510
BOOLEAN AtaAtapiReadLogicalSectorsLBA(IN OUT PDEVICE_UNIT DeviceUnit, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: hwide.c:187
static BOOLEAN AtaSendAtapiPacket(IN UCHAR Channel, IN PUCHAR AtapiPacket, IN UCHAR PacketSize, IN USHORT ByteCount)
Definition: hwide.c:376
#define ATAPI_PACKET_SIZE(IdentifyData)
Definition: hwide.c:23
BOOLEAN AtaInit(OUT PUCHAR DetectedCount)
Definition: hwide.c:139
#define AtaReadPort(Channel, Port)
Definition: hwide.c:29
#define AtaWriteBuffer(Channel, Buffer, Count)
Definition: hwide.c:32
#define MAX_CHANNELS
Definition: hwide.c:52
static BOOLEAN WaitForFlagsOr(IN UCHAR Channel, IN UCHAR FirstValue, IN UCHAR SecondValue, IN ULONG Timeout)
Definition: hwide.c:677
static BOOLEAN AtaReadLogicalSectorsLBA(IN PDEVICE_UNIT DeviceUnit, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: hwide.c:252
static VOID AtapiPrintSenseData(IN PDEVICE_UNIT DeviceUnit)
Definition: hwide.c:539
#define TAG_ATA_DEVICE
Definition: hwide.c:22
static PDEVICE_UNIT Units[MAX_CHANNELS *MAX_DEVICES]
Definition: hwide.c:55
#define IDX_IO1_o_BlockNumber
Definition: hwide.h:56
#define IDX_ATAPI_IO1_o_Command
Definition: hwide.h:103
#define IDX_IO1_o_CylinderHigh
Definition: hwide.h:58
#define ATA_DEVICE_LBA
Definition: hwide.h:307
#define IDE_STATUS_DRDY
Definition: hwide.h:117
#define ATAPI_MAGIC_MSB
Definition: hwide.h:287
#define IDX_ATAPI_IO1_o_ByteCountHigh
Definition: hwide.h:101
#define MAXIMUM_CDROM_SIZE
Definition: hwide.h:288
#define IDENTIFY_DATA_SIZE
Definition: hwide.h:284
#define IDX_IO1_i_BlockNumber
Definition: hwide.h:44
#define IDE_USE_LBA
Definition: hwide.h:133
#define IDE_STATUS_BUSY
Definition: hwide.h:119
#define ATA_DEVICE_NOT_READY
Definition: hwide.h:305
#define IDE_STATUS_ERROR
Definition: hwide.h:110
#define IDX_ATAPI_IO1_i_ByteCountHigh
Definition: hwide.h:92
#define IDE_DRIVE_SELECT_1
Definition: hwide.h:130
#define IDX_IO1_o_Feature
Definition: hwide.h:54
#define IDE_DC_RESET_CONTROLLER
Definition: hwide.h:139
#define IDX_IO1_i_Status
Definition: hwide.h:48
#define IDE_STATUS_DRQ
Definition: hwide.h:113
#define IDX_IO1_i_CylinderLow
Definition: hwide.h:45
#define ATA_PIO
Definition: hwide.h:161
VOID AtaFree()
#define IDE_DRIVE_1
Definition: hwide.h:128
#define IDX_ATAPI_IO1_o_ByteCountLow
Definition: hwide.h:100
#define IDX_IO1_i_BlockCount
Definition: hwide.h:43
#define IDX_ATAPI_IO1_i_Status
Definition: hwide.h:94
#define ATA_DEVICE_CHS
Definition: hwide.h:308
#define IDX_ATAPI_IO1_i_ByteCountLow
Definition: hwide.h:91
#define IDX_IO1_i_CylinderHigh
Definition: hwide.h:46
#define IDE_DRIVE_SELECT_2
Definition: hwide.h:131
#define IDX_IO1_o_DriveSelect
Definition: hwide.h:59
#define ATA_DEVICE_ATAPI
Definition: hwide.h:303
#define IDX_IO1_o_Command
Definition: hwide.h:60
#define ATA_DEVICE_NO_MEDIA
Definition: hwide.h:304
#define ATA_DEVICE_LBA48
Definition: hwide.h:306
#define IDX_ATAPI_IO1_o_Feature
Definition: hwide.h:97
#define IDX_IO1_i_Error
Definition: hwide.h:42
#define IDE_DC_DISABLE_INTERRUPTS
Definition: hwide.h:138
#define IDE_DC_REENABLE_CONTROLLER
Definition: hwide.h:142
#define IDX_IO2_o_Control
Definition: hwide.h:62
#define IDE_DRIVE_2
Definition: hwide.h:129
#define IDX_IO1_o_BlockCount
Definition: hwide.h:55
#define IDX_IO1_o_CylinderLow
Definition: hwide.h:57
#define IDX_ATAPI_IO1_i_Error
Definition: hwide.h:88
#define ATAPI_MAGIC_LSB
Definition: hwide.h:286
#define UCHAR_MAX
Definition: limits.h:25
#define USHRT_MAX
Definition: limits.h:38
#define ASSERT(a)
Definition: mode.c:44
#define min(a, b)
Definition: monoChain.cc:55
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4755
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:383
ULONG SectorCount
Definition: part_xbox.c:31
#define WRITE_PORT_UCHAR(p, d)
Definition: pc98vid.h:21
VOID StallExecutionProcessor(ULONG Microseconds)
Definition: pchw.c:60
unsigned short USHORT
Definition: pedump.c:61
static ULONG Timeout
Definition: ping.c:61
#define READ_TOC_FORMAT_SESSION
Definition: scsi.h:178
#define TRACE(s)
Definition: solgame.cpp:4
Definition: shell.h:41
UCHAR AdditionalSenseCode
Definition: cdrw_hw.h:1175
UCHAR AdditionalSenseCodeQualifier
Definition: cdrw_hw.h:1176
UCHAR SenseKey
Definition: cdrw_hw.h:1167
uint32_t * PULONG
Definition: typedefs.h:59
void * PVOID
Definition: typedefs.h:50
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define OUT
Definition: typedefs.h:40
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_In_ ULONG SectorSize
Definition: halfuncs.h:291
_In_ USHORT PacketSize
Definition: iofuncs.h:1058
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _In_ LARGE_INTEGER ByteCount
Definition: iotypes.h:1099
#define RtlUshortByteSwap(_x)
Definition: rtlfuncs.h:3197
unsigned char UCHAR
Definition: xmlstorage.h:181