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
AtaInit(OUT PUCHAR DetectedCount)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
AtaFree(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
AtaGetDevice(IN UCHAR UnitNumber)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
AtaAtapiReadLogicalSectorsLBA(IN OUT PDEVICE_UNIT DeviceUnit,IN ULONGLONG SectorNumber,IN ULONG SectorCount,OUT PVOID Buffer)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
AtaReadLogicalSectorsLBA(IN PDEVICE_UNIT DeviceUnit,IN ULONGLONG SectorNumber,IN ULONG SectorCount,OUT PVOID Buffer)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
AtaSendAtapiPacket(IN UCHAR Channel,IN PUCHAR AtapiPacket,IN UCHAR PacketSize,IN USHORT ByteCount)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
AtapiReadLogicalSectorLBA(IN PDEVICE_UNIT DeviceUnit,IN ULONGLONG SectorNumber,OUT PVOID Buffer)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
AtapiCapacityDetect(IN PDEVICE_UNIT DeviceUnit,OUT PULONGLONG TotalSectors,OUT PULONG SectorSize)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
AtapiRequestSense(IN PDEVICE_UNIT DeviceUnit,OUT PSENSE_DATA SenseData)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
AtapiPrintSenseData(IN PDEVICE_UNIT DeviceUnit)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
AtapiReadyCheck(IN OUT PDEVICE_UNIT DeviceUnit)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
WaitForFlags(IN UCHAR Channel,IN UCHAR Flags,IN UCHAR ExpectedValue,IN ULONG Timeout)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
WaitForFlagsOr(IN UCHAR Channel,IN UCHAR FirstValue,IN UCHAR SecondValue,IN ULONG Timeout)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
WaitForBusy(IN UCHAR Channel,IN ULONG Timeout)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
AtaHardReset(IN UCHAR Channel)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
SelectDevice(IN UCHAR Channel,IN UCHAR DeviceNumber)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
IdentifyDevice(IN UCHAR Channel,IN UCHAR DeviceNumber,OUT PDEVICE_UNIT * DeviceUnit)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 }
942