ReactOS  0.4.15-dev-1177-g6cb3b62
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 */
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 
56 
57 /* PRIVATE PROTOTYPES *********************************************************/
58 
59 static
60 BOOLEAN
62  IN UCHAR Channel,
63  IN UCHAR Flags,
64  IN UCHAR ExpectedValue,
66 );
67 
68 static
69 BOOLEAN
71  IN UCHAR Channel,
72  IN UCHAR FirstValue,
73  IN UCHAR SecondValue,
75 );
76 
77 static
78 BOOLEAN
80  IN UCHAR Channel,
82 );
83 
84 static
85 VOID
87  IN UCHAR Channel,
89 );
90 
91 static
92 BOOLEAN
94  IN UCHAR Channel,
96  OUT PDEVICE_UNIT *DeviceUnit
97 );
98 
99 static
100 BOOLEAN
102  IN PDEVICE_UNIT DeviceUnit,
103  OUT PSENSE_DATA SenseData
104 );
105 
106 static
107 VOID
109  IN PDEVICE_UNIT DeviceUnit
110 );
111 
112 static
113 BOOLEAN
115  IN OUT PDEVICE_UNIT DeviceUnit
116 );
117 
118 static
119 BOOLEAN
121  IN PDEVICE_UNIT DeviceUnit,
122  IN ULONGLONG SectorNumber,
124 );
125 
126 static
127 BOOLEAN
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 */
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  {
154  {
155  if (IdentifyDevice(Channel, DeviceNumber, &DeviceUnit))
156  {
157  Units[(*DetectedCount)++] = DeviceUnit;
158  }
159  }
160  }
161 
162  return (*DetectedCount > 0);
163 }
164 
165 VOID
167 {
168  UCHAR i;
169 
170  for (i = 0; i < RTL_NUMBER_OF(Units); ++i)
171  {
172  if (Units[i])
174  }
175 }
176 
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
188  IN OUT PDEVICE_UNIT DeviceUnit,
189  IN ULONGLONG SectorNumber,
191  OUT PVOID Buffer)
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 
250 static
251 BOOLEAN
253  IN PDEVICE_UNIT DeviceUnit,
254  IN ULONGLONG SectorNumber,
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 */
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 
374 static
375 BOOLEAN
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 */
397  AtaWritePort(Channel, IDX_ATAPI_IO1_o_ByteCountHigh, (ByteCount >> 8) & 0xFF);
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 
421 static
422 BOOLEAN
424  IN PDEVICE_UNIT DeviceUnit,
425  IN ULONGLONG SectorNumber,
426  OUT PVOID Buffer)
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 
472 static
473 VOID
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 
508 static
509 BOOLEAN
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 
537 static
538 VOID
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
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,
581  SenseData.AdditionalSenseCodeQualifier);
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 
648 static
649 BOOLEAN
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 
661 
662  while (Timeout--)
663  {
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
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 
688 
689  while (Timeout--)
690  {
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
705  IN UCHAR Channel,
706  IN ULONG Timeout)
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 
720 static
721 VOID
723 {
724  TRACE("AtaHardReset(Controller %d)\n", Channel);
725 
727  StallExecutionProcessor(100000);
731 }
732 
733 static
734 VOID
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 
748 static
749 BOOLEAN
751  IN UCHAR Channel,
753  OUT PDEVICE_UNIT *DeviceUnit)
754 {
755  UCHAR SignatureLow, SignatureHigh, SignatureCount, SignatureNumber;
756  UCHAR Command;
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 */
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);
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;
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
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 }
#define IDX_IO1_o_DriveSelect
Definition: hwide.h:59
#define SCSIOP_READ_TOC
Definition: cdrw_hw.h:927
DBG_DEFAULT_CHANNEL(DISK)
UCHAR SenseKey
Definition: cdrw_hw.h:1167
#define IN
Definition: typedefs.h:39
#define IDENTIFY_DATA_SIZE
Definition: hwide.h:284
VOID StallExecutionProcessor(ULONG Microseconds)
Definition: pchw.c:60
ULONG DummyData
Definition: cmdata.c:18
#define ATAPI_MAGIC_MSB
Definition: hwide.h:287
static BOOLEAN AtaSendAtapiPacket(IN UCHAR Channel, IN PUCHAR AtapiPacket, IN UCHAR PacketSize, IN USHORT ByteCount)
Definition: hwide.c:376
#define IDX_IO2_o_Control
Definition: hwide.h:62
#define ATAPI_MAGIC_LSB
Definition: hwide.h:286
#define TRUE
Definition: types.h:120
VOID AtaFree(VOID)
Definition: hwide.c:166
#define RtlUshortByteSwap(_x)
Definition: rtlfuncs.h:3199
#define IDE_STATUS_ERROR
Definition: hwide.h:110
#define ATA_PIO
Definition: hwide.h:161
unsigned char * PUCHAR
Definition: retypes.h:3
#define IDX_ATAPI_IO1_i_ByteCountHigh
Definition: hwide.h:92
#define SCSIOP_TEST_UNIT_READY
Definition: cdrw_hw.h:866
#define IDX_ATAPI_IO1_o_ByteCountHigh
Definition: hwide.h:101
BOOLEAN AtaInit(OUT PUCHAR DetectedCount)
Definition: hwide.c:139
#define ATA_DEVICE_LBA
Definition: hwide.h:307
#define IDE_COMMAND_IDENTIFY
Definition: atapi.h:118
#define ATAPI_PACKET_SIZE(IdentifyData)
Definition: hwide.c:23
#define SCSI_ADSENSE_LUN_NOT_READY
Definition: cdrw_hw.h:1218
#define IDE_COMMAND_READ
Definition: atapi.h:104
Definition: shell.h:41
static BOOLEAN AtapiReadLogicalSectorLBA(IN PDEVICE_UNIT DeviceUnit, IN ULONGLONG SectorNumber, OUT PVOID Buffer)
Definition: hwide.c:423
#define ATA_DEVICE_CHS
Definition: hwide.h:308
#define SCSI_SENSE_NOT_READY
Definition: cdrw_hw.h:1189
#define IDX_ATAPI_IO1_o_Command
Definition: hwide.h:103
#define ATA_DEVICE_LBA48
Definition: hwide.h:306
#define IDE_COMMAND_READ_EXT
Definition: ata.h:261
static BOOLEAN AtapiRequestSense(IN PDEVICE_UNIT DeviceUnit, OUT PSENSE_DATA SenseData)
Definition: hwide.c:510
#define SENSE_BUFFER_SIZE
Definition: cdrw_hw.h:1183
DWORD Id
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define USHRT_MAX
Definition: limits.h:38
#define ATA_DEVICE_NOT_READY
Definition: hwide.h:305
static VOID AtapiPrintSenseData(IN PDEVICE_UNIT DeviceUnit)
Definition: hwide.c:539
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define UINT64_C(val)
Definition: freeldr.h:23
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define AtaReadPort(Channel, Port)
Definition: hwide.c:29
#define IDX_IO1_o_Feature
Definition: hwide.h:54
#define ATA_STATUS_TIMEOUT
Definition: hwide.c:24
#define FALSE
Definition: types.h:117
#define SCSIOP_READ
Definition: cdrw_hw.h:905
#define SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
Definition: cdrw_hw.h:1221
FORCEINLINE PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: mm.h:177
#define ATA_DEVICE_NO_MEDIA
Definition: hwide.h:304
unsigned char BOOLEAN
static PDEVICE_UNIT Units[MAX_CHANNELS *MAX_DEVICES]
Definition: hwide.c:55
#define IDE_USE_LBA
Definition: hwide.h:133
smooth NULL
Definition: ftsmooth.c:416
#define AtaReadBuffer(Channel, Buffer, Count)
Definition: hwide.c:36
BOOLEAN AtaAtapiReadLogicalSectorsLBA(IN OUT PDEVICE_UNIT DeviceUnit, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: hwide.c:187
Definition: bufpool.h:45
#define IDX_IO1_o_CylinderHigh
Definition: hwide.h:58
void * PVOID
Definition: retypes.h:9
#define IDX_ATAPI_IO1_o_Feature
Definition: hwide.h:97
#define IDE_COMMAND_ATAPI_IDENTIFY
Definition: atapi.h:110
#define IDE_DC_REENABLE_CONTROLLER
Definition: hwide.h:142
UCHAR AdditionalSenseCodeQualifier
Definition: cdrw_hw.h:1176
#define TRACE(s)
Definition: solgame.cpp:4
static BOOLEAN IdentifyDevice(IN UCHAR Channel, IN UCHAR DeviceNumber, OUT PDEVICE_UNIT *DeviceUnit)
Definition: hwide.c:750
#define IDX_ATAPI_IO1_i_Error
Definition: hwide.h:88
#define SCSI_SENSEQ_BECOMING_READY
Definition: cdrw_hw.h:1313
#define IDX_IO1_o_BlockNumber
Definition: hwide.h:56
struct Command Command
uint64_t ULONGLONG
Definition: typedefs.h:67
static VOID AtapiCapacityDetect(IN PDEVICE_UNIT DeviceUnit, OUT PULONGLONG TotalSectors, OUT PULONG SectorSize)
Definition: hwide.c:474
#define READ_TOC_FORMAT_SESSION
Definition: scsi.h:178
#define IDX_IO1_i_BlockCount
Definition: hwide.h:43
#define IDX_IO1_i_CylinderLow
Definition: hwide.h:45
#define AtaWritePort(Channel, Port, Data)
Definition: hwide.c:26
static VOID SelectDevice(IN UCHAR Channel, IN UCHAR DeviceNumber)
Definition: hwide.c:735
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
unsigned char UCHAR
Definition: xmlstorage.h:181
#define IDX_ATAPI_IO1_o_ByteCountLow
Definition: hwide.h:100
Status
Definition: gdiplustypes.h:24
#define WRITE_PORT_UCHAR(p, d)
Definition: pc98vid.h:20
#define MAXIMUM_CDROM_SIZE
Definition: hwide.h:288
#define IDX_IO1_i_BlockNumber
Definition: hwide.h:44
static BOOLEAN WaitForBusy(IN UCHAR Channel, IN ULONG Timeout)
Definition: hwide.c:704
#define AtaWriteBuffer(Channel, Buffer, Count)
Definition: hwide.c:32
#define TAG_ATA_DEVICE
Definition: hwide.c:22
ULONG SectorCount
Definition: part_xbox.c:31
static BOOLEAN AtaReadLogicalSectorsLBA(IN PDEVICE_UNIT DeviceUnit, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: hwide.c:252
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _In_ LARGE_INTEGER ByteCount
Definition: iotypes.h:1081
#define IDX_IO1_o_CylinderLow
Definition: hwide.h:57
#define IDE_STATUS_BUSY
Definition: hwide.h:119
#define ERR(fmt,...)
Definition: debug.h:110
#define SCSI_SENSEQ_INIT_COMMAND_REQUIRED
Definition: cdrw_hw.h:1314
#define ATA_DEVICE_ATAPI
Definition: hwide.h:303
#define IDE_DRIVE_SELECT_1
Definition: hwide.h:130
#define IDE_DC_DISABLE_INTERRUPTS
Definition: hwide.h:138
static ULONG Timeout
Definition: ping.c:61
#define IDX_IO1_o_BlockCount
Definition: hwide.h:55
#define IDX_ATAPI_IO1_i_Status
Definition: hwide.h:94
_In_ USHORT PacketSize
Definition: iofuncs.h:1056
#define IDE_DRIVE_1
Definition: hwide.h:128
unsigned short USHORT
Definition: pedump.c:61
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
static BOOLEAN AtapiReadyCheck(IN OUT PDEVICE_UNIT DeviceUnit)
Definition: hwide.c:554
#define UCHAR_MAX
Definition: limits.h:25
#define IDX_IO1_o_Command
Definition: hwide.h:60
#define DbgDumpBuffer(mask, buf, len)
Definition: debug.h:119
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
static const ULONG BaseArray[]
Definition: hwide.c:41
#define IDE_STATUS_DRDY
Definition: hwide.h:117
static BOOLEAN WaitForFlagsOr(IN UCHAR Channel, IN UCHAR FirstValue, IN UCHAR SecondValue, IN ULONG Timeout)
Definition: hwide.c:677
#define SCSIOP_READ_CAPACITY
Definition: cdrw_hw.h:904
#define IDX_ATAPI_IO1_i_ByteCountLow
Definition: hwide.h:91
#define MAX_CHANNELS
Definition: hwide.c:52
PDEVICE_UNIT AtaGetDevice(IN UCHAR UnitNumber)
Definition: hwide.c:178
#define OUT
Definition: typedefs.h:40
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:384
#define DPRINT_DISK
Definition: debug.h:29
#define IDX_IO1_i_Error
Definition: hwide.h:42
#define IDE_DC_RESET_CONTROLLER
Definition: hwide.h:139
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IDE_DRIVE_2
Definition: hwide.h:129
#define SCSIOP_REQUEST_SENSE
Definition: cdrw_hw.h:870
#define IDE_COMMAND_ATAPI_PACKET
Definition: atapi.h:109
static BOOLEAN WaitForFlags(IN UCHAR Channel, IN UCHAR Flags, IN UCHAR ExpectedValue, IN ULONG Timeout)
Definition: hwide.c:650
_In_ ULONG SectorSize
Definition: halfuncs.h:291
_In_ PCHAR _In_ ULONG DeviceNumber
Definition: classpnp.h:1229
UCHAR AdditionalSenseCode
Definition: cdrw_hw.h:1175
#define IDE_STATUS_DRQ
Definition: hwide.h:113
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4751
#define IDX_IO1_i_Status
Definition: hwide.h:48
static VOID AtaHardReset(IN UCHAR Channel)
Definition: hwide.c:722
#define IDX_IO1_i_CylinderHigh
Definition: hwide.h:46
#define MAX_DEVICES
Definition: hwide.c:53
#define IDE_DRIVE_SELECT_2
Definition: hwide.h:131
FORCEINLINE VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: mm.h:186