LegacyIde.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /** @file
  2. Collect IDE information from Native EFI Driver
  3. Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "LegacyBiosInterface.h"
  7. BOOLEAN mIdeDataBuiltFlag = FALSE;
  8. /**
  9. Collect IDE Inquiry data from the IDE disks
  10. @param Private Legacy BIOS Instance data
  11. @param HddInfo Hdd Information
  12. @param Flag Reconnect IdeController or not
  13. @retval EFI_SUCCESS It should always work.
  14. **/
  15. EFI_STATUS
  16. LegacyBiosBuildIdeData (
  17. IN LEGACY_BIOS_INSTANCE *Private,
  18. IN HDD_INFO **HddInfo,
  19. IN UINT16 Flag
  20. )
  21. {
  22. EFI_STATUS Status;
  23. EFI_HANDLE IdeController;
  24. UINTN HandleCount;
  25. EFI_HANDLE *HandleBuffer;
  26. UINTN Index;
  27. EFI_DISK_INFO_PROTOCOL *DiskInfo;
  28. UINT32 IdeChannel;
  29. UINT32 IdeDevice;
  30. UINT32 Size;
  31. UINT8 *InquiryData;
  32. UINT32 InquiryDataSize;
  33. HDD_INFO *LocalHddInfo;
  34. UINT32 PciIndex;
  35. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  36. EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
  37. EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
  38. PCI_DEVICE_PATH *PciDevicePath;
  39. //
  40. // Only build data once
  41. // We have a problem with GetBbsInfo in that it can be invoked two
  42. // places. Once in BDS, when all EFI drivers are connected and once in
  43. // LegacyBoot after all EFI drivers are disconnected causing this routine
  44. // to hang. In LegacyBoot this function is also called before EFI drivers
  45. // are disconnected.
  46. // Cases covered
  47. // GetBbsInfo invoked in BDS. Both invocations in LegacyBoot ignored.
  48. // GetBbsInfo not invoked in BDS. First invocation of this function
  49. // proceeds normally and second via GetBbsInfo ignored.
  50. //
  51. PciDevicePath = NULL;
  52. LocalHddInfo = *HddInfo;
  53. Status = Private->LegacyBiosPlatform->GetPlatformHandle (
  54. Private->LegacyBiosPlatform,
  55. EfiGetPlatformIdeHandle,
  56. 0,
  57. &HandleBuffer,
  58. &HandleCount,
  59. (VOID *)&LocalHddInfo
  60. );
  61. if (!EFI_ERROR (Status)) {
  62. IdeController = HandleBuffer[0];
  63. //
  64. // Force IDE drive spin up!
  65. //
  66. if (Flag != 0) {
  67. gBS->DisconnectController (
  68. IdeController,
  69. NULL,
  70. NULL
  71. );
  72. }
  73. gBS->ConnectController (IdeController, NULL, NULL, FALSE);
  74. //
  75. // Do GetIdeHandle twice since disconnect/reconnect will switch to native mode
  76. // And GetIdeHandle will switch to Legacy mode, if required.
  77. //
  78. Private->LegacyBiosPlatform->GetPlatformHandle (
  79. Private->LegacyBiosPlatform,
  80. EfiGetPlatformIdeHandle,
  81. 0,
  82. &HandleBuffer,
  83. &HandleCount,
  84. (VOID *)&LocalHddInfo
  85. );
  86. }
  87. mIdeDataBuiltFlag = TRUE;
  88. //
  89. // Get Identity command from all drives
  90. //
  91. gBS->LocateHandleBuffer (
  92. ByProtocol,
  93. &gEfiDiskInfoProtocolGuid,
  94. NULL,
  95. &HandleCount,
  96. &HandleBuffer
  97. );
  98. Private->IdeDriveCount = (UINT8)HandleCount;
  99. for (Index = 0; Index < HandleCount; Index++) {
  100. Status = gBS->HandleProtocol (
  101. HandleBuffer[Index],
  102. &gEfiDiskInfoProtocolGuid,
  103. (VOID **)&DiskInfo
  104. );
  105. ASSERT_EFI_ERROR (Status);
  106. if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
  107. //
  108. // Locate which PCI device
  109. //
  110. Status = gBS->HandleProtocol (
  111. HandleBuffer[Index],
  112. &gEfiDevicePathProtocolGuid,
  113. (VOID *)&DevicePath
  114. );
  115. ASSERT_EFI_ERROR (Status);
  116. DevicePathNode = DevicePath;
  117. while (!IsDevicePathEnd (DevicePathNode)) {
  118. TempDevicePathNode = NextDevicePathNode (DevicePathNode);
  119. if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
  120. (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
  121. (DevicePathType (TempDevicePathNode) == MESSAGING_DEVICE_PATH) &&
  122. (DevicePathSubType (TempDevicePathNode) == MSG_ATAPI_DP))
  123. {
  124. PciDevicePath = (PCI_DEVICE_PATH *)DevicePathNode;
  125. break;
  126. }
  127. DevicePathNode = NextDevicePathNode (DevicePathNode);
  128. }
  129. if (PciDevicePath == NULL) {
  130. continue;
  131. }
  132. //
  133. // Find start of PCI device in HddInfo. The assumption of the data
  134. // structure is 2 controllers(channels) per PCI device and each
  135. // controller can have 2 drives(devices).
  136. // HddInfo[PciIndex+0].[0] = Channel[0].Device[0] Primary Master
  137. // HddInfo[PciIndex+0].[1] = Channel[0].Device[1] Primary Slave
  138. // HddInfo[PciIndex+1].[0] = Channel[1].Device[0] Secondary Master
  139. // HddInfo[PciIndex+1].[1] = Channel[1].Device[1] Secondary Slave
  140. // @bug eventually need to pass in max number of entries
  141. // for end of for loop
  142. //
  143. for (PciIndex = 0; PciIndex < 8; PciIndex++) {
  144. if ((PciDevicePath->Device == LocalHddInfo[PciIndex].Device) &&
  145. (PciDevicePath->Function == LocalHddInfo[PciIndex].Function)
  146. )
  147. {
  148. break;
  149. }
  150. }
  151. if (PciIndex == 8) {
  152. continue;
  153. }
  154. Status = DiskInfo->WhichIde (DiskInfo, &IdeChannel, &IdeDevice);
  155. if (!EFI_ERROR (Status)) {
  156. Size = sizeof (ATAPI_IDENTIFY);
  157. DiskInfo->Identify (
  158. DiskInfo,
  159. &LocalHddInfo[PciIndex + IdeChannel].IdentifyDrive[IdeDevice],
  160. &Size
  161. );
  162. if (IdeChannel == 0) {
  163. LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_PRIMARY;
  164. } else if (IdeChannel == 1) {
  165. LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SECONDARY;
  166. }
  167. InquiryData = NULL;
  168. InquiryDataSize = 0;
  169. Status = DiskInfo->Inquiry (
  170. DiskInfo,
  171. NULL,
  172. &InquiryDataSize
  173. );
  174. if (Status == EFI_BUFFER_TOO_SMALL) {
  175. InquiryData = (UINT8 *)AllocatePool (
  176. InquiryDataSize
  177. );
  178. if (InquiryData != NULL) {
  179. Status = DiskInfo->Inquiry (
  180. DiskInfo,
  181. InquiryData,
  182. &InquiryDataSize
  183. );
  184. }
  185. } else {
  186. Status = EFI_DEVICE_ERROR;
  187. }
  188. //
  189. // If ATAPI device then Inquiry will pass and ATA fail.
  190. //
  191. if (!EFI_ERROR (Status)) {
  192. ASSERT (InquiryData != NULL);
  193. //
  194. // If IdeDevice = 0 then set master bit, else slave bit
  195. //
  196. if (IdeDevice == 0) {
  197. if ((InquiryData[0] & 0x1f) == 0x05) {
  198. LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_CDROM;
  199. } else if ((InquiryData[0] & 0x1f) == 0x00) {
  200. LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_ZIPDISK;
  201. }
  202. } else {
  203. if ((InquiryData[0] & 0x1f) == 0x05) {
  204. LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_CDROM;
  205. } else if ((InquiryData[0] & 0x1f) == 0x00) {
  206. LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_ZIPDISK;
  207. }
  208. }
  209. FreePool (InquiryData);
  210. } else {
  211. if (IdeDevice == 0) {
  212. LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_IDE;
  213. } else {
  214. LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_IDE;
  215. }
  216. }
  217. }
  218. }
  219. }
  220. if (HandleBuffer != NULL) {
  221. FreePool (HandleBuffer);
  222. }
  223. return EFI_SUCCESS;
  224. }
  225. /**
  226. If the IDE channel is in compatibility (legacy) mode, remove all
  227. PCI I/O BAR addresses from the controller.
  228. @param IdeController The handle of target IDE controller
  229. **/
  230. VOID
  231. InitLegacyIdeController (
  232. IN EFI_HANDLE IdeController
  233. )
  234. {
  235. EFI_PCI_IO_PROTOCOL *PciIo;
  236. UINT32 IOBarClear;
  237. EFI_STATUS Status;
  238. PCI_TYPE00 PciData;
  239. //
  240. // If the IDE channel is in compatibility (legacy) mode, remove all
  241. // PCI I/O BAR addresses from the controller. Some software gets
  242. // confused if an IDE controller is in compatibility (legacy) mode
  243. // and has PCI I/O resources allocated
  244. //
  245. Status = gBS->HandleProtocol (
  246. IdeController,
  247. &gEfiPciIoProtocolGuid,
  248. (VOID **)&PciIo
  249. );
  250. if (EFI_ERROR (Status)) {
  251. return;
  252. }
  253. Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (PciData), &PciData);
  254. if (EFI_ERROR (Status)) {
  255. return;
  256. }
  257. //
  258. // Check whether this is IDE
  259. //
  260. if ((PciData.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE) ||
  261. (PciData.Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE))
  262. {
  263. return;
  264. }
  265. //
  266. // Clear bar for legacy IDE
  267. //
  268. IOBarClear = 0x00;
  269. if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_PNE) == 0) {
  270. PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x10, 1, &IOBarClear);
  271. PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x14, 1, &IOBarClear);
  272. }
  273. if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_SNE) == 0) {
  274. PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x18, 1, &IOBarClear);
  275. PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1C, 1, &IOBarClear);
  276. }
  277. return;
  278. }